Skip to content

Commit 0791829

Browse files
Merge pull request #11409 from iNavFlight/maintenance-9.x
Maintenance 9.x to maintenance-10
2 parents ba419f2 + 2db79da commit 0791829

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+1998
-271
lines changed

.github/workflows/ci.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,16 @@ jobs:
107107
with:
108108
name: targets
109109
path: targets.txt
110+
- name: Save PR number
111+
if: github.event_name == 'pull_request'
112+
run: echo "${{ github.event.pull_request.number }}" > pr_number.txt
113+
- name: Upload PR number
114+
if: github.event_name == 'pull_request'
115+
uses: actions/upload-artifact@v4
116+
with:
117+
name: pr-number
118+
path: pr_number.txt
119+
retention-days: 1
110120

111121
build-SITL-Linux-arm64:
112122
runs-on: ubuntu-22.04-arm
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
name: PR Test Builds
2+
3+
# Runs after "Build firmware" completes. Uses workflow_run (rather than
4+
# pull_request directly) so that secrets are available even for PRs from forks.
5+
#
6+
# Requires a repository secret PR_BUILDS_TOKEN with Contents: write access
7+
# to iNavFlight/pr-test-builds (fine-grained PAT or classic PAT with repo scope).
8+
on:
9+
workflow_run:
10+
workflows: ["Build firmware"]
11+
types: [completed]
12+
13+
jobs:
14+
publish:
15+
runs-on: ubuntu-latest
16+
# Only act on pull_request-triggered runs that succeeded.
17+
if: >
18+
github.event.workflow_run.event == 'pull_request' &&
19+
github.event.workflow_run.conclusion == 'success'
20+
# Prevent concurrent runs for the same PR branch racing on the
21+
# release delete/create cycle.
22+
concurrency:
23+
group: pr-test-build-${{ github.event.workflow_run.head_repository.full_name }}-${{ github.event.workflow_run.head_branch }}
24+
cancel-in-progress: true
25+
permissions:
26+
actions: read # to download artifacts from the triggering workflow run
27+
issues: write # github.rest.issues.* endpoints used to post PR comments
28+
pull-requests: write # to post the PR comment
29+
30+
steps:
31+
- name: Download PR number
32+
uses: actions/download-artifact@v4
33+
with:
34+
name: pr-number
35+
run-id: ${{ github.event.workflow_run.id }}
36+
github-token: ${{ secrets.GITHUB_TOKEN }}
37+
38+
- name: Read PR number
39+
id: pr
40+
run: |
41+
PR_NUM=$(tr -dc '0-9' < pr_number.txt)
42+
if [ -z "$PR_NUM" ]; then
43+
echo "::error::Invalid PR number in artifact"
44+
exit 1
45+
fi
46+
echo "number=${PR_NUM}" >> $GITHUB_OUTPUT
47+
48+
- name: Download firmware artifacts
49+
uses: actions/download-artifact@v4
50+
with:
51+
pattern: matrix-inav-*
52+
merge-multiple: true
53+
path: hexes
54+
run-id: ${{ github.event.workflow_run.id }}
55+
github-token: ${{ secrets.GITHUB_TOKEN }}
56+
57+
- name: Get build info
58+
id: info
59+
run: |
60+
COUNT=$(find hexes -name '*.hex' -type f | wc -l)
61+
if [ "$COUNT" -eq 0 ]; then
62+
echo "::error::No .hex files found in downloaded artifacts"
63+
exit 1
64+
fi
65+
echo "count=${COUNT}" >> $GITHUB_OUTPUT
66+
echo "short_sha=$(echo '${{ github.event.workflow_run.head_sha }}' | cut -c1-7)" >> $GITHUB_OUTPUT
67+
68+
# Delete the previous release for this PR (if any) so assets are replaced
69+
# cleanly on each new commit. --cleanup-tag removes the old tag so it is
70+
# recreated fresh pointing to the new commit.
71+
- name: Delete existing PR release
72+
env:
73+
GH_TOKEN: ${{ secrets.PR_BUILDS_TOKEN }}
74+
run: |
75+
gh release delete "pr-${{ steps.pr.outputs.number }}" \
76+
--repo iNavFlight/pr-test-builds --cleanup-tag --yes 2>/dev/null || true
77+
78+
- name: Create PR release
79+
env:
80+
GH_TOKEN: ${{ secrets.PR_BUILDS_TOKEN }}
81+
PR_NUMBER: ${{ steps.pr.outputs.number }}
82+
SHORT_SHA: ${{ steps.info.outputs.short_sha }}
83+
HEX_COUNT: ${{ steps.info.outputs.count }}
84+
REPO: ${{ github.repository }}
85+
run: |
86+
PR_URL="https://github.com/${REPO}/pull/${PR_NUMBER}"
87+
printf '%s\n\n%s\n\n%s\n' \
88+
"Test build for [PR #${PR_NUMBER}](${PR_URL}) — commit \`${SHORT_SHA}\`" \
89+
"**${HEX_COUNT} targets built.** Find your board's \`.hex\` file by name (e.g. \`MATEKF405SE.hex\`)." \
90+
"> Development build for testing only. Use Full Chip Erase when flashing." \
91+
> release-notes.md
92+
gh release create "pr-${PR_NUMBER}" hexes/*.hex \
93+
--repo iNavFlight/pr-test-builds \
94+
--prerelease \
95+
--title "PR #${PR_NUMBER} (${SHORT_SHA})" \
96+
--notes-file release-notes.md
97+
98+
- name: Post or update PR comment
99+
uses: actions/github-script@v7
100+
env:
101+
PR_NUMBER: ${{ steps.pr.outputs.number }}
102+
SHORT_SHA: ${{ steps.info.outputs.short_sha }}
103+
HEX_COUNT: ${{ steps.info.outputs.count }}
104+
with:
105+
script: |
106+
const prNumber = parseInt(process.env.PR_NUMBER, 10);
107+
if (isNaN(prNumber)) throw new Error(`Invalid PR number: ${process.env.PR_NUMBER}`);
108+
const shortSha = process.env.SHORT_SHA;
109+
const count = process.env.HEX_COUNT;
110+
const releaseUrl = `https://github.com/iNavFlight/pr-test-builds/releases/tag/pr-${prNumber}`;
111+
112+
const body = [
113+
'<!-- pr-test-build -->',
114+
'**Test firmware build ready** — commit `' + shortSha + '`',
115+
'',
116+
`[Download firmware for PR #${prNumber}](${releaseUrl})`,
117+
'',
118+
`${count} targets built. Find your board's \`.hex\` file by name on that page ` +
119+
'(e.g. `MATEKF405SE.hex`). Files are individually downloadable — no GitHub login required.',
120+
'',
121+
'> Development build for testing only. Use Full Chip Erase when flashing.',
122+
].join('\n');
123+
124+
const comments = await github.paginate(
125+
github.rest.issues.listComments,
126+
{
127+
owner: context.repo.owner,
128+
repo: context.repo.repo,
129+
issue_number: prNumber,
130+
}
131+
);
132+
133+
const existing = comments.find(c =>
134+
c.user.type === 'Bot' && c.body.includes('<!-- pr-test-build -->')
135+
);
136+
137+
if (existing) {
138+
await github.rest.issues.updateComment({
139+
owner: context.repo.owner,
140+
repo: context.repo.repo,
141+
comment_id: existing.id,
142+
body,
143+
});
144+
} else {
145+
await github.rest.issues.createComment({
146+
owner: context.repo.owner,
147+
repo: context.repo.repo,
148+
issue_number: prNumber,
149+
body,
150+
});
151+
}

0 commit comments

Comments
 (0)