|
1 | 1 | # Release Process |
2 | 2 |
|
3 | | -This guide walks maintainers through releasing a new version of **mitreattack-python**. |
4 | | -The process uses [Poetry](https://python-poetry.org/) for dependency management and building, |
5 | | -and [GitHub Actions](https://github.com/mitre-attack/mitreattack-python/actions) for automated linting, testing, and publishing to PyPI. |
| 3 | +Releases of **mitreattack-python** are fully automated. When commits are pushed (or squash-merged) to `main`, [Python Semantic Release (PSR)](https://python-semantic-release.readthedocs.io/) analyzes the commit messages and, if warranted, bumps the version, tags the release, creates a GitHub Release, and publishes the package to PyPI — all within the [CI pipeline](https://github.com/mitre-attack/mitreattack-python/actions). |
6 | 4 |
|
7 | | -## 1. Prepare for Release |
| 5 | +## How It Works |
8 | 6 |
|
9 | | -- Ensure all desired changes are merged into the `main` branch. |
10 | | -- If releasing for a new ATT&CK version, update `LATEST_VERSION` in `mitreattack/release_info.py`. |
| 7 | +1. **Commit messages drive versioning.** We follow the [Conventional Commits](https://www.conventionalcommits.org) specification. PSR parses commit messages to determine the appropriate [SemVer](https://semver.org/) bump: |
11 | 8 |
|
12 | | -## 2. Update Version and Metadata |
| 9 | + | Commit prefix | Version bump | Example | |
| 10 | + |---|---|---| |
| 11 | + | `feat:` | Minor (`0.X.0`) | `feat: add analytics to excel output` | |
| 12 | + | `fix:`, `perf:` | Patch (`0.0.X`) | `fix: handle missing data sources` | |
| 13 | + | `BREAKING CHANGE` in footer, or `!` after type | Major (`X.0.0`) | `feat!: drop Python 3.10 support` | |
| 14 | + | `build:`, `chore:`, `ci:`, `docs:`, `style:`, `refactor:`, `test:` | No release | `ci: update uv setup action` | |
13 | 15 |
|
14 | | -- Run `cz bump --files-only` |
15 | | - - This will increment the version field in `pyproject.toml` and other places according to semantic versioning rules. |
16 | | - - It will also update the `CHANGELOG.md` with all commit messages that are compatible with [Conventional Commits](https://www.conventionalcommits.org). |
17 | | - - NOTE: You should double-check the generated `CHANGELOG.md` file and make sure it looks good. |
18 | | -- Update other metadata as needed in `pyproject.toml` (dependencies, etc.). |
19 | | - - `poetry update --with dev --with docs` |
| 16 | +2. **PRs are squash-merged.** Individual commits within a PR do not need to follow conventional commits — only the PR title matters, as it becomes the squash merge commit message. The [`pr-title.yml`](../.github/workflows/pr-title.yml) workflow validates PR titles on open. |
20 | 17 |
|
21 | | -## 3. Local Validation (Recommended) |
| 18 | +3. **On push to `main`, the CI pipeline** (`.github/workflows/ci.yml`) runs: |
| 19 | + - **commitlint** — validates the squash merge commit message |
| 20 | + - **lint** — ruff check and format verification |
| 21 | + - **test** — pytest with coverage |
| 22 | + - **release** — PSR evaluates commits since the last tag, bumps version, tags, and creates a GitHub Release with build artifacts |
| 23 | + - **publish** — uploads the package to PyPI via trusted publishing (OIDC) |
22 | 24 |
|
23 | | -Before tagging and pushing, validate the release locally. Following these steps: |
| 25 | +## For Maintainers |
24 | 26 |
|
25 | | -```bash |
26 | | -# Pre-requisite: Install Poetry if not already installed |
27 | | -# https://python-poetry.org/docs/#installing-with-the-official-installer |
28 | | -curl -sSL https://install.python-poetry.org | python3 - |
| 27 | +### Triggering a Release |
| 28 | + |
| 29 | +No manual steps are needed. Simply merge a PR to `main` with a conventional commit title that includes a release-triggering prefix (`feat:`, `fix:`, or `perf:`). PSR will handle the rest. |
29 | 30 |
|
30 | | -# Clean previous builds |
31 | | -rm -rf dist/ |
| 31 | +### Pre-release Validation (Optional) |
32 | 32 |
|
| 33 | +If you want to validate locally before merging: |
| 34 | + |
| 35 | +```bash |
33 | 36 | # Install dependencies (including dev tools) |
34 | | -poetry install --with=dev |
| 37 | +just install |
35 | 38 |
|
36 | 39 | # Lint and format |
37 | | -poetry run ruff check |
38 | | -poetry run ruff format --check |
| 40 | +just lint |
39 | 41 |
|
40 | | -# Build docs |
41 | | -# This is managed directly by the Readthedocs site which is configured to watch our repository, but we should test it locally too |
42 | | -# https://app.readthedocs.org/projects/mitreattack-python/ |
43 | | -cd docs/ |
44 | | -poetry run python -m sphinx -T -b html -d _build/doctrees -D language=en . _build/html |
45 | | -cd .. |
46 | | - |
47 | | -# Run tests |
48 | | -poetry run pytest --cov=mitreattack --cov-report html |
| 42 | +# Run tests with coverage |
| 43 | +just test-cov |
49 | 44 |
|
50 | 45 | # Build the package |
51 | | -poetry build |
| 46 | +just build |
52 | 47 |
|
53 | 48 | # (Optional) Validate wheel contents |
54 | | -poetry run check-wheel-contents dist/ |
55 | | - |
56 | | -# (Optional) Install locally and smoke test |
57 | | -poetry run pip install --find-links=./dist mitreattack-python |
58 | | -poetry run python -c "import mitreattack; print(mitreattack.__version__)" |
59 | | -``` |
60 | | - |
61 | | -## 4. Commit and Tag the Release |
| 49 | +uv run check-wheel-contents dist/ |
62 | 50 |
|
63 | | -Make sure that after the above local testing you commit all changes! |
64 | | - |
65 | | -Perform the following steps to tag the release and push to GitHub: |
66 | | - |
67 | | -```bash |
68 | | -# Tag the release |
69 | | -git tag -a "vX.Y.Z" -m "mitreattack-python version X.Y.Z" |
70 | | - |
71 | | -# Push the commit and tag |
72 | | -git push |
73 | | -git push --tags |
| 51 | +# (Optional) Dry run semantic release |
| 52 | +just release-dry-run |
74 | 53 | ``` |
75 | 54 |
|
76 | | -## 5. Automated Publishing |
77 | | - |
78 | | -Once the tag is pushed to GitHub: |
79 | | - |
80 | | -- GitHub Actions will automatically lint, test, build, and publish the package to PyPI using the workflow in `.github/workflows/lint-publish.yml`. |
81 | | - |
82 | | -## 6. Verify Release |
83 | | - |
84 | | -Check the [GitHub Actions](https://github.com/mitre-attack/mitreattack-python/actions) for a successful workflow run. |
| 55 | +### Updating ATT&CK Version Metadata |
85 | 56 |
|
86 | | -Confirm the new version is available on [PyPI](https://pypi.org/project/mitreattack-python/). |
| 57 | +If releasing for a new ATT&CK version, update `LATEST_VERSION` in `mitreattack/release_info.py` before merging. |
87 | 58 |
|
88 | 59 | ## Notes |
89 | 60 |
|
90 | | -- All build and publish steps are handled by GitHub Actions once you push the tag. |
91 | | -- Manual local validation is optional but recommended before tagging. |
92 | | -- Readthedocs is used for documentation builds. [Check the status here](https://app.readthedocs.org/projects/mitreattack-python/). |
| 61 | +- All build, release, and publish steps are handled by GitHub Actions — no manual tagging or uploading. |
| 62 | +- Version is tracked in `pyproject.toml` (`project.version`) and synced to `docs/conf.py` and `mitreattack/__init__.py` by PSR. |
| 63 | +- Documentation builds are managed by [ReadTheDocs](https://app.readthedocs.org/projects/mitreattack-python/), which watches the repository. |
0 commit comments