Skip to content

Merge pull request #160 from DecaturMakers/automate-release-on-versio… #15

Merge pull request #160 from DecaturMakers/automate-release-on-versio…

Merge pull request #160 from DecaturMakers/automate-release-on-versio… #15

Workflow file for this run

# Workflow Requirements:
#
# 1. In repository Settings -> Actions -> General, ensure "Allow all actions and reusable workflows" is selected, and that under "Workflow permissions", "Read repository contents and packages permissions" is checked.
#
# Releases are driven by the version in pyproject.toml: when a commit lands on
# main with a version higher than the latest GitHub release, this workflow
# tags it, builds and pushes the Docker image to GHCR, publishes to PyPI, and
# creates a GitHub release. No manual tagging required.
name: Release
on:
push:
branches:
- main
permissions:
contents: write
packages: write
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Check version vs. latest release
id: version_check
env:
GH_TOKEN: ${{ github.token }}
run: |
CURRENT_VERSION=$(python3 -c "
import re, pathlib
text = pathlib.Path('pyproject.toml').read_text()
m = re.search(r'^version\s*=\s*\"([^\"]+)\"', text, re.MULTILINE)
print(m.group(1))
")
echo "current_version=$CURRENT_VERSION" >> "$GITHUB_OUTPUT"
LATEST_TAG=$(gh release list --limit 1 --json tagName --jq '.[0].tagName // empty' 2>/dev/null || true)
if [ -z "$LATEST_TAG" ]; then
echo "No existing releases found — first release"
echo "should_release=true" >> "$GITHUB_OUTPUT"
else
LATEST_VERSION="${LATEST_TAG#v}"
SHOULD=$(python3 -c "
current = tuple(int(x) for x in '$CURRENT_VERSION'.split('.'))
latest = tuple(int(x) for x in '$LATEST_VERSION'.split('.'))
print('true' if current > latest else 'false')
")
echo "Latest release: $LATEST_TAG, current version: $CURRENT_VERSION, should_release: $SHOULD"
echo "should_release=$SHOULD" >> "$GITHUB_OUTPUT"
fi
- name: Set up Docker Buildx
if: steps.version_check.outputs.should_release == 'true'
uses: docker/setup-buildx-action@v4
- name: Login to GHCR
if: steps.version_check.outputs.should_release == 'true'
run: echo "${{secrets.GITHUB_TOKEN}}" | docker login ghcr.io -u "${{ github.actor }}" --password-stdin
- name: Lowercase image repository name
if: steps.version_check.outputs.should_release == 'true'
id: image
run: echo "repo=${GITHUB_REPOSITORY,,}" >> "$GITHUB_OUTPUT"
- name: Docker Build and Push
if: steps.version_check.outputs.should_release == 'true'
uses: docker/build-push-action@v7
with:
push: true
sbom: true
labels: |
org.opencontainers.image.url=https://github.com/${{ github.repository }}
org.opencontainers.image.source=https://github.com/${{ github.repository }}
org.opencontainers.image.version=${{ steps.version_check.outputs.current_version }}
org.opencontainers.image.revision=${{ github.sha }}
tags: |
ghcr.io/${{ steps.image.outputs.repo }}:${{ steps.version_check.outputs.current_version }}
ghcr.io/${{ steps.image.outputs.repo }}:latest
- name: Build and publish to pypi
if: steps.version_check.outputs.should_release == 'true'
uses: JRubics/poetry-publish@v2.1
with:
pypi_token: ${{ secrets.PYPI_TOKEN }}
- name: Create git tag
if: steps.version_check.outputs.should_release == 'true'
run: |
VERSION="${{ steps.version_check.outputs.current_version }}"
git tag "$VERSION"
git push origin "$VERSION"
- name: Create GitHub Release
if: steps.version_check.outputs.should_release == 'true'
env:
GH_TOKEN: ${{ github.token }}
run: |
VERSION="${{ steps.version_check.outputs.current_version }}"
REPO="${{ github.repository }}"
IMAGE="ghcr.io/${{ steps.image.outputs.repo }}"
# Generate changelog via GitHub API
CHANGELOG=$(gh api \
"repos/$REPO/releases/generate-notes" \
-f tag_name="$VERSION" \
-f target_commitish="main" \
--jq '.body')
# Build release body in a file to avoid shell escaping issues
{
printf '%s\n' "$CHANGELOG"
printf '\n---\n\n## Docker Image\n\n```bash\n'
printf 'docker pull %s:%s\n' "$IMAGE" "$VERSION"
printf 'docker pull %s:latest\n' "$IMAGE"
printf '```\n'
printf '\n## Python Package\n\nhttps://pypi.org/project/machine_access_control/%s/\n' "$VERSION"
} > /tmp/release_body.md
gh release create "$VERSION" \
--title "Release $VERSION" \
--notes-file /tmp/release_body.md