Skip to content

Run the integration tests against the published conductor image - #7

Merged
devhawk merged 5 commits into
mainfrom
use-published-conductor-image
Aug 13, 2026
Merged

Run the integration tests against the published conductor image#7
devhawk merged 5 commits into
mainfrom
use-published-conductor-image

Conversation

@devhawk

@devhawk devhawk commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator

The tier-3 (conductor + Postgres container) tests have never run in CI. The harness demanded an explicit conductor source and, in practice, a local checkout — no published tag carried the v2 API — so the integration job was gated on a CONDUCTOR_IMAGE repo variable that was never set.

conductor 0.17.0 is the first release cut from a main containing controllers/apiv2 and the openapi subcommand, so dbosdev/conductor:latest now serves an API this CLI can talk to. Default to it.

Changes

  • internal/conductortest — conductor source resolves in precedence order: CONDUCTOR_DIR (build from a checkout; the escape hatch for unreleased conductor changes) → CONDUCTOR_IMAGE (a specific tag, used as-is so a locally built one works) → dbosdev/conductor:latest. Nothing to configure for the normal path; the old "fail if neither is set" branch is gone.
  • AlwaysPullImage on the default only. The tag moves, and testcontainers otherwise reuses whatever copy a machine cached — a developer who pulled latest once would quietly keep testing an old conductor. Scoping it to the default keeps an explicit CONDUCTOR_IMAGE that no registry serves working.
  • CI — the integration job loses its if: gate. It needs only Docker now. The license key still gates the tier at runtime, so fork PRs (no secret) skip the tests and the job stays green. vars.CONDUCTOR_IMAGE is still passed through, so a tag can be pinned without a code change.
  • Flake fix (separate commit)workflow fork is the first command TestWorkflowMutationsIntegration has conductor dispatch to the executor, and it ran once with no retry. Executor registration arrives over the WebSocket asynchronously after Launch, so the fork could beat it and fail with no healthy executors available (hit once in ten runs). It now polls for 30s like E1/E3/E4/D4 already do, keeping the last error so a genuine failure still reports its cause.
  • Docs.env.example and AGENTS.md rewritten for the image-by-default model, including how to re-vendor the spec straight from the image (make spec still needs a checkout).

Verification

Locally, with CONDUCTOR_DIR and CONDUCTOR_IMAGE both unset — the exact path CI takes — the full suite is green in ~70s, with no image build. I deleted the local latest tag first, so the pull path is exercised rather than just declared. make lint, go vet -tags integration, and the unit tests pass. The flaky test was then run 5×, all green.

The trade-off

Tracking a moving tag means a conductor release can turn this job red with no commit in this repo. That is the intent — an API break surfaces the day it ships rather than at the next deliberate bump — but it is a real change in what a red CI means here. The usual cause will be the vendored spec drifting from the released API; set the CONDUCTOR_IMAGE repo variable to an older tag to confirm a failure arrived with a release.

Note that main's vendored spec is already one release behind the image: it still marks GET /v2/orgs/{orgName}/permissions as OAuth-gated, which conductor dropped in dbos-inc/conductor#177. No integration test hits that route, so the suite passes either way, and the in-flight update-openapi-spec branch fixes it — its vendored spec is byte-identical to what the 0.17.0 image emits.

🤖 Generated with Claude Code

The tier-3 harness required an explicit conductor source and, in practice,
a local checkout: no published tag carried the v2 API, so CI gated the whole
integration job on a CONDUCTOR_IMAGE repo variable that was never set. The
job has therefore never run.

conductor 0.17.0 is the first release cut from a main that includes
controllers/apiv2 and the openapi subcommand, and it is on Docker Hub as a
multi-arch image, so latest now serves an API this CLI can talk to. Default
to it:

- conductortest picks its source in precedence order — CONDUCTOR_DIR (build
  from a checkout, the escape hatch for unreleased conductor changes), then
  CONDUCTOR_IMAGE (a specific tag, used as-is so a locally built one works),
  then dbosdev/conductor:latest. Nothing to configure for the normal path.
- The default sets AlwaysPullImage: the tag moves, and testcontainers would
  otherwise reuse whatever copy a machine had cached and quietly test an old
  conductor. It is scoped to the default so an explicit CONDUCTOR_IMAGE that
  no registry serves still works.
- The CI integration job loses its `if:` gate. It now needs only Docker; the
  license key still gates the tier at runtime, so fork PRs (no secret) skip
  the tests and the job stays green. CONDUCTOR_IMAGE is still passed through,
  so the repo variable can pin a tag without a code change.

Tracking a moving tag means a conductor release can turn this suite red with
no commit here. That is the intent — an API break should surface the day it
lands — and the usual cause is the vendored spec drifting from the released
API, which AGENTS.md now documents how to re-vendor straight from the image.
`workflow fork` is the first command TestWorkflowMutationsIntegration has
conductor dispatch to the executor, and it ran once with no retry. Executor
registration arrives over the WebSocket asynchronously after Launch, so the
fork can beat it and fail with "no healthy executors available" — observed
once in ten runs against the published image.

Poll it for 30s, matching what E1/E3/E4/D4 already do with their first
dispatched command, and keep the last error so a real failure still reports
the cause rather than an empty fork ID.
GitHub is deprecating the Node 20 runtime: checkout@v4 and setup-go@v5
target it and are already being force-run on Node 24, with a warning on
every run. Bump to the current majors, both of which declare node24.

Neither major carries a breaking change that reaches us: setup-go v6/v7 are
dependency and ESM migrations, and checkout v6 moves credentials to a
separate file while v7 blocks fork checkouts for pull_request_target and
workflow_run — this workflow triggers on pull_request.
Every push to a PR branch started a full parallel run, including the
~2-minute container-backed integration job, while the run it obsoleted kept
burning a runner to report on code nobody would merge.

Group runs per PR and cancel in progress. Scoped to pull_request via the
cancel-in-progress expression: pushes to main keep every run, so main keeps
an unbroken per-commit history to bisect. The group key falls back to
github.ref for push events, where head_ref is empty.
@devhawk
devhawk requested review from kraftp, maxdml and qianl15 August 13, 2026 18:20
The checks list says pass/fail and nothing else, which is too coarse here:
the conductor tier skips wholesale when the license key is absent, so a job
that ran nothing looks exactly like a job that ran everything. This PR's own
first CI run was that case — green, with every conductor test skipped.

Route the test targets through gotestsum (added as a module tool, like
oapi-codegen) when JUNIT names an output path, and have both CI jobs publish
the XML two ways: test-summary/action for a summary on the run page, and
upload-artifact for the raw file. Both if: always() — a failing run is when
the report matters most. `show: "fail, skip"` surfaces the skips with their
reason, which is the part the checks list cannot show.

Without JUNIT the targets stay a plain `go test`, so local runs are
unchanged and build no extra tooling. Matches the Java repo's setup.
@devhawk
devhawk merged commit 0cddbd1 into main Aug 13, 2026
4 checks passed
@devhawk
devhawk deleted the use-published-conductor-image branch August 13, 2026 18:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants