Skip to content

Commit d3ce8bb

Browse files
committed
ci: build release targets from a shared matrix manifest
Replace the ten copy-pasted per-target build blocks in release.yml with a single matrix job driven by .github/firmware-targets.json, shared with main.yaml so CI and release cannot disagree about the target list. The duplication had already drifted twice: - esp32-c3-N4 merged images were built with --chip esp32-c6 - esp32-N4 was built in CI but never released Also: cache pip/platformio, pin the toolchain (Core, esptool, nrfutil, intelhex, uf2conv) so a tag rebuilds identically, add permissions and timeouts, and gate asset upload on every target succeeding so a failed build can no longer leave a release with a partial asset set. Includes release-legacy.yml (arm A) for the A/B verification; temporary.
1 parent 5202d58 commit d3ce8bb

4 files changed

Lines changed: 557 additions & 175 deletions

File tree

‎.github/firmware-targets.json‎

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
{
2+
"$comment": [
3+
"Single source of truth for the firmware build targets.",
4+
"Consumed by both .github/workflows/main.yaml (CI) and .github/workflows/release.yml",
5+
"(release artifacts) via fromJSON, so the two can never disagree about which targets",
6+
"exist or how they are packaged.",
7+
"",
8+
"Adding a board = adding an entry here. Nothing else needs to change.",
9+
"",
10+
"Fields (esp32 family):",
11+
" chip - esptool --chip value. NOT derivable from the env name.",
12+
" flash_size - esptool --flash_size; matches board_upload.flash_size in platformio.ini.",
13+
" flash_mode/freq - baked into the merged image header by esptool merge_bin.",
14+
" bootloader_offset - 0x0000 on S3/C3/C6; 0x1000 on the classic ESP32.",
15+
"",
16+
"Debug-only envs in platformio.ini (e.g. esp32-s3-N16R8-extuart-debug) are deliberately",
17+
"absent: this file lists what ships."
18+
],
19+
"targets": [
20+
{
21+
"env": "nrf52840custom",
22+
"family": "nrf52"
23+
},
24+
{
25+
"env": "esp32-s3-N16R8",
26+
"family": "esp32",
27+
"chip": "esp32-s3",
28+
"flash_size": "16MB",
29+
"flash_mode": "dio",
30+
"flash_freq": "80m",
31+
"bootloader_offset": "0x0000"
32+
},
33+
{
34+
"env": "esp32-s3-N16R8-extuart",
35+
"family": "esp32",
36+
"chip": "esp32-s3",
37+
"flash_size": "16MB",
38+
"flash_mode": "dio",
39+
"flash_freq": "80m",
40+
"bootloader_offset": "0x0000"
41+
},
42+
{
43+
"env": "esp32-s3-N8R8",
44+
"family": "esp32",
45+
"chip": "esp32-s3",
46+
"flash_size": "8MB",
47+
"flash_mode": "dio",
48+
"flash_freq": "80m",
49+
"bootloader_offset": "0x0000"
50+
},
51+
{
52+
"env": "esp32-s3-N32R8",
53+
"family": "esp32",
54+
"chip": "esp32-s3",
55+
"flash_size": "32MB",
56+
"flash_mode": "dio",
57+
"flash_freq": "80m",
58+
"bootloader_offset": "0x0000"
59+
},
60+
{
61+
"env": "esp32-s3-N32R8-extuart",
62+
"family": "esp32",
63+
"chip": "esp32-s3",
64+
"flash_size": "32MB",
65+
"flash_mode": "dio",
66+
"flash_freq": "80m",
67+
"bootloader_offset": "0x0000"
68+
},
69+
{
70+
"env": "esp32-s3-E1004",
71+
"family": "esp32",
72+
"chip": "esp32-s3",
73+
"flash_size": "32MB",
74+
"flash_mode": "dio",
75+
"flash_freq": "80m",
76+
"bootloader_offset": "0x0000"
77+
},
78+
{
79+
"env": "esp32-c6-N4",
80+
"family": "esp32",
81+
"chip": "esp32-c6",
82+
"flash_size": "4MB",
83+
"flash_mode": "dio",
84+
"flash_freq": "80m",
85+
"bootloader_offset": "0x0000"
86+
},
87+
{
88+
"env": "esp32-c3-N4",
89+
"family": "esp32",
90+
"chip": "esp32-c3",
91+
"flash_size": "4MB",
92+
"flash_mode": "dio",
93+
"flash_freq": "80m",
94+
"bootloader_offset": "0x0000"
95+
},
96+
{
97+
"env": "esp32-c3-N16",
98+
"family": "esp32",
99+
"chip": "esp32-c3",
100+
"flash_size": "16MB",
101+
"flash_mode": "dio",
102+
"flash_freq": "80m",
103+
"bootloader_offset": "0x0000"
104+
},
105+
{
106+
"env": "esp32-N4",
107+
"family": "esp32",
108+
"chip": "esp32",
109+
"flash_size": "4MB",
110+
"flash_mode": "dio",
111+
"flash_freq": "40m",
112+
"bootloader_offset": "0x1000"
113+
}
114+
]
115+
}

