Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
name: Release
name: Legacy Release (deprecated)

# DEPRECATED: Replaced by release-prepare.yml and release-publish.yml
# Kept as a fallback. Remove once new workflows are verified.
on:
workflow_dispatch:
inputs:
Expand Down
218 changes: 218 additions & 0 deletions .github/workflows/release-prepare.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
name: Release Prepare

on:
workflow_dispatch:
inputs:
bump_type:
description: 'Version bump type'
required: true
type: choice
options:
- patch
- minor
- major
- pre
changelog:
description: 'Custom changelog entry (optional - leave empty to auto-generate)'
required: false
type: string

permissions:
contents: write
pull-requests: write

jobs:
prepare-release:
name: Prepare Release
runs-on: ubuntu-latest
outputs:
version: ${{ steps.bump.outputs.version }}

steps:
- name: Validate running from main
run: |
if [[ "${{ github.ref }}" != "refs/heads/main" ]]; then
echo "⚠️ WARNING: Running from ${{ github.ref }}"
echo "⚠️ Production releases should only run from main branch"
fi

- name: Checkout code
uses: actions/checkout@v5
with:
fetch-depth: 0

- name: Setup Python
uses: actions/setup-python@v6
with:
python-version: '3.10'

- name: Configure git
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"

- name: Install uv
run: |
curl -LsSf https://astral.sh/uv/install.sh | sh
echo "$HOME/.local/bin" >> $GITHUB_PATH

- name: Get current version
id: current
run: |
VERSION=$(grep -m1 -oP '^version = "\K[^"]+' pyproject.toml)
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "Current version: $VERSION"

- name: Bump version
id: bump
env:
CHANGELOG_INPUT: ${{ github.event.inputs.changelog }}
BUMP_TYPE: ${{ github.event.inputs.bump_type }}
run: |
chmod +x scripts/bump_version.py

if [ -z "$CHANGELOG_INPUT" ]; then
echo "ℹ️ No custom changelog provided. Will auto-generate from commits."
fi

if [ -n "$CHANGELOG_INPUT" ]; then
python scripts/bump_version.py "$BUMP_TYPE" --changelog "$CHANGELOG_INPUT"
else
python scripts/bump_version.py "$BUMP_TYPE"
fi

uv lock --no-progress

NEW_VERSION=$(grep -m1 -oP '^version = "\K[^"]+' pyproject.toml)
echo "version=$NEW_VERSION" >> $GITHUB_OUTPUT
echo "New version: $NEW_VERSION"

- name: Create release branch and push
env:
NEW_VERSION: ${{ steps.bump.outputs.version }}
run: |
BRANCH_NAME="release/v$NEW_VERSION"

if git ls-remote --exit-code --heads origin $BRANCH_NAME; then
echo "⚠️ Branch $BRANCH_NAME already exists. Deleting it first..."
git push origin --delete $BRANCH_NAME
fi

if git show-ref --verify --quiet refs/heads/$BRANCH_NAME; then
git branch -D $BRANCH_NAME
fi

git checkout -b $BRANCH_NAME
git add -A
git commit -m "chore: bump version to $NEW_VERSION

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>"

git push origin $BRANCH_NAME

COMMITTED_VERSION=$(git show HEAD:pyproject.toml | grep -m1 -oP '^version = "\K[^"]+')
if [ "$COMMITTED_VERSION" != "$NEW_VERSION" ]; then
echo "❌ ERROR: Version not committed correctly!"
exit 1
fi

- name: Create Pull Request
env:
GH_TOKEN: ${{ github.token }}
NEW_VERSION: ${{ steps.bump.outputs.version }}
GITHUB_REF: ${{ github.ref }}
GITHUB_ACTOR: ${{ github.actor }}
run: |
BRANCH_NAME="release/v$NEW_VERSION"

WARNING_TEXT=""
if [ "$GITHUB_REF" != "refs/heads/main" ]; then
WARNING_TEXT="**WARNING**: Not running from main branch!"
else
WARNING_TEXT="✅ Running from main branch"
fi

gh pr create \
--base main \
--head "$BRANCH_NAME" \
--title "Release v$NEW_VERSION" \
--body "## 🚀 Release v$NEW_VERSION

This PR was automatically created by the release workflow.

### ⚠️ Pre-merge Checklist
- [ ] Review CHANGELOG.md - ensure it has meaningful release notes
- [ ] Verify version numbers are correct in all files
- [ ] All CI checks are passing

### 📝 How to improve changelog
If the auto-generated changelog isn't good enough:
1. Edit CHANGELOG.md in this PR
2. Commit the changes
3. Then approve and merge

### 🔄 Release Process
After merging this PR, the **release-publish** workflow will:
1. Build the package from main
2. Require **manual approval** before publishing to PyPI
3. Publish to PyPI, create tag and GitHub release

### 🚨 Running from: $GITHUB_REF
$WARNING_TEXT

---
*Triggered by @$GITHUB_ACTOR*"

test-and-build:
name: Test and Build
needs: prepare-release
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v5
with:
ref: release/v${{ needs.prepare-release.outputs.version }}

