Skip to content

Run the integration suite on shipped defaults with committed lockfiles - #23

Merged
arcaputo3 merged 2 commits into
agent/idiomatic-scalajs-mill-workflowsfrom
agent/bun-honest-defaults
Aug 27, 2026
Merged

Run the integration suite on shipped defaults with committed lockfiles#23
arcaputo3 merged 2 commits into
agent/idiomatic-scalajs-mill-workflowsfrom
agent/bun-honest-defaults

Conversation

@arcaputo3

Copy link
Copy Markdown
Contributor

Stacked on #22 (agent/bun-renames). This is the PR that makes the suite's green mean what it
says: the integration suite now runs the plugin's SHIPPED defaults.

Why

Until now build.mill forced MILL_BUN_REQUIRE_LOCKFILE=false across the whole 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.

What changes

Fixture lockfiles are committed. All 13 real-bun dependency-bearing fixtures (every
TypeScript fixture installs — tsDeps always injects TypeScript plus ambient types — plus
scalajs-bundle, scalajs-transitive, scalajs-web) carry a bun.lock generated by the
pinned Bun 1.4.0, and their installs now run --frozen-lockfile in CI.

One command regenerates them all. mill.bun.RegenerateFixtureLocks re-locks every fixture:

MILL_BUN_REGENERATE_LOCKS=1 ./mill millbun.integration.testOnly mill.bun.RegenerateFixtureLocks

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_LOCKFILE forkEnv 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-transitive is restructured. lib and app both claimed the workspace root as
moduleDir, so both resolved the same bun.lock — only one dependency set could ever be
recorded there. lib now lives in lib/ with its own lockfile identity.

Lockfile-skew guard. Committed locks make the Bun pin load-bearing: bun.lock is forward-
but not backward-compatible (1.4.0 writes lockfileVersion: 2; 1.3.14 fails on it with a raw
UnknownLockfileVersion that never mentions how to recover). A frozen install against a lock
the 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

  • New typescript-stale-lock fixture: 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.
  • Unit tests for the lexical JSONC lockfileVersion extraction, the skew message, silent
    readable combinations, and the version-table completeness guard.
  • Full suites green under the strict default — every real-bun fixture now installs frozen.

arcaputo3 and others added 2 commits August 26, 2026 19:22
…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>
@arcaputo3 arcaputo3 closed this Aug 26, 2026
@arcaputo3 arcaputo3 reopened this Aug 26, 2026
@arcaputo3
arcaputo3 changed the base branch from agent/bun-renames to agent/idiomatic-scalajs-mill-workflows August 27, 2026 00:57
@arcaputo3
arcaputo3 merged commit 65e9a9d into agent/idiomatic-scalajs-mill-workflows Aug 27, 2026
8 checks passed
@arcaputo3
arcaputo3 deleted the agent/bun-honest-defaults branch August 27, 2026 00:58
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