fix(workflows): update artifact selection to exclude expired firmware size artifacts
This commit is contained in:
@@ -18,6 +18,18 @@ jobs:
|
|||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
# Per-board manifests carry the firmware's own metadata (activelySupported,
|
||||||
|
# displayName, ...) generated from each target's custom_meshtastic_* config.
|
||||||
|
- name: Download board manifests
|
||||||
|
uses: actions/download-artifact@v8
|
||||||
|
continue-on-error: true
|
||||||
|
with:
|
||||||
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run-id: ${{ github.event.workflow_run.id }}
|
||||||
|
pattern: manifest-*
|
||||||
|
path: ./manifests
|
||||||
|
merge-multiple: true
|
||||||
|
|
||||||
- name: Post or update web flasher link comment
|
- name: Post or update web flasher link comment
|
||||||
uses: actions/github-script@v8
|
uses: actions/github-script@v8
|
||||||
with:
|
with:
|
||||||
@@ -74,34 +86,52 @@ jobs:
|
|||||||
? new Date(archArtifacts[0].expires_at).toISOString().slice(0, 10)
|
? new Date(archArtifacts[0].expires_at).toISOString().slice(0, 10)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
// Per-board deep links from manifest-{platform}-{board}-{version} artifacts
|
// Read each built board's manifest (.mt.json). activelySupported,
|
||||||
const escapedVersion = version.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
// displayName and architecture come straight from the board's
|
||||||
const boardRe = new RegExp(`^manifest-([a-z0-9]+)-(.+)-${escapedVersion}$`);
|
// custom_meshtastic_* platformio config, so the list is in sync with
|
||||||
let boards = artifacts
|
// the firmware itself — no external device database needed.
|
||||||
.map((a) => boardRe.exec(a.name))
|
const fs = require('fs');
|
||||||
.filter(Boolean)
|
let boards = [];
|
||||||
.map((m) => ({ platform: m[1], board: m[2] }))
|
|
||||||
.sort((a, b) => a.board.localeCompare(b.board));
|
|
||||||
|
|
||||||
// Limit the list to devices the web flasher actively supports — the same
|
|
||||||
// activelySupported / non-portduino filter the flasher applies to its own
|
|
||||||
// device list — matching variant envs (-tft/-inkhud) to their base target.
|
|
||||||
// On a fetch failure, fall back to listing all built boards.
|
|
||||||
try {
|
try {
|
||||||
const hw = await (await fetch('https://api.meshtastic.org/resource/deviceHardware')).json();
|
boards = fs.readdirSync('./manifests')
|
||||||
const supported = new Set(
|
.filter((f) => f.endsWith('.mt.json'))
|
||||||
hw.filter((d) => d.activelySupported && !String(d.architecture || '').startsWith('portduino'))
|
.map((f) => {
|
||||||
.map((d) => d.platformioTarget),
|
try { return JSON.parse(fs.readFileSync(`./manifests/${f}`, 'utf8')); }
|
||||||
);
|
catch { return null; }
|
||||||
const baseTarget = (b) => b.replace(/-(tft|inkhud)$/, '');
|
})
|
||||||
boards = boards.filter((b) => supported.has(b.board) || supported.has(baseTarget(b.board)));
|
.filter((m) => m && m.activelySupported === true && m.platformioTarget)
|
||||||
|
.map((m) => ({
|
||||||
|
board: m.platformioTarget,
|
||||||
|
platform: m.architecture || '',
|
||||||
|
// displayName is maintainer-authored text; escape table-breaking pipes
|
||||||
|
displayName: String(m.displayName || m.platformioTarget).replace(/\|/g, '\\|'),
|
||||||
|
image: Array.isArray(m.images) && m.images[0] ? String(m.images[0]) : '',
|
||||||
|
}))
|
||||||
|
.sort((a, b) => a.board.localeCompare(b.board));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
core.warning(`Could not fetch device hardware list; listing all built boards. ${e.message}`);
|
core.warning(`Could not read board manifests: ${e.message}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const flasherUrl = `https://flasher.meshtastic.org/?pr=${prNumber}`;
|
const flasherUrl = `https://flasher.meshtastic.org/?pr=${prNumber}`;
|
||||||
|
// Device illustrations are served by the flasher from the same image
|
||||||
|
// names the manifest declares (custom_meshtastic_images). The flasher
|
||||||
|
// serves its SPA shell (HTML, 200) for unknown paths, so confirm each
|
||||||
|
// image really resolves to an image before linking it.
|
||||||
|
const imageBase = 'https://flasher.meshtastic.org/img/devices/';
|
||||||
|
await Promise.all(boards.map(async (b) => {
|
||||||
|
if (!b.image) return;
|
||||||
|
try {
|
||||||
|
const res = await fetch(`${imageBase}${encodeURIComponent(b.image)}`);
|
||||||
|
const type = res.headers.get('content-type') || '';
|
||||||
|
if (!res.ok || !type.startsWith('image/')) b.image = '';
|
||||||
|
} catch { b.image = ''; }
|
||||||
|
}));
|
||||||
|
|
||||||
const boardLines = boards
|
const boardLines = boards
|
||||||
.map((b) => `| [\`${b.board}\`](${flasherUrl}&device=${encodeURIComponent(b.board)}) | ${b.platform} |`)
|
.map((b) => {
|
||||||
|
const img = b.image ? `<img src="${imageBase}${encodeURIComponent(b.image)}" alt="" height="34">` : '';
|
||||||
|
return `| ${img} | ${b.displayName} | [\`${b.board}\`](${flasherUrl}&device=${encodeURIComponent(b.board)}) | ${b.platform} |`;
|
||||||
|
})
|
||||||
.join('\n');
|
.join('\n');
|
||||||
|
|
||||||
// Shields.io badges. Only non-user-controlled, charset-constrained values
|
// Shields.io badges. Only non-user-controlled, charset-constrained values
|
||||||
@@ -124,8 +154,8 @@ jobs:
|
|||||||
const boardTable = boards.length > 0 ? [
|
const boardTable = boards.length > 0 ? [
|
||||||
`<details><summary>Supported boards built by this PR (${boards.length})</summary>`,
|
`<details><summary>Supported boards built by this PR (${boards.length})</summary>`,
|
||||||
'',
|
'',
|
||||||
'| Board | Platform |',
|
'| | Device | Board | Platform |',
|
||||||
'| --- | --- |',
|
'| --- | --- | --- | --- |',
|
||||||
boardLines,
|
boardLines,
|
||||||
'',
|
'',
|
||||||
'</details>',
|
'</details>',
|
||||||
@@ -134,7 +164,7 @@ jobs:
|
|||||||
|
|
||||||
const body = [
|
const body = [
|
||||||
marker,
|
marker,
|
||||||
'## 🔦 Try this PR in the Web Flasher',
|
'## ⚡ Try this PR in the Web Flasher',
|
||||||
'',
|
'',
|
||||||
`[](${flasherUrl})`,
|
`[](${flasherUrl})`,
|
||||||
'',
|
'',
|
||||||
|
|||||||
@@ -286,11 +286,11 @@ jobs:
|
|||||||
--limit 1 --json databaseId --jq '.[0].databaseId // empty')
|
--limit 1 --json databaseId --jq '.[0].databaseId // empty')
|
||||||
if [ -n "$RUN_ID" ]; then
|
if [ -n "$RUN_ID" ]; then
|
||||||
ARTIFACT_NAME=$(gh api "repos/${{ github.repository }}/actions/runs/${RUN_ID}/artifacts" \
|
ARTIFACT_NAME=$(gh api "repos/${{ github.repository }}/actions/runs/${RUN_ID}/artifacts" \
|
||||||
--jq '.artifacts[] | select(.name | startswith("firmware-sizes-")) | .name' | head -1)
|
--jq '.artifacts[] | select(.name | startswith("firmware-sizes-")) | select(.expired == false) | .name' | head -1)
|
||||||
if [ -n "$ARTIFACT_NAME" ]; then
|
if [ -n "$ARTIFACT_NAME" ]; then
|
||||||
gh run download "$RUN_ID" -R "${{ github.repository }}" \
|
gh run download "$RUN_ID" -R "${{ github.repository }}" \
|
||||||
--name "$ARTIFACT_NAME" --dir ./baseline-develop/
|
--name "$ARTIFACT_NAME" --dir ./baseline-develop/
|
||||||
cp "./baseline-develop/${ARTIFACT_NAME}/current-sizes.json" ./develop-sizes.json
|
cp "./baseline-develop/current-sizes.json" ./develop-sizes.json
|
||||||
echo "found=true" >> "$GITHUB_OUTPUT"
|
echo "found=true" >> "$GITHUB_OUTPUT"
|
||||||
else
|
else
|
||||||
echo "found=false" >> "$GITHUB_OUTPUT"
|
echo "found=false" >> "$GITHUB_OUTPUT"
|
||||||
@@ -311,11 +311,11 @@ jobs:
|
|||||||
--limit 1 --json databaseId --jq '.[0].databaseId // empty')
|
--limit 1 --json databaseId --jq '.[0].databaseId // empty')
|
||||||
if [ -n "$RUN_ID" ]; then
|
if [ -n "$RUN_ID" ]; then
|
||||||
ARTIFACT_NAME=$(gh api "repos/${{ github.repository }}/actions/runs/${RUN_ID}/artifacts" \
|
ARTIFACT_NAME=$(gh api "repos/${{ github.repository }}/actions/runs/${RUN_ID}/artifacts" \
|
||||||
--jq '.artifacts[] | select(.name | startswith("firmware-sizes-")) | .name' | head -1)
|
--jq '.artifacts[] | select(.name | startswith("firmware-sizes-")) | select(.expired == false) | .name' | head -1)
|
||||||
if [ -n "$ARTIFACT_NAME" ]; then
|
if [ -n "$ARTIFACT_NAME" ]; then
|
||||||
gh run download "$RUN_ID" -R "${{ github.repository }}" \
|
gh run download "$RUN_ID" -R "${{ github.repository }}" \
|
||||||
--name "$ARTIFACT_NAME" --dir ./baseline-master/
|
--name "$ARTIFACT_NAME" --dir ./baseline-master/
|
||||||
cp "./baseline-master/${ARTIFACT_NAME}/current-sizes.json" ./master-sizes.json
|
cp "./baseline-master/current-sizes.json" ./master-sizes.json
|
||||||
echo "found=true" >> "$GITHUB_OUTPUT"
|
echo "found=true" >> "$GITHUB_OUTPUT"
|
||||||
else
|
else
|
||||||
echo "found=false" >> "$GITHUB_OUTPUT"
|
echo "found=false" >> "$GITHUB_OUTPUT"
|
||||||
|
|||||||
Reference in New Issue
Block a user