Skip to content

Commit 12e4e1c

Browse files
committed
Catch burned release tags and report failed releases
Releases are immutable, so a published release's tag can't be moved or reused even when its release run fails. v2.11.8 and v2.11.9 were tagged one ahead of the package version at their commits, failed the release workflow's tag/version check, and left nothing on PyPI or Docker Hub. Only the person who published them was notified. - Version Check now fails when v<version> is already a tag, since PyPI alone can't tell that a version has been burned. - The release workflow opens an issue for the team when it fails, with the run, the tag, the package version and what to do next. - Fold the never-published 2.11.7 and 2.11.8 changelog entries into 2.11.10, which is the first release to ship them.
1 parent 7179ede commit 12e4e1c

3 files changed

Lines changed: 63 additions & 12 deletions

File tree

‎.github/workflows/release.yml‎

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ jobs:
99
permissions:
1010
id-token: write
1111
contents: read
12+
issues: write
1213
steps:
1314
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
1415
with:
@@ -123,3 +124,44 @@ jobs:
123124
socketdev/cli:${{ env.VERSION }}
124125
build-args: |
125126
CLI_VERSION=${{ env.VERSION }}
127+
128+
# Releases are immutable, so a failed run leaves a published GitHub release whose
129+
# tag can never be reused, with nothing on PyPI or Docker Hub behind it. A failed
130+
# run only notifies whoever published the release, so raise it where the team
131+
# will see it.
132+
- name: Open an issue for the failed release
133+
if: failure()
134+
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
135+
env:
136+
VERSION: ${{ env.VERSION }}
137+
with:
138+
script: |
139+
const release = context.payload.release;
140+
const runUrl =
141+
`${context.serverUrl}/${context.repo.owner}/${context.repo.repo}` +
142+
`/actions/runs/${context.runId}`;
143+
const body = [
144+
`@SocketDev/customer-engineering the release workflow for [${release.tag_name}](${release.html_url}) ` +
145+
`(published by @${release.author.login}) failed: ${runUrl}`,
146+
'',
147+
`- Tag: \`${release.tag_name}\``,
148+
`- Package version at that commit: \`${process.env.VERSION || 'unknown'}\``,
149+
'',
150+
'Check the run for which step failed. If it failed before "Publish to PyPI", nothing reached PyPI or ' +
151+
'Docker Hub, but the GitHub release is immutable and its tag can never be reused.',
152+
'',
153+
'Before publishing another release:',
154+
'',
155+
'1. Edit this release\'s notes to say it was not published and name the release that replaces it.',
156+
'2. If the tag and the package version disagree, merge a PR that bumps the version to one with no ' +
157+
'existing tag (the Version Check workflow enforces this), then publish a release whose tag matches ' +
158+
'that version exactly. Do not pick the next tag number from the releases list.',
159+
].join('\n');
160+
161+
const created = await github.rest.issues.create({
162+
owner: context.repo.owner,
163+
repo: context.repo.repo,
164+
title: `Release ${release.tag_name} failed`,
165+
body,
166+
});
167+
core.error(`Release failed; opened #${created.data.number}`);

‎.github/workflows/version-check.yml‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ jobs:
4444
python3 <<'PY'
4545
import json
4646
import os
47+
import subprocess
4748
import tomllib
4849
import urllib.request
4950
from packaging import version
@@ -96,6 +97,21 @@ jobs:
9697
)
9798
raise SystemExit(1)
9899
100+
# Releases are immutable: once a v<version> release is published, its tag can't
101+
# be moved or reused, even when that release failed and nothing reached PyPI.
102+
# PyPI alone misses that, so a burned tag would only surface when the release
103+
# run fails after the merge.
104+
tag = f"v{os.environ['PR_VERSION']}"
105+
if subprocess.run(
106+
["git", "rev-parse", "--quiet", "--verify", f"refs/tags/{tag}"],
107+
capture_output=True,
108+
).returncode == 0:
109+
print(
110+
f"❌ Tag {tag} already exists, so {pr_ver} can never be released "
111+
f"(latest PyPI release: {pypi_ver}). Bump to a version with no tag."
112+
)
113+
raise SystemExit(1)
114+
99115
if pr_ver < main_ver:
100116
print(
101117
f"❌ Version moves backwards: main is {main_ver}, PR is {pr_ver}."

‎CHANGELOG.md‎

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## 2.11.10
44

5+
Versions 2.11.7 through 2.11.9 were never published to PyPI or Docker Hub. The
6+
GitHub releases tagged `v2.11.8` and `v2.11.9` have no packages behind them;
7+
their changes ship here.
8+
59
### Fixed: report why a new repository couldn't be created
610

711
- When a repository isn't in Socket yet and the API token can't create it, the
@@ -11,21 +15,10 @@
1115
- After the CLI creates a missing repository, its logging is no longer silenced
1216
for the rest of the run.
1317

14-
## 2.11.8
15-
1618
### Changed: bump pinned Coana CLI to 15.14.0
1719

18-
- Bumped the pinned reachability engine (the Coana CLI) from `15.13.3` to
19-
`15.14.0`. See the
20-
[reachability analysis changelog](https://docs.socket.dev/docs/reachability-analysis-changelog)
21-
for engine changes.
22-
23-
## 2.11.7
24-
25-
### Changed: bump pinned Coana CLI to 15.13.3
26-
2720
- Bumped the pinned reachability engine (the Coana CLI) from `15.13.2` to
28-
`15.13.3`. See the
21+
`15.14.0`. See the
2922
[reachability analysis changelog](https://docs.socket.dev/docs/reachability-analysis-changelog)
3023
for engine changes.
3124

0 commit comments

Comments
 (0)