- name: Verify version before build
env:
EXPECTED_VERSION: ${{ needs.prepare-release.outputs.version }}
run: |
ACTUAL_VERSION=$(grep -m1 -oP '^version = "\K[^"]+' pyproject.toml)
echo "Expected version: $EXPECTED_VERSION"
echo "Actual version: $ACTUAL_VERSION"

if [ "$ACTUAL_VERSION" != "$EXPECTED_VERSION" ]; then
echo "❌ ERROR: Version mismatch!"
exit 1
fi
echo "✓ Version verified: $ACTUAL_VERSION"

- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.10'

- name: Install uv
run: |
curl -LsSf https://astral.sh/uv/install.sh | sh
echo "$HOME/.local/bin" >> $GITHUB_PATH

- name: Setup build environment
run: |
uv venv
source .venv/bin/activate
uv pip install build twine

- name: Build and check package
run: |
source .venv/bin/activate
uv build
twine check dist/*
echo "=== Package contents ==="
python -m zipfile -l dist/*.whl | head -20

- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
170 changes: 170 additions & 0 deletions .github/workflows/release-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
name: Release Publish

on:
pull_request:
types: [closed]
branches: [main]
workflow_dispatch:
inputs:
dry_run:
description: 'Dry run (skip PyPI publish, still creates tag and GitHub release)'
required: false
type: boolean
default: false

permissions:
contents: write

jobs:
build:
name: Build from Main
if: >
github.event_name == 'workflow_dispatch' ||
(github.event.pull_request.merged == true &&
startsWith(github.event.pull_request.head.ref, 'release/v'))
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}

steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0

- name: Extract version from pyproject.toml
id: version
run: |
VERSION=$(grep -m1 -oP '^version = "\K[^"]+' pyproject.toml)
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "Version: $VERSION"

- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.10'

- name: Install uv
run: |
curl -LsSf https://astral.sh/uv/install.sh | sh
echo "$HOME/.local/bin" >> $GITHUB_PATH

- name: Build and check package
run: |
uv venv
source .venv/bin/activate
uv pip install build twine
uv build
twine check dist/*

- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: dist
path: dist/

release-approval:
name: Release Approval
needs: build
runs-on: ubuntu-latest
environment:
name: pypi-approval

steps:
- name: Approval checkpoint
env:
VERSION: ${{ needs.build.outputs.version }}
run: |
echo "✅ Build successful for v$VERSION"
echo "📦 Package ready for PyPI publication"
echo ""
echo "⚠️ MANUAL APPROVAL REQUIRED"
echo "Verify version and changelog before approving."

publish-pypi:
name: Publish to PyPI
needs: [build, release-approval]
runs-on: ubuntu-latest
environment:
name: pypi
url: https://pypi.org/project/bedrock-agentcore/

steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0

- name: Download artifacts
uses: actions/download-artifact@v5
with:
name: dist
path: dist/

- name: Verify PyPI token exists
if: github.event.inputs.dry_run != 'true'
env:
PYPI_TOKEN_SET: ${{ secrets.PYPI_API_TOKEN != '' }}
run: |
if [ "$PYPI_TOKEN_SET" != "true" ]; then
echo "❌ ERROR: PYPI_API_TOKEN not configured!"
exit 1
fi
echo "✓ PyPI token is configured"

- name: Check if version exists on PyPI
if: github.event.inputs.dry_run != 'true'
env:
VERSION: ${{ needs.build.outputs.version }}
run: |
if pip index versions bedrock-agentcore | grep -q "^Available versions.*$VERSION"; then
echo "❌ ERROR: Version $VERSION already exists on PyPI!"
exit 1
fi
echo "✓ Version $VERSION is not on PyPI, safe to publish"

- name: Publish to PyPI
if: github.event.inputs.dry_run != 'true'
uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.PYPI_API_TOKEN }}
skip-existing: false
verbose: true

- name: Wait for PyPI availability
if: github.event.inputs.dry_run != 'true'
env:
VERSION: ${{ needs.build.outputs.version }}
run: |
echo "Waiting for package to be available on PyPI..."
for i in {1..10}; do
if pip index versions bedrock-agentcore | grep -q "$VERSION"; then
echo "✓ Package version $VERSION is now available on PyPI"
break
fi
echo "Attempt $i/10: Package not yet available, waiting 30s..."
sleep 30
done

- name: Create and push tag
env:
VERSION: ${{ needs.build.outputs.version }}
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
git tag -a "v$VERSION" -m "Release v$VERSION"
git push origin "v$VERSION"

- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: v${{ needs.build.outputs.version }}
name: Bedrock AgentCore SDK v${{ needs.build.outputs.version }}
files: dist/*
generate_release_notes: true
body: |
## Installation
```bash
pip install bedrock-agentcore==${{ needs.build.outputs.version }}
```

## What's Changed
See [CHANGELOG.md](https://github.com/${{ github.repository }}/blob/v${{ needs.build.outputs.version }}/CHANGELOG.md) for details.
Loading