Skip to content

Python Release

Python Release #2

# PR titled "Release vX.Y.Z" → on merge, validate version.py matches, tag vX.Y.Z,
# create a GitHub release with install instructions.
name: Python Release
on:
pull_request:
types: [closed]
branches: [master]
workflow_dispatch:
inputs:
version:
description: "Version X.Y.Z (no leading v)"
required: true
type: string
permissions:
contents: write
jobs:
tag-and-release:
if: |
(github.event_name == 'pull_request' && github.event.pull_request.merged == true && startsWith(github.event.pull_request.title, 'Release ')) ||
github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.merge_commit_sha || github.sha }}
fetch-depth: 0
fetch-tags: true
- name: Resolve version
id: v
env:
EVENT: ${{ github.event_name }}
PR_TITLE: ${{ github.event.pull_request.title }}
IN_VERSION: ${{ github.event.inputs.version }}
run: |
set -euo pipefail
if [ "$EVENT" = "workflow_dispatch" ]; then
VERSION="$IN_VERSION"
else
# "Release vX.Y.Z"
VERSION="$(printf '%s' "$PR_TITLE" | sed -n 's/^Release v\(.*\)$/\1/p')"
fi
[ -n "$VERSION" ] || { echo "::error::could not parse version"; exit 1; }
echo "$VERSION" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$' || { echo "::error::invalid semver: $VERSION"; exit 1; }
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "tag=v${VERSION}" >> "$GITHUB_OUTPUT"
echo "Releasing v$VERSION"
- name: Validate version file
run: |
VERSION="${{ steps.v.outputs.version }}"
FILE_VERSION=$(grep -E "__version__\s*=\s*['\"]" src/pulse_otel/version.py | sed -E "s/.*__version__\s*=\s*['\"]([^'\"]+)['\"].*/\1/")
if [ -z "$FILE_VERSION" ]; then
echo "::error::could not find __version__ in src/pulse_otel/version.py"; exit 1
fi
if [ "$FILE_VERSION" != "$VERSION" ]; then
echo "::error::version file ($FILE_VERSION) != release version ($VERSION)"; exit 1
fi
echo "✅ Version file matches: $FILE_VERSION"
- name: Ensure tag is new
run: |
TAG="${{ steps.v.outputs.tag }}"
if git rev-parse -q --verify "refs/tags/$TAG" >/dev/null; then
echo "::error::tag $TAG already exists"; exit 1
fi
- name: Tag + push
env:
TAG: ${{ steps.v.outputs.tag }}
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git tag -a "$TAG" -m "Release $TAG"
git push origin "$TAG"
- uses: softprops/action-gh-release@v2
with:
tag_name: ${{ steps.v.outputs.tag }}
name: "v${{ steps.v.outputs.version }}"
body: |
${{ github.event.pull_request.body || format('Release v{0}', steps.v.outputs.version) }}
### Installation
```bash
pip install git+https://github.com/${{ github.repository }}.git@${{ steps.v.outputs.tag }}
```
make_latest: true