Skip to content

Commit 86f7bf4

Browse files
committed
workflows: Add Vendor Build and Release CI workflows
This commit introduces two new GitHub Actions workflows: 1. `build.vendor.yml` for building firmware for specified boards. 2. `release.vendor.yml` for managing the release process, including version determination and artifact publishing. Signed-off-by: Chiho Sin <[email protected]>
1 parent 062bc40 commit 86f7bf4

File tree

2 files changed

+355
-0
lines changed

2 files changed

+355
-0
lines changed

.github/workflows/build.vendor.yml

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
name: Vendor Build CI
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+
firmware_tag:
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: ubuntu-latest
34+
steps:
35+
- name: Clean workspace
36+
run: |
37+
sudo rm -rf bin
38+
sudo rm -rf ${{ inputs.board }}
39+
mkdir -p bin
40+
41+
- name: Build board ${{ inputs.board }}
42+
uses: fobe-projects/action-circuitpython-builder@main
43+
with:
44+
repo_remote: ${{ inputs.repo_remote }}
45+
repo_ref: ${{ inputs.repo_ref }}
46+
port: ${{ inputs.port }}
47+
board: ${{ inputs.board }}
48+
49+
- name: Package binaries
50+
run: |
51+
sudo mv bin ${{ inputs.board }}
52+
tar -cJf ${{ inputs.board }}${{ inputs.firmware_tag }}.tar.xz ${{ inputs.board }}
53+
54+
- name: Store binaries as an artifact
55+
uses: actions/upload-artifact@v4
56+
with:
57+
name: ${{ inputs.board }}${{ inputs.firmware_tag }}
58+
overwrite: true
59+
path: ${{ inputs.board }}${{ inputs.firmware_tag }}.tar.xz
Lines changed: 296 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,296 @@
1+
name: Vendor Release 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+
- '*'
15+
16+
jobs:
17+
setup:
18+
name: Setup
19+
strategy:
20+
fail-fast: false
21+
matrix:
22+
port:
23+
- espressif
24+
- nordic
25+
runs-on: ubuntu-latest
26+
steps:
27+
- uses: actions/checkout@v5
28+
- name: Generate matrix
29+
id: jsonStep
30+
run: |
31+
# Get all board directories for the specified port
32+
BOARDS_DIR="ports/${{matrix.port}}/boards"
33+
if [ -d "$BOARDS_DIR" ]; then
34+
# Get all directory names, exclude files, filter for fobe prefix, sort alphabetically
35+
BOARDS=$(find "$BOARDS_DIR" -mindepth 1 -maxdepth 1 -type d -exec basename {} \; | grep "^fobe" | sort | jq -R -s -c 'split("\n")[:-1]')
36+
else
37+
echo "Warning: Directory $BOARDS_DIR does not exist"
38+
BOARDS="[]"
39+
fi
40+
echo "Name: $GITHUB_REF_NAME Base: $GITHUB_BASE_REF Ref: $GITHUB_REF"
41+
echo "Port: ${{matrix.port}} Boards: $BOARDS"
42+
# Output the boards as a JSON object for the current port
43+
echo "${{matrix.port}}=$(jq -cn --argjson environments "$BOARDS" '{board: $environments}')" >> $GITHUB_OUTPUT
44+
outputs:
45+
espressif: ${{ steps.jsonStep.outputs.espressif }}
46+
nordic: ${{ steps.jsonStep.outputs.nordic }}
47+
48+
version:
49+
name: Determine Version
50+
runs-on: ubuntu-latest
51+
steps:
52+
- uses: actions/checkout@v5
53+
with:
54+
fetch-depth: 0
55+
- name: Fetch all tags
56+
run: |
57+
# Add upstream remote and fetch tags from original CircuitPython repository
58+
git remote add upstream https://github.com/adafruit/circuitpython.git
59+
git fetch upstream --tags --prune --force
60+
git fetch origin --tags --prune --force
61+
- name: Get version using version.py
62+
run: |
63+
# Use version.py to get the current version
64+
RAW_VERSION=$(python3 py/version.py)
65+
echo "Raw version from py/version.py: $RAW_VERSION"
66+
67+
# Determine if this is a tagged version or a non-tagged version
68+
if [[ "$RAW_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+(\.[0-9]+)?)?$ ]]; then
69+
# This is a tagged version (e.g., 10.0.0 or 10.0.0-beta.2 or 10.0.0-alpha.1)
70+
VERSION_TYPE="tagged"
71+
TARGET_VERSION="$RAW_VERSION"
72+
echo "This is a tagged version: $RAW_VERSION"
73+
elif [[ "$RAW_VERSION" =~ ^([0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+(\.[0-9]+)?)?)-[0-9]+-g[a-f0-9]+$ ]]; then
74+
# This is a non-tagged version (e.g., 10.0.0-beta.2-24-g2dc726497f)
75+
VERSION_TYPE="non_tagged"
76+
# Extract the tag part (everything before -N-gHASH)
77+
TARGET_VERSION=$(echo "$RAW_VERSION" | sed -E 's/-[0-9]+-g[a-f0-9]+$//')
78+
echo "This is a non-tagged version: $RAW_VERSION"
79+
echo "Target release tag: $TARGET_VERSION"
80+
else
81+
echo "❌ Error: Unrecognized version format: $RAW_VERSION"
82+
exit 1
83+
fi
84+
85+
# Generate firmware tag for file naming
86+
FW_DATE=$(date '+%Y%m%d')
87+
FW_TAG="-${FW_DATE}-${RAW_VERSION}"
88+
89+
echo "Version type: $VERSION_TYPE"
90+
echo "Raw version: $RAW_VERSION"
91+
echo "Target version: $TARGET_VERSION"
92+
echo "Firmware tag: $FW_TAG"
93+
94+
echo "version_type=${VERSION_TYPE}" >> $GITHUB_OUTPUT
95+
echo "raw_version=${RAW_VERSION}" >> $GITHUB_OUTPUT
96+
echo "target_version=${TARGET_VERSION}" >> $GITHUB_OUTPUT
97+
echo "firmware_tag=${FW_TAG}" >> $GITHUB_OUTPUT
98+
id: version
99+
outputs:
100+
version_type: ${{ steps.version.outputs.version_type }}
101+
raw_version: ${{ steps.version.outputs.raw_version }}
102+
target_version: ${{ steps.version.outputs.target_version }}
103+
firmware_tag: ${{ steps.version.outputs.firmware_tag }}
104+
105+
create-release:
106+
name: Create or Update Release
107+
needs: [setup, version]
108+
runs-on: ubuntu-latest
109+
permissions:
110+
contents: write
111+
steps:
112+
- uses: actions/checkout@v5
113+
with:
114+
fetch-depth: 0
115+
- name: Determine release strategy
116+
id: strategy
117+
run: |
118+
VERSION_TYPE="${{ needs.version.outputs.version_type }}"
119+
RAW_VERSION="${{ needs.version.outputs.raw_version }}"
120+
TARGET_VERSION="${{ needs.version.outputs.target_version }}"
121+
122+
echo "Version type: $VERSION_TYPE"
123+
echo "Raw version: $RAW_VERSION"
124+
echo "Target version: $TARGET_VERSION"
125+
126+
# Set release information
127+
echo "tag_name=$TARGET_VERSION" >> $GITHUB_OUTPUT
128+
echo "release_name=CircuitPython Firmware $TARGET_VERSION" >> $GITHUB_OUTPUT
129+
echo "raw_version=$RAW_VERSION" >> $GITHUB_OUTPUT
130+
echo "target_version=$TARGET_VERSION" >> $GITHUB_OUTPUT
131+
echo "version_type=$VERSION_TYPE" >> $GITHUB_OUTPUT
132+
133+
- name: Check existing release and handle accordingly
134+
id: check_release
135+
run: |
136+
TAG_NAME="${{ steps.strategy.outputs.tag_name }}"
137+
VERSION_TYPE="${{ steps.strategy.outputs.version_type }}"
138+
RAW_VERSION="${{ steps.strategy.outputs.raw_version }}"
139+
140+
# Check if release exists
141+
if gh release view "$TAG_NAME" >/dev/null 2>&1; then
142+
echo "Release $TAG_NAME exists"
143+
RELEASE_EXISTS=true
144+
else
145+
echo "Release $TAG_NAME does not exist"
146+
RELEASE_EXISTS=false
147+
fi
148+
149+
case "$VERSION_TYPE" in
150+
"tagged")
151+
if [ "$RELEASE_EXISTS" = true ]; then
152+
echo "❌ Release $TAG_NAME already exists for tagged version"
153+
echo "Skipping build to prevent duplicate releases"
154+
echo "continue=false" >> $GITHUB_OUTPUT
155+
exit 0
156+
else
157+
echo "✅ Tagged version $TAG_NAME does not have a release yet, proceeding with build"
158+
echo "continue=true" >> $GITHUB_OUTPUT
159+
echo "create_release=true" >> $GITHUB_OUTPUT
160+
echo "update_existing=false" >> $GITHUB_OUTPUT
161+
fi
162+
;;
163+
"non_tagged")
164+
if [ "$RELEASE_EXISTS" = true ]; then
165+
echo "✅ Found existing release $TAG_NAME for non-tagged version, will update it"
166+
echo "continue=true" >> $GITHUB_OUTPUT
167+
echo "create_release=false" >> $GITHUB_OUTPUT
168+
echo "update_existing=true" >> $GITHUB_OUTPUT
169+
else
170+
echo "❌ Target release $TAG_NAME does not exist for non-tagged version $RAW_VERSION"
171+
echo "Please create the target tag/release first: $TAG_NAME"
172+
echo "continue=false" >> $GITHUB_OUTPUT
173+
exit 0
174+
fi
175+
;;
176+
*)
177+
echo "❌ Error: Unknown version type: $VERSION_TYPE"
178+
echo "continue=false" >> $GITHUB_OUTPUT
179+
exit 1
180+
;;
181+
esac
182+
env:
183+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
184+
185+
- name: Update existing release
186+
if: steps.check_release.outputs.update_existing == 'true'
187+
run: |
188+
TAG_NAME="${{ steps.strategy.outputs.tag_name }}"
189+
RAW_VERSION="${{ steps.strategy.outputs.raw_version }}"
190+
191+
echo "Updating existing release $TAG_NAME with new build from $RAW_VERSION"
192+
193+
# Update the release body to reflect the latest build
194+
gh release edit "$TAG_NAME" \
195+
--title "${{ steps.strategy.outputs.release_name }}" \
196+
--notes "**Latest Build**: $RAW_VERSION
197+
**Commit**: ${{ github.sha }}
198+
199+
Please select the appropriate firmware file for your development board.
200+
201+
> ⚠️ Note: This release gets updated automatically with new builds from the development branch."
202+
env:
203+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
204+
205+
- name: Create Release
206+
if: steps.check_release.outputs.create_release == 'true'
207+
uses: softprops/action-gh-release@v2
208+
with:
209+
tag_name: ${{ steps.strategy.outputs.tag_name }}
210+
name: ${{ steps.strategy.outputs.release_name }}
211+
body: |
212+
**Version**: ${{ steps.strategy.outputs.raw_version }}
213+
**Commit**: ${{ github.sha }}
214+
215+
Please select the appropriate firmware file for your development board.
216+
draft: false
217+
prerelease: true
218+
token: ${{ secrets.GITHUB_TOKEN }}
219+
outputs:
220+
release_tag: ${{ steps.strategy.outputs.tag_name }}
221+
firmware_tag: ${{ needs.version.outputs.firmware_tag }}
222+
continue: ${{ steps.check_release.outputs.continue }}
223+
224+
build-espressif:
225+
name: Build Port Espressif
226+
needs: [setup, create-release]
227+
if: needs.create-release.outputs.continue == 'true'
228+
strategy:
229+
fail-fast: false
230+
matrix: ${{ fromJSON(needs.setup.outputs.espressif) }}
231+
uses: ./.github/workflows/build.vendor.yml
232+
with:
233+
repo_remote: origin
234+
repo_ref: ${{ github.sha }}
235+
port: espressif
236+
board: ${{ matrix.board }}
237+
firmware_tag: ${{ needs.create-release.outputs.firmware_tag }}
238+
release_tag: ${{ needs.create-release.outputs.release_tag }}
239+
secrets: inherit
240+
241+
build-nordic:
242+
name: Build Port Nordic
243+
needs: [setup, create-release]
244+
if: needs.create-release.outputs.continue == 'true'
245+
strategy:
246+
fail-fast: false
247+
matrix: ${{ fromJSON(needs.setup.outputs.nordic) }}
248+
uses: ./.github/workflows/build.vendor.yml
249+
with:
250+
repo_remote: origin
251+
repo_ref: ${{ github.sha }}
252+
port: nordic
253+
board: ${{ matrix.board }}
254+
firmware_tag: ${{ needs.create-release.outputs.firmware_tag }}
255+
release_tag: ${{ needs.create-release.outputs.release_tag }}
256+
secrets: inherit
257+
258+
publish:
259+
name: Publish Artifacts
260+
runs-on: ubuntu-latest
261+
needs: [create-release, build-espressif, build-nordic]
262+
steps:
263+
- name: Checkout
264+
uses: actions/checkout@v5
265+
266+
- name: Setup Python
267+
uses: actions/setup-python@v6
268+
with:
269+
python-version: 3.x
270+
271+
- uses: actions/download-artifact@v5
272+
with:
273+
merge-multiple: true
274+
path: ./publish
275+
276+
- name: Upload binaries to release
277+
if: ${{ needs.create-release.outputs.release_tag != '' }}
278+
uses: softprops/action-gh-release@v2
279+
with:
280+
tag_name: ${{ needs.create-release.outputs.release_tag }}
281+
files: ./publish/*
282+
token: ${{ secrets.GITHUB_TOKEN }}
283+
284+
- name: Publish firmware to fobe-projects.github.io
285+
uses: peaceiris/actions-gh-pages@v4
286+
with:
287+
deploy_key: ${{ secrets.FOBE_ARTIFACT_PAGES_DEPLOY_KEY }}
288+
external_repository: fobe-projects/fobe-projects.github.io
289+
publish_branch: main
290+
publish_dir: ./publish
291+
destination_dir: firmwares/circuitpython/${{ needs.create-release.outputs.release_tag }}
292+
keep_files: true
293+
user_name: github-actions[bot]
294+
user_email: github-actions[bot]@users.noreply.github.com
295+
commit_message: circuitpython/${{ needs.create-release.outputs.release_tag }}
296+
enable_jekyll: true

0 commit comments

Comments
 (0)