1- .PHONY : help install commit lint format test test-integration test-unit bump
1+ .PHONY : help install lint format test test-integration test-unit bump release pypi tree version changelog
22
33.DEFAULT_GOAL := help
44
5+ CURRENT_VERSION = $(shell grep '^version' pyproject.toml | head -1 | sed 's/.* "\(.* \) "/\1/')
6+
57help : # # Shows a help message with all available commands
68 @awk ' BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf " \033[36m%-15s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST )
79
10+
811install : # # Sets up the development environment
912 @echo " >>> Setting up the development environment..."
1013 @echo " 1. Creating virtual environment with uv..."
@@ -15,15 +18,6 @@ install: ## Sets up the development environment
1518 uv run pre-commit install --hook-type commit-msg --hook-type pre-commit --hook-type pre-push
1619 @echo " \n\033[0;32mSetup complete! Please activate the virtual environment with 'source .venv/bin/activate'.\033[0m"
1720
18- commit : # # Starts Commitizen for a guided commit message
19- @echo " >>> Starting Commitizen for a guided commit message..."
20- @if git diff --cached --quiet; then \
21- echo " \033[0;33mWarning: No changes added to commit (please use 'git add ...' first).\033[0m" ; \
22- exit 1; \
23- fi
24- uv run cz commit
25- uv run cz bump --changelog --allow-no-commit
26-
2721
2822lint : # # Checks code quality with ruff
2923 @echo " >>> Checking code quality with ruff..."
@@ -53,35 +47,96 @@ test-integration: ## Runs integration tests (requires CS_TOKEN env var or .env f
5347 fi ; \
5448 uv run pytest tests/integration -v --run-integration
5549
56- release : # # Pushes a new tag and release
57- @echo " >>> Starting release process..."
58- git config --global push.followTags true
50+ version : # # Shows the current project version
51+ @echo " $( CURRENT_VERSION) "
5952
60- @echo "\n>>> Verifying tag and pushing to remote..."
61- export VERSION=$$(uv run cz version --project); \
62- if [ -z "$${ VERSION}" ]; then \
63- echo "\033[0;31mERROR: Could not determine version using 'cz version --project'.\033[0m "; \
53+ bump : # # Bumps the version. Usage: make bump VERSION=0.5.0
54+ @if [ -z " $( VERSION ) " ] ; then \
55+ echo " \033[0;31mERROR: VERSION is required. Usage: make bump VERSION=0.5.0\033[0m " ; \
56+ echo " Current version: $( CURRENT_VERSION ) " ; \
6457 exit 1; \
65- fi; \
66- echo "--- Found project version: v$${VERSION} ---"; \
67- if git rev-parse "v$${VERSION}" >/dev/null 2>&1; then \
68- echo "--- Verified local tag v$${VERSION} exists. ---"; \
58+ fi
59+ @echo " >>> Bumping version from $( CURRENT_VERSION) to $( VERSION) ..."
60+ @sed -i ' ' ' s/^version = ".*"/version = "$(VERSION)"/' pyproject.toml
61+ @echo " \033[0;32mVersion updated to $( VERSION) in pyproject.toml\033[0m"
62+
63+ changelog : # # Generates a changelog entry from git log since last tag. Usage: make changelog [VERSION=x.y.z]
64+ @NEW_VERSION=$$ {VERSION:-$(CURRENT_VERSION ) }; \
65+ LAST_TAG=$$(git describe --tags --abbrev=0 2>/dev/null || echo "" ) ; \
66+ DATE=$$(date +%Y-%m-%d ) ; \
67+ echo " >>> Generating changelog for v$$ {NEW_VERSION} ($$ {DATE})..." ; \
68+ TMPFILE=$$(mktemp ) ; \
69+ echo " ## v$$ {NEW_VERSION} ($$ {DATE})" > $$ TMPFILE; \
70+ echo " " >> $$ TMPFILE; \
71+ if [ -n " $$ LAST_TAG" ]; then \
72+ FEATS=$$(git log $${LAST_TAG}..HEAD --pretty=format:"- %s" --grep="^feat" 2>/dev/null ) ; \
73+ FIXES=$$(git log $${LAST_TAG}..HEAD --pretty=format:"- %s" --grep="^fix" 2>/dev/null ) ; \
74+ REFACTORS=$$(git log $${LAST_TAG}..HEAD --pretty=format:"- %s" --grep="^refactor" 2>/dev/null ) ; \
75+ OTHERS=$$(git log $${LAST_TAG}..HEAD --pretty=format:"- %s" --invert-grep --grep="^feat" --grep="^fix" --grep="^refactor" 2>/dev/null ) ; \
6976 else \
70- echo "\033[0;31mERROR: Git tag v$${VERSION} was not found! Please check for errors.\033[0m"; \
71- exit 1; \
77+ FEATS=$$(git log --pretty=format:"- %s" --grep="^feat" 2>/dev/null ) ; \
78+ FIXES=$$(git log --pretty=format:"- %s" --grep="^fix" 2>/dev/null ) ; \
79+ REFACTORS=$$(git log --pretty=format:"- %s" --grep="^refactor" 2>/dev/null ) ; \
80+ OTHERS=" " ; \
7281 fi ; \
73- echo "--- Pushing commit and tag to remote... ---"; \
74- git tag -d v$${VERSION}; \
75- git tag -a v$${VERSION} -m "Release $${VERSION}"; \
76- git push --follow-tags; \
77- echo "\n\033[0;32m✅ SUCCESS: Tag v$${VERSION} pushed to GitHub. The release workflow has been triggered.\033[0m"
82+ if [ -n " $$ FEATS" ]; then echo " ### Features\n" >> $$ TMPFILE; echo " $$ FEATS" >> $$ TMPFILE; echo " " >> $$ TMPFILE; fi ; \
83+ if [ -n " $$ FIXES" ]; then echo " ### Fixes\n" >> $$ TMPFILE; echo " $$ FIXES" >> $$ TMPFILE; echo " " >> $$ TMPFILE; fi ; \
84+ if [ -n " $$ REFACTORS" ]; then echo " ### Refactors\n" >> $$ TMPFILE; echo " $$ REFACTORS" >> $$ TMPFILE; echo " " >> $$ TMPFILE; fi ; \
85+ if [ -n " $$ OTHERS" ]; then echo " ### Other\n" >> $$ TMPFILE; echo " $$ OTHERS" >> $$ TMPFILE; echo " " >> $$ TMPFILE; fi ; \
86+ if [ -f CHANGELOG.md ]; then \
87+ cat CHANGELOG.md >> $$ TMPFILE; \
88+ fi ; \
89+ mv $$ TMPFILE CHANGELOG.md; \
90+ echo " \033[0;32mChangelog updated.\033[0m"
91+
92+ release : # # Bumps version, updates changelog, commits, tags, and pushes. Usage: make release VERSION=0.5.0
93+ @if [ -z " $( VERSION) " ]; then \
94+ echo " \033[0;31mERROR: VERSION is required. Usage: make release VERSION=0.5.0\033[0m" ; \
95+ echo " Current version: $( CURRENT_VERSION) " ; \
96+ exit 1; \
97+ fi
98+ @echo " >>> Starting release v$( VERSION) ..."
99+ @# Guard: ensure working tree is clean (except for staged changes)
100+ @if [ -n " $$ (git status --porcelain)" ]; then \
101+ echo " \033[0;33mWarning: You have uncommitted changes. Please commit or stash them first.\033[0m" ; \
102+ git status --short; \
103+ exit 1; \
104+ fi
105+ @# Guard: ensure we are on main branch
106+ @BRANCH=$$(git rev-parse --abbrev-ref HEAD ) ; \
107+ if [ " $$ BRANCH" != " main" ]; then \
108+ echo " \033[0;33mWarning: You are on branch '$$ BRANCH', not 'main'. Continue? [y/N]\033[0m" ; \
109+ read -r CONFIRM; \
110+ if [ " $$ CONFIRM" != " y" ] && [ " $$ CONFIRM" != " Y" ]; then \
111+ echo " Aborted." ; \
112+ exit 1; \
113+ fi ; \
114+ fi
115+ @# Guard: ensure tag does not already exist
116+ @if git rev-parse " v$( VERSION) " > /dev/null 2>&1 ; then \
117+ echo " \033[0;31mERROR: Tag v$( VERSION) already exists.\033[0m" ; \
118+ exit 1; \
119+ fi
120+ @# Step 1: Bump version in pyproject.toml
121+ $(MAKE ) bump VERSION=$(VERSION )
122+ @# Step 2: Update CHANGELOG.md
123+ $(MAKE ) changelog VERSION=$(VERSION )
124+ @# Step 3: Commit and tag
125+ @echo " >>> Committing release..."
126+ git add pyproject.toml CHANGELOG.md
127+ git commit -m " release: v$( VERSION) "
128+ git tag -a " v$( VERSION) " -m " Release $( VERSION) "
129+ @# Step 4: Push commit and tag
130+ @echo " >>> Pushing to remote..."
131+ git push --follow-tags
132+ @echo " \n\033[0;32m✅ Released v$( VERSION) . GitHub Actions will publish to PyPI and create the GitHub Release.\033[0m"
78133
79- pypi : # # publishes to PyPI
134+ pypi : # # Builds and publishes to PyPI (usually called by CI)
80135 @echo " \n>>> Building package for distribution..."
81136 uv build
82137 @echo " \n>>> Publishing to PyPI..."
83138 uv publish
84- @echo " \n\033[0;32mPyPI release complete! The GitHub Action will now create the GitHub Release. \033[0m"
139+ @echo " \n\033[0;32mPyPI release complete!\033[0m"
85140
86- tree : # # shows filetree in terminal without uninteresting files
141+ tree : # # Shows filetree in terminal without uninteresting files
87142 tree -I " *.pyc|*.lock"
0 commit comments