‎.github/workflows/main.yaml‎

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,36 @@ on:
44
push:
55
pull_request:
66

7+
permissions:
8+
contents: read
9+
710
jobs:
11+
# The environment list lives in .github/firmware-targets.json, shared with
12+
# release.yml. Keeping one list means CI can't build a target the release
13+
# forgets to ship (which is how esp32-N4 went unreleased) or vice versa.
14+
targets:
15+
name: Load targets
16+
runs-on: ubuntu-latest
17+
timeout-minutes: 5
18+
outputs:
19+
environments: ${{ steps.load.outputs.environments }}
20+
steps:
21+
- uses: actions/checkout@v4
22+
- id: load
23+
run: |
24+
set -euo pipefail
25+
envs=$(jq -c '[.targets[].env]' .github/firmware-targets.json)
26+
echo "environments=${envs}" >> "${GITHUB_OUTPUT}"
27+
echo "Building: $(echo "${envs}" | jq -r 'join(", ")')"
28+
829
build:
30+
needs: targets
931
runs-on: ubuntu-latest
32+
timeout-minutes: 30
1033
strategy:
1134
fail-fast: false
1235
matrix:
13-
environment:
14-
- nrf52840custom
15-
- esp32-s3-N16R8
16-
- esp32-s3-N8R8
17-
- esp32-s3-N32R8
18-
- esp32-s3-N32R8-extuart
19-
- esp32-s3-N16R8-extuart
20-
- esp32-s3-E1004
21-
- esp32-c3-N4
22-
- esp32-c3-N16
23-
- esp32-c6-N4
24-
- esp32-N4
36+
environment: ${{ fromJSON(needs.targets.outputs.environments) }}
2537

2638
steps:
2739
- uses: actions/checkout@v4
@@ -37,8 +49,13 @@ jobs:
3749
- uses: actions/setup-python@v5
3850
with:
3951
python-version: '3.11'
52+
# Pinned to the same Core version release.yml uses. Unpinned here, CI can
53+
# pass on a different Core than the one that builds the release — the
54+
# exact split that broke the C3/C6 builds when the ESP platform was
55+
# floating on `stable` (see the 55.03.39 pin in platformio.ini).
56+
# Bump deliberately, together with release.yml.
4057
- name: Install PlatformIO Core
41-
run: pip install --upgrade platformio
58+
run: pip install platformio==6.1.19
4259

