Skip to content

Commit 13f43eb

Browse files
committed
Add release script, workflow, and versioning docs
- Create scripts/release.sh to tag semver + floating major tags - Add .github/workflows/release.yml to auto-create GitHub Releases - Document versioning convention and breaking change policy in CLAUDE.md https://claude.ai/code/session_015h9iYcSULNLdxvk8aZ8v3g
1 parent 55b4db9 commit 13f43eb

File tree

3 files changed

+108
-0
lines changed

3 files changed

+108
-0
lines changed

.github/workflows/release.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags:
6+
- "v*.*.*"
7+
8+
permissions:
9+
contents: write
10+
11+
jobs:
12+
release:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- name: Checkout
16+
uses: actions/checkout@v4
17+
18+
- name: Create GitHub Release
19+
uses: softprops/action-gh-release@v2
20+
with:
21+
tag_name: ${{ github.ref_name }}
22+
generate_release_notes: true

CLAUDE.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,41 @@ not just this one. Every change we make must account for the experience of those
6565
- **Discuss trade-offs**: if a feature requires consumers to make non-trivial changes (new secrets,
6666
new workflow jobs, new permissions), flag it in the PR for a deliberate decision.
6767

68+
## Versioning & Releases
69+
70+
We follow the standard GitHub Actions versioning convention using semantic versioning tags
71+
alongside floating major tags.
72+
73+
- **Semantic tags** (`v1.0.0`, `v1.2.3`) are immutable and mark exact releases.
74+
- **Floating major tags** (`v1`, `v2`) always point to the latest non-breaking release
75+
in that major line. Consumers use `uses: DeDuckProject/git-glimpse@v1` to stay on the
76+
latest compatible version.
77+
- Only cut `v2` (bump the major version) for **breaking changes**.
78+
79+
### What counts as a breaking change
80+
81+
- Removing or renaming an existing action input or output
82+
- Changing the default behavior of an existing input in a way that alters results
83+
- Requiring a new permission, secret, or workflow event that consumers must add
84+
- Dropping support for a previously supported runner OS or Node version
85+
86+
### How to release
87+
88+
```bash
89+
./scripts/release.sh <version> # e.g. ./scripts/release.sh 1.0.0
90+
```
91+
92+
The script will:
93+
1. Create the immutable tag `v<version>`
94+
2. Force-move the floating major tag (`v1`, `v2`, etc.) to the same commit
95+
3. Push both tags to origin
96+
97+
A GitHub Actions workflow (`.github/workflows/release.yml`) automatically creates a
98+
GitHub Release with auto-generated release notes when a `v*.*.*` tag is pushed.
99+
100+
**Important:** Never push a release without updating both the semantic and floating tags.
101+
The release script handles this automatically — always use it instead of manual tagging.
102+
68103
## Branching Convention
69104

70105
- Features: `feat/<name>`

scripts/release.sh

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
if [ $# -ne 1 ]; then
5+
echo "Usage: $0 <version>"
6+
echo "Example: $0 1.0.0"
7+
exit 1
8+
fi
9+
10+
VERSION="$1"
11+
12+
# Strip leading 'v' if provided
13+
VERSION="${VERSION#v}"
14+
15+
# Validate semver format
16+
if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
17+
echo "Error: '$VERSION' is not a valid semantic version (expected X.Y.Z)"
18+
exit 1
19+
fi
20+
21+
MAJOR="${VERSION%%.*}"
22+
TAG="v${VERSION}"
23+
MAJOR_TAG="v${MAJOR}"
24+
25+
# Ensure we're on a clean working tree
26+
if [ -n "$(git status --porcelain)" ]; then
27+
echo "Error: working tree is not clean. Commit or stash changes first."
28+
exit 1
29+
fi
30+
31+
# Create the immutable semver tag
32+
if git rev-parse "$TAG" >/dev/null 2>&1; then
33+
echo "Error: tag '$TAG' already exists. Semver tags are immutable."
34+
exit 1
35+
fi
36+
37+
git tag "$TAG"
38+
echo "Created tag $TAG"
39+
40+
# Force-move the floating major tag
41+
git tag -f "$MAJOR_TAG"
42+
echo "Moved tag $MAJOR_TAG -> $(git rev-parse --short HEAD)"
43+
44+
# Push both tags
45+
git push origin "$TAG"
46+
git push origin "$MAJOR_TAG" --force
47+
48+
echo ""
49+
echo "Release complete:"
50+
echo " $TAG (immutable semver tag)"
51+
echo " $MAJOR_TAG (floating major tag, force-updated)"

0 commit comments

Comments
 (0)