|
60 | 60 | echo "version=${VERSION}" >> "$GITHUB_OUTPUT" |
61 | 61 | echo "Building tag=${TAG} version=${VERSION}" |
62 | 62 |
|
| 63 | + - name: Verify tag is reachable from main |
| 64 | + # Releases must be cut from `main`. Tagging a feature branch (e.g. when |
| 65 | + # a stacked PR has merged into a parent feature branch but not yet into |
| 66 | + # `main`) silently produces a release whose contents diverge from the |
| 67 | + # canonical history. Precedent: v0.0.8/v0.0.9 were tagged from |
| 68 | + # feat/embed-lmnr-key after PR #33 merged into the feature branch |
| 69 | + # (not into main); main moved on without it and the bcode-laminar |
| 70 | + # package had to be re-landed in PR #39. This guard fails the release |
| 71 | + # before any binaries are uploaded. |
| 72 | + # |
| 73 | + # Resolves the tag name to a commit SHA via `git rev-parse` rather than |
| 74 | + # using `$GITHUB_SHA`. For `push: tags` the two are equivalent, but for |
| 75 | + # `workflow_dispatch` with `inputs.tag` `$GITHUB_SHA` is the dispatch |
| 76 | + # ref's HEAD (typically main), not the selected tag's commit — using it |
| 77 | + # would let a feature-branch tag pass the check trivially. |
| 78 | + env: |
| 79 | + TAG: ${{ steps.ver.outputs.tag }} |
| 80 | + run: | |
| 81 | + git fetch origin main --depth=1 |
| 82 | + TAG_SHA=$(git rev-parse -q --verify "refs/tags/${TAG}^{commit}") || { |
| 83 | + echo "::error::Tag ${TAG} does not exist locally. Create the tag on a main commit first (e.g. \`gh release create ${TAG} --target main\`), then re-run." |
| 84 | + exit 1 |
| 85 | + } |
| 86 | + if ! git merge-base --is-ancestor "$TAG_SHA" origin/main; then |
| 87 | + echo "::error::Tag ${TAG} points at $TAG_SHA which is not reachable from origin/main. Release tags must be cut from main." |
| 88 | + exit 1 |
| 89 | + fi |
| 90 | +
|
63 | 91 | - name: Setup Bun |
64 | 92 | uses: ./.github/actions/setup-bun |
65 | 93 |
|
|
0 commit comments