Make your first release¶
Picks up after First-run setup: you have a green dev cycle. This tutorial cuts a real release — branch, bump, changelog, tag, push.
Step 1 — Write a feature¶
Open src/afas_mcp_server/afas_mcp_server.py and edit hello():
def hello(someone: str = 'you') -> str:
"""Greet `someone` and announce the project."""
return f'Hello {someone} from afas_mcp_server!'
Update the smoke test under tests/ to match. Confirm the dev cycle is still green:
./workflow.cmd format && ./workflow.cmd lint && ./workflow.cmd test
Step 2 — Commit with Conventional Commits¶
git add -A
git commit -m "feat: greet someone by name"
The prefix does not drive the version bump — you'll pass that explicitly in the next step. What it drives is the release notes: when commitizen generates the changelog, it groups commits by prefix (feat: under "Features", fix: under "Bug Fixes", etc.). The lint step rejects any message that doesn't parse as Conventional Commits.
Step 3 — Cut the release¶
./workflow.cmd release -i minor
-i is your explicit version-increment choice (major, minor, patch, alpha, beta, or rc). The template does not infer it from commit messages.
The release task is the orchestrator. In order, it:
- Validates — working tree is clean and synced with origin, you're on
main. - Resolves the next version — runs
cz bump --dry-runto project the new version. - Checks for collisions — fails if the target tag or
release/<version>branch already exists locally or on origin. - Branches —
git checkout -b release/<version>. - Bumps —
cz bumpwrites the new version intopyproject.tomland creates the tag. - Updates the changelog —
cz changelogregeneratesdocs/changelog.mdand commits it. Signing follows yourcommit.gpgsignsetting; if signing is configured but no key can be reached — the usual case in CI — the commit is made unsigned and says so. Nothing is committed when the changelog is already current. - Pushes — branch and tag both go to origin.
- Opens the PR/MR — via the host's API when a token is set, otherwise prints a URL you can open yourself. Set
GITHUB_TOKENto a token withPull requests: read/write.
Pass --no-push to keep the branch and tag local for inspection.
Step 4 — Approve and merge¶
On your git host, approve the release PR/MR and merge with a merge commit (not a squash). The tag and bump land on main. If CI is configured for trusted publishing, release.publish fires automatically when the tag appears on main and your wheel lands on PyPI.
Verify¶
pip install <your_project_slug>==<new_version>from a fresh venv succeeds.pypi.org/project/<your_project_slug>/shows the new version.
You're done¶
You've cut a release. Next:
- Triage a security finding — what to do when pip-audit flags something.
- The scaffold — what the release shipped beyond the wheel (SBOM and security overview).