diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6985a4f..060eba8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,6 +4,9 @@ on: push: branches: [main] pull_request: + # Dispatched by spec-drift.yml on auto-regen branches, whose GITHUB_TOKEN + # pushes cannot fire pull_request events. + workflow_dispatch: concurrency: group: ${{ github.workflow }}-${{ github.ref }} diff --git a/.github/workflows/generated.yml b/.github/workflows/generated.yml index ea6db35..74a0836 100644 --- a/.github/workflows/generated.yml +++ b/.github/workflows/generated.yml @@ -2,6 +2,9 @@ name: Generated code check on: pull_request: + # Dispatched by spec-drift.yml on auto-regen branches, whose GITHUB_TOKEN + # pushes cannot fire pull_request events. + workflow_dispatch: concurrency: group: ${{ github.workflow }}-${{ github.ref }} diff --git a/.github/workflows/spec-drift.yml b/.github/workflows/spec-drift.yml index 6552b76..eddfeb8 100644 --- a/.github/workflows/spec-drift.yml +++ b/.github/workflows/spec-drift.yml @@ -1,4 +1,4 @@ -name: Spec drift check +name: Spec drift — auto regen PR on: schedule: @@ -6,17 +6,20 @@ on: workflow_dispatch: permissions: - contents: read - issues: write + contents: write + pull-requests: write + actions: write jobs: - check: + regen: runs-on: ubuntu-latest - timeout-minutes: 5 + timeout-minutes: 15 steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false + - uses: ./.github/actions/setup-uv + - run: uv sync --group regen - name: Fetch latest spec run: | BASE_URL=$(jq -r '.servers[0].url' openapi.json) @@ -26,27 +29,60 @@ jobs: id: drift run: | norm() { jq -S 'del(.info.description)' "$1"; } - if ! diff -u --label vendored --label upstream <(norm openapi.json) <(norm /tmp/latest-spec.json) > /tmp/spec.diff; then + if ! diff -u --label vendored --label upstream \ + <(norm openapi.json) <(norm /tmp/latest-spec.json) > /tmp/spec.diff; then echo "drifted=true" >> "$GITHUB_OUTPUT" fi - - name: Open or update issue + - name: Regenerate client + if: steps.drift.outputs.drifted == 'true' + run: | + cp /tmp/latest-spec.json openapi.json + if [[ -f openapi-overlay.yaml ]]; then + uv run oas-patch overlay openapi.json openapi-overlay.yaml -o /tmp/patched-spec.json + else + cp openapi.json /tmp/patched-spec.json + fi + uv run openapi-python-client generate \ + --path /tmp/patched-spec.json \ + --meta none \ + --config openapi-python-client-config.yaml \ + --custom-template-path custom-templates \ + --output-path ionq_core \ + --overwrite + - name: Compose PR body if: steps.drift.outputs.drifted == 'true' - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | { - echo "The spec at ${BASE_URL}/api-docs has diverged from the vendored openapi.json. Fetch the new spec and regenerate the client." - printf '\n
Diff (sorted, pretty-printed JSON)\n\n```diff\n' + echo "The spec at \`${BASE_URL}/api-docs\` has diverged from the vendored \`openapi.json\`. This PR fetches the new spec and regenerates the client." + printf '\n
Spec diff (sorted, pretty-printed JSON)\n\n```diff\n' head -c 60000 /tmp/spec.diff [[ $(wc -c < /tmp/spec.diff) -gt 60000 ]] && printf '\n... (truncated)\n' printf '```\n
\n' } > /tmp/body.md - existing=$(gh issue list --label spec-drift --state open --json number --jq '.[0].number // empty') - if [[ -z "$existing" ]]; then - gh issue create \ - --title "OpenAPI spec has changed upstream" \ - --body-file /tmp/body.md \ - --label spec-drift - else - gh issue edit "$existing" --body-file /tmp/body.md - fi + # Pushes and PR creation made with GITHUB_TOKEN never fire pull_request + # events, so the required checks are dispatched explicitly below — + # workflow_dispatch is exempt from that suppression. Team review comes + # from CODEOWNERS (GITHUB_TOKEN cannot request team reviewers itself). + - name: Open or update PR + if: steps.drift.outputs.drifted == 'true' + id: pr + uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1 + with: + branch: spec-drift/auto-regen + base: main + add-paths: | + openapi.json + ionq_core/ + commit-message: Regenerate client for updated OpenAPI spec + title: Regenerate client for updated OpenAPI spec + body-path: /tmp/body.md + labels: spec-drift + - name: Trigger required checks + if: steps.pr.outputs.pull-request-operation == 'created' || steps.pr.outputs.pull-request-operation == 'updated' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + # CodeQL runs via GitHub's default setup and has no dispatchable + # workflow file — confirm it reports on regen PRs. + gh workflow run ci.yml --ref spec-drift/auto-regen + gh workflow run generated.yml --ref spec-drift/auto-regen