chore: release v4.7.0 (#139) #8
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release | |
| # Publishes a GitHub Release when a v* tag is pushed (HACS reads GitHub | |
| # releases). Every release is published as a PRE-RELEASE (and off "latest") so a | |
| # new version is never served to the default / HACS channel before it has been | |
| # tested — promote it to a full release later (step 4). For final-version tags | |
| # (no -alpha/-beta/-rc suffix) it then rolls main forward to the next minor so | |
| # unreleased work no longer carries the just-released version. | |
| # | |
| # Release flow: | |
| # 1. bin/release.sh <version> -> opens the chore/release PR (bumps manifest) | |
| # 2. merge the PR | |
| # 3. git tag v<version> && git push <remote> v<version> -> triggers this workflow | |
| # 4. test the pre-release, then promote it to the latest full release: | |
| # gh release edit v<version> --prerelease=false --latest=true | |
| # | |
| # The next-minor bump is pushed directly to main with the default GITHUB_TOKEN; | |
| # where main is protected that push is rejected — run bin/bump-dev.sh to land the | |
| # same bump via a PR instead. | |
| on: | |
| push: | |
| tags: ['v*'] | |
| permissions: | |
| contents: write | |
| jobs: | |
| publish: | |
| runs-on: ubuntu-latest | |
| name: Publish GitHub Release | |
| outputs: | |
| version: ${{ steps.version.outputs.version }} | |
| prerelease: ${{ steps.version.outputs.prerelease }} | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - name: Extract and validate version from tag | |
| id: version | |
| env: | |
| REF: ${{ github.ref }} | |
| run: | | |
| VERSION="${REF#refs/tags/v}" | |
| # Reject off-spec tags (the same semver contract bin/release.sh | |
| # enforces), so a hand-pushed bad tag can't slip through. | |
| bin/bump-version.sh --validate "$VERSION" | |
| echo "version=$VERSION" >> "$GITHUB_OUTPUT" | |
| # Whether the tag itself is a semver pre-release (-alpha/-beta/-rc). | |
| # The GitHub Release is always published as a pre-release regardless | |
| # (see below); this output only gates the main-forward bump. | |
| if [[ "$VERSION" == *-* ]]; then | |
| echo "prerelease=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "prerelease=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Validate manifest version matches tag | |
| env: | |
| VERSION: ${{ steps.version.outputs.version }} | |
| run: | | |
| MANIFEST_VER=$(python3 -c "import json; print(json.load(open('custom_components/cover_time_based/manifest.json'))['version'])") | |
| if [ "$VERSION" != "$MANIFEST_VER" ]; then | |
| echo "::error::Tag v$VERSION does not match manifest.json version $MANIFEST_VER" | |
| exit 1 | |
| fi | |
| - name: Build release notes from CHANGELOG | |
| id: notes | |
| env: | |
| VERSION: ${{ steps.version.outputs.version }} | |
| PRERELEASE: ${{ steps.version.outputs.prerelease }} | |
| run: | | |
| # Use the hand-written, user-facing CHANGELOG section as the release | |
| # notes. changelog-section.sh exits 0 (found), 1 (no section for this | |
| # version), or >=2 (its own error, e.g. CHANGELOG.md missing): | |
| # - found -> use the section as the release body | |
| # - exit 1, pre-release -> auto-generated notes (-alpha/-beta/-rc may | |
| # legitimately have no entry yet) | |
| # - exit 1, final tag -> fail: a shipped release must have notes | |
| # (matches the repo's block-on-drift posture) | |
| # - exit >=2 -> a real error; fail regardless of tag | |
| rc=0 | |
| bin/changelog-section.sh "$VERSION" > release-notes.md || rc=$? | |
| if [ "$rc" -eq 0 ]; then | |
| echo "found=true" >> "$GITHUB_OUTPUT" | |
| elif [ "$rc" -eq 1 ] && [ "$PRERELEASE" = "true" ]; then | |
| echo "No CHANGELOG.md section for pre-release $VERSION; using auto-generated notes." | |
| echo "found=false" >> "$GITHUB_OUTPUT" | |
| elif [ "$rc" -eq 1 ]; then | |
| echo "::error::No CHANGELOG.md section for final release $VERSION — add the entry before tagging." | |
| exit 1 | |
| else | |
| echo "::error::changelog-section.sh failed (exit $rc) for $VERSION — see its message above." | |
| exit "$rc" | |
| fi | |
| - name: Create GitHub Release | |
| uses: softprops/action-gh-release@v3 | |
| with: | |
| # The CHANGELOG section when present, otherwise GitHub's auto-generated | |
| # notes (see the previous step). | |
| body_path: ${{ steps.notes.outputs.found == 'true' && 'release-notes.md' || '' }} | |
| generate_release_notes: ${{ steps.notes.outputs.found != 'true' }} | |
| # Every release is created as a pre-release and off "latest", so a new | |
| # version is never pushed straight to users on the default / HACS | |
| # channel. Test it, then promote to the full latest release with: | |
| # gh release edit v<version> --prerelease=false --latest=true | |
| prerelease: true | |
| make_latest: false | |
| bump: | |
| needs: publish | |
| # Only final-version tags (no pre-release suffix) roll main forward; an | |
| # -alpha/-beta/-rc tag leaves the version alone. | |
| if: needs.publish.outputs.prerelease == 'false' | |
| runs-on: ubuntu-latest | |
| name: Bump main to next minor | |
| steps: | |
| - uses: actions/checkout@v5 | |
| with: | |
| ref: main | |
| - name: Compute next minor and bump version files | |
| id: bump | |
| env: | |
| VERSION: ${{ needs.publish.outputs.version }} | |
| run: | | |
| NEXT=$(python3 -c "import os; mj, mn, _ = os.environ['VERSION'].split('-')[0].split('.'); print(f'{mj}.{int(mn)+1}.0')") | |
| echo "next=$NEXT" >> "$GITHUB_OUTPUT" | |
| # Same verified bump bin/release.sh uses, so the two can't drift. | |
| bin/bump-version.sh "$NEXT" | |
| - name: Commit and push the bump directly to main | |
| env: | |
| NEXT: ${{ steps.bump.outputs.next }} | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git add -A | |
| # No-op guard: if the manifest is already at $NEXT (e.g. a re-run, or | |
| # main was hand-bumped), there's nothing to commit — exit cleanly | |
| # rather than letting `git commit` fail the job under `set -e`. | |
| if git diff --cached --quiet; then | |
| echo "manifest already at $NEXT — nothing to bump; skipping commit/push." | |
| exit 0 | |
| fi | |
| git commit -m "chore: bump version to $NEXT for development" | |
| # main is unprotected, so the default GITHUB_TOKEN can push directly. | |
| git push origin HEAD:main |