A set of helper scripts and example GitHub Action workflows to aid in automated releases of Python and npm packages.
-
Enforces best practices:
- Has automated changelog for every release (optional)
- Is published to test server and verified with install and import of dist asset(s)
- Has commit message with hashes of dist file(s)
- Has annotated git tag in standard format
- Has GitHub release with changelog entry
- Reverts to Dev version after release (optional)
- Ensures packages are publishable on every commit
-
Prerequisites (see checklist below for details):
- Markdown changelog (optional)
- Bump version configuration
- Write access to GitHub repo and PyPI/npm registries for the package for one or more maintainers
⚠️ SECURITY NOTE: It is highly advised that the actual release workflow be run on a fork using API tokens generated by the maintainer. This allows the releases to be made in that person's name, and allows publish access to be controlled. Anyone with write access to a repository can run a workflow.
-
Typical workflow:
- When ready to make a release, go to the source repository and go to the Actions panel
- Select the Prepare Changelog workflow
- Run the Workflow with the version spec (usually the new version number), and make sure the target branch is correct
- When the run completes, review the changelog PR that was opened, making any desired edits
- Merge the PR
- Go to the GitHub page for your fork and go to the Actions panel
- Select the Create Release workflow
- Run the Workflow with the same version spec as before, and an optional post version spec if you want to go back to a dev version in the target branch. Select the appropriate branch as well
- When the workflow completes, go to the releases page in the main repository and verify that the new release is there with the correct changelog. You can also go to PyPI and/or npm to verify the package(s) are available.
To install the latest release locally, make sure you have pip installed and run:
pip install git+https://github.com/jupyter-server/release-helper
release-helper --help
release-helper prep-python --help
Note: The automated changelog handling is optional. If it is not desired, you can use the
check_release
and create_release
workflows only and leave the changelog calls out of them. You will need to generate your own text for the GitHub release.
- Switch to Markdown Changelog
- We recommend MyST, especially if some of your docs are in reStructuredText
- Can use
pandoc -s changelog.rst -o changelog.md
and some hand edits as needed - Note that directives can still be used
- Add HTML start and end comment markers to Changelog file - see example in CHANGELOG.md (view in raw mode)
- Add tbump support - see example metadata in pyproject.toml
- Add
release-helper
to yourtest
section inextras_require
in your setup config, e.g.
[options.extras_require]
test = coverage; pytest; pytest-cov; release-helper
- All publishers set up secrets in their fork:
- Create
PYPI_TOKEN
andTEST_PYPI_TOKEN
(if needed) - Create
NPM_TOKEN
(if needed) - Create
REPO_ACCESS_TOKEN
withpublic_repo
access
- Create
- One publisher adds their
TEST_PYPI_TOKEN
to the source repo's secrets for the release check workflow - Add workflows for
check_release
,create_changelog
, andcreate_release
- see the workflows in this repo - Optionally add workflow for
cancel
to cancel previous workflow runs when a new one is started - see cancel.yml - Start with the test PyPI server in
create-release
, then switch to the production server once it is fully working - If desired, add workflows, changelog, and
tbump
support to other active release branches
- Manual Github workflow
- Input is the version spec
- Targets the branch selected when starting the workflow
- Bumps the version
- By default, uses tbump or bump2version to bump the version based on presence of config files
- We recommend
tbump
instead ofbump2version
for most cases because it does not handle patch releases well when using prereleases.
- We recommend
- By default, uses tbump or bump2version to bump the version based on presence of config files
- Prepares the environment
- Sets up git config and branch
- Exports environment variables to
GITHUB_ENV
so they can be used in further steps
- Generates a changelog (using github-activity) using the PRs since the last tag on this branch.
- Gets the current version and then does a git checkout to clear state
- Adds a new version entry using a HTML comment markers in the changelog file
- Optionally resolves meeseeks backport PRs to their original PR
- Creates a PR with the changelog changes.
- Notes:
- This can be run on the repo by anyone with write access, since it only needs the built in
secrets.GITHUB_ACCESS_TOKEN
- The automated PR does not start workflows (a limitation of GitHub Actions). If you close and open the PR or make edits from within the GitHub UI it will trigger the workflows.
- Can be re-run using the same version spec. It will add new entries but preserve existing ones (in case they have been hand modified).
- This can be run on the repo by anyone with write access, since it only needs the built in
- Manual Github workflow
- Takes a version spec, optional post version spec, and optional branch
- Targets the branch selected when starting the workflow by default
- Ensures that the workflow file is the same one as the target branch
- Bumps version using the same method as the changelog action
- Prepares the environment using the same method as the changelog action
- Checks the package manifest using
check-manifest
- Checks the links in Markdown files
- Checks the changelog entry
- Looks for the current entry using the HTML comment markers
- Gets the expected changelog values using
github-activity
- Ensures that all PRs are the same between the two
- Writes the changelog entry out to a file to be used as the GitHub Release text
- Builds the wheel and source distributions
- Makes dists can be installed and imported in a virtual environment
- Adds a commit that includes the hashes of the dist files
- Creates an annotated version tag in standard format
- If given, bumps the version using the post version spec
- Pushes the commits and tag to the target
branch
- Publishes a GitHub release for the tag with the changelog entry as the text
- Publishes a PyPI release
- Runs as a standard workflow
- Runs both the Changelog steps and the Create Release Steps
- Does not make PRs or push git changes
- Publishes to the test PyPI server
- Creates a draft GitHub release and removes it
-
Use https://raw.githubusercontent.com for README images
-
Make a
.github/actions
folder withcreate_changelog
,check_release
, andcreate_release
actions- Add support for config in
pyproject.toml
orpackage.json
- Allow declaritve
pre-
andpost-
scripts to be run for the different steps so we can support more complex packages - Use a composite run steps action
- Inputs will be the
env
vars in the current workflow files plus the GitHub token
- Add support for config in
-
jupyter/notebook migration:
- Can be done immediately using the checklist
- Add
tbump
config to replacejsversion
step - Add
babel
andnpm
dependencies in the install step of the new workflows
-
lerna support
- Add to @jupyterlab/buildutils
- Add ability to start/stop a verdaccio server
- Use the publish script so we pick up
dist-tag
handling. Add option to pass--yes
for CLI - Create a temporary npm package and install/require the new packages
-
jupyterlab/lumino migration:
- We need to manually update the JS versions since we are in lerna independent mode. We will push the commit and resulting tags directly to the branch.
- Use the top level
package.json
as the versioned file (but still keep it private) - After creating the changelog, use the date instead of the version and add the JS packages
-
jupyterlab/jupyterlab migration:
- Changelog PR text should show the JS package version changes so we can audit them
- Pass a
--yes
flag to lernaversion
andpublish
when releasing on CI - Keep using
bump2version
since we need to use them for the JS packages, but collapse patch release intojlpm bumpversion patch
- Remove
publish.ts
in favor of the one inrelease-helper
. - Since we're using verdaccio, we don't need to wait for packages to be available to run
update-core-mode
, so we can just run that directly and removeprepare-python-release
- Use the verdaccio server to run the
release_test
after the npm prep command - We then have to update the
jupyterlab/staging/yarn.lock
file to replace the verdaccio registry with the public one. - Add
lab-prod
endpoint in binder so we can actually test with "released" packages for a given commit