Skip to content

Commit 915c134

Browse files
committed
add a tag.sh script to create signed release tags
Instead of a bare "git tag vX.Y.Z", which makes an unsigned lightweight tag and lets typos through, RELEASING.md now says to run ./tag.sh. The script accepts both "0.1.0" and "v0.1.0" (people forget the v), canonicalizes to "vX.Y.Z", and creates an SSH-signed annotated tag, requiring user.signingkey to be set. It refuses to proceed if the tag already exists on origin, always asking the remote rather than trusting possibly-stale local refs; an unpushed local-only tag is replaced. It does not push the tag (which is what triggers the Release workflow); it prints the push command to run instead. Updates tailscale/corp#24454 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com> Change-Id: I01cb076eeb8b34f1e2f5d42d9188ff7be2b31c4b
1 parent 04e9cf5 commit 915c134

2 files changed

Lines changed: 52 additions & 3 deletions

File tree

‎RELEASING.md‎

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,22 @@ Release with a changelog generated from the commit log.
99
## Cutting a release
1010

1111
1. Make sure the Test workflow is green on `main`.
12-
2. Tag and push:
12+
2. Run the release script, which creates an SSH-signed annotated tag
13+
after checking that the tag doesn't already exist on origin (a tag
14+
that exists only locally is replaced). It requires git's
15+
`user.signingkey` to be set to your SSH public key.
16+
17+
```sh
18+
./tag.sh v0.1.0
19+
```
20+
21+
3. Push the tag as the script instructs:
1322

1423
```sh
15-
git tag v0.1.0
1624
git push origin v0.1.0
1725
```
1826

19-
3. Watch the Release workflow in the Actions tab. When it finishes,
27+
4. Watch the Release workflow in the Actions tab. When it finishes,
2028
the release with all artifacts appears on the
2129
[Releases page](https://github.com/tailscale/tailcat/releases).
2230

‎tag.sh‎

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#!/usr/bin/env bash
2+
# tag.sh creates the SSH-signed tag for a new release but does not
3+
# push it. See RELEASING.md for the overall release process.
4+
set -euo pipefail
5+
6+
if [[ $# -ne 1 ]]; then
7+
echo "usage: $0 <version> (e.g. v0.1.0)" >&2
8+
exit 1
9+
fi
10+
11+
# Accept both "0.1.0" and "v0.1.0" and canonicalize to "v0.1.0".
12+
v="${1#v}"
13+
if [[ ! "$v" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then
14+
echo "tag.sh: invalid version \"$1\"; want something like v0.1.0" >&2
15+
exit 1
16+
fi
17+
tag="v$v"
18+
19+
if ! git config --get user.signingkey >/dev/null; then
20+
echo "tag.sh: git user.signingkey is not set; set it to your SSH public key with:" >&2
21+
echo " git config --global user.signingkey ~/.ssh/id_ed25519.pub" >&2
22+
exit 1
23+
fi
24+
25+
# The remote is the source of truth for whether a release exists, so
26+
# always ask it rather than trusting possibly-stale local refs. A tag
27+
# that exists only locally was never pushed and is fine to replace.
28+
echo "Checking whether $tag already exists on origin..."
29+
if [[ -n "$(git ls-remote --tags origin "refs/tags/$tag")" ]]; then
30+
echo "tag.sh: tag $tag already exists on origin" >&2
31+
exit 1
32+
fi
33+
34+
if git rev-parse -q --verify "refs/tags/$tag" >/dev/null; then
35+
echo "Replacing existing unpushed local tag $tag."
36+
fi
37+
38+
git -c gpg.format=ssh tag -s -f -m "tailcat $tag" "$tag"
39+
40+
echo "Created signed tag $tag. To push it and start the release:"
41+
echo " git push origin $tag"

0 commit comments

Comments
 (0)