Skip to content

release

release #2

Workflow file for this run

name: release
on:
workflow_dispatch:
inputs:
version:
description: 'Release version (e.g. 0.3.0)'
required: true
type: string
# Minimal default; individual jobs declare only what they need.
permissions:
contents: read
jobs:
test:
name: Test (Python ${{ matrix.python-version }})
runs-on: ubuntu-latest
strategy:
fail-fast: true
matrix:
python-version: ["3.10", "3.11", "3.12"]
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Install uv
uses: astral-sh/setup-uv@e58605a9b6da7c637471fab8847a5e5a6b8df081 # v5
- name: Set up Python ${{ matrix.python-version }}
run: uv python install ${{ matrix.python-version }}
- name: Install dependencies
run: uv sync --dev --python ${{ matrix.python-version }}
- name: Run tests
run: uv run --python ${{ matrix.python-version }} pytest tests/ -v
build:
name: Build distribution
needs: test
runs-on: ubuntu-latest
permissions:
contents: write # required to push the release tag
outputs:
version: ${{ steps.normalize.outputs.version }}
steps:
# Strip a leading 'v' once here; all downstream steps use the output.
- name: Normalize version
id: normalize
run: |
VERSION="${{ inputs.version }}"
VERSION="${VERSION#v}"
echo "version=${VERSION}" >> "${GITHUB_OUTPUT}"
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
fetch-depth: 0 # required: hatch-vcs derives the package version from git tags
- name: Configure git
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
# Create the tag locally so hatch-vcs can derive the package version during
# `uv build`. The tag is pushed to origin only AFTER a successful build to
# avoid leaving a dangling remote tag if the build fails.
- name: Create local release tag
run: git tag "v${{ steps.normalize.outputs.version }}"
- name: Install uv
uses: astral-sh/setup-uv@e58605a9b6da7c637471fab8847a5e5a6b8df081 # v5
- name: Build wheel and sdist
run: uv build
# Fail fast if the tag already exists on origin (e.g. re-running the workflow
# for the same version) before attempting to push, to surface a clear error
# rather than a confusing "already exists" git message.
- name: Push release tag
run: |
if git ls-remote --exit-code --tags origin \
"refs/tags/v${{ steps.normalize.outputs.version }}" > /dev/null 2>&1; then
echo "ERROR: tag v${{ steps.normalize.outputs.version }} already exists on origin" >&2
exit 1
fi
git push origin "v${{ steps.normalize.outputs.version }}"
- name: Upload dist artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: dist
path: dist/
if-no-files-found: error
# IMPORTANT: The PyPI and TestPyPI Trusted Publisher configurations must reference
# this workflow file (`.github/workflows/release.yml`). If they still point to the
# former `publish.yml`, OIDC token exchange will be rejected by PyPI/TestPyPI.
# Update both configs at https://pypi.org and https://test.pypi.org before running
# this workflow for the first time.
publish-testpypi:
name: Publish → TestPyPI
needs: build
runs-on: ubuntu-latest
environment:
name: testpypi
url: https://test.pypi.org/p/starfix
permissions:
id-token: write # required for OIDC trusted publishing
steps:
- name: Install uv
uses: astral-sh/setup-uv@e58605a9b6da7c637471fab8847a5e5a6b8df081 # v5
- name: Download dist artifact
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: dist
path: dist/
- name: Publish to TestPyPI
run: uv publish --publish-url https://test.pypi.org/legacy/ dist/*
publish-pypi:
name: Publish → PyPI
needs: [build, publish-testpypi]
runs-on: ubuntu-latest
environment:
name: pypi
url: https://pypi.org/p/starfix
permissions:
id-token: write # required for OIDC trusted publishing
contents: write # required for creating the GitHub Release
steps:
- name: Install uv
uses: astral-sh/setup-uv@e58605a9b6da7c637471fab8847a5e5a6b8df081 # v5
- name: Download dist artifact
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: dist
path: dist/
- name: Publish to PyPI
run: uv publish dist/*
- name: Create GitHub Release
uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2.6.2
with:
tag_name: "v${{ needs.build.outputs.version }}"
generate_release_notes: true
files: dist/*