Skip to content

refactor(pipeline): split pipeline.zig into focused modules (#434) - #438

Merged
apotema merged 1 commit into
developmentfrom
refactor/split-pipeline
Sep 26, 2026
Merged

apotema merged 1 commit into
developmentfrom
refactor/split-pipeline

Conversation

@apotema

@apotema apotema commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor

This is a refactor with no behaviour change. src/cli/pipeline.zig was 3,985 lines, which is over the toolkit's 1,000-line limit. It follows the serve.zig (#436) and provider_github.zig (#437) splits. The root re-exports the same public API (run, plus the three specs cli.zig re-exports), and every module is referenced from a root test {} block. The helpers shared by the tests live in pipeline/testing.zig.

One exception to "moves only": run

run was a single function of about 1,310 lines, so moving it whole was not an option. It is now split into stage functions. Each one is a verbatim block of the old body and runs the same statements in the same order. The mechanical changes:

  • Early exits. A stage that used to return code / return 1 now returns ?u8 (null means go on), or a small union { proceed / ready, exit: u8 }. run returns that code at the same point, so the exit statuses are unchanged.
  • Defers. Every resource with a defer stays declared in run: the arena, target_dir, the reporter and its errdefer failActiveStage, asm_bin, provider_sources, output_dir, the zig args/env and hook_site. Stages borrow them through pipeline/context.zig (Context). The watched serve's defer watch_replan.deinit(...) still fires after finishServe is evaluated and before run's own defers.
  • Hook plans. The anonymous hook_plans = .{ ... } literal is now the named HookPlans struct. The fields and the order they are evaluated in are unchanged.
  • Locals. Inside the stages, locals are bound from cx under their old names. &hook_site became hook_site, and &parsed_args became parsed_args (a pointer now).
  • No reordering. Nothing moved in or out of the order. For example, generate_out / build_out are still computed right before their stage runs.
  • Test fixture. One edit in test code: the anonymous fixture installer in the re-gate test (now in generate.zig) had to become pub fn install, because gateThenInstall lives in another file now.

File map

File Lines Contents
src/cli/pipeline.zig 406 Root: module doc and map, re-exports, ok, run (stale gate, parse, upgrade, feed/reporter setup, asm resolve, install call, hook site, ios/android handoff, zig env/args, stage calls), test {}
pipeline/args_resolve.zig 251 resolve (the NAME half of target resolution, platform/backend derivation), TargetRefusal, TargetVerdict, confirmTarget, EarlyVerdict, earlyTargetCheck + 2 tests
pipeline/install.zig 291 preInstall (compatibility, .prebuild, Python/SDL2 wiring), gateThenInstall, AssemblerInstaller, discoverAndPlan (discovery, ownership, plans, #378 gate, bundle check, plugin-core compat, lock write) + 1 test
pipeline/generate.zig 314 run (before/core/after generate, ASTC and --bake prepasses, fingerprints, emsdk activation), beforeGenerate + 1 test
pipeline/build.zig 210 run (before/core/after build, docker/progress/captured zig build, SDL2 DLL staging, labelle build finalisation), bundleStep
pipeline/run.zig 582 launch (run hooks, wasm export/serve + --watch wiring, iOS/Android deploys, docker/host launches), serveNoBuild, noteRunSharesStdout, crossTargetLaunchSkipped + 1 test, runOutcome, runOptionEnv
pipeline/context.zig 39 Context, HookPlans
pipeline/watch.zig 747 WasmRebuildCtx + its 3 tests, collectPrebuildIgnorePaths, CollectPrebuildIgnorePathsSpec
pipeline/watch_replan.zig 286 WatchReplan, Generation, Installer
pipeline/watch_replan_tests.zig 812 The 8 WatchReplan tests and the TwoStage fixture (they left the struct because WatchReplan plus its tests was about 1,060 lines)
pipeline/screenshot.zig 235 screenshot_suffixes, FileStamp, ScreenshotProbe, ScreenshotProbeSpec
pipeline/export_output.zig 209 resolveExportOutput and its path helpers, ResolveExportOutputSpec
pipeline/testing.zig 20 testSite (was WasmRebuildCtx.testSite)

The largest file is 812 lines.

Agnosticism guard allowlist delta

  • Added (11): every new file except context.zig: args_resolve, build, export_output, generate, install, run, screenshot, testing, watch, watch_replan and watch_replan_tests. Each one carries moved platform words (the legacy target/backend sites, wasm serve, bgfx#57, fixture "wasm"/"bgfx" tags).
  • Kept: cli/pipeline.zig. The root is still dirty (its module doc, .wasm, the ios/android handoff), and the stale-entry test that names it is unchanged.
  • Clean, so not listed: context.zig.
  • The allowlist goes from 58 to 69 entries, and the doc comment is updated to match.

Tests: same named-test set

Before After
Build summary (zig build test --summary all) 1072/1077 passed (5 skipped) 1073/1078 passed (5 skipped)
Main CLI test binary 1040 total 1041 total
Named test "…" decls from pipeline 35 35 (same names)
Guard 17 pass 17 pass

The test names were pulled from both test binaries (the builtin.test_functions strings) and diffed after stripping the namespace path, which the move changes. The two sets match: 1,084 entries each. The only differences are five compiler-numbered __struct_N ids on anonymous test fixtures. The +1 in the total is the new unnamed test {} aggregator in pipeline.zig, so none of the moved tests were dropped by lazy analysis.

Verification

Each command's exit code was checked on its own:

  • zig fmt --check (new and changed files): 0
  • zig build: 0
  • zig build -Dtarget=x86_64-windows: 0
  • zig build test (includes the guard): 0
  • zig build test-provider-dispatch: 0
  • test/provider_dispatch_e2e.py (25 invocations), provider_github_e2e.py (70), provider_config_e2e.py (21), provider_hooks_e2e.py (43), provider_targets_e2e.py (40), plugin_compat_e2e.py: all 0

Closes #434

https://claude.ai/code/session_01R2K5sJDL5Msn1uRTkybiDP


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

pipeline.zig (3,985 lines) becomes a root that keeps `run` as the stage
orchestrator (and the owner of every resource the stages borrow) over
src/cli/pipeline/:

  args_resolve.zig        target + platform resolution, earlyTargetCheck,
                          confirmTarget
  install.zig             pre-install work, gateThenInstall, discovery +
                          hook plans, the lock write
  generate.zig            before/core/after generate, ASTC + --bake
                          prepasses, the shader re-gate
  build.zig               core build, packaging finalisation, bundle step
  run.zig                 run branches, RunOutcome plumbing, --no-build
  context.zig             Context + HookPlans shared by the stages
  watch.zig               WasmRebuildCtx, collectPrebuildIgnorePaths
  watch_replan.zig        WatchReplan and its generations
  watch_replan_tests.zig  WatchReplan's tests
  screenshot.zig          ScreenshotProbe and its spec
  export_output.zig       resolveExportOutput and its spec
  testing.zig             testSite, shared by the rebuild tests

Moves plus import/pub fixes, except `run` itself: at ~1,310 lines it was
split into stage functions that run the same statements in the same
order (early exits carried back as an exit code, defers kept in `run`).
The public API and cli.zig's spec re-exports are unchanged; 35 named
tests before and after, identical in the test binary. The eleven new
files carrying moved platform words join the agnosticism allowlist
(58 -> 69 entries); context.zig is clean and not listed.

Claude-Session: https://claude.ai/code/session_01R2K5sJDL5Msn1uRTkybiDP
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 26, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-26T22:07:18.070372Z 8ec59b0 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@coderabbitai

coderabbitai Bot commented Sep 26, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: 3c4190ae-fe74-42c4-b476-6c80d6982f15

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@apotema
apotema merged commit da58951 into development Sep 26, 2026
8 checks passed
@apotema
apotema deleted the refactor/split-pipeline branch September 26, 2026 22:18
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.

1 participant