Skip to content

Commit 7757078

Browse files
ichard26felix-hildenJelleZijlstra
authored
Improve & update release process to reflect recent changes (#3242)
- Formalise release cadence guidelines - Overhaul release steps to be easier to follow and more thorough - Reorder changelog template to something more sensible - Update release automation docs to reflect recent improvements (notably the addition of in-repo mypyc wheel builds) Co-authored-by: Felix Hildén <[email protected]> Co-authored-by: Jelle Zijlstra <[email protected]>
1 parent 767604e commit 7757078

File tree

3 files changed

+156
-85
lines changed

3 files changed

+156
-85
lines changed

docs/contributing/release_process.md

+152-85
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,85 @@
11
# Release process
22

3-
_Black_ has had a lot of work automating its release process. This document sets out to
4-
explain what everything does and how to release _Black_ using said automation.
5-
6-
## Cutting a Release
7-
8-
To cut a release, you must be a _Black_ maintainer with `GitHub Release` creation
9-
access. Using this access, the release process is:
10-
11-
1. Cut a new PR editing `CHANGES.md` and the docs to version the latest changes
3+
_Black_ has had a lot of work done into standardizing and automating its release
4+
process. This document sets out to explain how everything works and how to release
5+
_Black_ using said automation.
6+
7+
## Release cadence
8+
9+
**We aim to release whatever is on `main` every 1-2 months.** This ensures merged
10+
improvements and bugfixes are shipped to users reasonably quickly, while not massively
11+
fracturing the user-base with too many versions. This also keeps the workload on
12+
maintainers consistent and predictable.
13+
14+
If there's not much new on `main` to justify a release, it's acceptable to skip a
15+
month's release. Ideally January releases should not be skipped because as per our
16+
[stability policy](labels/stability-policy), the first release in a new calendar year
17+
may make changes to the _stable_ style. While the policy applies to the first release
18+
(instead of only January releases), confining changes to the stable style to January
19+
will keep things predictable (and nicer) for users.
20+
21+
Unless there is a serious regression or bug that requires immediate patching, **there
22+
should not be more than one release per month**. While version numbers are cheap,
23+
releases require a maintainer to both commit to do the actual cutting of a release, but
24+
also to be able to deal with the potential fallout post-release. Releasing more
25+
frequently than monthly nets rapidly diminishing returns.
26+
27+
## Cutting a release
28+
29+
**You must have `write` permissions for the _Black_ repository to cut a release.**
30+
31+
The 10,000 foot view of the release process is that you prepare a release PR and then
32+
publish a [GitHub Release]. This triggers [release automation](#release-workflows) that
33+
builds all release artifacts and publishes them to the various platforms we publish to.
34+
35+
To cut a release:
36+
37+
1. Determine the release's version number
38+
- **_Black_ follows the [CalVer] versioning standard using the `YY.M.N` format**
39+
- So unless there already has been a release during this month, `N` should be `0`
40+
- Example: the first release in January, 2022 → `22.1.0`
41+
1. File a PR editing `CHANGES.md` and the docs to version the latest changes
42+
1. Replace the `## Unreleased` header with the version number
1243
1. Remove any empty sections for the current release
13-
2. Add a new empty template for the next release (template below)
14-
3. Example PR: [#2616](https://github.com/psf/black/pull/2616)
15-
4. Example title: `Update CHANGES.md for XX.X release`
16-
2. Once the release PR is merged ensure all CI passes
17-
1. If not, ensure there is an Issue open for the cause of failing CI (generally we'd
18-
want this fixed before cutting a release)
19-
3. Open `CHANGES.md` and copy the _raw markdown_ of the latest changes to use in the
20-
description of the GitHub Release.
21-
4. Go and [cut a release](https://github.com/psf/black/releases) using the GitHub UI so
22-
that all workflows noted below are triggered.
23-
1. The release version and tag should be the [CalVer](https://calver.org) version
24-
_Black_ used for the current release e.g. `21.6` / `21.5b1`
25-
2. _Black_ uses [setuptools scm](https://pypi.org/project/setuptools-scm/) to pull
26-
the current version for the package builds and release.
27-
5. Once the release is cut, you're basically done. It's a good practice to go and watch
28-
to make sure all the [GitHub Actions](https://github.com/psf/black/actions) pass,
29-
although you should receive an email to your registered GitHub email address should
30-
one fail.
31-
1. You should see all the release workflows and lint/unittests workflows running on
32-
the new tag in the Actions UI
33-
34-
If anything fails, please go read the respective action's log output and configuration
35-
file to reverse engineer your way to a fix/soluton.
36-
37-
## Changelog template
44+
1. (_optional_) Read through and copy-edit the changelog (eg. by moving entries,
45+
fixing typos, or rephrasing entries)
46+
1. Add a new empty template for the next release above
47+
([template below](#changelog-template))
48+
1. Update references to the latest version in
49+
{doc}`/integrations/source_version_control` and
50+
{doc}`/usage_and_configuration/the_basics`
51+
- Example PR: [GH-3139]
52+
1. Once the release PR is merged, wait until all CI passes
53+
- If CI does not pass, **stop** and investigate the failure(s) as generally we'd want
54+
to fix failing CI before cutting a release
55+
1. [Draft a new GitHub Release][new-release]
56+
1. Click `Choose a tag` and type in the version number, then select the
57+
`Create new tag: YY.M.N on publish` option that appears
58+
1. Verify that the new tag targets the `main` branch
59+
1. You can leave the release title blank, GitHub will default to the tag name
60+
1. Copy and paste the _raw changelog Markdown_ for the current release into the
61+
description box
62+
1. Publish the GitHub Release, triggering [release automation](#release-workflows) that
63+
will handle the rest
64+
1. At this point, you're basically done. It's good practice to go and [watch and verify
65+
that all the release workflows pass][black-actions], although you will receive a
66+
GitHub notification should something fail.
67+
- If something fails, don't panic. Please go read the respective workflow's logs and
68+
configuration file to reverse-engineer your way to a fix/solution.
69+
70+
Congratulations! You've successfully cut a new release of _Black_. Go and stand up and
71+
take a break, you deserve it.
72+
73+
```{important}
74+
Once the release artifacts reach PyPI, you may see new issues being filed indicating
75+
regressions. While regressions are not great, they don't automatically mean a hotfix
76+
release is warranted. Unless the regressions are serious and impact many users, a hotfix
77+
release is probably unnecessary.
78+
79+
In the end, use your best judgement and ask other maintainers for their thoughts.
80+
```
81+
82+
### Changelog template
3883

3984
Use the following template for a clean changelog after the release:
4085

@@ -45,101 +90,123 @@ Use the following template for a clean changelog after the release:
4590
4691
<!-- Include any especially major or disruptive changes here -->
4792
48-
### Style
93+
### Stable style
4994
5095
<!-- Changes that affect Black's stable style -->
5196
5297
### Preview style
5398
5499
<!-- Changes that affect Black's preview style -->
55100
56-
### _Blackd_
57-
58-
<!-- Changes to blackd -->
59-
60101
### Configuration
61102
62103
<!-- Changes to how Black can be configured -->
63104
64-
### Documentation
105+
### Packaging
65106
66-
<!-- Major changes to documentation and policies. Small docs changes
67-
don't need a changelog entry. -->
107+
<!-- Changes to how Black is packaged, such as dependency requirements -->
68108
69-
### Integrations
109+
### Parser
70110
71-
<!-- For example, Docker, GitHub Actions, pre-commit, editors -->
111+
<!-- Changes to the parser or to version autodetection -->
112+
113+
### Performance
114+
115+
<!-- Changes that improve Black's performance. -->
72116
73117
### Output
74118
75119
<!-- Changes to Black's terminal output and error messages -->
76120
77-
### Packaging
78-
79-
<!-- Changes to how Black is packaged, such as dependency requirements -->
121+
### _Blackd_
80122
81-
### Parser
123+
<!-- Changes to blackd -->
82124
83-
<!-- Changes to the parser or to version autodetection -->
125+
### Integrations
84126
85-
### Performance
127+
<!-- For example, Docker, GitHub Actions, pre-commit, editors -->
86128
87-
<!-- Changes that improve Black's performance. -->
129+
### Documentation
88130
131+
<!-- Major changes to documentation and policies. Small docs changes
132+
don't need a changelog entry. -->
89133
```
90134

91135
## Release workflows
92136

93-
All _Blacks_'s automation workflows use GitHub Actions. All workflows are therefore
94-
configured using `.yml` files in the `.github/workflows` directory of the _Black_
137+
All of _Black_'s release automation uses [GitHub Actions]. All workflows are therefore
138+
configured using YAML files in the `.github/workflows` directory of the _Black_
95139
repository.
96140

141+
They are triggered by the publication of a [GitHub Release].
142+
97143
Below are descriptions of our release workflows.
98144

99-
### Docker
145+
### Publish to PyPI
146+
147+
This is our main workflow. It builds an [sdist] and [wheels] to upload to PyPI where the
148+
vast majority of users will download Black from. It's divided into three job groups:
149+
150+
#### sdist + pure wheel
100151

101-
This workflow uses the QEMU powered `buildx` feature of docker to upload a `arm64` and
102-
`amd64`/`x86_64` build of the official _Black_ docker image™.
152+
This single job builds the sdist and pure Python wheel (i.e., a wheel that only contains
153+
Python code) using [build] and then uploads them to PyPI using [twine]. These artifacts
154+
are general-purpose and can be used on basically any platform supported by Python.
103155

104-
- Currently this workflow uses an API Token associated with @cooperlees account
156+
#### mypyc wheels (…)
105157

106-
### pypi_upload
158+
We use [mypyc] to compile _Black_ into a CPython C extension for significantly improved
159+
performance. Wheels built with mypyc are platform and Python version specific.
160+
[Supported platforms are documented in the FAQ](labels/mypyc-support).
107161

108-
This workflow builds a Python
109-
[sdist](https://docs.python.org/3/distutils/sourcedist.html) and
110-
[wheel](https://pythonwheels.com) using the latest
111-
[setuptools](https://pypi.org/project/setuptools/) and
112-
[wheel](https://pypi.org/project/wheel/) modules.
162+
These matrix jobs use [cibuildwheel] which handles the complicated task of building C
163+
extensions for many environments for us. Since building these wheels is slow, there are
164+
multiple mypyc wheels jobs (hence the term "matrix") that build for a specific platform
165+
(as noted in the job name in parentheses).
113166

114-
It will then use [twine](https://pypi.org/project/twine/) to upload both release formats
115-
to PyPI for general downloading of the _Black_ Python package. This is where
116-
[pip](https://pypi.org/project/pip/) looks by default.
167+
Like the previous job group, the built wheels are uploaded to PyPI using [twine].
117168

118-
- Currently this workflow uses an API token associated with @ambv's PyPI account
169+
#### Update stable branch
119170

120-
### Upload self-contained binaries
171+
So this job doesn't _really_ belong here, but updating the `stable` branch after the
172+
other PyPI jobs pass (they must pass for this job to start) makes the most sense. This
173+
saves us from remembering to update the branch sometime after cutting the release.
121174

122-
This workflow builds self-contained binaries for multiple platforms. This allows people
123-
to download the executable for their platform and run _Black_ without a
124-
[Python Runtime](https://wiki.python.org/moin/PythonImplementations) installed.
175+
- _Currently this workflow uses an API token associated with @ambv's PyPI account_
125176

126-
The created binaries are attached/stored on the associated
127-
[GitHub Release](https://github.com/psf/black/releases) for download over _IPv4 only_
128-
(GitHub still does not have IPv6 access 😢).
177+
### Publish executables
129178

130-
## Moving the `stable` tag
179+
This workflow builds native executables for multiple platforms using [PyInstaller]. This
180+
allows people to download the executable for their platform and run _Black_ without a
181+
[Python runtime](https://wiki.python.org/moin/PythonImplementations) installed.
131182

132-
_Black_ provides a stable tag for people who want to move along as _Black_ developers
133-
deem the newest version reliable. Here the _Black_ developers will move once the release
134-
has been problem free for at least ~24 hours from release. Given the large _Black_
135-
userbase we hear about bad bugs quickly. We do strive to continually improve our CI too.
183+
The created binaries are stored on the associated GitHub Release for download over _IPv4
184+
only_ (GitHub still does not have IPv6 access 😢).
136185

137-
### Tag moving process
186+
### docker
138187

139-
#### stable
188+
This workflow uses the QEMU powered `buildx` feature of Docker to upload an `arm64` and
189+
`amd64`/`x86_64` build of the official _Black_ Docker image™.
140190

141-
From a rebased `main` checkout:
191+
- _Currently this workflow uses an API Token associated with @cooperlees account_
192+
193+
```{note}
194+
This also runs on each push to `main`.
195+
```
142196

143-
1. `git tag -f stable VERSION_TAG`
144-
1. e.g. `git tag -f stable 21.5b1`
145-
1. `git push --tags -f`
197+
[black-actions]: https://github.com/psf/black/actions
198+
[build]: https://pypa-build.readthedocs.io/
199+
[calver]: https://calver.org
200+
[cibuildwheel]: https://cibuildwheel.readthedocs.io/
201+
[gh-3139]: https://github.com/psf/black/pull/3139
202+
[github actions]: https://github.com/features/actions
203+
[github release]: https://github.com/psf/black/releases
204+
[new-release]: https://github.com/psf/black/releases/new
205+
[mypyc]: https://mypyc.readthedocs.io/
206+
[mypyc-platform-support]:
207+
/faq.html#what-is-compiled-yes-no-all-about-in-the-version-output
208+
[pyinstaller]: https://www.pyinstaller.org/
209+
[sdist]:
210+
https://packaging.python.org/en/latest/glossary/#term-Source-Distribution-or-sdist
211+
[twine]: https://github.com/features/actions
212+
[wheels]: https://packaging.python.org/en/latest/glossary/#term-Wheel

docs/faq.md

+2
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ errors is not a goal. It can format all code accepted by CPython (if you find an
114114
where that doesn't hold, please report a bug!), but it may also format some code that
115115
CPython doesn't accept.
116116

117+
(labels/mypyc-support)=
118+
117119
## What is `compiled: yes/no` all about in the version output?
118120

119121
While _Black_ is indeed a pure Python project, we use [mypyc] to compile _Black_ into a

docs/the_black_code_style/index.md

+2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ style aspects and details might change according to the stability policy present
1919
below. Ongoing style considerations are tracked on GitHub with the
2020
[design](https://github.com/psf/black/labels/T%3A%20design) issue label.
2121

22+
(labels/stability-policy)=
23+
2224
## Stability Policy
2325

2426
The following policy applies for the _Black_ code style, in non pre-release versions of

0 commit comments

Comments
 (0)