Maintainer information#
Making a release#
For branch organization we use a variation of the GitHub
Flow with
the latest release branch named stable (due to ReadTheDocs constraints).
Making a major release#
Assume for concreteness that we are releasing version 0.20.0.
Preparation#
Make a tracking issue with a title like “0.20.0 release planning”. Add the checklist:
[ ] Update packages
[ ] Look for open PRs to add to the release milestone
[ ] Make sure all PRs in the release milestone are merged
[ ] Write release notes
[ ] Tidy changelog
Make a release notes blog post at pyodide-blog: https://github.com/pyodide/pyodide-blog
Generate the list of contributors for the release at the end of the release notes blog post with:
git shortlog -s 0.19.0.. | cut -f2- | grep -v '\[bot\]' | sort --ignore-case | tr '\n' ';' | sed 's/;/, /g;s/, $//' | fold -s
where
0.19.0is the tag for the last major release.Read the changelog and tidy it up by adding subsections, organizing, and proof reading it. Make a pull request with these changes titled “Rearrange changelog for 0.20.0 release” and merge it.
Make sure all the PRs that we want to release are merged and that the release notes are ready.
Releasing#
Switch to the main branch
Replace the
## Unreleasedheading in the changelog with## Version 0.20.0and add the date underneath it. Commit this.From the root of the repository run:
./tools/bump_version.py 0.20.0 --tag
This makes a release commit and tags it.
Push the release commit and tag to upstream. This triggers the release CI.
git push upstream main 0.20.0
Wait for CI to pass and release to be created.
Rename the
stablebranch to a release branch for the previous major version. For instance if last release was,0.20.0, the corresponding release branch would be0.20.X:git fetch upstream stable:stable git branch 0.20.X stable git push -u upstream 0.20.X
Create a new
stablebranch:git switch main git switch -C stable git push upstream stable --force
Set the version back to next development version with:
git switch main ./tools/bump_version.py 0.21.0 --dev git push upstream main
Making a minor release#
Assume for concreteness that we are releasing version 0.27.2.
Preparation#
Go through the commits on the main branch since the last release, find ones you want to backport and add the “needs backport” label to the pull requests. You can do this manually in the web interface on the GitHub PR or you can use
./tools/backports.py add-pr <pr-number>
List out the
needs backportPRs that are missing changelog entries with./tools/backports.py missing-changelogsand double check that every PR that should have a changelog does have one.
Read the changelog and tidy it up by adding subsections, organizing, and proof reading it. Make a pull request with these changes titled e.g., “Rearrange changelog for 0.27.2 release” and merge it.
Make the backport branch (on top of stable):
./tools/backports.py backport-branch
Make the update-changelog branch (on top of main) with:
./tools/backports.py changelog-branch
Open PRs for these two branches with:
./tools/backports.py open-release-prs
Use the backport branch PR as the release tracker.
Make sure that the CI passes on the backports branch and it is approved. When it does pass, set the date for the release in the changelog with:
./tools/backports.py set-date git switch backports-for-0.27.2 git push -f git switch changelog-for-0.27.2 git push -f
Then merge the two PRs.
Run
./tools/backport.py clear-prs
to clear all the “needs backport” labels.
Releasing#
Switch to the stable branch and
git pull.From the root of the repository run:
./tools/backport.py bump-version --tag
This makes a release commit and tags it.
Push the release commit and tag to
upstream/stable. This triggers the release CI.git push upstream stable 0.27.2
Wait for CI to pass and the release to be created.
Making an alpha release#
Assume for concreteness that we are releasing 0.28.0a1.
Preparation#
Any single maintainer can decide on their own to make an alpha release, it is not required to discuss it with other maintainers.
Name the first alpha release x.x.xa1 and in subsequent alphas increment the
final number. No preparation is necessary. Do not make any changes to the
changelog.
Release instructions#
Switch to the main branch and
git pull.From the root of the repository run:
./tools/bump_version.py 0.28.0a1 --tag
This makes a release commit and tags it.
Push the release commit and tag to
upstream/main. This triggers the release CI.git push upstream main 0.28.0a1
Put the version back with:
git revert 0.28.0a1 -n && git commit -m "Back to development version" git push upstream main
Wait for CI to pass and the release to be created.
Fixing documentation for a released version#
Cherry pick the corresponding documentation commits to the stable branch. Use
git commit --amend to add [skip ci] to the commit message.
Updating the Docker image#
Anyone with an account on hub.docker.com can follow the following steps:
Make whatever changes are needed to the Dockerfile.
Build the docker image with
docker build .in the Pyodide root directory. If the build succeeds, docker will give you a hash for the built image.Use
python ./tools/docker_image_tag.pyto find out what the new image tag should be. Tag the image with:docker image tag <image-hash> <your-docker-username>/pyodide-env:<image-tag>
Push the image with:
docker image push <your-docker-username>/pyodide-env:<image-tag>
Replace the image in
.circleci/config.ymlwith your newly created image. Open a pull request with your changes toDockerfileand.circleci/config.yml.When the tests pass and the pull request is approved, a maintainer must copy the new image into the
pyodidedockerhub account.Then replace the image tag in
.circleci/config.yml,.devcontainer/devcontainer.json, andrun_dockerwith the new image under thepyodidedockerhub account.
It’s also possible to update the docker image by pushing your changes to the
Dockerfile to a branch in the pyodide/pyodide repo (not on a fork) and
clicking Run workflow on
https://github.com/pyodide/pyodide/actions/workflows/docker_image.yml.
Updating packages#
Before updating the Python version and before making a major Pyodide release, we try to update all packages that are not too much trouble. Run
make -C packages update-all
to update all packages and make a pull request with these changes. There will be build/test failures, revert the packages that fail the build or tests and make a note to update them independently.
Updating pyodide-build#
To change the version of pyodide-build, change the commit of the pyodide-build submodule.
cd pyodide-build
git checkout "<COMMIT HASH>"
To test with a fork of pyodide-build, change the .gitmodules file to point to your fork and update the commit hash
# .gitmodules
[submodule "pyodide-build"]
path = pyodide-build
url = https://github.com/<yourfork>/pyodide-build
git submodule sync
cd pyodide-build
git checkout "<COMMIT HASH>"
Updating the Emscripten version#
To update Emscripten requires the following three steps:
Rebase the patches in
emsdk/patchesonto the new Emscripten version.Update the Emscripten version in
Makefile.envsUpdate the
struct_infojson file insrc/js/to match the version of the file in Emscripten.
All three of these steps are automated by tools/update_emscripten.py. To
update, you can say: ./tools/update_emscripten.py new_version. If there are
rebase conflicts, you will have to manually finish the rebase. Once the rebase
is completed, you can rerun update_emscripten.py. It will start over the
rebase from scratch but reuse your conflict resolutions using the git rerere
feature.
Updating Emscripten is an ABI break so all platformed wheels that are downloaded from an external URL need to be disabled until they are rebuilt.
After this is done, commit all the changes and open a PR. There are frequently complicated CI failures.
Upgrading pyodide to a new version of CPython#
Prerequisites#
The desired version of CPython must be available at:
The
specific releasesection of https://www.python.org/downloadshttps://hub.docker.com/_/python
https://github.com/actions/python-versions/releases
If doing a major version update, save time by Updating packages first.
Steps#
Follow the steps in “Updating the Docker image” to create a docker image for the new Python version.
Make sure you are in a Python virtual environment with the new version of Python and with
requirements.txtinstalled. (It is also possible to work in the docker image as an alternative.)Update the Python version in Makefile.envs
Update the Python version in the following locations:
.github/workflows/main.ymldocs/conf.pydocs/development/contributing.mddocs/development/building-and-testing-packages.mdenvironment.yml.pre-commit-config.yamlpyproject.toml
(TODO: make this list shorter.)
Rebase the patches:
Clone cpython and cd into it. Checkout the Python version you are upgrading from. For instance, if the old version is 3.11.3, use
git checkout v3.11.3(Python tags have a leading v.) Rungit am ~/path/to/pyodide/cpython/patches/*
Rebase the patches onto the new version of Python. For instance if updating from Python v3.11.3 to Python 3.12.1:
git rebase v3.11.3 --onto v3.12.1
Resolve conflicts / drop patches that have been upstreamed. If you have conflicts, make sure you are using diff3:
git config --global merge.conflictstyle diff3
Generate the new patches:
rm ~/path/to/pyodide/cpython/patches/* git format-patch v3.12.1 -o ~/path/to/pyodide/cpython/patches/
Try to build Python with
make -C cpython. Fix any build errors. If you modify the Python source in tree after a failed build it may be useful to runmake rebuild.Try to finish the build with a top level
make. Fix compile errors insrc/coreand any link errors. It may be useful to applyupgrade_pythoncapi.py --no-compatto the C extension insrc/code. https://github.com/python/pythoncapi-compat/blob/main/upgrade_pythoncapi.pyThe file most tightly coupled to the CPython version is
src/core/stack_switching/pystate.c. Consult the following greenlet file to figure out how to fix it: https://github.com/python-greenlet/greenlet/blob/master/src/greenlet/TPythonState.cppRun
python tools/make_test_list.pyThen run the core tests
pytest src/tests/test_core_python.pyand either fix the failures or updatesrc/tests/python_tests.yamlto skip or xfail them.Try to build packages with:
pyodide build-recipes '*'
Disable packages until the build succeeds. Then fix the build failures. In many cases, this just requires updating to the most recent version of the package. If you have trouble, try searching on the package’s issue tracker for “python 3.12” (or whatever the new version is). It’s best to create separate PRs for tricky package upgrades.
Fix failing package tests.
Old major Python upgrades#
Upgrading the ABI#
When you upgrade the Pyodide ABI, packages that were using the old ABI will no longer be available. Therefore, when updating the ABI, following procedure is required to temporarily disable and re-enable packages.
0. Stabilize and freeze the ABI#
There is a WIP discussion in #5580 about how to stabilize the ABI before making a release. Please discuss the ABI release with other maintainers before you decide to upgrade the ABI, and make sure that the ABI is stable and frozen.
1. Disable USE_PREBUILT_PACKAGES and upgrade the ABI in the nightly branch#
Pyodide CI uses prebuilt packages that are built with the ABI of the last release. To upgrade the ABI, you need to disable them, otherwise the CI will fail.
Find
USE_PREBUILT_PACKAGESenv variable in .circleci/config.yml and set it tofalse.Open a PR to upgrade the ABI. The target branch should not be
main, but a branch dedicated to the ABI upgrade. For instance, if you are upgrading the ABI to2025_0, the branch name can beabi-2025_0.
2. Release nightly xbuildenv#
After the ABI upgrade PR is merged, you need to release the nightly xbuildenv to make it possible for the packages to be built with the new ABI.
Go to pyodide/pyodide-build-environment-nightly and trigger Release Cross-build environment action.
This will create a new release with the new ABI. When running the action, set the target branch to the branch you created in the previous step,
and set the tag to nightly-<ABI>-<DATE>, for instance nightly-2025_0-2023-10-01.
3. Update packages and release new packages set#
Go to pyodide/pyodide-recipes and follow the guidelines in the
MAINTAINERS.md.
You’ll need to make a tag for the existing packages sets, and update the default_cross_build_env_url in the main branch.
If you updated the Python version, you also need to update the python version used in the CI.
When opening the PR, include [full build] in the title to trigger a full build of all packages, otherwise, only the small set of packages will be built.
Most likely, some of the packages will fail to build. You can disable them by adding _disabled: true to the recipes of the packages that are failing to build.
You don’t need to handle all the build failures in the same PR, you can open multiple PRs to fix the build failures, or let the package maintainers handle them.
Create a new tag for the new packages set when the build is successful. It will create a new release with the new packages set.
4. Re-enable USE_PREBUILT_PACKAGES and upgrade the ABI in the main branch#
Go back to pyodide/pyodide and update the PYODIDE_PREBUILT_PACKAGES_BASE variable in the Makefile.envs to the
new packages set you created in the previous step.
Then, re-enable USE_PREBUILT_PACKAGES in the .circleci/config.yml file and open a PR to merge it into the main branch.