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