Skip to content

Commit ccb2e2c

Browse files
authored
Merge pull request #55 from mxstack/feature/hatch-vcs-versioning
Migrate to hatch-vcs for automated versioning
2 parents 4425500 + 40828ef commit ccb2e2c

File tree

4 files changed

+268
-6
lines changed

4 files changed

+268
-6
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@ __pycache__
1313
/dist/
1414
/docs/html/
1515
/requirements-mxdev.txt
16+
src/mxmake/_version.py

CHANGES.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Changelog
22

3-
## 1.3.1 (unreleased)
3+
## 2.0.0 (unreleased)
44

55
- **Breaking**: Drop Python 3.9 support. Minimum Python version is now 3.10.
66
- Feature: Modernize codebase to use Python 3.10+ features (PEP 604 union types, built-in generic types).
@@ -11,7 +11,6 @@
1111
- Fix: theme for newer Sphinx 7.x.
1212
- Fix: interactive uv venv, use --allow-existing instead.
1313
- Feature: Add support for Python 3.14.
14-
- Feature: Add `docs-linkcheck` to check for broken links in the sphinx documentation.
1514
- Breaking: Removed `MXENV_UV_GLOBAL` setting in favor of automatic UV detection.
1615
When `PYTHON_PACKAGE_INSTALLER=uv`, mxmake now automatically detects and uses
1716
a globally installed `uv` if available. To force local installation of uv,
@@ -31,6 +30,7 @@
3130
- Improvement: Simplified mxenv.mk logic from 3+ nesting levels to 1-2 levels
3231
using computed intermediate variables (`USE_GLOBAL_UV`, `USE_LOCAL_UV`).
3332
Code is now more maintainable and easier to extend.
33+
- Chore: Migrate to hatch-vcs for automated versioning from git tags.
3434

3535
## 1.3.0 (2025-09-03)
3636

