Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 130 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
name: Release

on:
push:
tags:
- 'v*.*.*' # Trigger condition: v0.15.2, v1.0.0, etc.

permissions:
contents: write
id-token: write # For OIDC trusted publishing

jobs:
# Job 1: Build Python Package
build-python:
name: Build Python Package
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.10'

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install build twine

- name: Build package
run: python -m build

- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: python-package
path: dist/*

# Job 2: Publish to PyPI (using OIDC trusted publishing)
publish-pypi:
name: Publish to PyPI
needs: build-python
runs-on: ubuntu-latest
environment:
name: pypi
url: https://pypi.org/p/jupyter-mcp-server
permissions:
id-token: write # Required for OIDC
steps:
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: python-package
path: dist

- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
# No password needed, using OIDC trusted publishing
skip-existing: true

# Job 3: Build and Publish Docker Image
build-docker:
name: Build and Push Docker Image
runs-on: ubuntu-latest
permissions:
contents: read
packages: write # For GHCR
id-token: write # For Docker Hub OIDC (optional)
steps:
- uses: actions/checkout@v4

- name: Extract version from tag
id: version
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: |
datalayer/jupyter-mcp-server:latest
datalayer/jupyter-mcp-server:${{ steps.version.outputs.VERSION }}
cache-from: type=gha
cache-to: type=gha,mode=max

# Job 4: Create GitHub Release
create-release:
name: Create GitHub Release
needs: [publish-pypi, build-docker]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Fetch complete history for release creation

- name: Extract version
id: version
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT


- name: Create Release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ steps.version.outputs.VERSION }}
body: |
## 🚀 Release ${{ steps.version.outputs.VERSION }}

### 🔗 Links

- [PyPI](https://pypi.org/project/jupyter-mcp-server/${{ steps.version.outputs.VERSION }}/)
- [Docker Hub](https://hub.docker.com/r/datalayer/jupyter-mcp-server)
draft: false
prerelease: false
131 changes: 91 additions & 40 deletions RELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,55 +4,106 @@
~ BSD 3-Clause License
-->

# Making a new release of jupyter_mcp_server
# 🚀 Jupyter MCP Server Release Guide

The extension can be published to `PyPI` manually or using the [Jupyter Releaser](https://github.com/jupyter-server/jupyter_releaser).
This document provides detailed instructions on how to release the Jupyter MCP Server project using GitHub Actions.

## Manual release
## 📋 Release Process Overview

### Python package
The release process is defined in the `.github/workflows/release.yml` file and includes the following automated steps:

This repository can be distributed as Python
package. All of the Python
packaging instructions in the `pyproject.toml` file to wrap your extension in a
Python package. Before generating a package, we first need to install `build`.
1. **Python Package Build** - Build distribution packages (wheel and source distribution)
2. **PyPI Publishing** - Automatically publish to PyPI (using OIDC trusted publishing)
3. **Docker Image Build** - Build multi-platform Docker images
4. **GitHub Release Creation** - Automatically generate release notes (simplified version, without automatic changelog)

```bash
pip install build twine
```
## 🔖 Version Management

To create a Python source package (`.tar.gz`) and the binary package (`.whl`) in the `dist/` directory, do:
### Semantic Versioning
The project uses semantic versioning format: `v{major}.{minor}.{patch}`

```bash
python -m build
```
Examples:
- `v1.0.0` - Major version update
- `v1.1.0` - Minor feature update
- `v1.1.1` - Patch and bug fixes

Then to upload the package to PyPI, do:
### Version Tags
For releases, you need to push Git tags with version numbers:

```bash
twine upload dist/*
# Create and push version tag
git tag v1.0.0
git push origin v1.0.0
```

## Automated releases with the Jupyter Releaser

> [!NOTE]
> The extension repository is compatible with the Jupyter Releaser. But
> the GitHub repository and PyPI may need to be properly set up. Please
> follow the instructions of the Jupyter Releaser [checklist](https://jupyter-releaser.readthedocs.io/en/latest/how_to_guides/convert_repo_from_repo.html).

Here is a summary of the steps to cut a new release:

- Go to the Actions panel
- Run the "Step 1: Prep Release" workflow
- Check the draft changelog
- Run the "Step 2: Publish Release" workflow

> [!NOTE]
> Check out the [workflow documentation](https://jupyter-releaser.readthedocs.io/en/latest/get_started/making_release_from_repo.html)
> for more information.

## Publishing to `conda-forge`

If the package is not on conda forge yet, check the documentation to learn how to add it: https://conda-forge.org/docs/maintainer/adding_pkgs.html

Otherwise a bot should pick up the new version publish to PyPI, and open a new PR on the feedstock repository automatically.
## ⚙️ Release Workflow Trigger Conditions

The workflow is automatically triggered when:
- Pushing Git tags in the format `v*.*.*` (e.g., `v1.0.0`, `v2.1.3`)

**Configuration Steps:**

1. Configure Trusted Publisher in PyPI project settings
- Go to https://pypi.org/manage/project/jupyter-mcp-server/settings/publishing/
- Add GitHub Actions as a trusted publisher
- Configure:
- Owner: `datalayer`
- Repository: `jupyter-mcp-server`
- Workflow: `release.yml`
- Environment: `pypi`

2. GitHub repository settings
- Settings → Environments → New environment: `pypi`
- Configure protection rules (optional):
- Required reviewers (requires approval)
- Branch protection (only allows main branch)

Creating access token in Docker Hub:
- Settings → Security → Access Tokens
- Create restricted token (read/write only specific repository)
- Store as GitHub Secret:
- `DOCKERHUB_USERNAME` - Docker Hub username
- `DOCKERHUB_TOKEN` - Docker Hub access token

### GitHub Release
- Uses built-in `GITHUB_TOKEN`, no additional configuration required

## 📦 Release Artifacts

### Python Package
- **PyPI**: `https://pypi.org/project/jupyter-mcp-server/`
- **Formats**: wheel (`.whl`) and source distribution (`.tar.gz`)

### Docker Image
- **Repository**: `datalayer/jupyter-mcp-server`
- **Tags**:
- `latest` - Latest stable version
- `{version}` - Specific version number (e.g., `1.0.0`)

## 🔄 Release Steps

1. **Update Version Number**
```bash
# Edit version file
vim jupyter_mcp_server/__version__.py
```

2. **Create Release Tag**
```bash
git tag v1.0.0
git push origin v1.0.0
```

3. **Monitor Release Progress**
- Go to GitHub Actions page to view workflow run status
- Check if PyPI has been updated
- Verify Docker Hub has new images

## 🔄 Version Rollback

If serious issues occur during release:

1. **Delete GitHub Release** (if created)
2. **Delete package from PyPI** (if published) - Requires admin privileges
3. **Delete Docker image tags from Docker Hub**
4. **Push new tag to re-release**