Skip to content

Commit 6448160

Browse files
authored
feat: Add manual workflow dispatch for Docker builds to fix GHCR access (#55)
* feat: Add manual workflow dispatch for Docker builds Adds workflow_dispatch trigger to the publish workflow to enable manual Docker image builds to both Docker Hub and GHCR without requiring a new release. This addresses issue #48 where users cannot pull from ghcr.io because Docker images weren't built for recent releases. Features: - Manual trigger with tag input (e.g., v1.0.1) - Docker-only mode to skip PyPI publishing - Proper ref checkout for tagged versions - Maintains backward compatibility with release events Usage: Workflow can be manually triggered from GitHub Actions UI to rebuild Docker images for any existing git tag. Fixes #48 * fix: Address critical security and logic issues in workflow Fixes all issues identified in Claude Code review: 🚨 Critical Fixes: 1. Remove redundant condition in deploy-prod job - Was checking github.event_name == 'release' twice - Simplified to: !inputs.docker_only 2. Fix Docker job condition logic - Removed flawed always() + needs dependency - Now runs independently for release or manual triggers - Docker builds don't require PyPI deployment success 🔐 Security Improvements: 3. Add tag format validation - Validates semver format: v1.2.3 or v1.2.3-alpha - Prevents arbitrary git ref injection 4. Add tag existence verification - Verifies tag exists before building - Provides clear error messages 🔧 Best Practice Improvements: 5. Normalize tag value extraction - Creates normalized tag output for metadata - Handles both release and manual trigger sources 6. Remove needs dependency from docker job - Docker builds are independent of PyPI - Allows manual Docker-only builds without test deploy All changes maintain backward compatibility with release events while enabling secure manual Docker builds.
1 parent 953965b commit 6448160

File tree

1 file changed

+59
-12
lines changed

1 file changed

+59
-12
lines changed

.github/workflows/publish.yml

Lines changed: 59 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,17 @@ name: Publish Package
33
on:
44
release:
55
types: [published]
6+
workflow_dispatch:
7+
inputs:
8+
docker_only:
9+
description: 'Build and push Docker images only (skip PyPI)'
10+
required: false
11+
type: boolean
12+
default: true
13+
tag:
14+
description: 'Git tag to build from (e.g., v1.0.1)'
15+
required: true
16+
type: string
617

718
permissions:
819
contents: read
@@ -11,12 +22,16 @@ permissions:
1122
jobs:
1223
deploy-test:
1324
runs-on: ubuntu-latest
25+
# Skip PyPI deployment when manually triggered with docker_only
26+
if: ${{ github.event_name == 'release' || !inputs.docker_only }}
1427
environment: testpypi
1528
permissions:
1629
id-token: write
1730

1831
steps:
1932
- uses: actions/checkout@v4
33+
with:
34+
ref: ${{ inputs.tag || github.ref }}
2035

2136
- name: Install Nix
2237
uses: cachix/install-nix-action@v31
@@ -39,14 +54,16 @@ jobs:
3954
deploy-prod:
4055
needs: deploy-test
4156
runs-on: ubuntu-latest
42-
# Only deploy to PyPI for non-prerelease versions
43-
if: ${{ !github.event.release.prerelease }}
57+
# Only deploy to PyPI for non-prerelease versions and skip when manually triggered with docker_only
58+
if: ${{ github.event_name == 'release' && !github.event.release.prerelease && !inputs.docker_only }}
4459
environment: pypi
4560
permissions:
4661
id-token: write
4762

4863
steps:
4964
- uses: actions/checkout@v4
65+
with:
66+
ref: ${{ inputs.tag || github.ref }}
5067

5168
- name: Install Nix
5269
uses: cachix/install-nix-action@v31
@@ -65,14 +82,44 @@ jobs:
6582
uses: pypa/gh-action-pypi-publish@release/v1
6683

6784
docker:
68-
needs: deploy-test
85+
# Run if: (1) release event after test deploy, or (2) manual trigger
86+
# Note: Docker builds are independent and don't strictly require PyPI deployment
87+
if: ${{ github.event_name == 'release' || github.event_name == 'workflow_dispatch' }}
6988
runs-on: ubuntu-latest
7089
permissions:
7190
packages: write
72-
91+
7392
steps:
7493
- uses: actions/checkout@v4
75-
94+
with:
95+
ref: ${{ inputs.tag || github.ref }}
96+
97+
- name: Validate tag format
98+
if: github.event_name == 'workflow_dispatch'
99+
run: |
100+
if [[ ! "${{ inputs.tag }}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9\-\.]+)?$ ]]; then
101+
echo "❌ Invalid tag format. Expected: v1.2.3 or v1.2.3-alpha"
102+
exit 1
103+
fi
104+
105+
- name: Verify tag exists
106+
if: github.event_name == 'workflow_dispatch'
107+
run: |
108+
if ! git rev-parse --verify "refs/tags/${{ inputs.tag }}" >/dev/null 2>&1; then
109+
echo "❌ Tag ${{ inputs.tag }} does not exist"
110+
exit 1
111+
fi
112+
echo "✓ Tag ${{ inputs.tag }} verified"
113+
114+
- name: Normalize tag
115+
id: tag
116+
run: |
117+
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
118+
echo "tag=${{ inputs.tag }}" >> $GITHUB_OUTPUT
119+
else
120+
echo "tag=${{ github.ref_name }}" >> $GITHUB_OUTPUT
121+
fi
122+
76123
- name: Set up QEMU
77124
uses: docker/setup-qemu-action@v3
78125

@@ -84,7 +131,7 @@ jobs:
84131
with:
85132
username: ${{ secrets.DOCKERHUB_USERNAME }}
86133
password: ${{ secrets.DOCKERHUB_TOKEN }}
87-
134+
88135
- name: Login to GitHub Container Registry
89136
uses: docker/login-action@v3
90137
with:
@@ -100,14 +147,14 @@ jobs:
100147
utensils/mcp-nixos
101148
ghcr.io/utensils/mcp-nixos
102149
tags: |
103-
# Latest tag for stable releases
104-
type=raw,value=latest,enable=${{ !github.event.release.prerelease }}
105-
# Version tag from release
106-
type=semver,pattern={{version}}
150+
# Latest tag for stable releases (not for prereleases)
151+
type=raw,value=latest,enable=${{ github.event_name == 'release' && !github.event.release.prerelease || github.event_name == 'workflow_dispatch' }}
152+
# Version tag from release or manual input
153+
type=semver,pattern={{version}},value=${{ steps.tag.outputs.tag }}
107154
# Major.minor tag
108-
type=semver,pattern={{major}}.{{minor}}
155+
type=semver,pattern={{major}}.{{minor}},value=${{ steps.tag.outputs.tag }}
109156
# Major tag (only for stable releases)
110-
type=semver,pattern={{major}},enable=${{ !github.event.release.prerelease }}
157+
type=semver,pattern={{major}},value=${{ steps.tag.outputs.tag }},enable=${{ github.event_name == 'release' && !github.event.release.prerelease || github.event_name == 'workflow_dispatch' }}
111158
112159
- name: Build and push Docker image
113160
uses: docker/build-push-action@v6

0 commit comments

Comments
 (0)