feat: release automation script
This PR automates the release process according to our discussion in Frankfurt, see here (internal link) for more details.
Dependencies:
- ENV var
GITHUB_TOKENset -
gitcommand available locally
The script does the following:
- Runs locally with minimal dependencies (
pygithub, installed by tox, andgitcommand) - By default, release from the main branch, but other branch is supported.
- Release:
tox -e release. This detects version from the latest tag and suggests a new version for user confirmation. It can be overriden with user-provided value. - The script can detect open "update charm pins" PR and asks the user to merge those first.
- The script asks for a human-written title and a introductory paragraph for the release.
- Release note and
CHANGES.mdare formatted (for example, drop the GitHub usernames) with categorizations accordingly - The script automates version number changes in various files and creates a PR.
@tonyandrewmeyer @james-garner-canonical please have a look because I think according to the order it's going to be you guys doing releases soon.
Todo:
- [ ] Test the script by doing a real release.
- [ ] Update docs dependencies as separate process/PR.
Test in a mock repo
Existing old release
Release
$ python release.py
ℹ️ INFO: Latest version in branch "main"": 0.1.0
ℹ️ INFO: Suggested new version: 0.1.1
Input version to release (press enter to use suggested version 0.1.1), or 'c' to cancel:
⚠️ WARNING: Check out the releases page: https://github.com/IronCoreWorks/release-automation/releases before confirming!
Confirm creating release '0.1.1' on branch 'main'? [y/N]: y
ℹ️ INFO: Draft release created: https://github.com/IronCoreWorks/release-automation/releases/tag/untagged-6661b7012148818ad142.
================================================================================
Formatted release notes:
================================================================================
## What's Changed
### Features
* Add changes.md in https://github.com/IronCoreWorks/release-automation/pull/6
### Documentation
* Add version in https://github.com/IronCoreWorks/release-automation/pull/3
### Tests
* Add test in https://github.com/IronCoreWorks/release-automation/pull/4
**Full Changelog**: https://github.com/IronCoreWorks/release-automation/compare/0.1.0...0.1.1
================================================================================
The automatically generated title is: 0.1.1
Enter release title, press Enter to keep the auto-generated title:
> 0.1.1 Test Release
Enter release summary (multi-line supported, type '.' on a new line to finish):
The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog.
.
ℹ️ INFO: Release title and notes updated.
ℹ️ INFO: Updated CHANGES.md with new release notes.
ℹ️ INFO: Updated ops/version.py to release version: 0.1.1
ℹ️ INFO: Updated testing/pyproject.toml to release version: 0.1.1
ℹ️ INFO: Updated tracing/pyproject.toml to release version: 0.1.1
Switched to a new branch 'release-prep-0.1.1'
[release-prep-0.1.1 fd5967f] chore: prepare release 0.1.1
4 files changed, 17 insertions(+), 3 deletions(-)
Enumerating objects: 16, done.
Counting objects: 100% (16/16), done.
Delta compression using up to 10 threads
Compressing objects: 100% (6/6), done.
Writing objects: 100% (9/9), 1.80 KiB | 1.80 MiB/s, done.
Total 9 (delta 4), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (4/4), completed with 4 local objects.
remote:
remote: Create a pull request for 'release-prep-0.1.1' on GitHub by visiting:
remote: https://github.com/IronCore864/release-automation/pull/new/release-prep-0.1.1
remote:
To github.com:IronCore864/release-automation.git
* [new branch] release-prep-0.1.1 -> release-prep-0.1.1
ℹ️ INFO: Created PR: https://github.com/IronCoreWorks/release-automation/pull/10
Automated new release
Automated release PR
Post-release
$ python release.py --post-release
remote: Enumerating objects: 1, done.
remote: Counting objects: 100% (1/1), done.
remote: Total 1 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
Unpacking objects: 100% (1/1), 907 bytes | 453.00 KiB/s, done.
From github.com:IronCoreWorks/release-automation
fa80ad9..a4d32b4 main -> upstream/main
Switched to branch 'main'
Your branch is up to date with 'origin/main'.
Updating fa80ad9..a4d32b4
Fast-forward
CHANGES.md | 14 ++++++++++++++
ops/version.py | 2 +-
testing/pyproject.toml | 2 +-
tracing/pyproject.toml | 2 +-
4 files changed, 17 insertions(+), 3 deletions(-)
ℹ️ INFO: Updated ops/version.py to post-release version: 0.1.2.dev0
ℹ️ INFO: Updated testing/pyproject.toml to post-release version: 0.1.2.dev0
ℹ️ INFO: Updated tracing/pyproject.toml to post-release version: 0.1.2.dev0
Switched to a new branch 'post-release'
[post-release 5d204b5] chore: post release
3 files changed, 3 insertions(+), 3 deletions(-)
Enumerating objects: 14, done.
Counting objects: 100% (14/14), done.
Delta compression using up to 10 threads
Compressing objects: 100% (5/5), done.
Writing objects: 100% (8/8), 1.75 KiB | 1.75 MiB/s, done.
Total 8 (delta 3), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (3/3), completed with 3 local objects.
remote:
remote: Create a pull request for 'post-release' on GitHub by visiting:
remote: https://github.com/IronCore864/release-automation/pull/new/post-release
remote:
To github.com:IronCore864/release-automation.git
* [new branch] post-release -> post-release
ℹ️ INFO: Created PR: https://github.com/IronCoreWorks/release-automation/pull/11
Post-release PR
Re PR description:
git command available locally
I imagine it's pretty typical though. We all use git.
The PR doesn't seem to shell out to git or gh.
Could it be that the PR description is out of date?
Another test after refactoring according to all comments above:
$ git branch
main
$ python release.py --owner ironcoreworks --repo release-automation # testing org and repo
2025-07-10 11:13:14,849 - INFO - Latest tag in branch "main": 0.1.0
2025-07-10 11:13:14,850 - INFO - Suggested new version: 0.2.0
Input the new tag for the release (press enter to use the tag 0.2.0), or 'c' to cancel:
3.2.0
2025-07-10 11:13:17,939 - WARNING - Check out the releases page: https://github.com/ironcoreworks/release-automation/releases before confirming!
Confirm creating tag '3.2.0' on branch 'main'? [y/N]: y
2025-07-10 11:13:19,675 - INFO - Draft release created: https://github.com/IronCoreWorks/release-automation/releases/tag/untagged-5a42876b7b5b428d3b6b.
================================================================================
Formatted release notes:
================================================================================
## What's Changed
### Features
* Add changes.md in https://github.com/IronCoreWorks/release-automation/pull/6
* Update release automation script and versions in https://github.com/IronCoreWorks/release-automation/pull/20
* Update in https://github.com/IronCoreWorks/release-automation/pull/23
* Update release script in https://github.com/IronCoreWorks/release-automation/pull/24
### Documentation
* Add version in https://github.com/IronCoreWorks/release-automation/pull/3
### Tests
* Add test in https://github.com/IronCoreWorks/release-automation/pull/4
**Full Changelog**: https://github.com/IronCoreWorks/release-automation/compare/0.1.0...3.2.0
================================================================================
2025-07-10 11:13:19,676 - INFO - The automatically generated title is: 3.2.0
Enter release title, press Enter to keep the auto-generated title:
> Test release, ops 3.2.0, tracing 3.2.0, testing/scenario 8.2.0
Enter release summary (multi-line supported; type '.' on a new line to finish):
This is a release for testing the automation script.
The previous tag from my repo is 0.1.0, hence the suggested version is 0.2.0, which is overriden by values provided by the user.
A quick brown fox jumps over something that I forgot.
Put a single dot at the final line to finish drafting the introduction paragraph.
.
2025-07-10 11:13:38,740 - INFO - Release updated: https://github.com/IronCoreWorks/release-automation/releases/tag/untagged-01c17942f2ee6832d913.
2025-07-10 11:13:38,742 - INFO - Updated CHANGES.md with new release notes.
2025-07-10 11:13:38,742 - INFO - Suggested new scenario version: 8.2.0
Input new scenario version (press enter to use the suggested version 8.2.0), or 'c' to cancel:
Confirm using scenario version '8.2.0'? [y/N]: y
2025-07-10 11:13:47,429 - INFO - Updated ops/version.py to version 3.2.0
2025-07-10 11:13:47,430 - INFO - Updated pyproject.toml to version 8.2.0
2025-07-10 11:13:47,430 - INFO - Updated testing/pyproject.toml to version 8.2.0
2025-07-10 11:13:47,431 - INFO - Updated tracing/pyproject.toml to version 3.2.0
Using CPython 3.12.9
Resolved 149 packages in 304ms
Updated ops-scenario v8.2.0.dev0 -> v8.2.0
Updated ops-tracing v3.2.0.dev0 -> v3.2.0
Switched to a new branch 'release-prep-3.2.0'
[release-prep-3.2.0 0a8f4d0] chore: prepare release 3.2.0
6 files changed, 26 insertions(+), 9 deletions(-)
Enumerating objects: 20, done.
Counting objects: 100% (20/20), done.
Delta compression using up to 10 threads
Compressing objects: 100% (8/8), done.
Writing objects: 100% (11/11), 2.03 KiB | 2.03 MiB/s, done.
Total 11 (delta 6), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (6/6), completed with 6 local objects.
remote:
remote: Create a pull request for 'release-prep-3.2.0' on GitHub by visiting:
remote: https://github.com/IronCore864/release-automation/pull/new/release-prep-3.2.0
remote:
To github.com:IronCore864/release-automation.git
* [new branch] release-prep-3.2.0 -> release-prep-3.2.0
2025-07-10 11:13:53,908 - INFO - Created PR: https://github.com/IronCoreWorks/release-automation/pull/26
2025-07-10 11:13:53,908 - INFO - Draft release created. Please merge the version bump PR, publish the draft release, thenrun this script with --post-release to perform post-release actions.
Merged main into this branch, resolved the conflicts in HACKING.md, also tweaked the description in HACKING.md a little bit. Merging now.