RELEASE.md

Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
# mxmake Release Process Documentation
2+
3+
## Overview
4+
5+
The mxmake project uses **automated versioning via hatch-vcs**, which derives the version number from git tags during build time, eliminating manual version bumps in code.
6+
7+
## Prerequisites
8+
9+
- Commit access to the repository
10+
- PyPI publishing permissions (handled via GitHub Actions)
11+
- All tests passing on the main branch
12+
13+
## Step-by-Step Release Process
14+
15+
### 1. Prepare the Main Branch
16+
17+
Ensure you're on the main branch with all tests passing:
18+
19+
```bash
20+
git checkout main
21+
git pull origin main
22+
make test
23+
make check
24+
make typecheck
25+
git status # Should be clean
26+
```
27+
28+
### 2. Review Changes
29+
30+
Check what's changed since the last release:
31+
32+
```bash
33+
git log $(git describe --tags --abbrev=0)..HEAD --oneline
34+
```
35+
36+
### 3. Update CHANGES.md
37+
38+
Edit the changelog to:
39+
- Change "(unreleased)" to the release date (format: YYYY-MM-DD)
40+
- Add a new unreleased section for future changes
41+
- Maintain format: "## X.Y.Z (YYYY-MM-DD)"
42+
- Optionally include "[author]" at the end of each entry
43+
44+
Commit these changes:
45+
46+
```bash
47+
git add CHANGES.md
48+
git commit -m "Prepare release X.Y.Z"
49+
git push origin main
50+
```
51+
52+
### 4. Create a GitHub Release
53+
54+
1. Navigate to https://github.com/mxstack/mxmake/releases/new
55+
2. Click "Choose a tag" and type the version: `vX.Y.Z` (with the "v" prefix)
56+
3. Click "Create new tag: vX.Y.Z on publish"
57+
4. Set release title: `vX.Y.Z` or `Version X.Y.Z`
58+
5. Copy the relevant CHANGES.md section into the description
59+
6. Click "Publish release"
60+
61+
### 5. Monitor the Release
62+
63+
The GitHub Actions workflow automatically:
64+
- Runs tests across Python 3.9-3.14 on multiple operating systems
65+
- Runs linting, type checking, and variant tests
66+
- Builds the package with the version from the git tag
67+
- Publishes to PyPI if all tests pass
68+
69+
Monitor at: https://github.com/mxstack/mxmake/actions
70+
71+
### 6. Post-Release Verification
72+
73+
- Verify the package appears on PyPI: https://pypi.org/project/mxmake/
74+
- Check the version is correct
75+
- Optionally announce the release
76+
77+
## Version Numbering
78+
79+
**Format**: MAJOR.MINOR.PATCH (e.g., 1.4.0)
80+
81+
- **Git tags**: vMAJOR.MINOR.PATCH (e.g., v1.4.0)
82+
- **Package version**: MAJOR.MINOR.PATCH (v prefix automatically stripped)
83+
- The "v" prefix in tags is **required**
84+
85+
The project follows Semantic Versioning:
86+
- **MAJOR**: Breaking changes
87+
- **MINOR**: New features (backwards-compatible)
88+
- **PATCH**: Bug fixes (backwards-compatible)
89+
90+
## Development Versions
91+
92+
Between releases, development builds automatically receive versions like:
93+
94+
```
95+
1.4.0.dev3+g1234abc
96+
```
97+
98+
Where:
99+
- `1.4.0` = next release version from last tag
100+
- `dev3` = 3 commits since last tag
101+
- `g1234abc` = git commit hash
102+
103+
This happens automatically via hatch-vcs with no manual intervention needed.
104+
105+
## Emergency Hotfix Release
106+
107+
For urgent fixes to a released version:
108+
109+
1. Create a branch from the tag:
110+
```bash
111+
git checkout -b hotfix-1.4.1 v1.4.0
112+
```
113+
114+
2. Make and commit the fix:
115+
```bash
116+
git add .
117+
git commit -m "Fix critical bug"
118+
git push origin hotfix-1.4.1
119+
```
120+
121+
3. Create a pull request to main
122+
4. After merge, follow the normal release process with version `v1.4.1`
123+
124+
## Testing a Release (TestPyPI)
125+
126+
### Build Locally from a Tag
127+
128+
```bash
129+
git tag v1.4.0-rc1
130+
python -m build
131+
unzip -p dist/mxmake-*.whl mxmake/_version.py
132+
git tag -d v1.4.0-rc1
133+
```
134+
135+
### Upload to TestPyPI
136+
137+
```bash
138+
pip install twine
139+
twine upload --repository testpypi dist/*
140+
pip install --index-url https://test.pypi.org/simple/ mxmake
141+
```
142+
143+
## Release Checklist
144+
145+
- [ ] All tests passing on main branch
146+
- [ ] CHANGES.md updated with release date
147+
- [ ] New unreleased section added to CHANGES.md
148+
- [ ] Changes committed and pushed
149+
- [ ] GitHub release created with correct tag (vX.Y.Z format)
150+
- [ ] GitHub Actions workflow completed successfully
151+
- [ ] Package visible on PyPI with correct version
152+
- [ ] Release announced (if applicable)
153+
154+
## Troubleshooting
155+
156+
**Build fails with "version not found"**
157+
- Ensure you're in a git repository with tags fetched
158+
- Run: `git fetch --tags && python -m build`
159+
160+
**Version is wrong in built package**
161+
- Ensure clean checkout at the tagged commit
162+
- Run: `git checkout v1.4.0 && git status && python -m build`
163+
164+
**CI fails to publish to PyPI**
165+
- Check GitHub Actions workflow logs
166+
- Verify PyPI trusted publisher configuration
167+
- Contact repository maintainers
168+
169+
**README doesn't render correctly on PyPI**
170+
- Test locally: `python -m build && twine check dist/*`
171+
- Upload to TestPyPI first
172+
- Fix markdown formatting in relevant files
173+
174+
## Maintainer Notes
175+
176+
### PyPI Trusted Publisher Setup
177+
178+
Uses GitHub Actions OIDC for publishing (no API tokens needed):
179+
- Publisher: GitHub
180+
- Owner: mxstack
181+
- Repository: mxmake
182+
- Workflow: release.yml
183+
- Environment: release-pypi
184+
185+
### GitHub Release Environments
186+
187+
The workflow uses two environments:
188+
- **release-test-pypi**: Auto-publishes development versions to test.pypi.org on every main branch commit
189+
- **release-pypi**: Publishes official releases to pypi.org on GitHub release events
190+
191+
## Changelog Management
192+
193+
### Format
194+
195+
```markdown
196+
## Changes
197+
198+
## X.Y.Z (unreleased)
199+
200+
- Description of change
201+
202+
## X.Y.Z (YYYY-MM-DD)
203+
204+
- Description of change
205+
```
206+
207+
### Key Points
208+
209+
- Version in CHANGES.md is **manual** (you edit it)
210+
- Package version is **automatic** (from git tag via hatch-vcs)
211+
- Format: "## X.Y.Z (YYYY-MM-DD)" for released versions
212+
- Optionally add "[author]" at the end of each change entry
213+
214+
### Why This Works
215+
216+
With hatch-vcs, the package version is determined at build time from git tags. This means:
217+
- Maintain a human-readable changelog manually
218+
- Build system automatically gets the correct version
219+
- No need to sync version numbers across multiple files
220+
221+
## Manual Release (Not Recommended)
222+
223+
For emergency situations only:
224+
225+
```bash
226+
git checkout v1.4.0
227+
python -m build
228+
twine upload dist/*
229+
```
230+
231+
This bypasses CI checks and is not recommended for normal releases.
232+
233+
## Version Management Tools
234+
235+
### Check Current Version
236+
237+
```bash
238+
git describe --tags
239+
python -c "import mxmake; print(mxmake.__version__)"
240+
python -m build && unzip -p dist/mxmake-*.whl mxmake/_version.py
241+
```
242+
243+
### List All Releases
244+
245+
```bash
246+
git tag --list 'v*' --sort=-version:refname | head
247+
pip index versions mxmake
248+
```
249+
250+
## Further Reading
251+
252+
- [Semantic Versioning](https://semver.org/)
253+
- [hatch-vcs Documentation](https://github.com/ofek/hatch-vcs)
254+
- [GitHub Releases](https://docs.github.com/en/repositories/releasing-projects-on-github)
255+
- [PyPI Trusted Publishers](https://docs.pypi.org/trusted-publishers/)
256+
- [Python Packaging Guide](https://packaging.python.org/)

pyproject.toml

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
[project]
22
name = "mxmake"
33
description = "Generates a Python project-specific Makefile by using an extensible library of configurable Makefile snippets."
4-
version = "1.4.0"
54
keywords = ["development", "deployment", "make"]
65
authors = [
76
{name = "MX Stack Developers", email = "dev@bluedynamics.com" }
@@ -27,7 +26,13 @@ dependencies = [
2726
"mxdev>=4.0.2",
2827
"pyyaml"
2928
]
30-
dynamic = ["readme"]
29+
dynamic = ["readme", "version"]
30+
31+
[tool.hatch.version]
32+
source = "vcs"
33+
34+
[tool.hatch.build.hooks.vcs]
35+
version-file = "src/mxmake/_version.py"
3136

3237
[tool.hatch.metadata.hooks.fancy-pypi-readme]
3338
content-type = "text/markdown"
@@ -73,7 +78,7 @@ applications = "mxmake.topics:applications"
7378
i18n = "mxmake.topics:i18n"
7479

7580
[build-system]
76-
requires = ["hatchling", "hatch-fancy-pypi-readme"]
81+
requires = ["hatchling", "hatch-vcs", "hatch-fancy-pypi-readme"]
7782
build-backend = "hatchling.build"
7883

7984
[tool.pytest.ini_options]
@@ -96,7 +101,7 @@ python_version = "3.10"
96101
[tool.ruff]
97102
target-version = "py310"
98103
# Exclude a variety of commonly ignored directories.
99-
exclude = []
104+
exclude = ["src/mxmake/_version.py"]
100105

101106
[tool.ruff.lint]
102107
select = ["UP"] # Enable pyupgrade rules for Python 3.10+ modernization

0 commit comments

Comments
 (0)