-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
174 lines (159 loc) · 7.75 KB
/
Copy pathpr-build.yml
File metadata and controls
174 lines (159 loc) · 7.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# Build & analyze: build the firmware on each PR, on pushes to dev, and on-demand
# ("Run workflow"); publish it as a downloadable artifact, and on PRs post a unified
# report comment (build status + flash budget + public-API changes). Push/dispatch
# runs (no PR) put the same report — minus the PR-only public-API section — in the
# Actions job summary only.
#
# Scope (deliberately minimal):
# * Builds the f7 "clean" flavor only (firmware + in-tree apps). The default/extra
# app packs are PREBUILT binaries from xMasterX/all-the-plugins, NOT compiled
# from the PR, so bundling them validates nothing here.
# * Flash budget comes from the firmware ELF's `.free_flash` section MINUS the
# BLE coprocessor radio stack + FUS region that sits at the top of flash (the
# linker counts it as free, but it isn't usable). See fw_size_report.py.
# * The clean build also gates API drift: fbt fails if the exported API surface
# changes without targets/*/api_symbols.csv being updated + version-bumped.
#
# Artifacts/reports are named by branch + short SHA, so manual runs from dev work too.
# The PR report comment is posted by a separate workflow (pr-comment.yml) triggered on
# `workflow_run`: this job only builds and uploads the report as an artifact, so it needs
# no write access and works for fork PRs (whose token here is read-only). The same report
# is always written to the Actions job summary regardless.
name: Build & analyze
on:
push:
branches: [dev] # dev builds (active once this workflow is merged to dev)
pull_request:
workflow_dispatch: # manual "Run workflow" button (appears once this is on the default branch)
# Cancel an in-flight run when superseded: per PR for PRs, else per ref (pushes to dev
# and manual dispatches).
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
permissions:
contents: read # commenting is delegated to pr-comment.yml (workflow_run); no write needed here
env:
FBT_NO_SYNC: 0
FORCE_NO_DIRTY: "yes"
FBT_GIT_SUBMODULE_SHALLOW: 1
WORKFLOW_BRANCH_OR_TAG: ${{ github.head_ref || github.ref_name }}
jobs:
build:
name: f7 firmware
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- name: Checkout (PR merge ref)
uses: actions/checkout@v6
with:
submodules: recursive
clean: "true"
- name: Compute version vars
id: vars
shell: bash
run: |
if [ "${{ github.event_name }}" = "pull_request" ]; then
SHA="${{ github.event.pull_request.head.sha }}"
REF="${{ github.head_ref }}"
else
SHA="${{ github.sha }}"
REF="${{ github.ref_name }}"
fi
SHORT="${SHA:0:8}"
SAFE_REF="${REF//\//-}" # branch name, '/' -> '-' for artifact names
echo "sha8=$SHORT" >> "$GITHUB_OUTPUT"
echo "ref=$SAFE_REF" >> "$GITHUB_OUTPUT"
echo "dist=${SAFE_REF}-${SHORT}" >> "$GITHUB_OUTPUT"
- name: Build firmware (minimal / clean)
id: build
shell: bash
env:
DIST_SUFFIX: ${{ steps.vars.outputs.sha8 }}
run: |
rm -rf applications/main/clock_app/resources/apps/ || true
./fbt COMPACT=1 DEBUG=0 FBT_NO_SYNC="${FBT_NO_SYNC}" updater_package
- name: Upload firmware artifact
if: success()
uses: actions/upload-artifact@v7
with:
name: unleashed-fw-${{ steps.vars.outputs.dist }}
path: dist/f7-C/*
retention-days: 14
if-no-files-found: error
# ---------- Flash budget: DFU size + usable free flash ----------
# "Usable free" subtracts the BLE coprocessor (core2) radio stack + FUS region
# that sits at the top of flash — the linker's .free_flash counts it as free but
# it is not usable by our firmware. Resolve the configured stack from fbt_options.
- name: Measure firmware size
if: always()
shell: bash
run: |
SIZE_BIN="$(find toolchain -type f -path '*/bin/arm-none-eabi-size' 2>/dev/null | head -1)"
[ -z "$SIZE_BIN" ] && SIZE_BIN="$(command -v arm-none-eabi-size || true)"
ELF="$(find build -name firmware.elf -type f 2>/dev/null | head -1)"
DFU="$(find build -name firmware.dfu -type f 2>/dev/null | head -1)"
COPRO_BIN="$(python -c 'import fbt_options as o; print(f"{o.COPRO_STACK_BIN_DIR}/{o.COPRO_STACK_BIN}")' 2>/dev/null || true)"
COPRO_LABEL="$(python -c 'import fbt_options as o; print(o.COPRO_STACK_TYPE)' 2>/dev/null || true)"
[ -f "$COPRO_BIN" ] || COPRO_BIN=""
echo "size-bin=$SIZE_BIN | elf=$ELF | dfu=$DFU | copro=$COPRO_BIN ($COPRO_LABEL)"
python .github/scripts/fw_size_report.py \
--size-bin "$SIZE_BIN" --elf "$ELF" --dfu "$DFU" \
--copro-bin "$COPRO_BIN" --copro-label "$COPRO_LABEL" \
--out size_report.md || true
[ -f size_report.md ] || echo "_Size report unavailable._" > size_report.md
# ---------- Public API change report (PRs only) ----------
- name: Fetch PR base for API diff
if: always() && github.event_name == 'pull_request'
shell: bash
run: git fetch --no-tags --depth=1 origin "${{ github.event.pull_request.base.sha }}"
- name: Generate API change report
if: always() && github.event_name == 'pull_request'
shell: bash
run: |
python .github/scripts/api_symbols_report.py \
--base-ref "${{ github.event.pull_request.base.sha }}" \
--out api_report.md
# ---------- Assemble + publish the unified PR report ----------
- name: Assemble PR report
if: always()
shell: bash
env:
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
run: |
{
echo "<!-- unleashed-pr-report -->"
echo "## 🤖 Build & analyze — \`${{ steps.vars.outputs.ref }}\` @ \`${{ steps.vars.outputs.sha8 }}\`"
echo ""
if [ "${{ steps.build.outcome }}" = "success" ]; then
echo "✅ **Firmware built** — artifact \`unleashed-fw-${{ steps.vars.outputs.dist }}\` ([run]($RUN_URL))"
else
echo "❌ **Firmware build failed** — see the [run log]($RUN_URL)"
fi
echo ""
cat size_report.md 2>/dev/null || true
echo ""
cat api_report.md 2>/dev/null || true
} > pr_report.md
cat pr_report.md >> "$GITHUB_STEP_SUMMARY"
# ---------- Hand the report off to the privileged commenter ----------
# This job's token is read-only on fork PRs, so it can't comment itself. It uploads
# the assembled report + PR number; pr-comment.yml (triggered on workflow_run) posts
# it with a read-write token from the base-repo context. The PR number must travel
# via the artifact — github.event.workflow_run.pull_requests is empty for fork PRs.
- name: Save PR number
if: always() && github.event_name == 'pull_request'
run: echo "${{ github.event.pull_request.number }}" > pr_number.txt
# continue-on-error: a report/upload hiccup must not redden an otherwise-green build
# (the whole point of moving commenting out of this job). if-no-files-found still
# records the failure on the step; pr-comment.yml warns if the artifact never arrives.
- name: Upload PR report artifact
if: always() && github.event_name == 'pull_request'
continue-on-error: true
uses: actions/upload-artifact@v7
with:
name: pr-report
path: |
pr_report.md
pr_number.txt
retention-days: 1
if-no-files-found: error