Run the integration suite on shipped defaults with committed lockfiles - #23
Merged
arcaputo3 merged 2 commits intoAug 27, 2026
Merged
Conversation
…v hooks The TypeScript install task is canonically bunInstall; Mill's inherited npmInstall delegates to it and stays usable. All internal call sites use the canonical name, so install artifacts live in bunInstall.dest. Both module kinds share one test entrypoint name: testForked. The TypeScript test command `test` is a deprecated alias, and the Scala.js bunTest — which duplicated the inherited testForked exactly, since the overridden jsEnvConfig and testLinkTask already put every test run on Bun — is deprecated in its favor. TypeScript bunBundleFormat is Option[String], matching Scala.js. The type disagreement was the one rename no alias could bridge; 0.3.0 takes the one-time break, and None now lets `bun build` infer the format. BunWorkersModule.workerBundleFormat follows it directly. Environment hooks share one vocabulary: bunToolEnv (install, lock, build subprocesses) is defined once on BunToolchainModule and used by every runBun call site — Scala.js, TypeScript, workspace, publish, and workers modules previously mixed bunEnv() and bunToolEnv() — and the TypeScript bunRuntimeEnv is public instead of protected. Integration tests exercise the canonical names throughout, with explicit alias regression coverage: npmInstall must resolve to bunInstall.dest, and the deprecated test / bunTest commands must keep working until their removal at 1.0. MIGRATING-0.3.md documents the new rows and the bunBundleFormat break with a before/after example. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
build.mill forced MILL_BUN_REQUIRE_LOCKFILE=false across the entire integration suite, so the strict-lockfile default — the plugin's headline 0.3.0 behavior — was exercised by almost nothing. Every install-path bug fixed earlier in this stack lived in exactly that gap. All 13 real-bun dependency-bearing fixtures now commit a bun.lock generated by the pinned Bun 1.4.0 and install frozen in CI. The RegenerateFixtureLocks entry point re-locks every fixture in one command (MILL_BUN_REGENERATE_LOCKS=1 gates it; without the env it lists what it would do and touches nothing). The forkEnv default is removed; scalajs-dependency-manifests opts out in its own build.mill because its stub cannot produce a real lock. scalajs-transitive is restructured: lib and app both claimed the workspace root as moduleDir, so both resolved the same bun.lock and only one dependency set could be recorded there. lib now lives in lib/ with its own lockfile identity. Committed locks make the Bun pin load-bearing — bun.lock is forward- but not backward-compatible, and the raw UnknownLockfileVersion error from an older Bun never mentions how to recover. A frozen install against a lock the pinned Bun cannot read now fails before bun runs, telling the user to regenerate with bunLock or raise bunVersion. The supported-lockfile-version table lives beside the checksum table, and a unit test forces every bundled Bun to declare its entry. The new typescript-stale-lock fixture proves the guard fires before any bun subprocess is reached, and fails with the guard neutralized. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This was referenced Aug 26, 2026
arcaputo3
changed the base branch from
agent/bun-renames
to
agent/idiomatic-scalajs-mill-workflows
August 27, 2026 00:57
arcaputo3
merged commit Aug 27, 2026
65e9a9d
into
agent/idiomatic-scalajs-mill-workflows
8 checks passed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #22 (
agent/bun-renames). This is the PR that makes the suite's green mean what itsays: the integration suite now runs the plugin's SHIPPED defaults.
Why
Until now
build.millforcedMILL_BUN_REQUIRE_LOCKFILE=falseacross the whole integrationsuite, so the strict-lockfile default — the plugin's headline 0.3.0 behavior — was exercised by
almost nothing. Every install-path bug fixed earlier in this stack lived in exactly that gap.
What changes
Fixture lockfiles are committed. All 13 real-bun dependency-bearing fixtures (every
TypeScript fixture installs —
tsDepsalways injects TypeScript plus ambient types — plusscalajs-bundle,scalajs-transitive,scalajs-web) carry abun.lockgenerated by thepinned Bun 1.4.0, and their installs now run
--frozen-lockfilein CI.One command regenerates them all.
mill.bun.RegenerateFixtureLocksre-locks every fixture:Without the env guard it lists what it would do and touches nothing, so accidentally running it
as part of the suite is harmless. Regenerating 13 locks by hand on each dependency bump is not
sustainable — without this the committed locks would rot immediately.
The suite runs shipped defaults. The
MILL_BUN_REQUIRE_LOCKFILEforkEnv default is gone.Fixtures that deliberately test relaxed behavior opt out in their own build.mill with a comment
(
scalajs-dependency-manifests, whose stub can't produce a real lock).scalajs-transitiveis restructured.libandappboth claimed the workspace root asmoduleDir, so both resolved the samebun.lock— only one dependency set could ever berecorded there.
libnow lives inlib/with its own lockfile identity.Lockfile-skew guard. Committed locks make the Bun pin load-bearing:
bun.lockis forward-but not backward-compatible (1.4.0 writes
lockfileVersion: 2; 1.3.14 fails on it with a rawUnknownLockfileVersionthat never mentions how to recover). A frozen install against a lockthe pinned Bun cannot read now fails before bun runs, with: "Regenerate the lockfile with this
module's bunLock command, or raise bunVersion." The version table lives beside the checksum
table, and a unit test forces every bundled Bun to declare its supported lock version — adding a
Bun without it fails the build.
Tests
typescript-stale-lockfixture: pinned Bun 1.3.14, committed v2 lock, stubbed executable— the install fails before any bun subprocess is reached (the stub's marker file proves
it). Confirmed failing with the guard neutralized.
lockfileVersionextraction, the skew message, silentreadable combinations, and the version-table completeness guard.