From fa0959981a277574bfdc38e5313c0d681dc9e11f Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sat, 6 Jun 2026 14:10:07 +0100 Subject: [PATCH] refac --- .github/workflows/docker.yml | 54 ++++++--------------- .github/workflows/pypi.yml | 76 ++++++++++++------------------ .github/workflows/release.yml | 89 ++++++++--------------------------- 3 files changed, 63 insertions(+), 156 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 35e170c0..2ad3a953 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -17,52 +17,27 @@ permissions: packages: write jobs: - detect-version-change: + # ── Read version from pyproject.toml (release builds only) ───────────────── + read-version: if: github.ref == 'refs/heads/release' runs-on: ubuntu-latest outputs: - version_changed: ${{ steps.check.outputs.changed }} - version: ${{ steps.check.outputs.version }} + version: ${{ steps.pkg.outputs.version }} steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 2 + - uses: actions/checkout@v4 - - name: Check for version bump - id: check + - name: Read version + id: pkg run: | - CURRENT=$(python3 -c " + VERSION=$(python3 -c " import re, pathlib text = pathlib.Path('pyproject.toml').read_text() m = re.search(r'^version\s*=\s*\"([^\"]+)\"', text, re.M) print(m.group(1)) ") + echo "version=$VERSION" >> $GITHUB_OUTPUT - git show HEAD~1:pyproject.toml > /tmp/prev_pyproject.toml 2>/dev/null || true - if [ -f /tmp/prev_pyproject.toml ]; then - PREVIOUS=$(python3 -c " - import re, pathlib - text = pathlib.Path('/tmp/prev_pyproject.toml').read_text() - m = re.search(r'^version\s*=\s*\"([^\"]+)\"', text, re.M) - print(m.group(1) if m else '') - ") - else - PREVIOUS="" - fi - - echo "current=$CURRENT" - echo "previous=$PREVIOUS" - - if [ "$CURRENT" != "$PREVIOUS" ] && [ -n "$CURRENT" ]; then - echo "changed=true" >> "$GITHUB_OUTPUT" - echo "version=$CURRENT" >> "$GITHUB_OUTPUT" - echo "Version changed: $PREVIOUS -> $CURRENT" - else - echo "changed=false" >> "$GITHUB_OUTPUT" - echo "No version change detected" - fi - + # ── Dev builds (main branch) ────────────────────────────────────────────── build-dev: if: github.ref == 'refs/heads/main' strategy: @@ -145,9 +120,10 @@ jobs: -t "${{ env.IMAGE }}:dev-${SHORT_SHA}" \ $(printf '${{ env.IMAGE }}@sha256:%s ' *) + # ── Release builds (release branch) ─────────────────────────────────────── build-release: - needs: detect-version-change - if: github.ref == 'refs/heads/release' && needs.detect-version-change.outputs.version_changed == 'true' + needs: read-version + if: github.ref == 'refs/heads/release' strategy: fail-fast: false matrix: @@ -198,8 +174,8 @@ jobs: retention-days: 1 merge-release: - needs: [detect-version-change, build-release] - if: github.ref == 'refs/heads/release' && needs.detect-version-change.outputs.version_changed == 'true' + needs: [read-version, build-release] + if: github.ref == 'refs/heads/release' runs-on: ubuntu-latest steps: - name: Download digests @@ -222,7 +198,7 @@ jobs: - name: Create release multi-arch manifest working-directory: /tmp/digests run: | - VERSION="${{ needs.detect-version-change.outputs.version }}" + VERSION="${{ needs.read-version.outputs.version }}" MAJOR_MINOR="${VERSION%.*}" docker buildx imagetools create \ -t "${{ env.IMAGE }}:latest" \ diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml index f9db2537..33585951 100644 --- a/.github/workflows/pypi.yml +++ b/.github/workflows/pypi.yml @@ -1,71 +1,47 @@ name: Publish to PyPI on: - pull_request: - types: [closed] + push: branches: [release] +concurrency: + group: pypi-${{ github.ref }} + cancel-in-progress: false + permissions: contents: read jobs: - detect-version-change: - if: github.event.pull_request.merged == true && github.event.pull_request.head.ref == 'main' + build: runs-on: ubuntu-latest - outputs: - version_changed: ${{ steps.check.outputs.changed }} - version: ${{ steps.check.outputs.version }} steps: - - name: Checkout current commit + - name: Checkout uses: actions/checkout@v4 - with: - fetch-depth: 2 # need parent to diff against - - name: Check for version bump - id: check + - name: Read version + id: pkg run: | - # Extract version from current commit - CURRENT=$(python3 -c " + VERSION=$(python3 -c " import re, pathlib text = pathlib.Path('pyproject.toml').read_text() m = re.search(r'^version\s*=\s*\"([^\"]+)\"', text, re.M) print(m.group(1)) ") + echo "version=$VERSION" >> $GITHUB_OUTPUT - # Extract version from previous commit - git show HEAD~1:pyproject.toml > /tmp/prev_pyproject.toml 2>/dev/null || true - if [ -f /tmp/prev_pyproject.toml ]; then - PREVIOUS=$(python3 -c " - import re, pathlib - text = pathlib.Path('/tmp/prev_pyproject.toml').read_text() - m = re.search(r'^version\s*=\s*\"([^\"]+)\"', text, re.M) - print(m.group(1) if m else '') - ") - else - PREVIOUS="" - fi - - echo "current=$CURRENT" - echo "previous=$PREVIOUS" - - if [ "$CURRENT" != "$PREVIOUS" ] && [ -n "$CURRENT" ]; then - echo "changed=true" >> "$GITHUB_OUTPUT" - echo "version=$CURRENT" >> "$GITHUB_OUTPUT" - echo "Version changed: $PREVIOUS -> $CURRENT" + - name: Check if version already on PyPI + id: check + run: | + VERSION="${{ steps.pkg.outputs.version }}" + if pip index versions cptr 2>/dev/null | grep -q "$VERSION"; then + echo "skip=true" >> $GITHUB_OUTPUT + echo "Version $VERSION already on PyPI — skipping" else - echo "changed=false" >> "$GITHUB_OUTPUT" - echo "No version change detected" + echo "skip=false" >> $GITHUB_OUTPUT fi - build: - needs: detect-version-change - if: needs.detect-version-change.outputs.version_changed == 'true' - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Set up Node.js + if: steps.check.outputs.skip != 'true' uses: actions/setup-node@v4 with: node-version: "22" @@ -73,34 +49,40 @@ jobs: cache-dependency-path: cptr/frontend/package-lock.json - name: Build frontend + if: steps.check.outputs.skip != 'true' working-directory: cptr/frontend run: | npm ci npm run build - name: Set up Python + if: steps.check.outputs.skip != 'true' uses: actions/setup-python@v5 with: python-version: "3.12" - name: Install build tools + if: steps.check.outputs.skip != 'true' run: pip install hatchling build - name: Build package + if: steps.check.outputs.skip != 'true' run: python -m build - name: Upload dist artifacts + if: steps.check.outputs.skip != 'true' uses: actions/upload-artifact@v4 with: name: dist path: dist/ publish: - needs: [detect-version-change, build] + needs: build + if: needs.build.outputs.skip != 'true' runs-on: ubuntu-latest - environment: pypi # GitHub environment for deployment protection + environment: pypi permissions: - id-token: write # required for trusted publishing (OIDC) + id-token: write steps: - name: Download dist artifacts uses: actions/download-artifact@v4 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a9a306bf..6f58f8cb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,71 +1,20 @@ # ───────────────────────────────────────────────────────────────────────────── # Release — Create GitHub release from CHANGELOG, trigger Docker builds -# Runs only when main is merged into the release branch and pyproject.toml -# version changes. +# Runs on pushes to the release branch when version changes. # ───────────────────────────────────────────────────────────────────────────── name: Release on: - pull_request: - types: [closed] + push: branches: [release] concurrency: - group: release-${{ github.event.pull_request.base.ref || github.ref }} + group: release-${{ github.ref }} cancel-in-progress: false jobs: - # ── Detect version bump in pyproject.toml ───────────────────────────────── - detect-version-change: - if: github.event.pull_request.merged == true && github.event.pull_request.head.ref == 'main' - runs-on: ubuntu-latest - outputs: - version_changed: ${{ steps.check.outputs.changed }} - version: ${{ steps.check.outputs.version }} - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 2 - - - name: Check for version bump - id: check - run: | - CURRENT=$(python3 -c " - import re, pathlib - text = pathlib.Path('pyproject.toml').read_text() - m = re.search(r'^version\s*=\s*\"([^\"]+)\"', text, re.M) - print(m.group(1)) - ") - - git show HEAD~1:pyproject.toml > /tmp/prev_pyproject.toml 2>/dev/null || true - if [ -f /tmp/prev_pyproject.toml ]; then - PREVIOUS=$(python3 -c " - import re, pathlib - text = pathlib.Path('/tmp/prev_pyproject.toml').read_text() - m = re.search(r'^version\s*=\s*\"([^\"]+)\"', text, re.M) - print(m.group(1) if m else '') - ") - else - PREVIOUS="" - fi - - echo "current=$CURRENT" - echo "previous=$PREVIOUS" - - if [ "$CURRENT" != "$PREVIOUS" ] && [ -n "$CURRENT" ]; then - echo "changed=true" >> "$GITHUB_OUTPUT" - echo "version=$CURRENT" >> "$GITHUB_OUTPUT" - echo "Version changed: $PREVIOUS -> $CURRENT" - else - echo "changed=false" >> "$GITHUB_OUTPUT" - echo "No version change detected" - fi - # ── Create release and trigger downstream workflows ────────────────────── publish: - needs: detect-version-change - if: needs.detect-version-change.outputs.version_changed == 'true' runs-on: ubuntu-latest timeout-minutes: 10 permissions: @@ -74,9 +23,20 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Read version + id: pkg + run: | + VERSION=$(python3 -c " + import re, pathlib + text = pathlib.Path('pyproject.toml').read_text() + m = re.search(r'^version\s*=\s*\"([^\"]+)\"', text, re.M) + print(m.group(1)) + ") + echo "version=$VERSION" >> $GITHUB_OUTPUT + - name: Extract release notes from CHANGELOG run: | - VER="${{ needs.detect-version-change.outputs.version }}" + VER="${{ steps.pkg.outputs.version }}" awk "/^## \[${VER}\]/{found=1; next} /^## \[/{if(found) exit} found{print}" \ CHANGELOG.md > /tmp/release-notes.md @@ -84,21 +44,10 @@ jobs: env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - if gh release view "v${{ needs.detect-version-change.outputs.version }}" &>/dev/null; then - echo "Release v${{ needs.detect-version-change.outputs.version }} already exists — skipping creation" + if gh release view "v${{ steps.pkg.outputs.version }}" &>/dev/null; then + echo "Release v${{ steps.pkg.outputs.version }} already exists — skipping creation" else - gh release create "v${{ needs.detect-version-change.outputs.version }}" \ - --title "v${{ needs.detect-version-change.outputs.version }}" \ + gh release create "v${{ steps.pkg.outputs.version }}" \ + --title "v${{ steps.pkg.outputs.version }}" \ --notes-file /tmp/release-notes.md fi - - - name: Trigger Docker build - uses: actions/github-script@v7 - with: - script: | - github.rest.actions.createWorkflowDispatch({ - owner: context.repo.owner, - repo: context.repo.repo, - workflow_id: 'docker.yml', - ref: 'release', - })