diff --git a/.github/workflows/version.yml b/.github/workflows/version.yml index a88325a..2d59fdd 100644 --- a/.github/workflows/version.yml +++ b/.github/workflows/version.yml @@ -45,9 +45,24 @@ on: type: string required: false default: 'dev' + force-stable: + description: 'Cut a stable release even on non-default branches (skips the --prerelease flag). Use when a non-default branch should own version cutting and the default branch acts as a deploy-only rubber stamp.' + type: boolean + required: false + default: false + create-rc-baseline: + description: 'After a stable release on the default branch, auto-create the next-minor RC prerelease tag on rc-branch. Set to false when the RC line is not maintained (e.g. when force-stable is used elsewhere).' + type: boolean + required: false + default: true + expose-latest-on-noops: + description: 'When semrel exits without cutting a new tag (rubber-stamp merges into a branch where the release already exists), still expose the latest stable release as outputs.version. Prevents downstream build/deploy/announce steps from falling back to a stale git-describe result across a divergent merge.' + type: boolean + required: false + default: false outputs: version: - description: 'The version produced, or empty if no release was cut.' + description: 'The version produced, or empty if no release was cut (unless expose-latest-on-noops is true, in which case the latest stable tag is exposed).' value: ${{ jobs.release.outputs.version }} jobs: @@ -109,10 +124,19 @@ jobs: RC_LINE: ${{ steps.detect.outputs.rc-line }} WITH_CHANGELOG_DEFAULT: ${{ inputs.changelog-on-default }} WITH_CHANGELOG_RC: ${{ inputs.changelog-on-rc }} + FORCE_STABLE: ${{ inputs.force-stable }} run: | set -- --token "$GH_TOKEN" --version-file --allow-no-changes - if [ "$CURRENT_REF" != "$DEFAULT_BRANCH" ] && [ -n "$RC_LINE" ]; then - set -- "$@" --prerelease --maintained-version "$RC_LINE" + if [ "$CURRENT_REF" != "$DEFAULT_BRANCH" ]; then + if [ "$FORCE_STABLE" = "true" ]; then + # go-semantic-release's condition-github plugin refuses a non-default + # branch with "configured to only publish from " unless the + # config says otherwise. Override defaultBranch so the condition sees + # branch==defaultBranch and proceeds. + set -- "$@" --ci-condition-opt "defaultBranch=$CURRENT_REF" + elif [ -n "$RC_LINE" ]; then + set -- "$@" --prerelease --maintained-version "$RC_LINE" + fi fi if { [ "$CURRENT_REF" = "$DEFAULT_BRANCH" ] && [ "$WITH_CHANGELOG_DEFAULT" = "true" ]; } || \ { [ "$CURRENT_REF" != "$DEFAULT_BRANCH" ] && [ "$WITH_CHANGELOG_RC" = "true" ]; }; then @@ -122,8 +146,27 @@ jobs: - name: Expose version id: version + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + EXPOSE_LATEST_ON_NOOP: ${{ inputs.expose-latest-on-noops }} run: | - if [ -f .version ]; then echo "version=$(cat .version)" >> "$GITHUB_OUTPUT"; fi + if [ -f .version ]; then + echo "version=$(cat .version)" >> "$GITHUB_OUTPUT" + elif [ "$EXPOSE_LATEST_ON_NOOP" = "true" ]; then + # Rubber-stamp path: semrel found no bump because the tag already + # exists on a merged branch. `git describe` on divergent histories + # can pick the wrong tag by rev-list distance, so read from GH + # releases instead — same source semrel itself used. + latest=$(gh release list \ + --repo "$GITHUB_REPOSITORY" \ + --exclude-pre-releases \ + --limit 1 \ + --json tagName \ + --jq '.[0].tagName' | sed 's/^v//') + if [ -n "$latest" ]; then + echo "version=$latest" >> "$GITHUB_OUTPUT" + fi + fi - name: Commit changelog if: | @@ -141,7 +184,9 @@ jobs: fi - name: Create next RC baseline - if: github.ref_name == github.event.repository.default_branch + if: | + inputs.create-rc-baseline && + github.ref_name == github.event.repository.default_branch env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} RC_BRANCH: ${{ inputs.rc-branch }}