|
8 | 8 | push: |
9 | 9 | branches: [main] |
10 | 10 |
|
| 11 | +concurrency: |
| 12 | + # Serialize main releases to avoid concurrent tag/release races. |
| 13 | + group: release-${{ github.ref }} |
| 14 | + cancel-in-progress: false |
| 15 | + |
11 | 16 | permissions: |
12 | 17 | # Default to read-only; release job elevates to write for tagging/releases. |
13 | 18 | contents: read |
|
22 | 27 |
|
23 | 28 | jobs: |
24 | 29 | release: |
25 | | - # Computes semantic version from conventional commits, creates git tag, |
26 | | - # and publishes GitHub release. |
| 30 | + # Computes semantic version from conventional commits and creates git tag. |
27 | 31 | name: Compute Version and Tag |
28 | 32 | runs-on: ubuntu-latest |
29 | 33 | permissions: |
@@ -88,26 +92,13 @@ jobs: |
88 | 92 | } |
89 | 93 | git config user.name "github-actions[bot]" |
90 | 94 | git config user.email "github-actions[bot]@users.noreply.github.com" |
91 | | - git rev-parse "$VERSION" >/dev/null 2>&1 && { |
| 95 | + git show-ref --verify --quiet "refs/tags/$VERSION" && { |
92 | 96 | echo "ERROR: tag '$VERSION' already exists."; |
93 | 97 | exit 1; |
94 | 98 | } |
95 | 99 | git tag -a "$VERSION" -m "release $VERSION" |
96 | 100 | git push origin "$VERSION" |
97 | 101 |
|
98 | | - - name: Compute release date |
99 | | - if: steps.version.outputs.changed == 'true' |
100 | | - id: release_date |
101 | | - run: echo "date=$(date -u +%Y-%m-%d)" >> "$GITHUB_OUTPUT" |
102 | | - |
103 | | - - name: Create GitHub release |
104 | | - if: steps.version.outputs.changed == 'true' |
105 | | - uses: softprops/action-gh-release@v3 |
106 | | - with: |
107 | | - tag_name: ${{ steps.version.outputs.version }} |
108 | | - name: Release v${{ steps.version.outputs.version }} (${{ steps.release_date.outputs.date }}) |
109 | | - generate_release_notes: true |
110 | | - |
111 | 102 | build: |
112 | 103 | # Build distributions only when semver-action reports a new release. |
113 | 104 | name: Build Package Artifacts |
@@ -156,6 +147,12 @@ jobs: |
156 | 147 | - name: Build distributions |
157 | 148 | run: poetry build |
158 | 149 |
|
| 150 | + - name: Smoke test built wheel |
| 151 | + run: | |
| 152 | + python -m pip install --upgrade pip |
| 153 | + python -m pip install --no-deps dist/*.whl |
| 154 | + vstack --help >/dev/null |
| 155 | +
|
159 | 156 | - name: Validate built artifact version |
160 | 157 | run: | |
161 | 158 | EXPECTED="${{ needs.release.outputs.version }}" |
@@ -194,3 +191,47 @@ jobs: |
194 | 191 |
|
195 | 192 | - name: Publish to PyPI |
196 | 193 | uses: pypa/gh-action-pypi-publish@release/v1 |
| 194 | + |
| 195 | + cleanup-failed-release-tag: |
| 196 | + # Delete freshly created release tag when downstream jobs fail. |
| 197 | + name: Cleanup Failed Release Tag |
| 198 | + runs-on: ubuntu-latest |
| 199 | + needs: [release, build, publish] |
| 200 | + if: ${{ always() && needs.release.outputs.changed == 'true' && (needs.build.result == 'failure' || needs.publish.result == 'failure') }} |
| 201 | + permissions: |
| 202 | + contents: write |
| 203 | + |
| 204 | + steps: |
| 205 | + - name: Checkout |
| 206 | + uses: actions/checkout@v6 |
| 207 | + |
| 208 | + - name: Delete failed release tag |
| 209 | + run: | |
| 210 | + VERSION="${{ needs.release.outputs.version }}" |
| 211 | + if git ls-remote --exit-code --tags origin "refs/tags/$VERSION" >/dev/null; then |
| 212 | + git push origin ":refs/tags/$VERSION" |
| 213 | + echo "Deleted failed release tag '$VERSION' from origin." |
| 214 | + else |
| 215 | + echo "Tag '$VERSION' already absent; nothing to delete." |
| 216 | + fi |
| 217 | +
|
| 218 | + github-release: |
| 219 | + # Create GitHub Release only after package build and publish succeed. |
| 220 | + name: Publish GitHub Release |
| 221 | + runs-on: ubuntu-latest |
| 222 | + needs: [release, publish] |
| 223 | + if: needs.release.outputs.changed == 'true' |
| 224 | + permissions: |
| 225 | + contents: write |
| 226 | + |
| 227 | + steps: |
| 228 | + - name: Compute release date |
| 229 | + id: release_date |
| 230 | + run: echo "date=$(date -u +%Y-%m-%d)" >> "$GITHUB_OUTPUT" |
| 231 | + |
| 232 | + - name: Create GitHub release |
| 233 | + uses: softprops/action-gh-release@v3 |
| 234 | + with: |
| 235 | + tag_name: ${{ needs.release.outputs.version }} |
| 236 | + name: Release v${{ needs.release.outputs.version }} (${{ steps.release_date.outputs.date }}) |
| 237 | + generate_release_notes: true |
0 commit comments