diff --git a/.github/workflows/tag-release.yml b/.github/workflows/tag-release.yml index ef43d1d..27c02d0 100644 --- a/.github/workflows/tag-release.yml +++ b/.github/workflows/tag-release.yml @@ -1,16 +1,74 @@ # A merged release PR (VERSION changed on main) becomes the vX.Y.Z tag and # GitHub Release, created with the App token so publication triggers. +# +# The manual run is the recovery for a push event GitHub never delivered +# (the merge of #167, 2026-09-28: no workflow ran for it at all). It tags the +# commit on main that last changed VERSION, and refuses if that tag exists. name: Tag release on: push: branches: [main] paths: [VERSION] + workflow_dispatch: {} permissions: contents: read jobs: tag: + if: github.event_name == 'push' uses: PyDevices/.github/.github/workflows/reusable-tag-on-release-merge.yml@publishing-v6 secrets: inherit + + tag-manual: + if: github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/main' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Find the release commit + id: detect + run: | + V=$(tr -d '[:space:]' < VERSION) + if ! [[ "$V" =~ ^[0-9]+\.[0-9]+\.[0-9]+((a|b|rc)[0-9]+|\.dev[0-9]+)?$ ]]; then + echo "VERSION reads '$V', which is not a release version." >&2 + exit 1 + fi + if git rev-parse -q --verify "refs/tags/v$V" >/dev/null; then + echo "Tag v$V already exists; nothing to do." + echo "changed=false" >> "$GITHUB_OUTPUT"; exit 0 + fi + # The merge that brought the VERSION change onto main: what the + # push run would have tagged. + SHA=$(git log -1 --first-parent --format=%H -- VERSION) + if [ "$(git show "$SHA:VERSION" | tr -d '[:space:]')" != "$V" ]; then + echo "VERSION at $SHA does not read $V." >&2 + exit 1 + fi + echo "changed=true" >> "$GITHUB_OUTPUT" + echo "version=$V" >> "$GITHUB_OUTPUT" + echo "sha=$SHA" >> "$GITHUB_OUTPUT" + echo "Tagging v$V at $SHA" + + - name: Mint App token + if: steps.detect.outputs.changed == 'true' + id: app-token + uses: actions/create-github-app-token@v3 + with: + app-id: ${{ secrets.PYDEVICES_APP_ID }} + private-key: ${{ secrets.PYDEVICES_APP_PRIVATE_KEY }} + + - name: Create tag and Release + if: steps.detect.outputs.changed == 'true' + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + V: ${{ steps.detect.outputs.version }} + SHA: ${{ steps.detect.outputs.sha }} + run: | + PRERELEASE="" + [[ "$V" =~ (a|b|rc)[0-9]+$|\.dev[0-9]+$ ]] && PRERELEASE="--prerelease" + gh release create "v$V" --target "$SHA" \ + --title "v$V" --generate-notes $PRERELEASE