From 64a0667947297bf8fe4574b326e0bb7bae029c63 Mon Sep 17 00:00:00 2001 From: Gunnar Skjold Date: Sun, 15 Mar 2026 09:31:59 +0100 Subject: [PATCH 1/2] Added workflow to attach firmware in PR (#1160) * Added PR workflow that creates a comment with firmware zip * Fixed URL * Show version in comment --- .github/workflows/pr-build-env.yml | 81 +++++++++++++++++++++ .github/workflows/pull-request.yml | 110 +++++++++++++++++++++++++++++ 2 files changed, 191 insertions(+) create mode 100644 .github/workflows/pr-build-env.yml create mode 100644 .github/workflows/pull-request.yml diff --git a/.github/workflows/pr-build-env.yml b/.github/workflows/pr-build-env.yml new file mode 100644 index 00000000..a38d153e --- /dev/null +++ b/.github/workflows/pr-build-env.yml @@ -0,0 +1,81 @@ +name: PR build with env + +on: + workflow_call: + inputs: + env: + description: 'The environment to build for' + required: true + type: string + is_esp32: + description: 'Whether the build is for ESP32 based firmware' + required: false + type: boolean + default: true + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Check out code from repo + uses: actions/checkout@v4 + + - name: Cache Python dependencies + uses: actions/cache@v4 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('platformio.ini') }} + + - name: Cache PlatformIO dependencies + uses: actions/cache@v4 + with: + path: ~/.pio/libdeps + key: ${{ runner.os }}-pio-${{ hashFiles('platformio.ini') }} + + - name: Set up Python 3.9 + uses: actions/setup-python@v5 + with: + python-version: 3.9 + + - name: Inject secrets into ini file + run: | + sed -i 's/NO_AMS2MQTT_PRICE_KEY/AMS2MQTT_PRICE_KEY="${{secrets.AMS2MQTT_PRICE_KEY}}"/g' platformio.ini + sed -i 's/NO_AMS2MQTT_PRICE_AUTHENTICATION/AMS2MQTT_PRICE_AUTHENTICATION="${{secrets.AMS2MQTT_PRICE_AUTHENTICATION}}"/g' platformio.ini + sed -i 's/NO_AMS2MQTT_SC_KEY/AMS2MQTT_SC_KEY=\\"${{secrets.AMS2MQTT_SC_KEY}}\\"/g' platformio.ini + sed -i 's/NO_ENERGY_SPEEDOMETER_USER/ENERGY_SPEEDOMETER_USER=\\"${{secrets.ENERGY_SPEEDOMETER_USER}}\\"/g' platformio.ini + sed -i 's/NO_ENERGY_SPEEDOMETER_PASS/ENERGY_SPEEDOMETER_PASS=\\"${{secrets.ENERGY_SPEEDOMETER_PASS}}\\"/g' platformio.ini + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -U platformio css_html_js_minify + + - name: Set up node + uses: actions/setup-node@v4 + with: + node-version: '19.x' + + - name: Build with node + run: | + cd lib/SvelteUi/app + npm ci + npm run build + cd - + env: + CI: false + + - name: PlatformIO lib install + run: pio lib install + + - name: Build firmware + run: pio run -e ${{ inputs.env }} + + - name: Create zip file + run: /bin/sh scripts/${{ inputs.env }}/mkzip.sh + + - name: Upload zip as artifact + uses: actions/upload-artifact@v4 + with: + name: ${{ inputs.env }} + path: ${{ inputs.env }}.zip + retention-days: 7 diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml new file mode 100644 index 00000000..eac3399b --- /dev/null +++ b/.github/workflows/pull-request.yml @@ -0,0 +1,110 @@ +name: Pull Request build + +on: + pull_request: + types: [opened, synchronize, reopened] + +jobs: + build-esp32s2: + uses: ./.github/workflows/pr-build-env.yml + secrets: inherit + with: + env: esp32s2 + is_esp32: true + + build-esp32s3: + uses: ./.github/workflows/pr-build-env.yml + secrets: inherit + with: + env: esp32s3 + is_esp32: true + + build-esp32c3: + uses: ./.github/workflows/pr-build-env.yml + secrets: inherit + with: + env: esp32c3 + is_esp32: true + + build-esp32: + uses: ./.github/workflows/pr-build-env.yml + secrets: inherit + with: + env: esp32 + is_esp32: true + + build-esp32solo: + uses: ./.github/workflows/pr-build-env.yml + secrets: inherit + with: + env: esp32solo + is_esp32: true + + build-esp8266: + uses: ./.github/workflows/pr-build-env.yml + secrets: inherit + with: + env: esp8266 + is_esp32: false + + comment: + needs: + - build-esp32s2 + - build-esp32s3 + - build-esp32c3 + - build-esp32 + - build-esp32solo + - build-esp8266 + runs-on: ubuntu-latest + permissions: + pull-requests: write + steps: + - name: Post PR comment with download links + uses: actions/github-script@v7 + with: + script: | + const { owner, repo } = context.repo; + const prNumber = context.payload.pull_request.number; + const runId = context.runId; + const runUrl = `https://github.com/${owner}/${repo}/actions/runs/${runId}`; + + // Get the commit SHA (short version) + const sha = context.payload.pull_request.head.sha; + const shortSha = sha.substring(0, 7); + + // Fetch the list of artifacts for this run via the API + const artifactsResp = await github.rest.actions.listWorkflowRunArtifacts({ owner, repo, run_id: runId }); + const artifacts = artifactsResp.data.artifacts; + + const envs = ['esp32s2', 'esp32s3', 'esp32c3', 'esp32', 'esp32solo', 'esp8266']; + const lines = envs.map(env => { + const artifact = artifacts.find(a => a.name === env); + if (artifact) { + // The artifact download page URL - directly navigable in the browser + const artifactUrl = `${runUrl}#artifacts-${env}`; + return `- **${env}**: [Download ${env}.zip](https://github.com/${owner}/${repo}/actions/runs/${runId}/artifacts/${artifact.id})`; + } + return `- **${env}**: ⚠️ artifact not found`; + }); + + const body = [ + '## 🔧 PR Build Artifacts', + '', + `**Version**: \`${shortSha}\``, + '', + 'All environments built successfully. Download the zip files:', + '', + ...lines, + '', + `> Artifacts expire after 7 days. [View workflow run](${runUrl})`, + ].join('\n'); + + // Find and delete any previous bot comment to keep the PR clean + const comments = await github.rest.issues.listComments({ owner, repo, issue_number: prNumber }); + for (const comment of comments.data) { + if (comment.user.type === 'Bot' && comment.body.includes('PR Build Artifacts')) { + await github.rest.issues.deleteComment({ owner, repo, comment_id: comment.id }); + } + } + + await github.rest.issues.createComment({ owner, repo, issue_number: prNumber, body }); From 13aff62aff001f6ff9115526999e61f798ca6e65 Mon Sep 17 00:00:00 2001 From: Gunnar Skjold Date: Sun, 15 Mar 2026 10:07:45 +0100 Subject: [PATCH 2/2] Fixed PR workflow double zipping (#1162) * Added .zip extension to avoid double zipping * Fixed double zip --- .github/workflows/pr-build-env.yml | 5 +++-- .github/workflows/pull-request.yml | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pr-build-env.yml b/.github/workflows/pr-build-env.yml index a38d153e..d229972c 100644 --- a/.github/workflows/pr-build-env.yml +++ b/.github/workflows/pr-build-env.yml @@ -74,8 +74,9 @@ jobs: run: /bin/sh scripts/${{ inputs.env }}/mkzip.sh - name: Upload zip as artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: - name: ${{ inputs.env }} + name: ${{ inputs.env }}.zip path: ${{ inputs.env }}.zip + archive: false retention-days: 7 diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index eac3399b..dd212e81 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -78,7 +78,7 @@ jobs: const envs = ['esp32s2', 'esp32s3', 'esp32c3', 'esp32', 'esp32solo', 'esp8266']; const lines = envs.map(env => { - const artifact = artifacts.find(a => a.name === env); + const artifact = artifacts.find(a => a.name === `${env}.zip`); if (artifact) { // The artifact download page URL - directly navigable in the browser const artifactUrl = `${runUrl}#artifacts-${env}`;