From 64a74488d8e7cf9762dd2003ff2edb85c04dc8e7 Mon Sep 17 00:00:00 2001 From: FBumann <117816358+FBumann@users.noreply.github.com> Date: Mon, 23 Mar 2026 14:03:42 +0100 Subject: [PATCH 1/7] ci: adopt blueprint release pipeline - release.yaml: release-please on push to main, calls publish on release - publish.yaml: tag push + workflow_call, creates GitHub Release for manual tags Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/publish.yaml | 72 ++++++++++++++++++++++++++++++++++ .github/workflows/release.yaml | 53 +++---------------------- 2 files changed, 78 insertions(+), 47 deletions(-) create mode 100644 .github/workflows/publish.yaml diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml new file mode 100644 index 0000000..0f4b86a --- /dev/null +++ b/.github/workflows/publish.yaml @@ -0,0 +1,72 @@ +name: Publish + +on: + push: + tags: ["v*"] + workflow_call: + inputs: + tag: + required: true + type: string + +permissions: + contents: write + id-token: write + attestations: write + +jobs: + publish: + name: Build & publish to PyPI + runs-on: ubuntu-24.04 + timeout-minutes: 10 + environment: + name: pypi + url: https://pypi.org/project/fluxopt_plot + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ inputs.tag || github.ref_name }} + fetch-depth: 0 + + - uses: astral-sh/setup-uv@v7 + with: + enable-cache: true + + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Build + run: uv build + + - uses: pypa/gh-action-pypi-publish@release/v1 + + github-release: + name: Create GitHub Release + if: github.event_name == 'push' + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.ref_name }} + + - name: Create GitHub Release + run: | + if [[ "$TAG" == *-* ]]; then + gh release create "$TAG" --generate-notes --prerelease + else + gh release create "$TAG" --generate-notes + fi + env: + GH_TOKEN: ${{ github.token }} + TAG: ${{ github.ref_name }} + + deploy-docs: + name: Deploy docs + needs: [publish] + permissions: + contents: write + uses: ./.github/workflows/docs.yaml + with: + deploy: true + version: ${{ inputs.tag || github.ref_name }} diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 09038bc..14a1f18 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -3,16 +3,6 @@ name: Release on: push: branches: [main] - workflow_dispatch: - inputs: - branch: - description: Branch to create the release from - required: true - default: main - prerelease: - description: Create a pre-release - type: boolean - default: true permissions: contents: write @@ -26,7 +16,7 @@ jobs: release_created: ${{ steps.release.outputs.release_created }} tag_name: ${{ steps.release.outputs.tag_name }} steps: - - uses: actions/create-github-app-token@v3 + - uses: actions/create-github-app-token@v2 id: app-token with: app-id: ${{ secrets.APP_ID }} @@ -35,48 +25,17 @@ jobs: - uses: googleapis/release-please-action@v4 id: release with: + token: ${{ steps.app-token.outputs.token }} config-file: .release-please-config.json manifest-file: .release-please-manifest.json - token: ${{ steps.app-token.outputs.token }} - target-branch: ${{ inputs.branch || github.ref_name }} - prerelease: ${{ inputs.prerelease }} publish: - name: Build & publish to PyPI - needs: [release-please] + needs: release-please if: needs.release-please.outputs.release_created - runs-on: ubuntu-24.04 - timeout-minutes: 10 - environment: - name: pypi - url: https://pypi.org/project/fluxopt_plot permissions: id-token: write - steps: - - uses: actions/checkout@v6 - with: - fetch-depth: 0 - - - uses: astral-sh/setup-uv@v7 - with: - enable-cache: true - - - uses: actions/setup-python@v6 - with: - python-version: "3.12" - - - name: Build - run: uv build - - - uses: pypa/gh-action-pypi-publish@release/v1 - - deploy-docs: - name: Deploy docs - needs: [release-please, publish] - if: needs.release-please.outputs.release_created - permissions: contents: write - uses: ./.github/workflows/docs.yaml + attestations: write + uses: ./.github/workflows/publish.yaml with: - deploy: true - version: ${{ needs.release-please.outputs.tag_name }} + tag: ${{ needs.release-please.outputs.tag_name }} From 11b04b5ca3d2e02b5a3b04b8e62503a6d141181d Mon Sep 17 00:00:00 2001 From: FBumann <117816358+FBumann@users.noreply.github.com> Date: Mon, 23 Mar 2026 14:11:13 +0100 Subject: [PATCH 2/7] fix(ci): gate github-release on publish and add idempotency check Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/publish.yaml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 0f4b86a..4f4424d 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -43,7 +43,8 @@ jobs: github-release: name: Create GitHub Release - if: github.event_name == 'push' + needs: [publish] + if: github.event_name == 'push' && needs.publish.result == 'success' runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 @@ -52,6 +53,10 @@ jobs: - name: Create GitHub Release run: | + if gh release view "$TAG" &>/dev/null; then + echo "Release $TAG already exists, skipping." + exit 0 + fi if [[ "$TAG" == *-* ]]; then gh release create "$TAG" --generate-notes --prerelease else From 820bd8c35ad4ee72f1aeb98ffbee4a19c3ee431c Mon Sep 17 00:00:00 2001 From: FBumann <117816358+FBumann@users.noreply.github.com> Date: Mon, 23 Mar 2026 14:15:33 +0100 Subject: [PATCH 3/7] ci: remove deploy-docs from publish, keep docs build in CI Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/ci.yaml | 26 ++++++++++++++++++++++++-- .github/workflows/publish.yaml | 10 ---------- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index dddfe6d..5fddd08 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -82,9 +82,30 @@ jobs: files: coverage.xml fail_ci_if_error: false + docs: + name: Docs build + runs-on: ubuntu-24.04 + timeout-minutes: 5 + steps: + - uses: actions/checkout@v6 + + - uses: astral-sh/setup-uv@v7 + with: + enable-cache: true + + - uses: actions/setup-python@v6 + with: + python-version: "3.12" + + - name: Install dependencies + run: uv sync --extra docs + + - name: Build docs + run: uv run mkdocs build --strict + ci-success: name: CI Success - needs: [lint, typecheck, test] + needs: [lint, typecheck, test, docs] if: always() runs-on: ubuntu-24.04 steps: @@ -92,7 +113,8 @@ jobs: run: | if [[ "${{ needs.lint.result }}" != "success" || \ "${{ needs.typecheck.result }}" != "success" || \ - "${{ needs.test.result }}" != "success" ]]; then + "${{ needs.test.result }}" != "success" || \ + "${{ needs.docs.result }}" != "success" ]]; then echo "::error::One or more CI jobs failed" exit 1 fi diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 4f4424d..25259f5 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -65,13 +65,3 @@ jobs: env: GH_TOKEN: ${{ github.token }} TAG: ${{ github.ref_name }} - - deploy-docs: - name: Deploy docs - needs: [publish] - permissions: - contents: write - uses: ./.github/workflows/docs.yaml - with: - deploy: true - version: ${{ inputs.tag || github.ref_name }} From 7dda08d91a3f3569a5931b13a60895ace0253779 Mon Sep 17 00:00:00 2001 From: FBumann <117816358+FBumann@users.noreply.github.com> Date: Mon, 23 Mar 2026 14:24:49 +0100 Subject: [PATCH 4/7] ci: add Read the Docs config with uv Co-Authored-By: Claude Opus 4.6 (1M context) --- .readthedocs.yaml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 .readthedocs.yaml diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 0000000..a287eb6 --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,18 @@ +version: 2 + +mkdocs: + configuration: mkdocs.yml + +build: + os: ubuntu-24.04 + tools: + python: "3.13" + jobs: + pre_create_environment: + - asdf plugin add uv + - asdf install uv latest + - asdf global uv latest + create_environment: + - uv venv "${READTHEDOCS_VIRTUALENV_PATH}" + install: + - UV_PROJECT_ENVIRONMENT="${READTHEDOCS_VIRTUALENV_PATH}" uv sync --frozen --group docs From 95078dc0ea7106614264de8cc955462238ae9a47 Mon Sep 17 00:00:00 2001 From: FBumann <117816358+FBumann@users.noreply.github.com> Date: Mon, 23 Mar 2026 16:17:23 +0100 Subject: [PATCH 5/7] ci: add publish concurrency group, clean up pr-title trigger Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/pr-title.yaml | 2 +- .github/workflows/publish.yaml | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pr-title.yaml b/.github/workflows/pr-title.yaml index 8537600..0ede70d 100644 --- a/.github/workflows/pr-title.yaml +++ b/.github/workflows/pr-title.yaml @@ -4,7 +4,7 @@ on: push: branches: ['release-please--**'] pull_request: - types: [opened, edited, synchronize, reopened] + types: [opened, edited, reopened] jobs: validate: diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 25259f5..5582c3e 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -9,6 +9,10 @@ on: required: true type: string +concurrency: + group: publish-${{ inputs.tag || github.ref_name }} + cancel-in-progress: false + permissions: contents: write id-token: write From 59c0f326b93e1b16c2f0f08fcfe651d11085b7f3 Mon Sep 17 00:00:00 2001 From: FBumann <117816358+FBumann@users.noreply.github.com> Date: Mon, 23 Mar 2026 16:54:35 +0100 Subject: [PATCH 6/7] fix: remove --frozen from RTD uv sync (no lockfile) Co-Authored-By: Claude Opus 4.6 (1M context) --- .readthedocs.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index a287eb6..c8730e8 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -15,4 +15,4 @@ build: create_environment: - uv venv "${READTHEDOCS_VIRTUALENV_PATH}" install: - - UV_PROJECT_ENVIRONMENT="${READTHEDOCS_VIRTUALENV_PATH}" uv sync --frozen --group docs + - UV_PROJECT_ENVIRONMENT="${READTHEDOCS_VIRTUALENV_PATH}" uv sync --group docs From db60b83af8482ab465b74f03f13325ef758a862d Mon Sep 17 00:00:00 2001 From: FBumann <117816358+FBumann@users.noreply.github.com> Date: Tue, 24 Mar 2026 12:23:45 +0100 Subject: [PATCH 7/7] fix(ci): restore synchronize trigger in pr-title Without synchronize, the check doesn't re-trigger on new commits. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/pr-title.yaml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/.github/workflows/pr-title.yaml b/.github/workflows/pr-title.yaml index 0ede70d..82f0046 100644 --- a/.github/workflows/pr-title.yaml +++ b/.github/workflows/pr-title.yaml @@ -4,17 +4,17 @@ on: push: branches: ['release-please--**'] pull_request: - types: [opened, edited, reopened] + types: [opened, edited, synchronize, reopened] jobs: validate: name: Validate conventional commit format + if: github.event_name == 'pull_request' runs-on: ubuntu-24.04 + permissions: + pull-requests: read steps: - - if: ${{ github.event_name != 'push' }} - uses: amannn/action-semantic-pull-request@v6 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - uses: amannn/action-semantic-pull-request@v6 with: types: | feat @@ -28,6 +28,5 @@ jobs: requireScope: false subjectPattern: ^.+$ subjectPatternError: "PR title must have a description after the type" - - - if: ${{ github.event_name == 'push' }} - run: echo "Release Please PRs always use valid conventional commit format" + env: + GITHUB_TOKEN: ${{ github.token }}