Skip to content

ci: validate newly-regen'd SDKs against the latest released Outpost #926

@leggetter

Description

@leggetter

Trigger

The Speakeasy bot opens PRs that regen SDKs (chore: 🐝 Update SDK - Generate OUTPOST-TS 1.3.0 (#NNN) style). Today nothing exercises that SDK against a running server before it's published. If the regen produces an SDK that silently misroutes requests — like the discriminator-union dispatch bug we hit in #920 — it ships and we hear about it from a customer.

The release order makes this useful: Outpost is tagged → sdk-generate-on-release runs against that tag → bot opens SDK PR → SDK is published. The newly-regen'd SDK is being prepared to ship against a server that already exists. We can test that pairing directly.

Question this workflow answers

"Does the newly-regen'd SDK in this PR work against the latest released Outpost?"

Different from #925, which asks "does this PR's spec match this PR's server?" — both are needed.

This workflow #925
Trigger PRs touching sdks/outpost-typescript/** PRs touching spec / SDK / server-shape paths
Server hookdeck/outpost:<latest-release> (docker) go build ./cmd/outpost-server from PR
SDK The PR's regen output Regen from PR's spec via regenerate-sdk.sh

Implementation notes

  • Resolve latest release dynamically at workflow runtime — this repo uses namespaced tags (sdks/outpost-typescript/v1.3.0 for SDK, plain v1.0.3 for Outpost), so gh release view returns the wrong thing. Use:

    gh api repos/hookdeck/outpost/releases \
      --jq '[.[] | select(.tag_name | test("^v[0-9]+\\.[0-9]+\\.[0-9]+$")) | select(.prerelease == false)][0].tag_name'
    # → v1.0.3

    Filters on the bare vX.Y.Z pattern and skips prereleases. Auto-updating; no per-release bump.

  • Service containers same as ci(spec-sdk-tests): add workflow that runs the contract suite against a local Outpost #925: Postgres, redis/redis-stack-server (RediSearch for tenants.list), RabbitMQ.

  • Server via docker pull hookdeck/outpost:<tag>. Migrations via the same image's migrate apply.

  • SDK built from the PR: npm install && npm run build in sdks/outpost-typescript. No speakeasy run — the regen is the PR.

  • Tests: same spec-sdk-tests suite, .env pointing at localhost.

Why PR-triggered, not folded into the gen workflow

  • The PR is where humans investigate failures. Test results next to the diff is more actionable than buried in Actions logs for a non-PR workflow run.
  • Folding tests into sdk-generate-on-release.yml couples "did the regen succeed" with "does the regen work," and that workflow is already complex (reusable workflow, three-language fan-out, version detection).
  • Failure on the PR keeps the PR open and red — visible. Failure inside the gen workflow can silently suppress the PR.
  • The gen workflow can still gate auto-merge on this check passing if we want strict "merge only if green" semantics.

Open questions

  • TS only initially, or fan out to Go and Python on day one? TS first is probably right — the bug we caught was TS-specific (Zod union dispatch); Go and Python have different failure modes that may or may not be reachable via this suite.
  • Should the trigger also include chore(sdks) PRs that touch .speakeasy/workflow.yaml (chore(sdks): drop x-speakeasy-pagination overlay from all SDK sources #919-style overlay drops) or only the per-language dirs?

Related

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions