1+ name : Release on Changelog Update
2+
13on :
24 push :
3- tags :
4- - ' v3.*'
5- - ' v4.*'
6-
7- name : Upload Release Assets
5+ branches :
6+ - master
7+ paths :
8+ - ' CHANGELOG.md'
89
910env :
1011 MAKEOPTS : -j
@@ -13,27 +14,78 @@ permissions:
1314 contents : write
1415
1516jobs :
16- upload_release :
17- name : Upload Release Assets
17+ release :
18+ name : Build and Release
1819 runs-on : ubuntu-24.04
1920 steps :
20- - name : Install cross-compiler
21- run : sudo apt-get update && sudo apt-get install --yes gcc-arm-none-eabi
2221 - name : Checkout code
2322 uses : actions/checkout@v4
2423 with :
2524 submodules : true
2625 fetch-depth : 0
26+
27+ - name : Extract latest version and release notes from CHANGELOG.md
28+ id : changelog
29+ run : |
30+ # Find the first versioned section (skip [Unreleased])
31+ # Pattern: ## [x.y.z...] - date
32+ VERSION=$(grep -oP '(?<=^## \[)[^\]]+(?=\])' CHANGELOG.md | grep -v -i '^Unreleased$' | head -1)
33+
34+ if [ -z "$VERSION" ]; then
35+ echo "No versioned release found in CHANGELOG.md"
36+ exit 1
37+ fi
38+
39+ echo "version=$VERSION" >> "$GITHUB_OUTPUT"
40+ echo "tag=v$VERSION" >> "$GITHUB_OUTPUT"
41+
42+ # Extract release notes between this version's heading and the next ## heading
43+ # Use awk to capture lines between the target section and the next section
44+ ESCAPED_VERSION=$(printf '%s' "$VERSION" | sed 's/[.[\*^$()+?{|]/\\&/g')
45+ NOTES=$(awk "/^## \\[$ESCAPED_VERSION\\]/{found=1; next} found && /^## \\[/{exit} found{print}" CHANGELOG.md)
46+
47+ # Write notes to a file for the release body
48+ echo "$NOTES" > /tmp/release_notes.md
49+
50+ echo "Detected version: $VERSION"
51+ echo "Release notes:"
52+ cat /tmp/release_notes.md
53+
54+ - name : Check if release already exists
55+ id : check_release
56+ env :
57+ GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
58+ run : |
59+ TAG="v${{ steps.changelog.outputs.version }}"
60+ if gh release view "$TAG" --repo "$GITHUB_REPOSITORY" > /dev/null 2>&1; then
61+ echo "Release $TAG already exists. Skipping."
62+ echo "exists=true" >> "$GITHUB_OUTPUT"
63+ else
64+ echo "exists=false" >> "$GITHUB_OUTPUT"
65+ fi
66+
67+ - name : Install cross-compiler
68+ if : steps.check_release.outputs.exists == 'false'
69+ run : sudo apt-get update && sudo apt-get install --yes gcc-arm-none-eabi
70+
2771 - run : pipx install poetry
72+ if : steps.check_release.outputs.exists == 'false'
73+
2874 - run : poetry install --only=build
75+ if : steps.check_release.outputs.exists == 'false'
76+
2977 - name : Create credits file
78+ if : steps.check_release.outputs.exists == 'false'
3079 run : |
3180 echo "$PYBRICKS_EV3_CREDITS" > bricks/ev3/ci_credits.txt
3281 env :
3382 PYBRICKS_EV3_CREDITS : ${{ secrets.PYBRICKS_EV3_CREDITS }}
83+
3484 - name : Build firmware
85+ if : steps.check_release.outputs.exists == 'false'
3586 run : |
36- export MICROPY_GIT_TAG=ci-release-${{ github.run_number }}-$(git describe --tags --dirty --always --exclude "@pybricks/*")
87+ TAG="${{ steps.changelog.outputs.tag }}"
88+ export MICROPY_GIT_TAG=ci-release-${{ github.run_number }}-${TAG}
3789 export MICROPY_GIT_HASH=$(echo ${{ github.sha }} | cut -c1-8)
3890 poetry run make $MAKEOPTS -C micropython/mpy-cross
3991 poetry run make $MAKEOPTS -C bricks/movehub
@@ -43,27 +95,37 @@ jobs:
4395 poetry run make $MAKEOPTS -C bricks/essentialhub
4496 poetry run make $MAKEOPTS -C bricks/nxt
4597 poetry run make $MAKEOPTS -C bricks/ev3
46- - name : Get tag
47- run : echo "GITHUB_TAG=${GITHUB_REF#*refs/tags/}" >> $GITHUB_ENV
98+
4899 - name : Create Release and Upload Assets
100+ if : steps.check_release.outputs.exists == 'false'
49101 env :
50102 GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
51- tag : ${{ github.ref_name }}
52103 run : |
53- if [[ "${{ contains(env.GITHUB_TAG, 'a') || contains(env.GITHUB_TAG, 'b') || contains(env.GITHUB_TAG, 'c') }}" == "true" ]]; then
104+ TAG="${{ steps.changelog.outputs.tag }}"
105+ VERSION="${{ steps.changelog.outputs.version }}"
106+
107+ # Determine pre-release flag (alpha, beta, release candidate)
108+ PRERELEASE_FLAG=""
109+ if [[ "$VERSION" == *a* ]] || [[ "$VERSION" == *b* ]] || [[ "$VERSION" == *rc* ]]; then
54110 PRERELEASE_FLAG="--prerelease"
55- else
56- PRERELEASE_FLAG=""
57111 fi
112+
113+ # Rename and collect firmware assets
58114 HUBS="movehub cityhub technichub primehub essentialhub nxt ev3"
115+ ASSETS=""
59116 for HUB in $HUBS; do
60- NEW_FILENAME="./bricks/$HUB/build/pybricks-$HUB-${{ env.GITHUB_TAG }} .zip"
117+ NEW_FILENAME="./bricks/$HUB/build/pybricks-$HUB-$TAG .zip"
61118 mv "./bricks/$HUB/build/firmware.zip" "$NEW_FILENAME"
62119 ASSETS="$ASSETS $NEW_FILENAME"
63120 done
64- gh release create "$tag" \
121+
122+ # Create the git tag and GitHub release
123+ git tag "$TAG"
124+ git push origin "$TAG"
125+
126+ gh release create "$TAG" \
65127 --repo="$GITHUB_REPOSITORY" \
66- --title="${tag#v }" \
67- -F CHANGELOG .md \
128+ --title="${VERSION }" \
129+ -F /tmp/release_notes .md \
68130 $PRERELEASE_FLAG \
69131 $ASSETS
0 commit comments