Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .github/chainguard/spec-sync.sts.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# spec-sync opens the weekly OpenAPI-regeneration PR and merges it into this repo only,
# holding no key. Pattern: self-modify in ionq-actions/octo-sts/docs/patterns/release-please.md.
issuer: https://token.actions.githubusercontent.com
# Name and immutable-ID subject forms; ionq=25356822, ionq-core-python=1204464907.
subject_pattern: "^repo:(ionq/ionq-core-python|[^/@]+@25356822/[^/@:]+@1204464907):ref:refs/heads/main$"
claim_pattern:
enterprise: "^ionq$"
permissions:
contents: write
pull_requests: write
issues: write # PR labels ride the issues API
52 changes: 0 additions & 52 deletions .github/workflows/spec-drift.yml

This file was deleted.

88 changes: 88 additions & 0 deletions .github/workflows/spec-sync.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
name: Spec sync

on:
schedule:
- cron: "0 9 * * 1"
workflow_dispatch:

concurrency:
group: spec-sync
cancel-in-progress: false

permissions:
contents: read
id-token: write

jobs:
sync:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Check for drift
id: drift
run: |
BASE_URL=$(jq -r '.servers[0].url' openapi.json)
curl -sf "${BASE_URL}/api-docs" -o /tmp/latest-spec.json
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
echo "drifted=true" >> "$GITHUB_OUTPUT"
{
echo "Weekly sync of \`openapi.json\` with ${BASE_URL}/api-docs and client regeneration. Merges automatically once all required checks pass."
printf '\n<details><summary>Diff (sorted, pretty-printed JSON)</summary>\n\n```diff\n'
head -c 60000 /tmp/spec.diff
[[ $(wc -c < /tmp/spec.diff) -gt 60000 ]] && printf '\n... (truncated)\n'
printf '```\n</details>\n'
} > /tmp/pr-body.md
fi
- if: steps.drift.outputs.drifted == 'true'
uses: ./.github/actions/setup-uv
- name: Regenerate client
if: steps.drift.outputs.drifted == 'true'
run: |
cp /tmp/latest-spec.json openapi.json
uv sync --group regen
uv run oas-patch overlay openapi.json openapi-overlay.yaml -o /tmp/patched-spec.json
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: Mint token
if: steps.drift.outputs.drifted == 'true'
id: sts
uses: octo-sts/action@f603d3be9d8dd9871a265776e625a27b00effe05 # v1.1.1
with:
domain: octo-sts.gh.ionq.co
scope: ${{ github.repository }}
identity: spec-sync
- name: Create or update PR
if: steps.drift.outputs.drifted == 'true'
id: pr
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1
with:
token: ${{ steps.sts.outputs.token }}
add-paths: |
openapi.json
ionq_core
Comment thread
splch marked this conversation as resolved.
branch: spec-sync
commit-message: Sync OpenAPI spec with upstream
title: Sync OpenAPI spec with upstream
body-path: /tmp/pr-body.md
labels: spec-drift
sign-commits: true
delete-branch: true
- name: Merge once checks pass
if: steps.pr.outputs.pull-request-number
env:
GH_TOKEN: ${{ steps.sts.outputs.token }}
PR: ${{ steps.pr.outputs.pull-request-number }}
run: |
# Poll until required check runs attach; gh errors instead of waiting when none are reported yet.
for _ in $(seq 30); do gh pr checks "$PR" --required --json name >/dev/null 2>&1 && break; sleep 10; done
gh pr checks "$PR" --required --watch --fail-fast
gh pr merge "$PR" --squash --admin
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ Workflows live in [`.github/workflows/`](.github/workflows/) — `ls` it for the

- **`generated.yml`** runs the regenerator on every PR and fails if `git diff ionq_core/` is non-empty. This is what catches hand-edits to generated files.
- **`integration.yml`** is on a weekly cron and `workflow_dispatch` only — it does not run per PR, so don't rely on it for fast feedback.
- **`spec-drift.yml`** opens or updates a `spec-drift`-labeled issue when upstream `openapi.json` diverges from the vendored copy.
- **`spec-sync.yml`** opens a `spec-drift`-labeled PR re-vendoring `openapi.json` and regenerating the client when upstream drifts, then squash-merges it once all required checks pass (auth: [octo-sts trust policy](.github/chainguard/spec-sync.sts.yaml); merge: the App's PR-only `main`-ruleset bypass).
- **`release.yml`** triggers on `v*` tags only and refuses mismatched tag/version pairs or republishing existing PyPI versions.

When authoring a new workflow, use the local [`.github/actions/setup-uv`](.github/actions/setup-uv) composite action rather than `astral-sh/setup-uv` directly, for consistency with the existing matrix.
Expand All @@ -121,7 +121,7 @@ When authoring a new workflow, use the local [`.github/actions/setup-uv`](.githu

- Branch off `main`. CODEOWNERS is `@ionq/developer-tools`.
- PR titles become release-notes lines (`gh release create --generate-notes`). Imperative mood, user-facing, no leading ticket number.
- User-visible changes go under `## [Unreleased]` in `CHANGELOG.md`, in [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) format.
- User-visible changes go under `## [Unreleased]` in `CHANGELOG.md`, in [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) format. Automated `spec-sync` PRs skip this; write their entries at release time from the merged `spec-drift`-labeled PRs.
- Release: bump `pyproject.toml` `[project] version`, promote `[Unreleased]` → `[X.Y.Z]` in `CHANGELOG.md`, tag `vX.Y.Z`. `release.yml` rejects mismatched tag/version pairs and refuses to republish an existing PyPI version.

## Things to avoid (and what to do instead)
Expand Down
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ uv run openapi-python-client generate \

Keep this command in sync with the [`generated`](.github/workflows/generated.yml) workflow, which runs the same invocation on every PR. Post-generation hooks (in `openapi-python-client-config.yaml`) inject SPDX/`@generated` headers, hide `AuthenticatedClient.token` from `repr`, and run `ruff` fix-and-format.

Commit the regenerated files alongside the spec or template change that caused them. Spec drift is checked weekly by [`spec-drift.yml`](.github/workflows/spec-drift.yml), which opens an issue if `openapi.json` falls behind upstream.
Commit the regenerated files alongside the spec or template change that caused them. Spec drift is handled weekly by [`spec-sync.yml`](.github/workflows/spec-sync.yml), which opens a regeneration PR carrying the spec diff and merges it once all required checks pass.

## Pull request workflow

Expand All @@ -94,7 +94,7 @@ Commit the regenerated files alongside the spec or template change that caused t

There is no enforced commit-message format, but PR titles become release notes via `gh release create --generate-notes`. Write each title as the line you would want to see in a changelog: imperative mood, user-facing, no leading ticket number.

User-visible changes should also be reflected in [CHANGELOG.md](CHANGELOG.md) under the next release section, in [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) format.
User-visible changes should also be reflected in [CHANGELOG.md](CHANGELOG.md) under the next release section, in [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) format. Automated `spec-sync` PRs are the exception: they merge without an entry, and the release author writes entries for them from the merged `spec-drift`-labeled PRs, whose bodies carry each spec diff.

## Contributor License Agreement

Expand Down
6 changes: 6 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}