Skip to content

Commit 431c91f

Browse files
committed
feat: add fix-release workflow for handling failed releases - Created comprehensive fix-release.yaml workflow with validation and safety checks - Added options to selectively republish package, container, or both - Included dry-run mode for testing without actual publishing - Added checks for existing versions on PyPI and container registry - Fixed PYPI_PASSWORD -> PYPI_TOKEN in manual release workflow - Provides detailed summary of fix operations
1 parent 4752f75 commit 431c91f

File tree

2 files changed

+188
-1
lines changed

2 files changed

+188
-1
lines changed

.github/workflows/fix-release.yaml

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
name: Fix Release
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
tag:
7+
description: 'Tag/version to fix (e.g., v1.2.3 or 1.2.3)'
8+
required: true
9+
type: string
10+
publish_package:
11+
description: 'Republish package to PyPI'
12+
required: true
13+
type: boolean
14+
default: true
15+
publish_container:
16+
description: 'Republish container images'
17+
required: true
18+
type: boolean
19+
default: true
20+
dry_run:
21+
description: 'Dry run mode (test without actually publishing)'
22+
required: false
23+
type: boolean
24+
default: false
25+
26+
permissions:
27+
contents: read
28+
packages: write
29+
id-token: write
30+
31+
jobs:
32+
validate-inputs:
33+
runs-on: ubuntu-latest
34+
outputs:
35+
normalized_tag: ${{ steps.normalize.outputs.tag }}
36+
steps:
37+
- name: Normalize tag format
38+
id: normalize
39+
run: |
40+
TAG="${{ github.event.inputs.tag }}"
41+
# Remove 'v' prefix if present for consistency
42+
NORMALIZED_TAG=${TAG#v}
43+
# Add 'v' prefix for git operations
44+
GIT_TAG="v${NORMALIZED_TAG}"
45+
echo "tag=${GIT_TAG}" >> $GITHUB_OUTPUT
46+
echo "Normalized tag: ${GIT_TAG}"
47+
48+
- uses: actions/checkout@v4
49+
with:
50+
fetch-tags: true
51+
52+
- name: Verify tag exists
53+
run: |
54+
if ! git tag -l | grep -q "^${{ steps.normalize.outputs.tag }}$"; then
55+
echo "❌ Tag ${{ steps.normalize.outputs.tag }} does not exist"
56+
echo "Available tags:"
57+
git tag -l | tail -10
58+
exit 1
59+
fi
60+
echo "✅ Tag ${{ steps.normalize.outputs.tag }} exists"
61+
62+
fix-package:
63+
needs: validate-inputs
64+
if: ${{ github.event.inputs.publish_package == 'true' }}
65+
runs-on: ubuntu-latest
66+
67+
env:
68+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
69+
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
70+
DRY_RUN: ${{ github.event.inputs.dry_run }}
71+
72+
steps:
73+
- uses: actions/checkout@v4
74+
with:
75+
ref: ${{ needs.validate-inputs.outputs.normalized_tag }}
76+
fetch-tags: true
77+
78+
- uses: asdf-vm/actions/install@v4
79+
80+
- name: Check if package version already exists on PyPI
81+
run: |
82+
TAG="${{ needs.validate-inputs.outputs.normalized_tag }}"
83+
VERSION=${TAG#v}
84+
echo "Checking if transcribe-me version ${VERSION} exists on PyPI..."
85+
86+
if pip index versions transcribe-me | grep -q "${VERSION}"; then
87+
echo "⚠️ Version ${VERSION} already exists on PyPI"
88+
echo "This will likely fail unless you're using --skip-existing or test PyPI"
89+
else
90+
echo "✅ Version ${VERSION} not found on PyPI, safe to publish"
91+
fi
92+
93+
- name: Publish package to PyPI
94+
run: |
95+
if [[ "${{ github.event.inputs.dry_run }}" == "true" ]]; then
96+
echo "🧪 DRY RUN: Would publish package to PyPI"
97+
echo "Command that would run: make publish-package"
98+
else
99+
echo "📦 Publishing package to PyPI..."
100+
make publish-package
101+
fi
102+
103+
fix-container:
104+
needs: validate-inputs
105+
if: ${{ github.event.inputs.publish_container == 'true' }}
106+
runs-on: ubuntu-latest
107+
108+
strategy:
109+
matrix:
110+
arch: [linux/amd64, linux/arm64]
111+
112+
env:
113+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
114+
115+
steps:
116+
- uses: actions/checkout@v4
117+
with:
118+
ref: ${{ needs.validate-inputs.outputs.normalized_tag }}
119+
fetch-depth: 1
120+
121+
- run: git fetch --tags origin
122+
123+
- uses: docker/setup-qemu-action@v3
124+
- uses: docker/setup-buildx-action@v3
125+
126+
- name: Check existing container images
127+
run: |
128+
TAG="${{ needs.validate-inputs.outputs.normalized_tag }}"
129+
VERSION=${TAG#v}
130+
echo "Checking for existing container images..."
131+
132+
# Check if images already exist (this will fail gracefully if they don't)
133+
docker manifest inspect ghcr.io/echohello-dev/transcribe-me:${VERSION} 2>/dev/null && \
134+
echo "⚠️ Image ghcr.io/echohello-dev/transcribe-me:${VERSION} already exists" || \
135+
echo "✅ Image ghcr.io/echohello-dev/transcribe-me:${VERSION} not found, safe to publish"
136+
137+
docker manifest inspect ghcr.io/echohello-dev/transcribe-me:latest 2>/dev/null && \
138+
echo "⚠️ Image ghcr.io/echohello-dev/transcribe-me:latest already exists (will be overwritten)" || \
139+
echo "✅ Image ghcr.io/echohello-dev/transcribe-me:latest not found"
140+
141+
- name: Publish container image
142+
run: |
143+
if [[ "${{ github.event.inputs.dry_run }}" == "true" ]]; then
144+
echo "🧪 DRY RUN: Would publish container image for ${{ matrix.arch }}"
145+
echo "Command that would run: make publish-image"
146+
else
147+
echo "🐳 Publishing container image for ${{ matrix.arch }}..."
148+
make publish-image
149+
fi
150+
env:
151+
DOCKER_DEFAULT_PLATFORM: ${{ matrix.arch }}
152+
153+
summary:
154+
needs: [validate-inputs, fix-package, fix-container]
155+
if: always()
156+
runs-on: ubuntu-latest
157+
steps:
158+
- name: Release fix summary
159+
run: |
160+
echo "## 🔧 Release Fix Summary" >> $GITHUB_STEP_SUMMARY
161+
echo "" >> $GITHUB_STEP_SUMMARY
162+
echo "**Tag:** ${{ needs.validate-inputs.outputs.normalized_tag }}" >> $GITHUB_STEP_SUMMARY
163+
echo "**Dry Run:** ${{ github.event.inputs.dry_run }}" >> $GITHUB_STEP_SUMMARY
164+
echo "" >> $GITHUB_STEP_SUMMARY
165+
166+
if [[ "${{ github.event.inputs.publish_package }}" == "true" ]]; then
167+
if [[ "${{ needs.fix-package.result }}" == "success" ]]; then
168+
echo "✅ **Package:** Successfully published" >> $GITHUB_STEP_SUMMARY
169+
else
170+
echo "❌ **Package:** Failed to publish" >> $GITHUB_STEP_SUMMARY
171+
fi
172+
else
173+
echo "⏭️ **Package:** Skipped" >> $GITHUB_STEP_SUMMARY
174+
fi
175+
176+
if [[ "${{ github.event.inputs.publish_container }}" == "true" ]]; then
177+
if [[ "${{ needs.fix-container.result }}" == "success" ]]; then
178+
echo "✅ **Container:** Successfully published" >> $GITHUB_STEP_SUMMARY
179+
else
180+
echo "❌ **Container:** Failed to publish" >> $GITHUB_STEP_SUMMARY
181+
fi
182+
else
183+
echo "⏭️ **Container:** Skipped" >> $GITHUB_STEP_SUMMARY
184+
fi
185+
186+
echo "" >> $GITHUB_STEP_SUMMARY
187+
echo "View the [release on GitHub](https://github.com/${{ github.repository }}/releases/tag/${{ needs.validate-inputs.outputs.normalized_tag }})" >> $GITHUB_STEP_SUMMARY

.github/workflows/release.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616

1717
env:
1818
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
19-
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
19+
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
2020

2121
steps:
2222
- uses: actions/checkout@v4

0 commit comments

Comments
 (0)