Skip to content

Commit 0c0d319

Browse files
Merge pull request #43 from DeDuckProject/claude/setup-action-versioning-Tnd7l
Add release automation with semantic versioning
2 parents 55b4db9 + 1ad9278 commit 0c0d319

File tree

3 files changed

+86
-0
lines changed

3 files changed

+86
-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: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,19 @@ 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 use semver tags (`v1.0.0`) alongside a floating major tag (`v1`) — consumers pin to `@v1`.
71+
Only bump the major version for breaking changes (e.g. removed/renamed inputs, new required secrets).
72+
73+
To release:
74+
75+
```bash
76+
./scripts/release.sh 1.0.0
77+
```
78+
79+
Always use the script — it handles both tags atomically. Never tag manually.
80+
6881
## Branching Convention
6982

7083
- 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)