Skip to content

ci: gate PR jobs with trunk-io/dynamic-ci - #1170

Merged
trunk-io[bot] merged 1 commit into
tyler/aggregate-gatefrom
tyler/dynamic-ci
Aug 27, 2026
Merged

ci: gate PR jobs with trunk-io/dynamic-ci#1170
trunk-io[bot] merged 1 commit into
tyler/aggregate-gatefrom
tyler/dynamic-ci

Conversation

@TylerJang27

@TylerJang27 TylerJang27 commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

Adds trunk-io/dynamic-ci (the Dynamic CI Filter) to the four PR workflows, in the pre-job mode trunk2 uses: one upstream dynamic-ci-filter job asks Trunk for a per-job verdict, and every downstream job gates on its output.

Difference from trunk2: TRUNK_PUBLIC_API_ADDRESS is deliberately not overridden, so the action hits prod (api.trunk.io) with secrets.TRUNK_PROD_ORG_API_TOKEN. This repo's merge queue and CI history live in prod, not staging.

Workflow Gated jobs Left ungated
pull_request.yml build_release, test, trunk_check_runner, build_pyo3, build_wasm gate (must always report)
pyo3.yml linux, linux-pytest, macos, sdist get-date-sha, publish-annotation (non-PR only), gate
ruby.yml build, build-ruby-gem, test-ruby-gem-uploads gate
wasm.yml build gate

release_cli.yml is untouched — its pull_request trigger is already paths-scoped.

Nothing changes outside pull requests

Every gate leads with an explicit event escape, so push-to-main, tags and workflow_dispatch run everything outright:

if: >-
  !cancelled() &&
  (github.event_name != 'pull_request' ||
  needs.dynamic-ci-filter.outputs.build != 'false')

The escape is redundant with fail-open (a skipped filter job exports empty outputs, and '' != 'false' already runs everything) but is written out so main's behavior can't depend on that side effect — and so widening the filter job to push later can't start skipping jobs on main.

Stacked on #1173

Based on #1173, which adds the fan-in gate job each workflow needs before any of this is mergeable. Without it, a matrix job skipped at job level reports one check under the unexpanded name and the 12 required per-leg contexts hang on "Expected" forever. Read that PR first; merge order is #1173 -> ruleset context swap -> this.

The gate jobs are deliberately not gated by Dynamic CI and are not in the filter's outputs: block. A gate that could be skipped could not report, which defeats its whole purpose.

Wiring notes

  • Fail open. Gates test != 'false', never == 'true'. A missing verdict — outage, unseen job, unresolved key — emits no output, and '' != 'false' runs the job.
  • !cancelled() on every gate so the skipped filter job doesn't auto-skip its dependents.
  • Failure propagation preserved. Where !cancelled() replaced a plain needs, an explicit needs.<upstream>.result == 'success' keeps the behavior that a failed upstream skips its consumers: testbuild_release, linux-pytestlinux, linux/macos/sdistget-date-sha, test-ruby-gem-uploadsbuild-ruby-gem.
  • Artifact producers run when their consumer does. build_release also runs when test is wanted, linux when linux-pytest is wanted, build-ruby-gem when test-ruby-gem-uploads is wanted — otherwise download-artifact would have nothing to fetch.
  • Merge queue. Not special-cased: the service short-circuits trunk-merge/ branches to run-everything. That covers draft merge-queue PRs, which arrive as pull_request events.
  • No actions/checkout in the filter job (trunk2 has one): the action reads only runner env vars and the event payload; the service derives the diff from baseSha/commitSha via the GitHub App.
  • Pinned @v1, matching this repo's convention. The action's README suggests an immutable tag (v0.1.0) if we want it held still during beta.

Trade-off to weigh

Fewer dogfood uploads. pull_request.yml's test, all of ruby.yml, and pyo3.yml's linux-pytest exist partly to push real results into Trunk (EWhNPVic, 2tYJWMu7, T5yKSn9h, z2dzjLHm, 4B2wfoEU, 6E6WINjl, 68IdP3pq). A skipped job uploads nothing, so PR-side dogfood data thins out on changes the engine judges unrelated.

Verification so far

  • trunk check clean on all four workflows (actionlint, prettier, yamllint, checkov, shellcheck, shfmt). actionlint validates each needs.dynamic-ci-filter.outputs.<key> against the filter's declared outputs:, so the re-export wiring is checked mechanically.
  • Every exported key names a real job and is read by exactly one gate (verified by script).
  • Observed both directions: on acd96a3b (which touched the workflows) linux ×2, macos ×2 and sdist all ran; on the empty commit 729bf24b every gated job across all four workflows skipped, and all four runs still concluded success.

@trunk-io

trunk-io Bot commented Aug 27, 2026

Copy link
Copy Markdown

😎 Stack merged successfully - details.

@trunk-staging-io

trunk-staging-io Bot commented Aug 27, 2026

Copy link
Copy Markdown

Static BadgeStatic BadgeStatic Badge

Failed Test Failure Summary Logs
pending_quarantine_test should be quarantined when run with variant A test marked as pending was expected to fail but unexpectedly passed. Logs ↗︎
variant_quarantine_test should be quarantined when run with variant A test expected the sum of 2 + 2 to be 5, but it was actually 4, indicating a failing assertion. Logs ↗︎

View Full Report ↗︎Docs

@trunk-io

trunk-io Bot commented Aug 27, 2026

Copy link
Copy Markdown

Static BadgeStatic BadgeStatic Badge

Failed Test Failure Summary Logs
pending_quarantine_test should be quarantined when run with variant A test marked as pending was expected to fail but unexpectedly passed. Logs ↗︎
variant_quarantine_test should be quarantined when run with variant A test expected the sum of 2 + 2 to be 5, but it was actually 4, indicating a failing assertion. Logs ↗︎

View Full Report ↗︎Docs

@TylerJang27
TylerJang27 changed the base branch from main to tyler/aggregate-gate August 27, 2026 16:23
Adds the Dynamic CI Filter in pre-job mode to the four PR workflows
(pull_request, pyo3, ruby, wasm): one upstream job asks Trunk for a
per-job verdict and every downstream job gates on its output.

Gating is scoped to pull_request explicitly -- every gate leads with
`github.event_name != 'pull_request' ||`, so push (main), tags and
workflow_dispatch run everything outright rather than relying on the
skipped filter job's empty outputs.

Unlike trunk2, TRUNK_PUBLIC_API_ADDRESS is left unset so the action talks
to prod (api.trunk.io) with TRUNK_PROD_ORG_API_TOKEN -- this repo's merge
queue and CI history are in prod, not staging.
@trunk-io
trunk-io Bot merged commit 0b76b8d into main Aug 27, 2026
23 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants