Skip to content

Commit 5ac9089

Browse files
elifarleyclaude
andcommitted
Add release versioning targets: make version and make release
- Add scripts/release.sh: Validates semver version, checks for clean git state, creates annotated tag, and pushes to origin - Add make version target: Queries setuptools_scm to show current calculated version - Add make release VERSION=x.y.z target: Delegates to release.sh for safe, repeatable releases - Add setuptools-scm to dev dependencies in pyproject.toml - Update Makefile help documentation The release workflow is now clean and logic-free (all logic in scripts/release.sh), enabling safe tag creation and pushing as part of the development workflow. 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
1 parent abdf7c6 commit 5ac9089

3 files changed

Lines changed: 68 additions & 4 deletions

File tree

Makefile

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,14 @@ COV_HTML := htmlcov
2525
# If HATCH is available, we use it for running commands to ensure isolation.
2626
# Otherwise, we fall back to the local python environment.
2727
ifeq (, $(shell command -v $(HATCH) 2> /dev/null))
28-
# Hatch not found
28+
# Hatch not found - use local python
2929
RUNNER := $(PY) -m
30+
PYTHON_CMD := $(PY)
3031
BUILD_CMD := $(PY) -m build
3132
else
32-
# Hatch found
33+
# Hatch found - use hatch environment
3334
RUNNER := $(HATCH) run
35+
PYTHON_CMD := $(HATCH) run python
3436
BUILD_CMD := $(HATCH) build
3537
endif
3638

@@ -61,6 +63,10 @@ Targets:
6163
test-case Run specific test case (K=pattern)
6264
coverage-open Open coverage HTML report
6365

66+
# Release
67+
version Show current project version (calculated from git)
68+
release Create and push a new release tag (V=x.y.z)
69+
6470
# Build & Dist
6571
build Build wheel + sdist (clean first)
6672
clean Remove all build artifacts and __pycache__
@@ -71,7 +77,7 @@ Targets:
7177
endef
7278
export HELP_MESSAGE
7379

74-
.PHONY: help install dev format check-format lint test quick test-file test-case coverage-open build wheel sdist docs clean distclean ci
80+
.PHONY: help install dev format check-format lint test quick test-file test-case coverage-open build wheel sdist docs clean distclean ci release version
7581

7682
.DEFAULT_GOAL := help
7783

@@ -120,7 +126,15 @@ test-case: ## Run specific test case (K=pattern)
120126
$(RUNNER) $(PYTEST) $(PYTEST_ARGS) -k "$(K)" $(ARGS)
121127

122128
coverage-open:
123-
@$(PY) -c "import webbrowser, os; f = os.path.join(os.getcwd(), '$(COV_HTML)', 'index.html'); print('Opening:', f); webbrowser.open('file://' + f) if os.path.exists(f) else print('Run make test first.')"
129+
@$(PYTHON_CMD) -c "import webbrowser, os; f = os.path.join(os.getcwd(), '$(COV_HTML)', 'index.html'); print('Opening:', f); webbrowser.open('file://' + f) if os.path.exists(f) else print('Run make test first.')"
130+
131+
# ---------- Release ----------
132+
version v: ## Show current project version
133+
@$(PYTHON_CMD) -m setuptools_scm
134+
135+
release: ## Create and push a new release tag
136+
@chmod +x scripts/release.sh
137+
@./scripts/release.sh $(V)
124138

125139
# ---------- Build & Docs ----------
126140
build: ## Build dists

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ dev = [
3131
"pytest>=7.0.0",
3232
"pytest-cov>=4.0.0",
3333
"build>=1.0.0",
34+
"setuptools-scm>=8.0",
3435
]
3536

3637
[tool.setuptools_scm]

scripts/release.sh

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#!/usr/bin/env bash
2+
set -e
3+
4+
# scripts/release.sh
5+
# Handles the git tagging and pushing for a new release.
6+
# Usage: ./scripts/release.sh <version>
7+
8+
VERSION="$1"
9+
10+
# 1. Validation
11+
if [ -z "$VERSION" ]; then
12+
echo "Error: V argument is required."
13+
echo "Usage: make release V=1.2.3"
14+
exit 1
15+
fi
16+
17+
# Validate SemVer format (X.Y.Z, no 'v' prefix)
18+
if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z-]+)?$ ]]; then
19+
echo "Error: Version '$VERSION' does not match SemVer format (X.Y.Z)."
20+
echo "Example: 1.0.0, 0.2.1-rc1"
21+
exit 1
22+
fi
23+
24+
# Check for clean working directory
25+
if [ -n "$(git status --porcelain)" ]; then
26+
echo "Error: Git working directory is not clean."
27+
echo "Please commit or stash changes before releasing."
28+
exit 1
29+
fi
30+
31+
# Check if tag already exists
32+
if git rev-parse "refs/tags/$VERSION" >/dev/null 2>&1; then
33+
echo "Error: Tag '$VERSION' already exists."
34+
exit 1
35+
fi
36+
37+
# 2. Execution
38+
echo "Preparing release $VERSION..."
39+
40+
# Create annotated tag
41+
git tag -a "$VERSION" -m "Release $VERSION"
42+
echo "✅ Created git tag: $VERSION"
43+
44+
# Push tag
45+
echo "Pushing tag to origin..."
46+
git push origin "$VERSION"
47+
echo "✅ Pushed tag to origin"
48+
49+
echo "🚀 Release $VERSION triggered! Check GitHub Actions for progress."

0 commit comments

Comments
 (0)