update_changelog
def update_changelog(
txt, ver, notes, marker:str='<!-- do not remove -->\n'
):Insert notes into changelog txt after marker, replacing any existing section for ver
nbdev.release provides 3 commands that you can run from your shell to manage your changelog file and git releases:
nbdev-changelog: creates a CHANGELOG.md file from closed and labeled GitHub issuesnbdev-release-git: tags and creates a release in GitHub for the current versionnbdev-release-gh: calls nbdev-changelog, lets you edit the result, then pushes to git and calls nbdev-release-gitIt provides 3 futher commands for releasing packages on pypi or conda:
nbdev-pypi: Create and upload a pypi installernbdev-conda: Create and upload a conda installernbdev-release-both: Create and upload both pypi and conda installersHere’s a brief demonstration of how to use the changelog and git release tools in nbdev.release. This demo first creates an issue using the gh command line tool, and then closes it using git; you can also use GitHub’s web interface for both of these tasks. (Note that this functionality used to be in a project called fastrelease, so in the video the command line tools have different names, starting with fastrelease_ instead of nbdev-).
You’ll need to get a GitHub personal access token if you haven’t already. To do so, click here and enter “nbdev” in the “Note” section, and click the repo checkbox.
Then click “Generate Token” at the bottom of the screen, and copy the token (the long string of letters and numbers shown). You can easily do that by clicking the little clipboard icon next to the token.

