name: Publish to PyPI
on:
release:
types: [published]
jobs:
build:
name: Build distribution
runs-on: ubuntu-latest
steps:
- name: Validate release tag format
run: |
TAG="${{ github.ref_name }}"
if [[ ! "$TAG" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$ ]]; then
echo "Error: Release tag '$TAG' does not follow semantic versioning (e.g., 0.1.0, 1.0.0-beta.1)"
exit 1
fi
echo "Valid semantic version: $TAG"
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Validate version consistency
run: |
TAG="${{ github.ref_name }}"
PKG_VERSION=$(grep -oP '__version__\s*=\s*"\K[^"]+' src/mirdan/__init__.py)
if [ "$TAG" != "$PKG_VERSION" ]; then
echo "Error: Git tag '$TAG' does not match package version '$PKG_VERSION' in src/mirdan/__init__.py"
exit 1
fi
echo "Version consistency verified: tag=$TAG, package=$PKG_VERSION"
- name: Install uv
uses: astral-sh/setup-uv@6b9c6063abd6010835644d4c2e1bef4cf5cd0fca # v4.2.0
with:
enable-cache: true
cache-dependency-glob: "uv.lock"
- name: Set up Python
run: uv python install 3.13
- name: Create virtual environment and install dependencies
run: |
uv venv
uv pip install build twine
- name: Build sdist and wheel
run: uv run python -m build
- name: Check distribution with twine
run: uv run twine check dist/*
- name: Upload distribution artifacts
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: dist
path: dist/
if-no-files-found: error
test-publish:
name: Publish to TestPyPI
needs: build
runs-on: ubuntu-latest
environment:
name: testpypi
url: https://test.pypi.org/p/mirdan
permissions:
id-token: write
steps:
- name: Download distribution artifacts
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: dist
path: dist/
- name: Publish to TestPyPI
uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # v1.12.4
with:
repository-url: https://test.pypi.org/legacy/
attestations: true
verify-testpypi:
name: Verify TestPyPI installation
needs: test-publish
runs-on: ubuntu-latest
steps:
- name: Set up Python
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
with:
python-version: "3.13"
- name: Wait for TestPyPI to update
run: sleep 30
- name: Install from TestPyPI
run: |
pip install --index-url https://test.pypi.org/simple/ \
--extra-index-url https://pypi.org/simple/ \
mirdan
- name: Verify installation
run: |
python -c "import mirdan; print(f'Successfully imported mirdan version: {mirdan.__version__}')"
publish:
name: Publish to PyPI
needs: verify-testpypi
runs-on: ubuntu-latest
environment:
name: pypi
url: https://pypi.org/p/mirdan
permissions:
id-token: write
steps:
- name: Download distribution artifacts
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: dist
path: dist/
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # v1.12.4
with:
attestations: true