Skip to content

Commit 87f05eb

Browse files
committed
workflow: Add CI workflows for building firmware and syncing repository
This commit introduces two new GitHub Actions workflows: 1. `fobe_build.yml` for building firmware for different ports and boards. 2. `fobe_sync.yml` for syncing the fork with the upstream repository. These workflows enhance the CI/CD process by automating builds and ensuring the repository is up-to-date. Signed-off-by: Chiho Sin <[email protected]>
1 parent d0410b4 commit 87f05eb

File tree

3 files changed

+381
-0
lines changed

3 files changed

+381
-0
lines changed

.github/workflows/fobe_build.yml

Lines changed: 295 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,295 @@
1+
name: Build CI
2+
3+
permissions:
4+
contents: write
5+
6+
concurrency:
7+
group: ci-${{ github.head_ref || github.run_id }}
8+
cancel-in-progress: true
9+
10+
on:
11+
workflow_dispatch:
12+
push:
13+
tags:
14+
- v*
15+
- "!v*-nightly"
16+
schedule:
17+
- cron: 0 2 * * *
18+
19+
jobs:
20+
setup:
21+
name: Setup
22+
strategy:
23+
fail-fast: false
24+
matrix:
25+
port:
26+
- esp32
27+
- nrf
28+
runs-on: ubuntu-24.04
29+
steps:
30+
- uses: actions/checkout@v5
31+
- name: Generate matrix
32+
id: jsonStep
33+
run: |
34+
# Get all board directories for the specified port
35+
BOARDS_DIR="ports/${{matrix.port}}/boards"
36+
if [ -d "$BOARDS_DIR" ]; then
37+
# Get all directory names, exclude files, filter for FOBE prefix, sort alphabetically
38+
BOARDS=$(find "$BOARDS_DIR" -mindepth 1 -maxdepth 1 -type d -exec basename {} \; | grep "^FOBE" | sort | jq -R -s -c 'split("\n")[:-1]')
39+
else
40+
echo "Warning: Directory $BOARDS_DIR does not exist"
41+
BOARDS="[]"
42+
fi
43+
echo "Name: $GITHUB_REF_NAME Base: $GITHUB_BASE_REF Ref: $GITHUB_REF"
44+
echo "Port: ${{matrix.port}} Boards: $BOARDS"
45+
# Output the boards as a JSON object for the current port
46+
echo "${{matrix.port}}=$(jq -cn --argjson environments "$BOARDS" '{board: $environments}')" >> $GITHUB_OUTPUT
47+
outputs:
48+
esp32: ${{ steps.jsonStep.outputs.esp32 }}
49+
nrf: ${{ steps.jsonStep.outputs.nrf }}
50+
51+
version:
52+
name: Determine Version
53+
runs-on: ubuntu-24.04
54+
steps:
55+
- uses: actions/checkout@v5
56+
with:
57+
fetch-depth: 0
58+
- name: Fetch all tags
59+
run: |
60+
# Add upstream remote and fetch tags from original MicroPython repository
61+
git remote add upstream https://github.com/micropython/micropython.git
62+
git fetch upstream --tags --prune --force
63+
git fetch origin --tags --prune --force
64+
- name: Get release version string
65+
run: |
66+
FW_DATE=$(date '+%Y%m%d')
67+
# same logic as makeversionhdr.py, convert git-describe output into semver-compatible
68+
FW_GIT_TAG="$(git describe --tags --dirty --always --match 'v[1-9].*')"
69+
FW_SEMVER_MAJOR_MINOR_PATCH="$(echo "${FW_GIT_TAG}" | cut -d'-' -f1)"
70+
FW_SEMVER_PRERELEASE="$(echo "${FW_GIT_TAG}" | cut -s -d'-' -f2-)"
71+
if [[ -z ${FW_SEMVER_PRERELEASE} ]]; then
72+
FW_SEMVER="${FW_SEMVER_MAJOR_MINOR_PATCH}"
73+
else
74+
FW_SEMVER="${FW_SEMVER_MAJOR_MINOR_PATCH}-$(echo "${FW_SEMVER_PRERELEASE}" | tr - .)"
75+
fi
76+
# Check for invalid version pattern (commits after a release tag without proper preview versioning)
77+
# Match patterns like "v1.27.0-1.g8b38d1e3e-1-g67c133d9b" or "v1.27.0-123-ga4fa2c7f6"
78+
if [[ "$FW_GIT_TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+-[0-9]+[\.-]g[0-9a-f]+ ]]; then
79+
echo "❌ Error: Invalid version pattern detected: $FW_GIT_TAG"
80+
echo "This indicates commits after a release tag without proper preview versioning."
81+
echo "Please create a new preview tag (e.g., v1.27.1-preview) before committing new changes."
82+
echo "Expected format: vX.Y.Z-preview-N-gHASH instead of vX.Y.Z-N-gHASH"
83+
exit 1
84+
fi
85+
FW_TAG="-${FW_DATE}-${FW_SEMVER}"
86+
echo "Firmware version: ${FW_SEMVER}"
87+
echo "Firmware tag: ${FW_TAG}"
88+
echo "version=${FW_SEMVER}" >> $GITHUB_OUTPUT
89+
echo "firmware_tag=${FW_TAG}" >> $GITHUB_OUTPUT
90+
id: version
91+
outputs:
92+
version: ${{ steps.version.outputs.version }}
93+
firmware_tag: ${{ steps.version.outputs.firmware_tag }}
94+
95+
create-release:
96+
name: Create or Update Release
97+
needs: [setup, version]
98+
runs-on: ubuntu-24.04
99+
permissions:
100+
contents: write
101+
steps:
102+
- uses: actions/checkout@v5
103+
with:
104+
fetch-depth: 0
105+
- name: Determine release strategy
106+
id: strategy
107+
run: |
108+
VERSION="${{ needs.version.outputs.version }}"
109+
echo "Raw version: $VERSION"
110+
# Check if this is a SHA-based preview version (contains commit hash pattern like v1.27.0-preview.98.g8fd42d8e5)
111+
if [[ "$VERSION" =~ \.[0-9]+\.g[a-f0-9]+$ ]]; then
112+
# Extract base version for SHA-based preview (e.g., v1.27.0-preview.98.g8fd42d8e5 -> v1.27.0-preview)
113+
BASE_VERSION=$(echo "$VERSION" | sed -E 's/\.[0-9]+\.g[a-f0-9]+$//')
114+
echo "version_type=sha_preview" >> $GITHUB_OUTPUT
115+
echo "tag_name=$BASE_VERSION" >> $GITHUB_OUTPUT
116+
echo "release_name=MicroPython Firmware $BASE_VERSION" >> $GITHUB_OUTPUT
117+
echo "original_version=$VERSION" >> $GITHUB_OUTPUT
118+
echo "This is a SHA-based preview version, will attach to base preview release: $BASE_VERSION"
119+
# Check if this is a manual preview version (ends with -preview)
120+
elif [[ "$VERSION" =~ -preview$ ]]; then
121+
echo "version_type=preview" >> $GITHUB_OUTPUT
122+
echo "tag_name=$VERSION" >> $GITHUB_OUTPUT
123+
echo "release_name=MicroPython Firmware $VERSION" >> $GITHUB_OUTPUT
124+
echo "original_version=$VERSION" >> $GITHUB_OUTPUT
125+
echo "This is a preview release"
126+
elif [[ "$VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
127+
echo "version_type=stable" >> $GITHUB_OUTPUT
128+
echo "tag_name=$VERSION" >> $GITHUB_OUTPUT
129+
echo "release_name=MicroPython Firmware $VERSION" >> $GITHUB_OUTPUT
130+
echo "original_version=$VERSION" >> $GITHUB_OUTPUT
131+
echo "This is a stable release"
132+
else
133+
echo "This is an unknown release type"
134+
echo "version_type=unknown" >> $GITHUB_OUTPUT
135+
echo "tag_name=$VERSION" >> $GITHUB_OUTPUT
136+
echo "release_name=MicroPython Firmware $VERSION" >> $GITHUB_OUTPUT
137+
echo "original_version=$VERSION" >> $GITHUB_OUTPUT
138+
# exit 1
139+
fi
140+
141+
- name: Check existing release and handle accordingly
142+
id: check_release
143+
run: |
144+
TAG_NAME="${{ steps.strategy.outputs.tag_name }}"
145+
VERSION_TYPE="${{ steps.strategy.outputs.version_type }}"
146+
ORIGINAL_VERSION="${{ steps.strategy.outputs.original_version }}"
147+
148+
# Check if release exists
149+
if gh release view "$TAG_NAME" >/dev/null 2>&1; then
150+
echo "Release $TAG_NAME exists"
151+
RELEASE_EXISTS=true
152+
else
153+
echo "Release $TAG_NAME does not exist"
154+
RELEASE_EXISTS=false
155+
fi
156+
157+
case "$VERSION_TYPE" in
158+
"stable"|"preview")
159+
if [ "$RELEASE_EXISTS" = true ]; then
160+
echo "❌ Error: Release $TAG_NAME already exists for $VERSION_TYPE version"
161+
echo "Exiting workflow to prevent duplicate builds"
162+
exit 1
163+
else
164+
echo "continue=true" >> $GITHUB_OUTPUT
165+
echo "create_release=true" >> $GITHUB_OUTPUT
166+
echo "update_existing=false" >> $GITHUB_OUTPUT
167+
fi
168+
;;
169+
"sha_preview")
170+
if [ "$RELEASE_EXISTS" = true ]; then
171+
echo "Found existing preview release $TAG_NAME, will update it with new build artifacts"
172+
echo "continue=true" >> $GITHUB_OUTPUT
173+
echo "create_release=false" >> $GITHUB_OUTPUT
174+
echo "update_existing=true" >> $GITHUB_OUTPUT
175+
else
176+
echo "❌ Error: Base preview release $TAG_NAME does not exist for SHA preview version $ORIGINAL_VERSION"
177+
echo "Please create the base preview tag first: $TAG_NAME"
178+
exit 1
179+
fi
180+
;;
181+
*)
182+
echo "continue=true" >> $GITHUB_OUTPUT
183+
echo "create_release=true" >> $GITHUB_OUTPUT
184+
echo "update_existing=false" >> $GITHUB_OUTPUT
185+
;;
186+
esac
187+
env:
188+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
189+
190+
- name: Update existing preview release
191+
if: steps.check_release.outputs.update_existing == 'true'
192+
run: |
193+
TAG_NAME="${{ steps.strategy.outputs.tag_name }}"
194+
ORIGINAL_VERSION="${{ steps.strategy.outputs.original_version }}"
195+
196+
# Get current release assets
197+
echo "Getting current release assets..."
198+
ASSETS=$(gh release view "$TAG_NAME" --json assets --jq '.assets[].name')
199+
echo "Current assets: $ASSETS"
200+
201+
# Extract version numbers from asset names and sort them
202+
# Pattern: BOARD-vX.Y.Z-preview.N.gHASH.tar.xz -> extract N
203+
echo "Analyzing asset versions..."
204+
VERSION_NUMBERS=$(echo "$ASSETS" | grep -E '\-v[0-9]+\.[0-9]+\.[0-9]+\-preview\.[0-9]+\.g[a-f0-9]+\.tar\.xz$' | \
205+
sed -E 's/.*-v[0-9]+\.[0-9]+\.[0-9]+-preview\.([0-9]+)\.g[a-f0-9]+\.tar\.xz$/\1/' | \
206+
sort -nr | \
207+
uniq)
208+
209+
echo "Found version numbers: $VERSION_NUMBERS"
210+
211+
# Keep only the latest 3 versions (current build will be the 4th)
212+
OLD_VERSIONS=$(echo "$VERSION_NUMBERS" | tail -n +4)
213+
214+
if [ -n "$OLD_VERSIONS" ]; then
215+
echo "Will delete assets from old versions: $OLD_VERSIONS"
216+
for old_version in $OLD_VERSIONS; do
217+
# Find and delete assets matching this version
218+
OLD_ASSETS=$(echo "$ASSETS" | grep -E "\-preview\.${old_version}\.g[a-f0-9]+\.tar\.xz$")
219+
for asset in $OLD_ASSETS; do
220+
echo "Deleting old asset: $asset"
221+
gh release delete-asset "$TAG_NAME" "$asset" --yes 2>/dev/null || true
222+
done
223+
done
224+
else
225+
echo "No old versions to clean (less than 4 versions total)"
226+
fi
227+
228+
# Update the release body to reflect the latest version
229+
gh release edit "$TAG_NAME" \
230+
--title "${{ steps.strategy.outputs.release_name }}" \
231+
--notes "**Latest Version**: $ORIGINAL_VERSION
232+
**Commit**: ${{ github.sha }}
233+
234+
Please select the appropriate firmware file for your development board.
235+
236+
> ⚠️ Note: This is a preview release that gets updated with the latest builds automatically.
237+
> Only the latest 4 versions of build artifacts are kept."
238+
env:
239+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
240+
241+
- name: Create Release
242+
if: steps.check_release.outputs.create_release == 'true'
243+
uses: softprops/action-gh-release@v2
244+
with:
245+
tag_name: ${{ steps.strategy.outputs.tag_name }}
246+
name: ${{ steps.strategy.outputs.release_name }}
247+
body: |
248+
**Version**: ${{ steps.strategy.outputs.original_version }}
249+
**Commit**: ${{ github.sha }}
250+
**Commit**: 4
251+
252+
Please select the appropriate firmware file for your development board.
253+
254+
${{ steps.strategy.outputs.version_type == 'preview' && '> ⚠️ Note: This is a preview release that may get updated with newer builds.' || '' }}
255+
draft: false
256+
prerelease: ${{ steps.strategy.outputs.version_type != 'stable' }}
257+
token: ${{ secrets.GITHUB_TOKEN }}
258+
outputs:
259+
tag_name: ${{ steps.strategy.outputs.tag_name }}
260+
version: ${{ steps.strategy.outputs.original_version }}
261+
continue: ${{ steps.check_release.outputs.continue }}
262+
263+
build-esp32:
264+
name: Build Port ESP32
265+
needs: [setup, create-release]
266+
if: needs.create-release.outputs.continue == 'true'
267+
strategy:
268+
fail-fast: false
269+
matrix: ${{ fromJSON(needs.setup.outputs.esp32) }}
270+
uses: ./.github/workflows/fobe_build_firmware.yml
271+
with:
272+
repo_remote: origin
273+
repo_ref: ${{ github.sha }}
274+
port: esp32
275+
board: ${{ matrix.board }}
276+
version: ${{ needs.create-release.outputs.version }}
277+
release_tag: ${{ needs.create-release.outputs.tag_name }}
278+
secrets: inherit
279+
280+
build-nrf:
281+
name: Build Port NRF
282+
needs: [setup, create-release]
283+
if: needs.create-release.outputs.continue == 'true'
284+
strategy:
285+
fail-fast: false
286+
matrix: ${{ fromJSON(needs.setup.outputs.nrf) }}
287+
uses: ./.github/workflows/fobe_build_firmware.yml
288+
with:
289+
repo_remote: origin
290+
repo_ref: ${{ github.sha }}
291+
port: nrf
292+
board: ${{ matrix.board }}
293+
version: ${{ needs.create-release.outputs.version }}
294+
release_tag: ${{ needs.create-release.outputs.tag_name }}
295+
secrets: inherit
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
name: Build Firmware
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
repo_remote:
7+
required: false
8+
type: string
9+
default: origin
10+
repo_ref:
11+
required: false
12+
type: string
13+
default: ${{ github.sha }}
14+
port:
15+
required: true
16+
type: string
17+
board:
18+
required: true
19+
type: string
20+
version:
21+
required: true
22+
type: string
23+
release_tag:
24+
required: false
25+
type: string
26+
27+
permissions:
28+
contents: write
29+
30+
jobs:
31+
build:
32+
name: Build ${{ inputs.board }}
33+
runs-on: self-hosted
34+
steps:
35+
- name: Build board ${{ inputs.board }}
36+
uses: fobe-projects/action-micropython-builder@main
37+
with:
38+
repo_remote: ${{ inputs.repo_remote }}
39+
repo_ref: ${{ inputs.repo_ref }}
40+
port: ${{ inputs.port }}
41+
board: ${{ inputs.board }}
42+
43+
- name: Package binaries
44+
run: |
45+
sudo mv bin ${{ inputs.board }}
46+
tar -cJf ${{ inputs.board }}-${{ inputs.version }}.tar.xz ${{ inputs.board }}
47+
48+
- name: Upload binaries to release
49+
if: ${{ inputs.release_tag != '' }}
50+
uses: softprops/action-gh-release@v2
51+
with:
52+
tag_name: ${{ inputs.release_tag }}
53+
files: ${{ inputs.board }}-${{ inputs.version }}.tar.xz
54+
token: ${{ secrets.GITHUB_TOKEN }}
55+
56+
- name: Store binaries as an artifact
57+
if: ${{ inputs.release_tag == '' }}
58+
uses: actions/upload-artifact@v4
59+
with:
60+
name: firmware-${{ inputs.board }}-${{ github.sha }}.zip
61+
overwrite: true
62+
path: ${{ inputs.board }}-${{ inputs.version }}.tar.xz

.github/workflows/fobe_sync.yml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
name: Sync CI
2+
3+
permissions:
4+
contents: write
5+
6+
concurrency:
7+
group: ci-${{ github.head_ref || github.run_id }}
8+
cancel-in-progress: true
9+
10+
on:
11+
workflow_dispatch:
12+
schedule:
13+
- cron: 0 1 * * *
14+
15+
jobs:
16+
sync:
17+
name: Sync Fork
18+
runs-on: ubuntu-latest
19+
env:
20+
GH_TOKEN: ${{ github.token }}
21+
steps:
22+
- uses: actions/checkout@v5
23+
- name: Sync Upstream Repository
24+
run: gh repo sync fobe-projects/micropython --source micropython/micropython

0 commit comments

Comments
 (0)