|
1 | | -.PHONY: clean clean-pyc clean-build clean-test clean-all test run build publish help install dev-install |
| 1 | +.PHONY: clean clean-pyc clean-build clean-test clean-all test run build publish help install dev-install version bump-patch bump-minor bump-major release |
2 | 2 |
|
3 | 3 | # Default target |
4 | 4 | help: |
|
20 | 20 | @echo " check - Run all checks (lint, typecheck, security, test)" |
21 | 21 | @echo " run - Run the server" |
22 | 22 | @echo " build - Build the project" |
23 | | - @echo " publish - Build and publish to PyPI" |
| 23 | + @echo "" |
| 24 | + @echo "Release targets:" |
| 25 | + @echo " version - Show current version" |
| 26 | + @echo " bump-patch - Bump patch version (0.0.X)" |
| 27 | + @echo " bump-minor - Bump minor version (0.X.0)" |
| 28 | + @echo " bump-major - Bump major version (X.0.0)" |
| 29 | + @echo " publish - Create tag and trigger automated release" |
| 30 | + @echo " release - Alias for publish" |
24 | 31 |
|
25 | 32 | # Basic clean - Python bytecode and common artifacts |
26 | 33 | clean: clean-pyc clean-build |
@@ -142,32 +149,120 @@ build: clean-build |
142 | 149 | fi |
143 | 150 | @echo "Build complete. Distributions are in the 'dist' folder." |
144 | 151 |
|
145 | | -# Publish the package to PyPI using twine |
146 | | -publish: build |
147 | | - @echo "Publishing package..." |
148 | | - @if [ ! -d "dist" ] || [ -z "$$(ls -A dist 2>/dev/null)" ]; then \ |
149 | | - echo "Error: No distribution files found. Run 'make build' first."; \ |
| 152 | +# ============================================================================ |
| 153 | +# Version Management and Release Targets |
| 154 | +# ============================================================================ |
| 155 | + |
| 156 | +# Show current version |
| 157 | +version: |
| 158 | + @version=$$(grep '^version = ' pyproject.toml | cut -d'"' -f2); \ |
| 159 | + echo "Current version: $$version" |
| 160 | + |
| 161 | +# Bump patch version (0.0.X) |
| 162 | +bump-patch: |
| 163 | + @echo "Bumping patch version..." |
| 164 | + @current=$$(grep '^version = ' pyproject.toml | cut -d'"' -f2); \ |
| 165 | + major=$$(echo $$current | cut -d. -f1); \ |
| 166 | + minor=$$(echo $$current | cut -d. -f2); \ |
| 167 | + patch=$$(echo $$current | cut -d. -f3); \ |
| 168 | + new_patch=$$(($$patch + 1)); \ |
| 169 | + new_version="$$major.$$minor.$$new_patch"; \ |
| 170 | + sed -i.bak "s/^version = \"$$current\"/version = \"$$new_version\"/" pyproject.toml && rm pyproject.toml.bak; \ |
| 171 | + echo "Version bumped: $$current -> $$new_version"; \ |
| 172 | + echo "Review the change, then run 'make publish' to release" |
| 173 | + |
| 174 | +# Bump minor version (0.X.0) |
| 175 | +bump-minor: |
| 176 | + @echo "Bumping minor version..." |
| 177 | + @current=$$(grep '^version = ' pyproject.toml | cut -d'"' -f2); \ |
| 178 | + major=$$(echo $$current | cut -d. -f1); \ |
| 179 | + minor=$$(echo $$current | cut -d. -f2); \ |
| 180 | + new_minor=$$(($$minor + 1)); \ |
| 181 | + new_version="$$major.$$new_minor.0"; \ |
| 182 | + sed -i.bak "s/^version = \"$$current\"/version = \"$$new_version\"/" pyproject.toml && rm pyproject.toml.bak; \ |
| 183 | + echo "Version bumped: $$current -> $$new_version"; \ |
| 184 | + echo "Review the change, then run 'make publish' to release" |
| 185 | + |
| 186 | +# Bump major version (X.0.0) |
| 187 | +bump-major: |
| 188 | + @echo "Bumping major version..." |
| 189 | + @current=$$(grep '^version = ' pyproject.toml | cut -d'"' -f2); \ |
| 190 | + major=$$(echo $$current | cut -d. -f1); \ |
| 191 | + new_major=$$(($$major + 1)); \ |
| 192 | + new_version="$$new_major.0.0"; \ |
| 193 | + sed -i.bak "s/^version = \"$$current\"/version = \"$$new_version\"/" pyproject.toml && rm pyproject.toml.bak; \ |
| 194 | + echo "Version bumped: $$current -> $$new_version"; \ |
| 195 | + echo "Review the change, then run 'make publish' to release" |
| 196 | + |
| 197 | +# Automated release - creates tag and pushes to trigger GitHub Actions |
| 198 | +publish: |
| 199 | + @echo "Starting automated release process..." |
| 200 | + @echo "" |
| 201 | + @# Get current version |
| 202 | + @version=$$(grep '^version = ' pyproject.toml | cut -d'"' -f2); \ |
| 203 | + tag="v$$version"; \ |
| 204 | + echo "Version: $$version"; \ |
| 205 | + echo "Tag: $$tag"; \ |
| 206 | + echo ""; \ |
| 207 | + \ |
| 208 | + echo "Pre-flight checks:"; \ |
| 209 | + echo "=================="; \ |
| 210 | + \ |
| 211 | + if git diff --quiet && git diff --cached --quiet; then \ |
| 212 | + echo "✓ Working directory is clean"; \ |
| 213 | + else \ |
| 214 | + echo "✗ Working directory has uncommitted changes"; \ |
| 215 | + echo ""; \ |
| 216 | + git status --short; \ |
| 217 | + echo ""; \ |
| 218 | + echo "Please commit or stash your changes before releasing."; \ |
150 | 219 | exit 1; \ |
151 | | - fi |
152 | | - @last_build=$$(ls -t dist/*.tar.gz dist/*.whl 2>/dev/null | head -n 2); \ |
153 | | - if [ -z "$$last_build" ]; then \ |
154 | | - echo "Error: No valid distribution files found."; \ |
| 220 | + fi; \ |
| 221 | + \ |
| 222 | + if git tag -l | grep -q "^$$tag$$"; then \ |
| 223 | + echo "✗ Tag $$tag already exists"; \ |
| 224 | + echo ""; \ |
| 225 | + echo "To delete and recreate:"; \ |
| 226 | + echo " git tag -d $$tag"; \ |
| 227 | + echo " git push origin :refs/tags/$$tag"; \ |
155 | 228 | exit 1; \ |
| 229 | + else \ |
| 230 | + echo "✓ Tag $$tag does not exist yet"; \ |
156 | 231 | fi; \ |
157 | | - echo "Uploading: $$last_build"; \ |
158 | | - twine upload $$last_build |
159 | | - @echo "Publish complete." |
160 | | - |
161 | | -# Publish to test PyPI |
162 | | -publish-test: build |
163 | | - @echo "Publishing to test PyPI..." |
164 | | - @last_build=$$(ls -t dist/*.tar.gz dist/*.whl 2>/dev/null | head -n 2); \ |
165 | | - if [ -z "$$last_build" ]; then \ |
166 | | - echo "Error: No valid distribution files found."; \ |
| 232 | + \ |
| 233 | + current_branch=$$(git rev-parse --abbrev-ref HEAD); \ |
| 234 | + echo "✓ Current branch: $$current_branch"; \ |
| 235 | + echo ""; \ |
| 236 | + \ |
| 237 | + echo "This will:"; \ |
| 238 | + echo " 1. Create and push tag $$tag"; \ |
| 239 | + echo " 2. Trigger GitHub Actions to:"; \ |
| 240 | + echo " - Create a GitHub release with changelog"; \ |
| 241 | + echo " - Run tests on all platforms"; \ |
| 242 | + echo " - Build and publish to PyPI"; \ |
| 243 | + echo ""; \ |
| 244 | + read -p "Continue? (y/N) " -n 1 -r; \ |
| 245 | + echo ""; \ |
| 246 | + if [[ ! $$REPLY =~ ^[Yy]$$ ]]; then \ |
| 247 | + echo "Aborted."; \ |
167 | 248 | exit 1; \ |
168 | 249 | fi; \ |
169 | | - echo "Uploading to test PyPI: $$last_build"; \ |
170 | | - twine upload --repository testpypi $$last_build |
| 250 | + \ |
| 251 | + echo ""; \ |
| 252 | + echo "Creating and pushing tag..."; \ |
| 253 | + git tag -a "$$tag" -m "Release $$tag" && \ |
| 254 | + git push origin "$$tag" && \ |
| 255 | + echo "" && \ |
| 256 | + echo "✓ Tag pushed successfully!" && \ |
| 257 | + echo "" && \ |
| 258 | + echo "GitHub Actions workflows triggered:" && \ |
| 259 | + echo " - Release creation: https://github.com/$$(git config --get remote.origin.url | sed 's/.*://;s/.git$$//')/actions/workflows/release.yml" && \ |
| 260 | + echo " - PyPI publishing: https://github.com/$$(git config --get remote.origin.url | sed 's/.*://;s/.git$$//')/actions/workflows/publish.yml" && \ |
| 261 | + echo "" && \ |
| 262 | + echo "Monitor progress at: https://github.com/$$(git config --get remote.origin.url | sed 's/.*://;s/.git$$//')/actions" |
| 263 | + |
| 264 | +# Alias for publish |
| 265 | +release: publish |
171 | 266 |
|
172 | 267 | # Check code quality |
173 | 268 | lint: |
|
0 commit comments