It’s easiest to save the token as an environment variable GITHUB_TOKEN that can be automatically accessed. We recommend you do this is by adding the following to the end of your .bashrc or .zshrc file:
…and then replace the xxx with the token you just copied. It will automatically be available whenever you start a new shell (but don’t forget to source that file or open a new shell after you change it.).
Now you’re ready to create your release notes. These are created in a file called CHANGELOG.md. Here’s an example of what it creates: nbdev CHANGELOG.
All issues with the label bug, enhancement, or breaking that have been closed in your repo since your last release will be added to the top of this file. If you haven’t made any releases before, then all issues with those labels will be included.
Therefore, before you create or update CHANGELOG.md, go to your GitHub issues page, remove is:open from the filter, and label any issues you want included with one of the labels above. When you’ve done that, you can create or update your release notes by running in your terminal:
nbdev-changelog
Each issue title will be added. Open CHANGELOG.md in your editor and make any edits that you want, and then commit the file to your repo (remember to git add it!)
You should now tag a release. This will create a tag in GitHub with your current version number in __init__.py, and will then make it into a release, using your latest release notes as the description of the release:
nbdev-release-git
After you run this, be sure to increment your version number. You can either edit it manually, or if you use nbdev it can be done for you by running:
nbdev-bump-version
To complete both of the steps above, run:
nbdev-release-gh
If the changelog was generated and reviewed separately, complete the release without regenerating it, opening an editor, or prompting:
nbdev-release-gh --no-changelog --no-editor --yes
Automatic changelog generation stops when the current branch does not contain the latest GitHub release, as happens for an update to an older version. Write CHANGELOG.md manually and use the command above. The next section shows the complete process.
See the screencast above for a demonstration of the interactive workflow.
Sometimes the latest release is 2.x, but you need to fix version 1.x. The example below starts from release 1.1.0 and publishes 1.1.1.
A Git worktree is a second project folder connected to the same repository. It lets you open the older version without changing your usual project folder:
Bump the version, make the fix, and test it:
Write the new CHANGELOG.md entry yourself. Automatic changelog generation is intended for the latest release, so skip it here. Review the changes before releasing:
The release command pushes the 1.x branch to GitHub, then tags the code it released. Because 1.x is not the repository’s default branch, the release is not marked as “Latest” on GitHub, so the repo front page keeps showing the newest version. After checking the GitHub release and PyPI package, remove the extra folder:
The extra folder uses a little more disk space, and you need to run each command in the right folder. In return, the latest and older versions remain available at the same time. This is useful when other terminals or Python sessions are using the main project folder.
For a small update with a clean project folder, you can instead switch that folder to the older release:
Then follow the same bump, fix, changelog, test, and release steps above. When finished, return to the latest code:
This alternative uses one folder and fewer commands. While the release is in progress, however, your usual project folder and any editable Python installation based on it will contain the older version.
Releases target the exact pushed commit. Automatic changelogs are limited to the latest release line; maintenance releases use a manually written changelog.
Insert notes into changelog txt after marker, replacing any existing section for ver
update_changelog makes changelog generation idempotent: if the changelog already has a section for ver (e.g. from an earlier run whose release never happened), it’s replaced rather than duplicated. That also means regenerating discards any manual edits to that pending section, so curate the changelog after its final generation. It also owns the spacing: two blank lines between version sections and a single newline at EOF, whether or not notes has trailing newlines.
log = "# Release notes\n\n<!-- do not remove -->\n\n## 0.0.1\n\n- First release\n"
test_eq(update_changelog("# Release notes\n\n<!-- do not remove -->\n", '0.0.1', '\n## 0.0.1\n\n- First release'), log)
upd = update_changelog(log, '0.0.2', '\n## 0.0.2\n\n- New feature')
assert upd.index('## 0.0.2') < upd.index('## 0.0.1')
assert '- New feature\n\n\n## 0.0.1' in upd
print(upd)# Release notes
<!-- do not remove -->
## 0.0.2
- New feature
## 0.0.1
- First release
Regenerating notes for a version that already has a pending section gives the same result as generating them fresh:
Create CHANGELOG.md from GitHub issues
To create a markdown changelog, first create a Release object, optionally passing a mapping from GitHub labels to markdown titles. Put your github token in a file named token at the root of your repo. Release attempts to fetch values for arguments from the following locations if not supplied:
[project.urls] in pyproject.toml. This is the owner name of the repository on GitHub. For example for the repo fastai/fastcore the owner would be fastai.name in [project] in pyproject.toml. This is the name of the repository on GitHub. For example for the repo fastai/fastcore the repo would be fastcore. You can instead pass "owner/repo" (e.g. "fastai/fastcore") to set both at once.token at the root of your repo. Creating a token is discussed in the setup section.label_groups in [tool.nbdev] in pyproject.toml. This is a mapping from label names to titles in your release notes. If not specified, this defaults to:Create the CHANGELOG.md file, or return the proposed text if debug is True
Tag and create a release in GitHub for the current version
This uses the version information from your __init__.py. When releasing from a branch other than the repo’s default branch (e.g. a fix to an older version), the release is not marked as the repo’s latest on GitHub.
All relevant pull requests and issues are fetched from the GitHub API, and are categorized according to a user-supplied mapping from labels to markdown headings.
Create a CHANGELOG.md file from closed and labeled GitHub issues
Create a GitHub release (changelog should already be committed/pushed). Returns the release.
Tag and create a release in GitHub for the current version
async def release_gh(
token:str=None, # Optional GitHub token (otherwise `token` file is used)
repo:str=None, # "repo" or "owner/repo" to use instead of pyproject.toml values
no_changelog:<function store_true at 0x7f39ddf953a0>=False, # Skip changelog creation (assumes CHANGELOG.md is up to date)
no_editor:<function store_true at 0x7f39ddf953a0>=False, # Skip opening CHANGELOG.md in an editor
yes:<function store_true at 0x7f39ddf953a0>=False, # Release without asking for confirmation
):Create the changelog, optionally edit it, then push and create the GitHub release
Output path for conda build
Writes a meta.yaml file to the conda directory of the current directory
This function is used in the conda_package CLI command.
NB: you need to first of all upload your package to PyPi, before creating the conda package.
Writes a requirements.txt file to directory based on pyproject.toml.
This function can be used in situations where you need to generate a requirements.txt file for a project.
Upload name to anaconda
def release_conda(
path:str='conda', # Path where package will be created
do_build:<function bool_arg at 0x7f39ddfd5120>=True, # Run `conda build` step
build_args:str='', # Additional args (as str) to send to `conda build`
skip_upload:<function store_true at 0x7f39ddf953a0>=False, # Skip `anaconda upload` step
mambabuild:<function store_true at 0x7f39ddf953a0>=False, # Use `mambabuild` (requires `boa`)
upload_user:str=None, # Optional user to upload package to
):Create a meta.yaml file ready to be built into a package, and optionally build and upload it
Prints GitHub tag only if a newer release exists on Pypi compared to an Anaconda Repo.
To build and upload a conda package, cd to the root of your repo, and then:
nbdev-conda-package
Or to do things more manually:
nbdev-conda-package --do-build false
cd conda
conda build --no-anaconda-upload --output-folder build {name}
anaconda upload build/noarch/{name}-{ver}-*.tar.bz2
Add --debug to the conda build command to debug any problems that occur. Note that the build step takes a few minutes. Add -u {org_name} to the anaconda upload command if you wish to upload to an organization, or pass upload_user to nbdev-conda-package.
NB: you need to first of all upload your package to PyPi, before creating the conda package.
Create and upload Python package to PyPI
Use --repository flag to upload to TestPypi (e.g. nbdev-pypi --repository testpypi) and custom/private repositories.
The ~/.pypirc file can be updated to configure the additional repositories, see example below:
[distutils]
index-servers =
pypi
testpypi
private-repository
[pypi]
username = __token__
password = <PyPI token>
[testpypi]
username = __token__
password = <TestPyPI token>
[private-repository]
repository = <private-repository URL>
username = <private-repository username>
password = <private-repository password>Use nbdev-pypi --repository private-repository to upload to the private repository.
def release_both(
path:str='conda', # Path where package will be created
do_build:<function bool_arg at 0x7f39ddfd5120>=True, # Run `conda build` step
build_args:str='', # Additional args (as str) to send to `conda build`
skip_upload:<function store_true at 0x7f39ddf953a0>=False, # Skip `anaconda upload` step
mambabuild:<function store_true at 0x7f39ddf953a0>=False, # Use `mambabuild` (requires `boa`)
upload_user:str=None, # Optional user to upload package to
repository:str='pypi', # Pypi respository to upload to (defined in ~/.pypirc)
):Release both conda and PyPI packages
By default, a post-release version increments .postN; other versions increment their patch component. Passing --part explicitly selects a release component and removes the post suffix.
Increment version in init.py by one