4360
- name: Build ${{ matrix.environment }}
4461
run: platformio run --environment ${{ matrix.environment }}
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
# ARM A of the Phase A A/B test — TEMPORARY, delete before merging.
2+
#
3+
# This is release.yml exactly as it stands on OpenDisplay/Firmware @ 2.25.1,
4+
# with three mechanical changes so it can be dispatched against the same source
5+
# and the same version string as the new matrix workflow:
6+
# 1. workflow_dispatch(tag) instead of only release:published
7+
# 2. checkout pinned to that tag
8+
# 3. BUILD_VERSION from that tag instead of github.ref_name
9+
# (github.ref_name would be the branch under dispatch, which would bake a
10+
# different version string into the binaries and invalidate the diff)
11+
# Nothing else is touched — no pins, no caching, no chip/flash parameters.
12+
name: Release Firmware (legacy, A/B arm A)
13+
14+
on:
15+
workflow_dispatch:
16+
inputs:
17+
tag:
18+
description: "Tag to build"
19+
required: true
20+
type: string
21+
22+
jobs:
23+
build-and-upload:
24+
name: Build & Upload Firmware
25+
runs-on: ubuntu-latest
26+
27+
steps:
28+
- name: Checkout Code
29+
uses: actions/checkout@v4
30+
with:
31+
ref: ${{ inputs.tag }}
32+
33+
- name: Install PlatformIO & Tools
34+
run: |
35+
python -m pip install --upgrade pip
36+
pip install platformio
37+
pip install esptool
38+
pip install --upgrade intelhex
39+
pip install adafruit-nrfutil
40+
curl -L https://raw.githubusercontent.com/microsoft/uf2/master/utils/uf2conv.py -o uf2conv.py
41+
curl -L https://raw.githubusercontent.com/microsoft/uf2/master/utils/uf2families.json -o uf2families.json
42+
chmod +x uf2conv.py
43+
44+
- name: Build & Package NRF Firmware
45+
run: |
46+
export PLATFORMIO_BUILD_FLAGS="-D BUILD_VERSION=\"${{ inputs.tag }}\" -D SHA=$GITHUB_SHA"
47+
pio run --environment nrf52840custom
48+
mkdir firmware_output
49+
cp .pio/build/nrf52840custom/firmware.hex firmware_output/NRF52840.hex
50+
TAG_NAME=${{ inputs.tag }}
51+
adafruit-nrfutil dfu genpkg --dev-type 0x0052 --application firmware_output/NRF52840.hex firmware_output/NRF52840.zip
52+
python uf2conv.py firmware_output/NRF52840.hex --family 0xADA52840 --output firmware_output/NRF52840.uf2
53+
54+
- name: Build & Package esp32-s3-N16R8 Firmware
55+
run: |
56+
export PLATFORMIO_BUILD_FLAGS="-D BUILD_VERSION=\"${{ inputs.tag }}\" -D SHA=$GITHUB_SHA"
57+
pioenv=esp32-s3-N16R8
58+
pio run --environment ${pioenv}
59+
mkdir ${pioenv}
60+
cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin ${pioenv}/boot_app0.bin
61+
cp .pio/build/${pioenv}/firmware.bin ${pioenv}/firmware.bin
62+
cp .pio/build/${pioenv}/bootloader.bin ${pioenv}/bootloader.bin
63+
cp .pio/build/${pioenv}/partitions.bin ${pioenv}/partitions.bin
64+
cd ${pioenv}
65+
esptool.py --chip esp32-s3 merge_bin -o merged-firmware.bin --flash_mode dio --flash_freq 80m --flash_size 16MB 0x0000 bootloader.bin 0x8000 partitions.bin 0xe000 boot_app0.bin 0x10000 firmware.bin
66+
cd ..
67+
cp ${pioenv}/firmware.bin firmware_output/${pioenv}.bin
68+
cp ${pioenv}/merged-firmware.bin firmware_output/${pioenv}_full.bin
69+
70+
- name: Build & Package esp32-s3-N16R8-extuart Firmware
71+
run: |
72+
export PLATFORMIO_BUILD_FLAGS="-D BUILD_VERSION=\"${{ inputs.tag }}\" -D SHA=$GITHUB_SHA"
73+
pioenv=esp32-s3-N16R8-extuart
74+
pio run --environment ${pioenv}
75+
mkdir ${pioenv}
76+
cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin ${pioenv}/boot_app0.bin
77+
cp .pio/build/${pioenv}/firmware.bin ${pioenv}/firmware.bin
78+
cp .pio/build/${pioenv}/bootloader.bin ${pioenv}/bootloader.bin
79+
cp .pio/build/${pioenv}/partitions.bin ${pioenv}/partitions.bin
80+
cd ${pioenv}
81+
esptool.py --chip esp32-s3 merge_bin -o merged-firmware.bin --flash_mode dio --flash_freq 80m --flash_size 16MB 0x0000 bootloader.bin 0x8000 partitions.bin 0xe000 boot_app0.bin 0x10000 firmware.bin
82+
cd ..
83+
cp ${pioenv}/firmware.bin firmware_output/${pioenv}.bin
84+
cp ${pioenv}/merged-firmware.bin firmware_output/${pioenv}_full.bin
85+
86+
- name: Build & Package esp32-s3-N8R8 Firmware
87+
run: |
88+
export PLATFORMIO_BUILD_FLAGS="-D BUILD_VERSION=\"${{ inputs.tag }}\" -D SHA=$GITHUB_SHA"
89+
pioenv=esp32-s3-N8R8
90+
pio run --environment ${pioenv}
91+
mkdir ${pioenv}
92+
cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin ${pioenv}/boot_app0.bin
93+
cp .pio/build/${pioenv}/firmware.bin ${pioenv}/firmware.bin
94+
cp .pio/build/${pioenv}/bootloader.bin ${pioenv}/bootloader.bin
95+
cp .pio/build/${pioenv}/partitions.bin ${pioenv}/partitions.bin
96+
cd ${pioenv}
97+
esptool.py --chip esp32-s3 merge_bin -o merged-firmware.bin --flash_mode dio --flash_freq 80m --flash_size 8MB 0x0000 bootloader.bin 0x8000 partitions.bin 0xe000 boot_app0.bin 0x10000 firmware.bin
98+
cd ..
99+
cp ${pioenv}/firmware.bin firmware_output/${pioenv}.bin
100+
cp ${pioenv}/merged-firmware.bin firmware_output/${pioenv}_full.bin
101+
102+
- name: Build & Package esp32-s3-N32R8 Firmware
103+
run: |
104+
export PLATFORMIO_BUILD_FLAGS="-D BUILD_VERSION=\"${{ inputs.tag }}\" -D SHA=$GITHUB_SHA"
105+
pioenv=esp32-s3-N32R8
106+
pio run --environment ${pioenv}
107+
mkdir ${pioenv}
108+
cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin ${pioenv}/boot_app0.bin
109+
cp .pio/build/${pioenv}/firmware.bin ${pioenv}/firmware.bin
110+
cp .pio/build/${pioenv}/bootloader.bin ${pioenv}/bootloader.bin
111+
cp .pio/build/${pioenv}/partitions.bin ${pioenv}/partitions.bin
112+
cd ${pioenv}
113+
esptool.py --chip esp32-s3 merge_bin -o merged-firmware.bin --flash_mode dio --flash_freq 80m --flash_size 32MB 0x0000 bootloader.bin 0x8000 partitions.bin 0xe000 boot_app0.bin 0x10000 firmware.bin
114+
cd ..
115+
cp ${pioenv}/firmware.bin firmware_output/${pioenv}.bin
116+
cp ${pioenv}/merged-firmware.bin firmware_output/${pioenv}_full.bin
117+
118+
- name: Build & Package esp32-s3-N32R8-extuart Firmware
119+
run: |
120+
export PLATFORMIO_BUILD_FLAGS="-D BUILD_VERSION=\"${{ inputs.tag }}\" -D SHA=$GITHUB_SHA"
121+
pioenv=esp32-s3-N32R8-extuart
122+
pio run --environment ${pioenv}
123+
mkdir ${pioenv}
124+
cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin ${pioenv}/boot_app0.bin
125+
cp .pio/build/${pioenv}/firmware.bin ${pioenv}/firmware.bin
126+
cp .pio/build/${pioenv}/bootloader.bin ${pioenv}/bootloader.bin
127+
cp .pio/build/${pioenv}/partitions.bin ${pioenv}/partitions.bin
128+
cd ${pioenv}
129+
esptool.py --chip esp32-s3 merge_bin -o merged-firmware.bin --flash_mode dio --flash_freq 80m --flash_size 32MB 0x0000 bootloader.bin 0x8000 partitions.bin 0xe000 boot_app0.bin 0x10000 firmware.bin
130+
cd ..
131+
cp ${pioenv}/firmware.bin firmware_output/${pioenv}.bin
132+
cp ${pioenv}/merged-firmware.bin firmware_output/${pioenv}_full.bin
133+
134+
- name: Build & Package esp32-s3-E1004 Firmware
135+
run: |
136+
export PLATFORMIO_BUILD_FLAGS="-D BUILD_VERSION=\"${{ inputs.tag }}\" -D SHA=$GITHUB_SHA"
137+
pioenv=esp32-s3-E1004
138+
pio run --environment ${pioenv}
139+
mkdir ${pioenv}
140+
cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin ${pioenv}/boot_app0.bin
141+
cp .pio/build/${pioenv}/firmware.bin ${pioenv}/firmware.bin
142+
cp .pio/build/${pioenv}/bootloader.bin ${pioenv}/bootloader.bin
143+
cp .pio/build/${pioenv}/partitions.bin ${pioenv}/partitions.bin
144+
cd ${pioenv}
145+
esptool.py --chip esp32-s3 merge_bin -o merged-firmware.bin --flash_mode dio --flash_freq 80m --flash_size 32MB 0x0000 bootloader.bin 0x8000 partitions.bin 0xe000 boot_app0.bin 0x10000 firmware.bin
146+
cd ..
147+
cp ${pioenv}/firmware.bin firmware_output/${pioenv}.bin
148+
cp ${pioenv}/merged-firmware.bin firmware_output/${pioenv}_full.bin
149+
150+
- name: Build & Package esp32-c6-N4 Firmware
151+
run: |
152+
export PLATFORMIO_BUILD_FLAGS="-D BUILD_VERSION=\"${{ inputs.tag }}\" -D SHA=$GITHUB_SHA"
153+
pioenv=esp32-c6-N4
154+
pio run --environment ${pioenv}
155+
mkdir ${pioenv}
156+
cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin ${pioenv}/boot_app0.bin
157+
cp .pio/build/${pioenv}/firmware.bin ${pioenv}/firmware.bin
158+
cp .pio/build/${pioenv}/bootloader.bin ${pioenv}/bootloader.bin
159+
cp .pio/build/${pioenv}/partitions.bin ${pioenv}/partitions.bin
160+
cd ${pioenv}
161+
esptool.py --chip esp32-c6 merge_bin -o merged-firmware.bin --flash_mode dio --flash_freq 80m --flash_size 4MB 0x0000 bootloader.bin 0x8000 partitions.bin 0xe000 boot_app0.bin 0x10000 firmware.bin
162+
cd ..
163+
cp ${pioenv}/firmware.bin firmware_output/${pioenv}.bin
164+
cp ${pioenv}/merged-firmware.bin firmware_output/${pioenv}_full.bin
165+
166+
- name: Build & Package esp32-c3-N4 Firmware
167+
run: |
168+
export PLATFORMIO_BUILD_FLAGS="-D BUILD_VERSION=\"${{ inputs.tag }}\" -D SHA=$GITHUB_SHA"
169+
pioenv=esp32-c3-N4
170+
pio run --environment ${pioenv}
171+
mkdir ${pioenv}
172+
cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin ${pioenv}/boot_app0.bin
173+
cp .pio/build/${pioenv}/firmware.bin ${pioenv}/firmware.bin
174+
cp .pio/build/${pioenv}/bootloader.bin ${pioenv}/bootloader.bin
175+
cp .pio/build/${pioenv}/partitions.bin ${pioenv}/partitions.bin
176+
cd ${pioenv}
177+
esptool.py --chip esp32-c6 merge_bin -o merged-firmware.bin --flash_mode dio --flash_freq 80m --flash_size 4MB 0x0000 bootloader.bin 0x8000 partitions.bin 0xe000 boot_app0.bin 0x10000 firmware.bin
178+
cd ..
179+
cp ${pioenv}/firmware.bin firmware_output/${pioenv}.bin
180+
cp ${pioenv}/merged-firmware.bin firmware_output/${pioenv}_full.bin
181+
182+
- name: Build & Package esp32-c3-N16 Firmware
183+
run: |
184+
export PLATFORMIO_BUILD_FLAGS="-D BUILD_VERSION=\"${{ inputs.tag }}\" -D SHA=$GITHUB_SHA"
185+
pioenv=esp32-c3-N16
186+
pio run --environment ${pioenv}
187+
mkdir ${pioenv}
188+
cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin ${pioenv}/boot_app0.bin
189+
cp .pio/build/${pioenv}/firmware.bin ${pioenv}/firmware.bin
190+
cp .pio/build/${pioenv}/bootloader.bin ${pioenv}/bootloader.bin
191+
cp .pio/build/${pioenv}/partitions.bin ${pioenv}/partitions.bin
192+
cd ${pioenv}
193+
esptool.py --chip esp32-c3 merge_bin -o merged-firmware.bin --flash_mode dio --flash_freq 80m --flash_size 16MB 0x0000 bootloader.bin 0x8000 partitions.bin 0xe000 boot_app0.bin 0x10000 firmware.bin
194+
cd ..
195+
cp ${pioenv}/firmware.bin firmware_output/${pioenv}.bin
196+
cp ${pioenv}/merged-firmware.bin firmware_output/${pioenv}_full.bin
197+
198+
# A/B change: emit artifacts instead of publishing to a release, so arm A
199+
# produces a downloadable set to diff against arm B without touching any
200+
# release on the fork.
201+
- uses: actions/upload-artifact@v4
202+
with:
203+
name: armA-legacy
204+
path: firmware_output/*
205+
retention-days: 7
206+
if-no-files-found: error

0 commit comments

Comments
 (0)