Skip to content

Commit 94e5062

Browse files
committed
feat: split release workflow into prepare and publish
1 parent 328acba commit 94e5062

3 files changed

Lines changed: 378 additions & 1 deletion

File tree

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
name: Release
1+
name: Legacy Release (deprecated)
22

3+
# DEPRECATED: Replaced by release-prepare.yml and release-publish.yml
4+
# Kept as a fallback. Remove once new workflows are verified.
35
on:
46
workflow_dispatch:
57
inputs:
Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
name: Release Prepare
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
bump_type:
7+
description: 'Version bump type'
8+
required: true
9+
type: choice
10+
options:
11+
- patch
12+
- minor
13+
- major
14+
- pre
15+
changelog:
16+
description: 'Custom changelog entry (optional - leave empty to auto-generate)'
17+
required: false
18+
type: string
19+
20+
permissions:
21+
contents: write
22+
pull-requests: write
23+
24+
jobs:
25+
prepare-release:
26+
name: Prepare Release
27+
runs-on: ubuntu-latest
28+
outputs:
29+
version: ${{ steps.bump.outputs.version }}
30+
31+
steps:
32+
- name: Validate running from main
33+
if: github.ref != 'refs/heads/main'
34+
run: |
35+
echo "❌ ERROR: Must run from main branch, got ${{ github.ref }}"
36+
exit 1
37+
38+
- name: Checkout code
39+
uses: actions/checkout@v5
40+
with:
41+
fetch-depth: 0
42+
43+
- name: Setup Python
44+
uses: actions/setup-python@v6
45+
with:
46+
python-version: '3.10'
47+
48+
- name: Configure git
49+
run: |
50+
git config --global user.name "github-actions[bot]"
51+
git config --global user.email "github-actions[bot]@users.noreply.github.com"
52+
53+
- name: Install uv
54+
run: |
55+
curl -LsSf https://astral.sh/uv/install.sh | sh
56+
echo "$HOME/.local/bin" >> $GITHUB_PATH
57+
58+
- name: Get current version
59+
id: current
60+
run: |
61+
VERSION=$(grep -m1 -oP '^version = "\K[^"]+' pyproject.toml)
62+
echo "version=$VERSION" >> $GITHUB_OUTPUT
63+
echo "Current version: $VERSION"
64+
65+
- name: Bump version
66+
id: bump
67+
env:
68+
CHANGELOG_INPUT: ${{ github.event.inputs.changelog }}
69+
BUMP_TYPE: ${{ github.event.inputs.bump_type }}
70+
run: |
71+
chmod +x scripts/bump_version.py
72+
73+
if [ -z "$CHANGELOG_INPUT" ]; then
74+
echo "ℹ️ No custom changelog provided. Will auto-generate from commits."
75+
fi
76+
77+
if [ -n "$CHANGELOG_INPUT" ]; then
78+
python scripts/bump_version.py "$BUMP_TYPE" --changelog "$CHANGELOG_INPUT"
79+
else
80+
python scripts/bump_version.py "$BUMP_TYPE"
81+
fi
82+
83+
uv lock --no-progress
84+
85+
NEW_VERSION=$(grep -m1 -oP '^version = "\K[^"]+' pyproject.toml)
86+
echo "version=$NEW_VERSION" >> $GITHUB_OUTPUT
87+
echo "New version: $NEW_VERSION"
88+
89+
- name: Create release branch and push
90+
env:
91+
NEW_VERSION: ${{ steps.bump.outputs.version }}
92+
run: |
93+
BRANCH_NAME="release/v$NEW_VERSION"
94+
95+
if git ls-remote --exit-code --heads origin $BRANCH_NAME; then
96+
echo "⚠️ Branch $BRANCH_NAME already exists. Deleting it first..."
97+
git push origin --delete $BRANCH_NAME
98+
fi
99+
100+
if git show-ref --verify --quiet refs/heads/$BRANCH_NAME; then
101+
git branch -D $BRANCH_NAME
102+
fi
103+
104+
git checkout -b $BRANCH_NAME
105+
git add -A
106+
git commit -m "chore: bump version to $NEW_VERSION
107+
108+
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>"
109+
110+
git push origin $BRANCH_NAME
111+
112+
COMMITTED_VERSION=$(git show HEAD:pyproject.toml | grep -m1 -oP '^version = "\K[^"]+')
113+
if [ "$COMMITTED_VERSION" != "$NEW_VERSION" ]; then
114+
echo "❌ ERROR: Version not committed correctly!"
115+
exit 1
116+
fi
117+
118+
- name: Create Pull Request
119+
env:
120+
GH_TOKEN: ${{ github.token }}
121+
NEW_VERSION: ${{ steps.bump.outputs.version }}
122+
GITHUB_REF: ${{ github.ref }}
123+
GITHUB_ACTOR: ${{ github.actor }}
124+
run: |
125+
BRANCH_NAME="release/v$NEW_VERSION"
126+
127+
WARNING_TEXT=""
128+
if [ "$GITHUB_REF" != "refs/heads/main" ]; then
129+
WARNING_TEXT="**WARNING**: Not running from main branch!"
130+
else
131+
WARNING_TEXT="✅ Running from main branch"
132+
fi
133+
134+
gh pr create \
135+
--base main \
136+
--head "$BRANCH_NAME" \
137+
--title "Release v$NEW_VERSION" \
138+
--body "## 🚀 Release v$NEW_VERSION
139+
140+
This PR was automatically created by the release workflow.
141+
142+
### ⚠️ Pre-merge Checklist
143+
- [ ] Review CHANGELOG.md - ensure it has meaningful release notes
144+
- [ ] Verify version numbers are correct in all files
145+
- [ ] All CI checks are passing
146+
147+
### 📝 How to improve changelog
148+
If the auto-generated changelog isn't good enough:
149+
1. Edit CHANGELOG.md in this PR
150+
2. Commit the changes
151+
3. Then approve and merge
152+
153+
### 🔄 Release Process
154+
After merging this PR, the **release-publish** workflow will:
155+
1. Build the package from main
156+
2. Require **manual approval** before publishing to PyPI
157+
3. Publish to PyPI, create tag and GitHub release
158+
159+
### 🚨 Running from: $GITHUB_REF
160+
$WARNING_TEXT
161+
162+
---
163+
*Triggered by @$GITHUB_ACTOR*"
164+
165+
test-and-build:
166+
name: Test and Build
167+
needs: prepare-release
168+
runs-on: ubuntu-latest
169+
170+
steps:
171+
- uses: actions/checkout@v5
172+
with:
173+
ref: release/v${{ needs.prepare-release.outputs.version }}
174+
175+
- name: Verify version before build
176+
env:
177+
EXPECTED_VERSION: ${{ needs.prepare-release.outputs.version }}
178+
run: |
179+
ACTUAL_VERSION=$(grep -m1 -oP '^version = "\K[^"]+' pyproject.toml)
180+
echo "Expected version: $EXPECTED_VERSION"
181+
echo "Actual version: $ACTUAL_VERSION"
182+
183+
if [ "$ACTUAL_VERSION" != "$EXPECTED_VERSION" ]; then
184+
echo "❌ ERROR: Version mismatch!"
185+
exit 1
186+
fi
187+
echo "✓ Version verified: $ACTUAL_VERSION"
188+
189+
- name: Set up Python
190+
uses: actions/setup-python@v6
191+
with:
192+
python-version: '3.10'
193+
194+
- name: Install uv
195+
run: |
196+
curl -LsSf https://astral.sh/uv/install.sh | sh
197+
echo "$HOME/.local/bin" >> $GITHUB_PATH
198+
199+
- name: Setup build environment
200+
run: |
201+
uv venv
202+
source .venv/bin/activate
203+
uv pip install build twine
204+
205+
- name: Build and check package
206+
run: |
207+
source .venv/bin/activate
208+
uv build
209+
twine check dist/*
210+
echo "=== Package contents ==="
211+
python -m zipfile -l dist/*.whl | head -20
212+
213+
- name: Upload artifacts
214+
uses: actions/upload-artifact@v4
215+
with:
216+
name: dist
217+
path: dist/
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
name: Release Publish
2+
3+
on:
4+
pull_request:
5+
types: [closed]
6+
branches: [main]
7+
8+
permissions:
9+
contents: write
10+
11+
jobs:
12+
build:
13+
name: Build from Main
14+
if: >
15+
github.event.pull_request.merged == true &&
16+
startsWith(github.event.pull_request.head.ref, 'release/v')
17+
runs-on: ubuntu-latest
18+
outputs:
19+
version: ${{ steps.version.outputs.version }}
20+
21+
steps:
22+
- uses: actions/checkout@v5
23+
with:
24+
fetch-depth: 0
25+
26+
- name: Extract version from pyproject.toml
27+
id: version
28+
run: |
29+
VERSION=$(grep -m1 -oP '^version = "\K[^"]+' pyproject.toml)
30+
echo "version=$VERSION" >> $GITHUB_OUTPUT
31+
echo "Version: $VERSION"
32+
33+
- name: Set up Python
34+
uses: actions/setup-python@v6
35+
with:
36+
python-version: '3.10'
37+
38+
- name: Install uv
39+
run: |
40+
curl -LsSf https://astral.sh/uv/install.sh | sh
41+
echo "$HOME/.local/bin" >> $GITHUB_PATH
42+
43+
- name: Build and check package
44+
run: |
45+
uv venv
46+
source .venv/bin/activate
47+
uv pip install build twine
48+
uv build
49+
twine check dist/*
50+
51+
- name: Upload artifacts
52+
uses: actions/upload-artifact@v4
53+
with:
54+
name: dist
55+
path: dist/
56+
57+
release-approval:
58+
name: Release Approval
59+
needs: build
60+
runs-on: ubuntu-latest
61+
environment:
62+
name: pypi-approval
63+
64+
steps:
65+
- name: Approval checkpoint
66+
env:
67+
VERSION: ${{ needs.build.outputs.version }}
68+
run: |
69+
echo "✅ Build successful for v$VERSION"
70+
echo "📦 Package ready for PyPI publication"
71+
echo ""
72+
echo "⚠️ MANUAL APPROVAL REQUIRED"
73+
echo "Verify version and changelog before approving."
74+
75+
publish-pypi:
76+
name: Publish to PyPI
77+
needs: [build, release-approval]
78+
runs-on: ubuntu-latest
79+
environment:
80+
name: pypi
81+
url: https://pypi.org/project/bedrock-agentcore/
82+
83+
steps:
84+
- uses: actions/checkout@v5
85+
with:
86+
fetch-depth: 0
87+
88+
- name: Download artifacts
89+
uses: actions/download-artifact@v5
90+
with:
91+
name: dist
92+
path: dist/
93+
94+
- name: Verify PyPI token exists
95+
env:
96+
PYPI_TOKEN_SET: ${{ secrets.PYPI_API_TOKEN != '' }}
97+
run: |
98+
if [ "$PYPI_TOKEN_SET" != "true" ]; then
99+
echo "❌ ERROR: PYPI_API_TOKEN not configured!"
100+
exit 1
101+
fi
102+
echo "✓ PyPI token is configured"
103+
104+
- name: Check if version exists on PyPI
105+
env:
106+
VERSION: ${{ needs.build.outputs.version }}
107+
run: |
108+
if pip index versions bedrock-agentcore | grep -q "^Available versions.*$VERSION"; then
109+
echo "❌ ERROR: Version $VERSION already exists on PyPI!"
110+
exit 1
111+
fi
112+
echo "✓ Version $VERSION is not on PyPI, safe to publish"
113+
114+
- name: Publish to PyPI
115+
uses: pypa/gh-action-pypi-publish@release/v1
116+
with:
117+
password: ${{ secrets.PYPI_API_TOKEN }}
118+
skip-existing: false
119+
verbose: true
120+
121+
- name: Wait for PyPI availability
122+
env:
123+
VERSION: ${{ needs.build.outputs.version }}
124+
run: |
125+
echo "Waiting for package to be available on PyPI..."
126+
for i in {1..10}; do
127+
if pip index versions bedrock-agentcore | grep -q "$VERSION"; then
128+
echo "✓ Package version $VERSION is now available on PyPI"
129+
break
130+
fi
131+
echo "Attempt $i/10: Package not yet available, waiting 30s..."
132+
sleep 30
133+
done
134+
135+
- name: Create and push tag
136+
env:
137+
VERSION: ${{ needs.build.outputs.version }}
138+
run: |
139+
git config --global user.name "github-actions[bot]"
140+
git config --global user.email "github-actions[bot]@users.noreply.github.com"
141+
git tag -a "v$VERSION" -m "Release v$VERSION"
142+
git push origin "v$VERSION"
143+
144+
- name: Create GitHub Release
145+
uses: softprops/action-gh-release@v2
146+
with:
147+
tag_name: v${{ needs.build.outputs.version }}
148+
name: Bedrock AgentCore SDK v${{ needs.build.outputs.version }}
149+
files: dist/*
150+
generate_release_notes: true
151+
body: |
152+
## Installation
153+
```bash
154+
pip install bedrock-agentcore==${{ needs.build.outputs.version }}
155+
```
156+
157+
## What's Changed
158+
See [CHANGELOG.md](https://github.com/${{ github.repository }}/blob/v${{ needs.build.outputs.version }}/CHANGELOG.md) for details.

0 commit comments

Comments
 (0)