publish.yml•6 kB
name: Publish Package
on:
release:
types: [published]
workflow_dispatch:
inputs:
docker_only:
description: 'Build and push Docker images only (skip PyPI)'
required: false
type: boolean
default: true
tag:
description: 'Git tag to build from (e.g., v1.0.1)'
required: true
type: string
permissions:
contents: read
packages: write
jobs:
deploy-test:
runs-on: ubuntu-latest
# Skip PyPI deployment when manually triggered with docker_only
if: ${{ github.event_name == 'release' || !inputs.docker_only }}
environment: testpypi
permissions:
id-token: write
steps:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.tag || github.ref }}
- name: Install Nix
uses: cachix/install-nix-action@v31
with:
nix_path: nixpkgs=channel:nixos-unstable
extra_nix_config: |
experimental-features = nix-command flakes
accept-flake-config = true
- name: Build package with Nix
run: |
nix develop --command build
ls -la dist/
- name: Publish package to Test PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
repository-url: https://test.pypi.org/legacy/
deploy-prod:
needs: deploy-test
runs-on: ubuntu-latest
# Only deploy to PyPI for non-prerelease versions and skip when manually triggered with docker_only
if: ${{ github.event_name == 'release' && !github.event.release.prerelease && !inputs.docker_only }}
environment: pypi
permissions:
id-token: write
steps:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.tag || github.ref }}
- name: Install Nix
uses: cachix/install-nix-action@v31
with:
nix_path: nixpkgs=channel:nixos-unstable
extra_nix_config: |
experimental-features = nix-command flakes
accept-flake-config = true
- name: Build package with Nix
run: |
nix develop --command build
ls -la dist/
- name: Publish package to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
docker:
# Run if: (1) release event after test deploy, or (2) manual trigger
# Note: Docker builds are independent and don't strictly require PyPI deployment
if: ${{ github.event_name == 'release' || github.event_name == 'workflow_dispatch' }}
runs-on: ubuntu-latest
permissions:
packages: write
steps:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.tag || github.ref }}
- name: Validate tag format
if: github.event_name == 'workflow_dispatch'
run: |
if [[ ! "${{ inputs.tag }}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.-]+)?$ ]]; then
echo "❌ Invalid tag format. Expected: v1.2.3 or v1.2.3-alpha"
exit 1
fi
- name: Verify tag exists
if: github.event_name == 'workflow_dispatch'
run: |
if ! git rev-parse --verify "refs/tags/${{ inputs.tag }}" >/dev/null 2>&1; then
echo "❌ Tag ${{ inputs.tag }} does not exist"
exit 1
fi
echo "✓ Tag ${{ inputs.tag }} verified"
- name: Normalize tag
id: tag
run: |
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
echo "tag=${{ inputs.tag }}" >> $GITHUB_OUTPUT
else
echo "tag=${{ github.ref_name }}" >> $GITHUB_OUTPUT
fi
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: |
utensils/mcp-nixos
ghcr.io/utensils/mcp-nixos
tags: |
# Latest tag for stable releases (not for prereleases)
type=raw,value=latest,enable=${{ github.event_name == 'release' && !github.event.release.prerelease || github.event_name == 'workflow_dispatch' }}
# Version tag from release or manual input
type=semver,pattern={{version}},value=${{ steps.tag.outputs.tag }}
# Major.minor tag
type=semver,pattern={{major}}.{{minor}},value=${{ steps.tag.outputs.tag }}
# Major tag (only for stable releases)
type=semver,pattern={{major}},value=${{ steps.tag.outputs.tag }},enable=${{ github.event_name == 'release' && !github.event.release.prerelease || github.event_name == 'workflow_dispatch' }}
- name: Build and push Docker image
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
platforms: linux/amd64,linux/arm64
- name: Make GHCR package public
continue-on-error: true
run: |
echo "Setting GHCR package visibility to public..."
# Note: This requires the workflow to have admin permissions on the package
# If the package doesn't exist yet or permissions are insufficient, this will fail gracefully
gh api --method PATCH \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"/orgs/utensils/packages/container/mcp-nixos" \
-f visibility=public || echo "Could not set visibility via API. Please set manually at: https://github.com/orgs/utensils/packages/container/mcp-nixos/settings"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}