release

Auto-generated tagged releases and release notes from GitHub issues

Overview

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 issues
  • nbdev_release_git: tags and creates a release in GitHub for the current version
  • nbdev_release_gh: calls nbdev_changelog, lets you edit the result, then pushes to git and calls nbdev_release_git

It provides 3 futher commands for releasing packages on pypi or conda:

  • nbdev_pypi: Create and upload a pypi installer
  • nbdev_conda: Create and upload a conda installer
  • nbdev_release_both: Create and upload both pypi and conda installers

Here’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_).

Setup

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.

Copying your 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:

export GITHUB_TOKEN=xxx

…and then replace the xxx with the token you just copied. It will automatically be avaialble whenever you start a new shell (but don’t forget to source that file or open a new shell after you change it.).

Creating release notes

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

The titles and bodies of each issue 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!)

Tagging a release

You should now tag a release. This will create a tag in GitHub with your current version number in settings.ini, 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 in settings.ini. You can either edit it manually, or if you use nbdev it can be done for you by running:

nbdev_bump_version

Doing both (creating release notes, and tagging a release)

To complete both of the steps above, run:

nbdev_release_gh

See the screencast above for a demonstration of this.

Python API


source

Release


def Release(
    owner:NoneType=None, repo:NoneType=None, token:NoneType=None, groups:VAR_KEYWORD
):

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:

  • owner: fetched from the field user in settings.ini. This is the owner name of the repository on GitHub. For example for the repo fastai/fastcore the owner would be fastai.
  • repo: fetched from the field lib_name in settings.ini. This is the name of the repository on GitHub. For example for the repo fastai/fastcore the owner would be fastcore.
  • token: fetched from a file named token at the root of your repo. Creating a token is discussed in the setup section.
  • groups: (optional) fetched from the field label_groups in settings.ini, which is a JSON string. This is a mapping from label names to titles in your release notes. If not specified, this defaults to:
{"breaking": "Breaking Changes", "enhancement":"New Features", "bug":"Bugs Squashed"}

source

Release.changelog


def changelog(
    debug:bool=False, # Just print the latest changes, instead of updating file
):

Create the CHANGELOG.md file, or return the proposed text if debug is True

rel = Release()
# print(rel.changelog(debug=True))

source

Release.release


def release(
    
):

Tag and create a release in GitHub for the current version

This uses the version information from your settings.ini.


source

Release.latest_notes


def latest_notes(
    
):

Latest CHANGELOG entry

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.

CLI functions


source

changelog


def changelog(
    debug:store_true=False, # Print info to be added to CHANGELOG, instead of updating file
    repo:str=None, # repo to use instead of `lib_name` from `settings.ini`
):

Create a CHANGELOG.md file from closed and labeled GitHub issues


source

release_git


def release_git(
    token:str=None, # Optional GitHub token (otherwise `token` file is used)
):

Tag and create a release in GitHub for the current version


source

release_gh


def release_gh(
    token:str=None, # Optional GitHub token (otherwise `token` file is used)
):

Calls nbdev_changelog, lets you edit the result, then pushes to git and calls nbdev_release_git

Publish Packages


source

pypi_json


def pypi_json(
    s
):

Dictionary decoded JSON for PYPI path s


source

latest_pypi


def latest_pypi(
    name
):

Latest version of name on pypi


source

pypi_details


def pypi_details(
    name
):

Version, URL, and SHA256 for name from pypi


source

conda_output_path


def conda_output_path(
    name, build:str='build'
):

Output path for conda build


source

write_conda_meta


def write_conda_meta(
    path:str='conda'
):

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.


source

write_requirements


def write_requirements(
    path:str=''
):

Writes a requirements.txt file to directory based on settings.ini.

This function can be used in situations where you need to generate a requirements.txt file for a project.


source

anaconda_upload


def anaconda_upload(
    name, loc:NoneType=None, user:NoneType=None, token:NoneType=None, env_token:NoneType=None
):

Upload name to anaconda

from fastcore.xtras import globtastic

source

release_conda


def release_conda(
    path:str='conda', # Path where package will be created
    do_build:bool_arg=True, # Run `conda build` step
    build_args:str='', # Additional args (as str) to send to `conda build`
    skip_upload:store_true=False, # Skip `anaconda upload` step
    mambabuild:store_true=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


source

chk_conda_rel


def chk_conda_rel(
    nm:str, # Package name on pypi
    apkg:str=None, # Anaconda Package (defaults to {nm})
    channel:str='fastai', # Anaconda Channel
    force:store_true=False, # Always return github tag
):

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.


source

release_pypi


def release_pypi(
    repository:str='pypi', # Respository to upload to (defined in ~/.pypirc)
):

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.


source

release_both


def release_both(
    path:str='conda', # Path where package will be created
    do_build:bool_arg=True, # Run `conda build` step
    build_args:str='', # Additional args (as str) to send to `conda build`
    skip_upload:store_true=False, # Skip `anaconda upload` step
    mambabuild:store_true=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

Bump Version


source

bump_version


def bump_version(
    version, part:int=2, unbump:bool=False
):

source

nbdev_bump_version


def nbdev_bump_version(
    part:int=2, # Part of version to bump
    unbump:bool=False, # Reduce version instead of increasing it
):

Increment version in settings.ini by one