Create delightful software with Jupyter Notebooks
—
Automated publishing to PyPI, GitHub releases, and changelog generation. nbdev provides comprehensive release management tools that handle version bumping, changelog generation, and publishing to multiple platforms.
Main class for managing package releases across platforms.
class Release:
"""
Release management for nbdev projects.
Handles the complete release process including:
- Version management
- Changelog generation
- PyPI publishing
- GitHub release creation
- Documentation updates
"""
def __init__(self, owner: str = None, repo: str = None, token: str = None):
"""
Initialize release manager.
Args:
owner: GitHub repository owner
repo: GitHub repository name
token: GitHub API token for releases
"""Create git tags and releases.
def release_git(tag: str = None, msg: str = None):
"""
Create git tag and release.
Args:
tag: Version tag (defaults to current version in settings)
msg: Release message (defaults to changelog entry)
Creates a git tag for the current version and pushes it to
the remote repository for release tracking.
"""Create GitHub releases with assets and release notes.
def release_gh(tag: str = None, notes: str = None,
draft: bool = False, prerelease: bool = False):
"""
Create GitHub release.
Args:
tag: Release tag (defaults to current version)
notes: Release notes (defaults to changelog)
draft: Create as draft release
prerelease: Mark as prerelease
Creates a GitHub release with automatically generated
release notes from changelog and project information.
"""Generate and manage project changelogs.
def changelog(tag: str = None, since_tag: str = None):
"""
Generate changelog for release.
Args:
tag: Target release tag
since_tag: Previous release tag to compare from
Returns:
Formatted changelog with commits, issues, and PRs
since the last release.
"""Get information about PyPI packages and releases.
def pypi_json(name: str):
"""
Get PyPI package information.
Args:
name: Package name on PyPI
Returns:
JSON data about the package including versions,
metadata, and download statistics.
"""
def latest_pypi(name: str):
"""
Get latest PyPI version for a package.
Args:
name: Package name on PyPI
Returns:
Latest version string available on PyPI
"""from nbdev.release import Release, release_git, release_gh, changelog
from nbdev.config import get_config
def complete_release(version: str):
"""Complete release workflow."""
config = get_config()
# 1. Update version in project
from nbdev.config import update_version
update_version(version)
# 2. Generate changelog
notes = changelog(tag=version)
print(f"Changelog:\n{notes}")
# 3. Create git release
release_git(tag=version, msg=f"Release {version}")
# 4. Create GitHub release
release_gh(tag=version, notes=notes)
# 5. Publish to PyPI (manual step)
print(f"Ready to publish {config.lib_name} {version} to PyPI")
print("Run: python -m build && twine upload dist/*")
complete_release("1.2.0")from nbdev.config import update_version, get_config
from nbdev.release import latest_pypi
def check_version_status():
"""Check current version against PyPI."""
config = get_config()
current_version = config.version
try:
pypi_version = latest_pypi(config.lib_name)
print(f"Current version: {current_version}")
print(f"PyPI version: {pypi_version}")
if current_version == pypi_version:
print("⚠ Version matches PyPI - need to bump version")
else:
print("✓ Version is different from PyPI")
except Exception as e:
print(f"Could not check PyPI: {e}")
check_version_status()from nbdev.release import Release, release_gh
# Create GitHub release with custom notes
release_notes = """
## New Features
- Added advanced export functionality
- Improved test performance
## Bug Fixes
- Fixed merge conflict resolution
- Resolved documentation links
## Breaking Changes
- Updated API for configuration management
"""
release_gh(tag="2.0.0", notes=release_notes)from nbdev.release import release_gh
# Create draft release for review
release_gh(tag="2.0.0-beta", draft=True, prerelease=True)
# Review and publish manually on GitHub# .github/workflows/release.yml
name: Release
on:
push:
tags: ['v*']
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.9'
- name: Install nbdev
run: pip install nbdev
- name: Create GitHub Release
run: python -c "from nbdev.release import release_gh; release_gh()"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}from nbdev.release import latest_pypi, Release
from nbdev.config import update_version, get_config
def auto_version_bump(bump_type='patch'):
"""Automatically bump version."""
config = get_config()
current = config.version
# Parse version (simple implementation)
parts = current.split('.')
major, minor, patch = map(int, parts)
if bump_type == 'major':
major += 1
minor = patch = 0
elif bump_type == 'minor':
minor += 1
patch = 0
else: # patch
patch += 1
new_version = f"{major}.{minor}.{patch}"
update_version(new_version)
print(f"Version bumped: {current} → {new_version}")
return new_version
# Bump patch version
new_ver = auto_version_bump('patch')Release management uses configuration from settings.ini:
# Release configuration
version = 1.0.0
author = Your Name
author_email = you@example.com
copyright = 2024 onwards, %(author)s
license = apache2
git_url = https://github.com/yourusername/yourprojectGH_HOST: strGitHub API host URL for release operations.
CONDA_WARNING: strWarning message about conda package publishing requirements.
from nbdev.release import Release, release_gh
from nbdev.config import get_config
def multi_platform_release():
"""Release to multiple platforms."""
config = get_config()
version = config.version
# 1. GitHub release
release_gh(tag=version)
# 2. PyPI release (requires separate setup)
print("Publishing to PyPI...")
import subprocess
subprocess.run(['python', '-m', 'build'])
subprocess.run(['twine', 'upload', 'dist/*'])
# 3. Conda release (if configured)
print("Consider publishing to conda-forge")
print(CONDA_WARNING)
multi_platform_release()from nbdev.release import pypi_json, latest_pypi
from nbdev.test import nbdev_test
from nbdev.export import nb_export
def validate_release():
"""Validate project before release."""
print("1. Running tests...")
if not nbdev_test():
return False, "Tests failed"
print("2. Checking exports...")
nb_export()
print("3. Checking PyPI status...")
config = get_config()
try:
current_pypi = latest_pypi(config.lib_name)
if current_pypi == config.version:
return False, "Version already exists on PyPI"
except:
pass # Package might not exist yet
return True, "Ready for release"
valid, message = validate_release()
print(f"Release validation: {message}")Complete Release Example:
from nbdev.release import Release, release_git, release_gh, changelog
from nbdev.config import update_version, get_config
from nbdev.test import nbdev_test
from nbdev.export import nb_export
def full_release_workflow(new_version: str):
"""Complete release workflow with validation."""
print(f"Starting release workflow for version {new_version}")
# 1. Validate current state
print("Validating project state...")
if not nbdev_test():
print("❌ Tests failed - aborting release")
return False
# 2. Update version
print(f"Updating version to {new_version}")
update_version(new_version)
# 3. Export latest code
print("Exporting notebooks...")
nb_export()
# 4. Generate changelog
print("Generating changelog...")
notes = changelog(tag=new_version)
# 5. Create releases
print("Creating git release...")
release_git(tag=new_version, msg=f"Release {new_version}")
print("Creating GitHub release...")
release_gh(tag=new_version, notes=notes)
print(f"✅ Release {new_version} completed successfully!")
print("Don't forget to publish to PyPI with:")
print(" python -m build && twine upload dist/*")
return True
# Execute full release
full_release_workflow("1.3.0")Install with Tessl CLI
npx tessl i tessl/pypi-nbdev