Skip to content

Commit 92eaa14

Browse files
anshal21claude
andcommitted
Add Makefile with one-command release target
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 43cd471 commit 92eaa14

1 file changed

Lines changed: 61 additions & 0 deletions

File tree

Makefile

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# FirstOps SDK — dev + release tasks.
2+
#
3+
# Release: make release VERSION=0.2.1
4+
# -> bumps pyproject version, runs tests, commits, tags v0.2.1, pushes the
5+
# tag, and the GitHub `publish.yml` workflow builds + publishes to PyPI.
6+
#
7+
# PyPI versions are immutable: every release needs a NEW version. This target
8+
# keeps the pyproject version and the git tag in lockstep so they can't drift.
9+
10+
.PHONY: help install test build clean release
11+
12+
PYTHON ?= python3
13+
VENV ?= .venv
14+
PY = $(VENV)/bin/python
15+
16+
help:
17+
@echo "make install create venv + install package and dev deps"
18+
@echo "make test run the test suite"
19+
@echo "make build build wheel + sdist into dist/"
20+
@echo "make clean remove build artifacts"
21+
@echo "make release VERSION=X.Y.Z bump version, test, tag, and publish to PyPI"
22+
23+
$(VENV):
24+
$(PYTHON) -m venv $(VENV)
25+
26+
install: $(VENV)
27+
$(PY) -m pip install --upgrade pip
28+
$(PY) -m pip install -e ".[dev]" build
29+
30+
test:
31+
$(PY) -m pytest -q
32+
33+
build: clean
34+
$(PY) -m build
35+
36+
clean:
37+
rm -rf dist build src/*.egg-info *.egg-info
38+
39+
release:
40+
@if [ -z "$(VERSION)" ]; then \
41+
echo "Usage: make release VERSION=X.Y.Z"; exit 1; fi
42+
@echo "$(VERSION)" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+([abrc][0-9]+|\.post[0-9]+|\.dev[0-9]+)?$$' \
43+
|| { echo "VERSION must look like 1.2.3 (got '$(VERSION)')"; exit 1; }
44+
@if [ -n "$$(git status --porcelain)" ]; then \
45+
echo "Working tree not clean — commit or stash your changes first."; \
46+
echo "(A release commit should contain ONLY the version bump.)"; exit 1; fi
47+
@if git rev-parse "v$(VERSION)" >/dev/null 2>&1; then \
48+
echo "Tag v$(VERSION) already exists. Pick a new version (PyPI is immutable)."; exit 1; fi
49+
@echo ">> bumping pyproject.toml -> $(VERSION)"
50+
@$(PY) -c "import re,pathlib; p=pathlib.Path('pyproject.toml'); s=p.read_text(); s,n=re.subn(r'(?m)^version = \".*\"','version = \"$(VERSION)\"',s,count=1); assert n==1,'version line not found'; p.write_text(s)"
51+
@echo ">> running tests"
52+
@$(PY) -m pytest -q
53+
@echo ">> committing + tagging v$(VERSION)"
54+
@git add pyproject.toml
55+
@git commit -m "Release v$(VERSION)"
56+
@git tag -a "v$(VERSION)" -m "firstops v$(VERSION)"
57+
@echo ">> pushing branch + tag (triggers the PyPI publish workflow)"
58+
@git push
59+
@git push origin "v$(VERSION)"
60+
@echo ">> released v$(VERSION). Watch the publish run:"
61+
@echo " gh run watch \$$(gh run list --workflow=publish.yml -L1 --json databaseId -q '.[0].databaseId') --exit-status"

0 commit comments

Comments
 (0)