Skip to content

Share the integration harness and cover the last untested features - #25

Merged
arcaputo3 merged 9 commits into
agent/idiomatic-scalajs-mill-workflowsfrom
agent/bun-test-harness
Aug 27, 2026
Merged

Share the integration harness and cover the last untested features#25
arcaputo3 merged 9 commits into
agent/idiomatic-scalajs-mill-workflowsfrom
agent/bun-test-harness

Conversation

@arcaputo3

Copy link
Copy Markdown
Contributor

Stacked on #24 (agent/bun-windows-ci).

Harness

All five fixture suites copy-pasted the same tester / outputPath / commandLogPath helpers,
and ~20 assertions re-encoded Mill's out/<module>/<task> layout per suite. BunIntegrationSuite
now owns both; the suites and the lock regenerator extend it.

Duplication

bundle and bundleFast differed only in linker (fullLinkJS vs fastLinkJS) and --bytecode,
across ~30 duplicated lines of args assembly. Both now delegate to one Task.Anon body while
staying separately cached tasks. (bundleFast deliberately never bytecode-compiles; its scaladoc
now says so.) The Scala.js web stages already shared prepareWebStage — only the thin cached
wrappers differ, which is the right shape, so they're untouched.

First-ever coverage for three shipped features

  • BunSQLiteModuletypescript-compile mixes it in with a discovered data/app.db and
    asserts it reaches the compile workspace. The fixture chains bunCompileResources through
    super, because an unqualified override silently drops the mixin's contribution — exactly the
    mistake a user would make, so the fixture models the correct form.
  • npmOverrides end-to-end — new typescript-overrides fixture: lib pins is-odd@^3.0.0,
    app pins is-odd@3.0.1; the override resolves the conflict, installs against a committed
    lock, and the generated package.json carries the resolved specifier plus the overrides block.
    (The conflict-fails path is already unit-tested.)
  • bunDoctor — evaluated in the managed-toolchain suite.

Also

Full suites green. Not covered here, deliberately: a dev() end-to-end test (needs a
spawn/poll/kill harness for a long-running server — worth its own focused change) and
compileExecutables cross-compilation (bun downloads a full target runtime per cross target;
needs a caching decision first).

arcaputo3 and others added 7 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>
The plugin carries Windows-specific code — bun.exe extraction,
executableCandidates, the mill.bat fork path in the integration
harness — with zero coverage. Both jobs now run on windows-latest with
fail-fast off, using bash as the step shell so one ./mill invocation
works on all three platforms. The official Mill 1.1.5 mill.bat launcher
is committed; build.mill already selects it on Windows, but it never
existed, so the integration suite could not have forked a fixture build
there at all.

Both jobs also cache ~/.cache/mill-bun keyed on the toolchain source,
so a managed-Bun run downloads each pinned archive once per platform
rather than once per CI run.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The sh wrapper fetches Mill's native launcher, which has no Windows
build — every Windows step died instantly with "This native mill
launcher supports only Linux and macOS." A launcher-selection step now
points Windows at the committed mill.bat and everything else at ./mill.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
All five fixture suites copy-pasted the same tester/outputPath/
commandLogPath helpers and each re-encoded Mill's out/<module>/<task>
layout; BunIntegrationSuite now owns both, and the regenerator uses it
too.

bundle and bundleFast differed only in linker and --bytecode across 30
duplicated lines of args assembly; both now delegate to one Task.Anon
body. bundleFast never bytecode-compiles — it exists for iteration
speed — and its scaladoc says so.

First-ever coverage for three shipped features:
- BunSQLiteModule: typescript-compile mixes it in with a discovered
  data/app.db and asserts it lands in the compile workspace. The
  fixture chains bunCompileResources through super — an unqualified
  override silently drops the mixin's contribution, which is exactly
  the mistake a user would make, so the fixture models the right form.
- npmOverrides end-to-end: the new typescript-overrides fixture has lib
  and app pinning conflicting is-odd specifiers; the override resolves
  the install against a committed lock, and the generated package.json
  carries both the resolved specifier and the overrides block.
- bunDoctor: evaluated in the managed-toolchain suite.

Also fixes the two scaladoc examples that still used Mill 0.x's
millSourcePath (BunSQLiteModule, BunWorkersModule) — neither compiled.

Re-running RegenerateFixtureLocks against the committed locks produces
zero diffs, confirming lock generation is deterministic.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…t there

os.perms throws on NTFS, and bun.exe needs no executable bit — the
permission half of the cross-filesystem publish test now runs only on
POSIX. First genuine Windows finding; the managed-bun leg (download,
extraction, shared cache, eviction recovery, mill.bat forking) already
passes on windows-latest.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
arcaputo3 and others added 2 commits August 26, 2026 20:33
The fixture's bun-proxy is a POSIX sh script, which CreateProcess
cannot execute — the only failure in the entire Windows integration
suite. The fixture now carries bun-proxy.cmd with identical semantics
(log first-arg:marker, delegate to PATH bun, propagate the exit code)
and picks the right one per platform.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@arcaputo3
arcaputo3 changed the base branch from agent/bun-windows-ci to agent/idiomatic-scalajs-mill-workflows August 27, 2026 00:57
@arcaputo3
arcaputo3 merged commit 2ec60a7 into agent/idiomatic-scalajs-mill-workflows Aug 27, 2026
6 checks passed
@arcaputo3
arcaputo3 deleted the agent/bun-test-harness 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