Skip to content
Merged
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
75 changes: 75 additions & 0 deletions .github/workflows/catalog-drift.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
name: API catalog drift

# Regenerates the embedded API catalog from the upstream gdcorp-platform
# commerce.*-specification repos and fails if the committed catalog has drifted.
# This is the source-drift guard (catches per-operation / per-endpoint changes).
# The always-on structural guard (domains + endpoint counts vs the intentional
# list) lives in `cargo test`
# (committed_catalog_matches_expected_domains_and_manifest) and runs on every PR.
#
# Requires a token with read access to the gdcorp-platform spec repos, provisioned
# as the `CATALOG_SPEC_TOKEN` secret. The default GITHUB_TOKEN only reaches this
# repo. A missing token is a configuration error and fails the job.
#
# Scheduled workflows only run from a repository's default branch. While
# `rust-port` is not the default, run this check on every push to `rust-port`;
# the weekly schedule activates when `rust-port` becomes the default branch.
# `workflow_dispatch` also allows an on-demand check of any branch.

on:
schedule:
- cron: "17 6 * * 1" # Mondays ~06:17 UTC after rust-port becomes default
push:
branches:
- rust-port
workflow_dispatch:

permissions:
contents: read

jobs:
drift:
runs-on: ubuntu-latest
# Guard against a hung network fetch to the spec repos burning runner minutes.
timeout-minutes: 20
defaults:
run:
working-directory: rust
steps:
- name: Checkout code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0

- name: Check for spec token
working-directory: .
env:
CATALOG_SPEC_TOKEN: ${{ secrets.CATALOG_SPEC_TOKEN }}
run: |
if [ -z "$CATALOG_SPEC_TOKEN" ]; then
echo "::error::CATALOG_SPEC_TOKEN must be configured with read access to gdcorp-platform specification repositories."
exit 1
fi

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable

- name: Regenerate catalog from upstream specs
# Runs from the job-default working-directory (rust/) — cargo needs the workspace.
env:
GITHUB_TOKEN: ${{ secrets.CATALOG_SPEC_TOKEN }}
run: cargo run -p generate-api-catalog

- name: Fail on drift
working-directory: .
run: |
# manifest.json carries a generated-at timestamp that changes every run;
# stage the generated directory, then unstage that timestamp-only file.
# The staged diff catches modifications, deletions, and new untracked domains.
git add -A -- rust/schemas/api
git restore --staged -- rust/schemas/api/manifest.json

if ! git diff --cached --quiet -- rust/schemas/api; then
echo "::error::Embedded API catalog is stale vs upstream commerce.*-specification repos. Regenerate with: (cd rust && GITHUB_TOKEN=<token> cargo run -p generate-api-catalog) and commit."
git diff --cached --stat -- rust/schemas/api
exit 1
fi
echo "API catalog is in sync with upstream specs."
1 change: 1 addition & 0 deletions rust/Cargo.lock

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

99 changes: 99 additions & 0 deletions rust/api-catalog-sources.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
{
"version": 1,
"remote": [
{
"domain": "bulk-operations",
"repository": "commerce.bulk-operations-specification"
},
{
"domain": "businesses",
"repository": "commerce.businesses-specification"
},
{
"domain": "catalog-products",
"repository": "commerce.catalog-products-specification"
},
{
"domain": "channels",
"repository": "commerce.channels-specification"
},
{
"domain": "chargebacks",
"repository": "commerce.chargebacks-specification"
},
{
"domain": "customer-profiles",
"repository": "commerce.customer-profiles-specification"
},
{
"domain": "fulfillments",
"repository": "commerce.fulfillments-specification"
},
{
"domain": "location-addresses",
"repository": "location.addresses-specification"
},
{
"domain": "metafields",
"repository": "commerce.metafields-specification"
},
{
"domain": "onboarding",
"repository": "commerce.onboarding-specification"
},
{
"domain": "orders",
"repository": "commerce.orders-specification"
},
{
"domain": "payment-requests",
"repository": "commerce.payment-requests-specification"
},
{
"domain": "payments",
"repository": "commerce.payments-specification"
},
{
"domain": "price-adjustments",
"repository": "commerce.price-adjustments-specification"
},
{
"domain": "recommendations",
"repository": "commerce.recommendations-specification"
},
{
"domain": "shipping",
"repository": "commerce.shipping-specification"
},
{
"domain": "stores",
"repository": "commerce.stores-specification"
},
{
"domain": "subscriptions",
"repository": "commerce.subscriptions-specification"
},
{
"domain": "taxes",
"repository": "commerce.taxes-specification"
},
{
"domain": "transactions",
"repository": "commerce.transactions-specification"
}
],
"local": [
{
"domain": "hosting-nodejs",
"path": "schemas/openapi/hosting-nodejs-public-v1.yaml"
}
],
"legacyTypescript": {
"status": "retired-on-rust-port",
"sharedDomainCount": 20,
"rustOnlyDomains": [
"hosting-nodejs"
],
"rationale": "The legacy TypeScript catalog contains the 20 remote domains above. hosting-nodejs is intentionally Rust-only because it is generated from the CLI's vendored public hosting specification."
}
}
4 changes: 2 additions & 2 deletions rust/schemas/api/manifest.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"generated": "2026-06-02T22:25:00.564300686+00:00",
"generated": "2026-07-15T11:40:00.622620+00:00",
"domains": {
"subscriptions": {
"file": "subscriptions.json",
Expand All @@ -14,7 +14,7 @@
"transactions": {
"file": "transactions.json",
"title": "Transactions API",
"endpointCount": 7
"endpointCount": 17
},
"orders": {
"file": "orders.json",
Expand Down
Loading