release-publish.yml•4.52 kB
name: Release and Publish to PyPI and GitHub Container Registry
on:
workflow_dispatch:
inputs:
create_release_notes:
description: 'Auto-generate release notes'
type: boolean
default: true
draft_release:
description: 'Create as draft release'
type: boolean
default: true
tag_as_latest:
description: 'Tag Docker image as latest'
type: boolean
default: true
permissions:
contents: write
packages: write
jobs:
prepare_release:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.get_version.outputs.version }}
steps:
- name: Check out the repository
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install uv
uses: astral-sh/setup-uv@v5
with:
enable-cache: true
- name: Install dependencies for testing
run: |
make dev-deps
- name: Run tests
run: |
make test
- name: Install dependencies for release
run: |
uv pip install --system toml
- name: Get version
id: get_version
run: |
VERSION=$(python -c "import toml; print(toml.load('pyproject.toml')['project']['version'])")
echo "VERSION=$VERSION" >> $GITHUB_ENV
echo "version=$VERSION" >> $GITHUB_OUTPUT
- name: Build package
run: |
mkdir -p dist
pip install build
python -m build
- name: Create GitHub Release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
RELEASE_VERSION="v${VERSION}"
if [ "${{ github.event.inputs.create_release_notes }}" == "true" ]; then
GENERATE_NOTES="--generate-notes"
else
GENERATE_NOTES=""
fi
if [ "${{ github.event.inputs.draft_release }}" == "true" ]; then
DRAFT_FLAG="--draft"
else
DRAFT_FLAG=""
fi
echo "Creating release: $RELEASE_VERSION"
gh release create $RELEASE_VERSION \
--title "$RELEASE_VERSION" \
$GENERATE_NOTES \
$DRAFT_FLAG \
dist/*
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
retention-days: 1
publish_pypi:
needs: prepare_release
runs-on: ubuntu-latest
steps:
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: dist
path: dist/
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install uv
uses: astral-sh/setup-uv@v5
- name: Publish to PyPI
run: |
uv pip install --system twine
twine upload dist/*
env:
TWINE_USERNAME: ${{ secrets.TWINE_USERNAME }}
TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }}
publish_ghcr:
needs: prepare_release
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Check out the repository
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Prepare Docker tags
id: docker_tags
run: |
TAGS="ghcr.io/${{ github.repository }}:${{ needs.prepare_release.outputs.version }}"
if [ "${{ github.event.inputs.tag_as_latest }}" == "true" ]; then
TAGS="$TAGS,ghcr.io/${{ github.repository }}:latest"
echo "Including latest tag"
else
echo "Skipping latest tag"
fi
echo "tags=$TAGS" >> $GITHUB_OUTPUT
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: true
platforms: linux/amd64,linux/arm64
tags: ${{ steps.docker_tags.outputs.tags }}
labels: |
org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}
org.opencontainers.image.description=MCP Panther
org.opencontainers.image.licenses=Apache-2.0
cache-from: type=gha
cache-to: type=gha,mode=max