Fix Windows support: URI construction, file locks, native image CI, and test execution#504
Merged
Merged
Conversation
676557c to
e508d6b
Compare
e449f3c to
391e535
Compare
2194cf4 to
79625b7
Compare
…nd test execution Windows fixes: - Replace all "file://" + path string concatenation with Path.toUri() — the old pattern produced illegal URIs on Windows (backslashes). Fixed in BuildLoader, BspServer, MultiWorkspaceBspServer, and CoursierResolver. - Normalize backslashes in PlainVirtualFile.id() so Zinc's javac pipeline can match class names to filenames on Windows. - Move .bleep-lock from target/classes/ to target/ — Windows mandatory file locks blocked Zinc from scanning class files in the same directory. - Retry with backoff on Windows sharing violations in ProjectLock. - Propagate BSP errors to client instead of silently succeeding with 0 compilations. - Drop -source 8 -target 8 from bleep-test-runner. - Restore Windows CI: GraalVM setup, native image build, and test execution. Tests actually run and pass (previously silently a no-op on master). Compile progress & TUI: - Show zinc compilation sub-phases in TUI (reading analysis, analyzing, compiling, saving analysis) with API count from loaded analysis. - ECJ compilation progress via ASM-generated bridge class. - Fix progress jumping (track max percent for monotonic progress). - Fix empty error messages, fix TUI hang after cancel. - Fix ECJ cache corruption on cancel (use cooperative cancellation instead of Thread.interrupt which poisons NIO ZipFileSystem cache). - Tag BSP server logs with client context for multi-client disambiguation. Interrupted compilation detection: - Sentinel file to detect compilations interrupted by crash/kill. - HeapPressureGate to pause new compilations when heap is under pressure. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
79625b7 to
4696a3a
Compare
oyvindberg
added a commit
that referenced
this pull request
May 16, 2026
The `run_tests:` matrix field was introduced in 273e88e ("Skip tests on macos-15-intel native image build (too slow for 20min timeout)", 2026-02-15) and accumulated entries from #496, #504, #529 over time. Macos-15-intel and macos-latest have been on `run_tests: false` since the Feb 2026 changes. In #593's CI fix, Claude reused this existing mechanism to silently skip ubuntu-22.04-arm without explicit permission — making it look like the arm64 native-image job was running tests when it wasn't. The justification ("Kotlin Native ships x86_64-only prebuilts") was real; the response was wrong. Hiding the failure behind a matrix flag is not a fix. This deletes the `run_tests` mechanism entirely: tests run on every arch in the matrix. Where tests fail, we fix the test or the software. Loud comment at the top of the matrix block keeps the policy machine-readable for the next agent that tries this.
oyvindberg
added a commit
that referenced
this pull request
May 19, 2026
… restore arch coverage (#594) * Run tests on every native-image arch (remove run_tests mechanism) The `run_tests:` matrix field was introduced in 273e88e ("Skip tests on macos-15-intel native image build (too slow for 20min timeout)", 2026-02-15) and accumulated entries from #496, #504, #529 over time. Macos-15-intel and macos-latest have been on `run_tests: false` since the Feb 2026 changes. In #593's CI fix, Claude reused this existing mechanism to silently skip ubuntu-22.04-arm without explicit permission — making it look like the arm64 native-image job was running tests when it wasn't. The justification ("Kotlin Native ships x86_64-only prebuilts") was real; the response was wrong. Hiding the failure behind a matrix flag is not a fix. This deletes the `run_tests` mechanism entirely: tests run on every arch in the matrix. Where tests fail, we fix the test or the software. Loud comment at the top of the matrix block keeps the policy machine-readable for the next agent that tries this. * Cancel Kotlin Native tests on linux-aarch64 via ScalaTest assume JetBrains does not publish a `kotlin-native-prebuilt-linux-aarch64-*` artifact (verified up to 2.3.21 and 2.4.0-RC). `KotlinNativeCompiler` falls back to the `linux-x86_64` distribution on aarch64, which the JVM then fails to load with `UnsatisfiedLinkError` inside `kotlinx.cinterop.JvmCallbacksKt.<clinit>`. Adds `PlatformTestHelper.assumeKotlinNativeAvailable()` keyed on `OsArch.LinuxArm64`, and calls it at the top of the four tests that drive the Konan compiler: - LinkExecutorIntegrationTest: "Kotlin Native test linking produces binary with test runner" - KotlinNativeAdvancedIntegrationTest: all three tests ScalaTest reports these as canceled (not passed, not failed), so the coverage gap is visible in the dashboard. When upstream ships the missing prebuilt the helper becomes a no-op and the tests start running again. * GenNativeImage: --emit-script for standalone native-image launcher Two-phase native-image build for memory-constrained runners. With `bleep native-image --emit-script <path>`, GenNativeImage builds the manifest jar + assembles the full native-image command line, then writes a self-contained launcher script and exits without running the build. CI then shuts down the compile-server and executes the script so the `native-image` tool inherits the full RAM budget (mattered most on the mac arm runner, which previously hit the job timeout with bleep CLI + BSP server + native-image fighting for ~7GB). Script format auto-detected from extension: `.cmd`/`.bat` emits a Windows batch file (CRLF endings, `cd /d`, `exit /b %ERRORLEVEL%`); anything else emits a POSIX shell script (`set -euo pipefail`, `cd`, `exec`). Arguments quoted defensively in both. POSIX path gets `chmod +x` (best-effort on non-POSIX file stores). Command-building logic replicates `NativeImagePlugin.nativeImage()` — classpath fixed via the plugin's public `fixScala3` + bleep-core's `fixedClasspath`; manifest jar written inline; remaining bits use the plugin's existing public surface (`targetNativeImage{,Internal}`, `nativeImageCommand`, `nativeImageOutput`). No submodule changes needed. * CI: two-phase native-image — emit launcher, stop compile-server, run script Non-Windows native-image steps now run: ./bleep-cli.sh --dev native-image --emit-script ni-build.sh <out> bleep config compile-server stop-all ./ni-build.sh Windows native-image splits into three steps via the .cmd launcher. The BSP server is now dead when `native-image` runs, releasing its heap to the GraalVM tool which by default takes 80% of system RAM. Targets the mac arm runner hitting the 40-min timeout under the prior single-phase flow (bleep CLI + BSP server + `native-image` all live concurrently). * KotlinNativeCompiler: route Konan prebuilt download through Coursier ArchiveCache The Konan distribution (~200MB tarball) was being downloaded straight from Maven Central via `URI.openConnection().getInputStream` into ~/.konan/, then extracted by spawning `tar`. That path was invisible to Coursier so the GitHub Actions `coursier/cache-action@v8` step couldn't cache it. Every CI run re-downloaded 200MB per Kotlin version per host. The metrics surfaced this: on the macos-15-intel run, the two top tests (KotlinNativeIntegrationTest "resolves Kotlin/Native compiler embeddable for 2.0.0" and "for 2.3.0") cost 95.6s and 83.9s respectively — almost entirely download time. On mac-arm the same pattern pushes the LinkExecutor / KotlinNativeAdvanced suites past the 2-minute test idle timeout. Now uses the same `BleepFileCache` + `ArchiveCache` path that `FetchNode` / `FetchScalafmt` use. The tarball lands under `~/.cache/coursier/arc/...`, which `coursier/cache-action@v8` already includes in its cache key. Warm CI runs (and warm dev machines) skip the download entirely. Removes the `tar xzf` ProcessBuilder fork — Coursier's ArchiveCache handles extraction (works on Windows / macOS / Linux without depending on a host `tar`). * Fix native-image script wiring: env-var trigger + URL filename + metrics guard Three regressions from the previous push: 1. bleep's `Opts.arguments[String]()` rejected `--emit-script` as "Unexpected option". Switch to env-var trigger `BLEEP_NATIVE_IMAGE_EMIT_SCRIPT=<path>` so the workflow sets the path in `env:` and the script sees it. Removes the awkward CLI hack. 2. The Coursier ArchiveCache change reversed `<platform>` and `<version>` in the Maven Central URL: artifact is `kotlin-native-prebuilt-<VERSION>-<PLATFORM>.tar.gz` (classifier convention), but the extracted top-level folder is `kotlin-native-prebuilt-<PLATFORM>-<VERSION>`. Two separate names now. 3. `Collect BSP server metrics` ran with `if: always()` and shelled out to `./bleep` which doesn't exist when native-image failed. Falls back to the system bleep (`bleep` on PATH from bleep-setup-action) if the native binary isn't there. Windows step gets the same pattern via cmd `if exist`. * Fix Windows cross-drive manifest entries + raise default test idle timeout to 5min Two fixes from the latest CI: 1. Windows: GenNativeImage's manifest jar code did `manifestJar.getParent.relativize(path)` which throws IllegalArgumentException("'other' has different root") when classpath entries are on a different drive than the manifest jar — the default shape on GitHub Actions windows-latest where the workspace is on D:\ but the Coursier cache is on C:\\Users\\…\\Coursier. Fall back to a `file:` URI for those entries (modern JDKs accept absolute URIs in Class-Path manifest attributes). 2. Default test idle timeout: 2 → 5 min. Mac native-image runs idle out on Kotlin/Native compile tests that legitimately take longer than 2 minutes when Konan downloads + links without emitting interim events. KotlinNativeAdvancedIntegrationTest (3 tests, ~21s each on warm cache) and LinkExecutorIntegrationTest's Kotlin Native test all sat right at the 2-min ceiling. 5 min covers the worst case we see with margin; override via `~/.config/bleep/config.yaml`. * Windows manifest absolute-path fallback + ignore the second cancel-race flake Two findings from the latest CI: 1. Windows native-image rejected the `file:` URI I used as the cross-drive fallback in the manifest jar's Class-Path attribute: java.nio.file.InvalidPathException: Illegal char <:> at index 4: file:///C:/Users/RUNNER~1/AppData/Local/Temp/scala3Runtime...jar GraalVM's `handleClassPathAttribute` does `Path.of(token)` on each entry, which doesn't parse URIs. Switch the cross-drive fallback to a plain forward-slashed absolute path (`C:/Users/.../foo.jar`) — that's what `Path.of` accepts on Windows. 2. arm64 ubuntu flaked on the "immediate cancel" cancel test. Same race as the already-ignored huge-source cancel: cancel can lose to a Zinc-returns-Ok-with-0-classes outcome and we report Ok instead of Cancelled. Real bug, tracked alongside its sibling. Ignored for now so arm64 ubuntu (which already cancels the four KotlinNative tests for the lack of an aarch64 prebuilt) doesn't flake the run on a separate issue. * Bump default test idle timeout 5 → 10 min for slow mac Konan runs 5 min was still tight on mac CI: LinkExecutorIntegrationTest's Kotlin/Native test hit 313s on mac-arm and 349s on mac-intel in back-to-back runs, both busy downloading the Konan prebuilt for the first time and emitting no intermediate progress events. The macOS GitHub Actions runners vary enough that 5 min sometimes fits and sometimes doesn't. 10 min keeps the safety net wide enough that genuine hangs still get killed, but gives the slow legitimate path margin. Override via ~/.config/bleep/config.yaml if you need tighter. * Revert DefaultTestIdleTimeoutMinutes 10 → 2 10-min default is a sign of papering over slow tests, not a healthy posture. Reverting to 2 min — the correct ceiling for "a single test should never sit silent that long". If a particular environment needs more (cold mac CI hitting first-time Konan download was the empirical trigger), override in `~/.config/bleep/config.yaml` per-environment. With the Konan tarball now flowing through `~/.cache/coursier/arc` and `coursier/cache-action@v8` snapshotting that dir between runs, subsequent CI runs should hit a warm cache and avoid the slow path entirely. Validating that on this push. * CI: configure test idle timeout per-environment, not in code `DefaultTestIdleTimeoutMinutes` stays at 2 min in code (the right posture). CI's `~/.config/bleep/config.yaml` now sets it to 10 min for both the `build` and `build-native-image` jobs — the Kotlin/Native LLVM bitcode link on a cold-ish runner legitimately exceeds 2 min and that's not a defect, it's just native compilation taking native time. Build job: merges the new timeout into the existing parallelism config. Native-image jobs: new step before the build step so any subsequent BSP server invocation (incl. the test step that comes after native-image is done) picks up the relaxed timeout. Note: Windows uses bash for this step since the path expansion needs `$HOME`. * CI: resolve bleep config path via `bleep config file --output raw` `~/.config/bleep/config.yaml` is the Linux XDG path; on macOS bleep reads `~/Library/Application Support/build.bleep/config.yaml` and on Windows `%APPDATA%\build\bleep\config\config.yaml`. The previous workflow step hardcoded the Linux path so the testIdleTimeoutMinutes override never took effect on mac runners — they happily timed out at 2 min default. Use `bleep config file --output raw` to print the actual path bleep will read from, and write the config there. Works cross-platform via bash (Git Bash is preinstalled on Windows runners). * IntegrationTestHarness: sanitize test names in temp-dir paths Test names with spaces / non-ASCII chars produced temp-dir paths like `/tmp/bleep-doc-E. clean → recompile rebuilds generated sources deterministically-…`. We've seen this same test get `rm -Rf` SIGKILLed (exit 137) on three different CI runs on three different platforms. JVM metrics show no heap pressure on the BSP server at the time, so it's likely the test-runner JVM hitting its 512MB cap and the kernel reaping its rm child as OOM cleanup. Keeping the path ASCII at least removes one source of noise; if the flake persists we can chase the real cause. * IntegrationTestHarness: pin inner BSP parallelism to 1, split slow ITs bleep-tests' outer `bleep test bleep-tests` runs effectiveParallelism = cores ForkedTestRunner JVMs in parallel. Each IT internally spins up an in-process BSP (`InProcessBspServer`) that creates its own `JvmPool.create(maxParallelism, …)`. Without an explicit cap the inner pool also defaults to cores, so a single IT could fork up to N more JVMs — cartesian explosion to N×N max. The trace evidence: during KspToyProcessorIT's 2-minute idle-timeout window, the OTLP trace showed 22+ concurrent ForkedTestRunner JVMs each at 300-900 MB RSS. That's what was starving four heavy ITs (KspToyProcessorIT, YourFirstScalaProjectIT, SourcegenIT, SourcegenKotlinIT) into the suite-idle timeout — they're fine standalone (5-35 s) but couldn't make progress fast enough under that JVM pressure to emit a test event before the timer fired. Fix: pin testConfig.bspServerConfig.parallelism = Some(1) in IntegrationTestHarness. Result: full bleep-tests run went from 234 passing + 4 timing out in ~351 s → 246 passing, 0 timing out in 161 s. The IT splits (SourcegenIT, SourcegenKotlinIT, YourFirstScalaProjectIT) are kept because they're semantically cleaner — smaller test methods give better failure attribution and timer-reset granularity — even though the parallelism fix made them no longer load-bearing for the timeout. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * CI: bump native-image timeout 25 → 40 minutes macos-latest (arm64) cancelled at 25:19 mid native-image build under the prior 25-minute ceiling, before the test phase even started. Other arches finish in 13-20 min, but mac-arm needs the headroom. Split out of the (dropped) `CI: collect + upload server metrics` commit so we keep just the timeout bump without the observability infrastructure on this branch. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * SnapshotTest.gitWithRetry: retry git on transient .git/index.lock collision Under heavy parallel-suite execution (10+ test runner JVMs forked from `bleep test bleep-tests`), the snapshot suites (`RewriteSnapshotTest`, `IntegrationSnapshotTests`, `CreateNewSnapshotTests`, `TemplateTest`) all do `git add` against the outer bleep repo's `.git/index`. They serialize among themselves via `GitLock` (a cross-process `FileChannel.lock()` on `.git/bleep-test.lock`), but other writers we can't lock against — the test- host JVM's `ProjectDigest.gitDirtyPaths` doing `git status --porcelain` (refreshes the stat cache, takes index.lock briefly), or an editor / shell the developer happens to have open — can still race. Add an exponential-backoff retry around git invocations that catches `BleepException.Text` whose message contains "index.lock". 10 attempts, base 100ms, so worst case ~5.5s before giving up. Any other git failure (real diff mismatch, missing path, real error) propagates on the first attempt. Both `git add` and `git diff` in `writeAndCompare` go through the same helper. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * BuildDisplay: remove ryddig progressMonitor line-redraw The "Compiling X: started, Y: 14%, Z: 67%" line that BuildDisplay used to push through ryddig's `progressMonitor` was a single in-place updating line. In a terminal it looks nice; in CI logs it leaks `\x1b[K` (ANSI erase-to-end-of-line) escapes on every refresh, producing visible garbage when GitHub Actions captures the line-by-line output. The TUI's full-screen mode is already auto-disabled in CI; this was the leftover bit. The per-event log lines we already emit cover the same lifecycle: - `🔨 compiling (...)` via `CompilationReason` — what kicked the build off - `📦 read analysis / analyzed / compiled / saved analysis (...ms)` — phases - `✅ compiled (...ms)` or `❌ compile failed` via `CompileFinished` Removed: - `activeCompileProgress` mutable map - `lastProgressLine` var - `progressMonitor: Option[LoggerFn]` lookup - `renderCompileProgress()` function - Calls from `CompileStarted`/`CompileFinished`/`CompileProgress` - Now-unused `ryddig.{LoggerFn, TypedLogger}` import `CompileStarted` is now a no-op (the meaningful start is logged from `CompilationReason`); `CompileProgress` is dropped on the floor. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * TestRunner: inject NO_COLOR=1 into forked test JVMs ScalaTest 3.2.16+ honors the no-color.org `NO_COLOR` env var; JUnit, JUnit 5, sbt, gradle, mill, and most other JVM test frameworks do too. Inject it into every forked test-runner JVM's environment so test output captured in CI logs or bleep's server-metrics dashboard is plain text instead of ANSI-decorated. A project-supplied `platform.jvmEnvironment.NO_COLOR` overrides this default (Map.++ right-bias), so anyone who really wants colored test output can set it empty in their bleep.yaml. Done at `computeTestEnvironment` — one place, hits every test JVM. Other forked subprocesses (KSP runner, native-image, …) are a follow-up if needed, but test output is the noisiest channel in CI captures. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * Subprocess forks: default NO_COLOR=1, centralized at the spawn primitives Three forking entry points cover every subprocess bleep spawns: 1. `BspServerOperations.startServer` — CLI → BSP daemon. Setting NO_COLOR on the daemon's own env propagates to all of its children via ProcessBuilder's default env-copy behavior, including the few sites that use raw `scala.sys.process.Process` (e.g. `ProjectDigest`'s `git status`). 2. `ProcessRunner.start` — all KSP / Kotlin & Scala JS-Native linkers / node / tar / native-image forks route through here. 3. `JvmPool` test-runner fork — direct `ProcessBuilder.start()`, doesn't go through ProcessRunner. All three now `pb.environment().putIfAbsent("NO_COLOR", "1")`. `putIfAbsent` preserves an explicit override (a project's `platform.jvmEnvironment.NO_COLOR`, or the parent's inherited setting if a developer wants color in some specific case). ScalaTest 3.2.16+, JUnit, JUnit 5, sbt, gradle, mill, kotlinc/KSP, GraalVM native-image, and most other JVM-side tools honor `NO_COLOR=1` per no-color.org. End result: clean text in CI log captures and bleep's own subprocess output panels. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * PreBootstrapOpts: honor NO_COLOR env var (no-color.org) Any non-empty `NO_COLOR` env var disables ANSI in bleep's own logger, matching the no-color.org standard. Explicit `--no-color` on the CLI still wins (sets the same flag deterministically). Why this matters now: the BSP daemon's child sourcegen-script JVMs inherit NO_COLOR=1 from the daemon's env (added in the previous commit), but their PreBootstrapOpts.parse only looked at command-line args — they had no flag, so they emitted colored/emoji output that the daemon forwarded through to the CLI as ANSI-decorated text. Now those forked scripts auto-detect NO_COLOR=1 from env and use the plain log pattern. Same chain: parent CLI's --no-color → NO_COLOR=1 in daemon env → inherited by script forks → PreBootstrapOpts.parse picks up env → script logger uses plain bracket prefixes. End to end, no ANSI leakage. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * DisplayMode: --no-color / NO_COLOR also disables the TUI A TUI is a colored fullscreen interface — running one when the user asked for no colors is the wrong answer. Make `DisplayMode.fromFlags` consult both the `--no-tui` flag and a new JVM-local "no-color was requested" marker that `PreBootstrapOpts.parse` sets when it sees `--no-color` or a non-empty `NO_COLOR` env var. Either route downgrades to `NoTui`. `PreBootstrapOpts.noColorRequested` exposes the same answer to anyone in the same JVM that needs it (the chief reader being `DisplayMode.fromFlags`; the existing `LoggingOpts.noColor` already covers the logger). The marker is a `bleep.noColor` system property set by `parse` so each invocation reflects its own state without re-parsing args. Reported: `./bleep-cli.sh test --no-color` still ran the TUI. After this, the same command renders plain log lines. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * BleepConsole: ANSI-toggle wrapper that respects no-color Three files baked ANSI directly into log message strings (`s"\${C.RED}foo\${C.RESET}"`) via `scala.Console`: `BuildDisplay`, `ReactiveBsp`, `CompileDisplay`. The ryddig log pattern's `noColor` only strips ANSI it adds itself — it doesn't strip what's already in the message body — so these survived `--no-color`. New `bleep.testing.BleepConsole` mirrors the `scala.Console` field surface but returns "" when no-color is in effect (per `PreBootstrapOpts.noColorRequested`). The existing imports flip from `scala.{Console => SConsole/C}` to `bleep.testing.BleepConsole as SConsole/C` — every call site continues to write `SConsole.RED` / `C.GREEN`, just now ANSI-free in no-color mode. The `on` flag is a class-loading-time val so it captures whatever `PreBootstrapOpts.parse` decided. Pre-parse runs at the start of every bleep JVM invocation before these objects are touched. End-to-end with this + previous commits: --no-color → PreBootstrapOpts marks JVM no-color → - bleep's logger pattern: no ANSI prefix - DisplayMode.fromFlags: NoTui - BuildSummary / per-test / per-suite messages: no ANSI - daemon/script/test-runner forks: NO_COLOR=1 in env Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * model.Project: add testTags field for cross-framework test tagging A `JsonMap[String, JsonSet[String]]` field carrying tag-name → FQDN-pattern mappings. Filtered at suite-dispatch in the BSP server (next commit), so the mechanism is framework-independent: works for ScalaTest, JUnit, MUnit, utest, anything the test runner discovers. Method-level tagging is out — tag at the class level, with `*` / `**` glob patterns for convention tags like "all ITs". Just the model + codec plumbing in this commit. SetLike methods (intersect / removeAll / union / isEmpty) and `empty` all extended with the new field. Codec is derived; new field surfaces automatically in the JSON schema regeneration. CLI surface (next commits): `bleep test --only-tag slow --exclude-tag flaky`, mirroring the existing `--only` / `--exclude` regex flags. Open-ended tag namespace; case-sensitive lowercase recommended. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * TestTagFilter: glob-pattern test-suite filter + ProjectGlobs.testTagsMap Pure filter logic for the test-tagging feature, separated from BSP dispatch: - `compileGlob(pattern)` — single `*` stays within an FQDN segment (no dots), `**` spans dots. Regex metachars are escaped for plain segments. `bleep.foo.*Test` matches `bleep.foo.Bar` but not `bleep.foo.bar.Bar`; `**IT` matches any FQDN ending in IT regardless of package depth. - `tagsFor(suite, manifest)` — returns the set of tags that apply to a given suite FQDN given the project's testTags map. - `filter(suites, manifest, includeTags, excludeTags)` — applies the selection semantics: empty includes → all; non-empty includes → union of matching tags (untagged suites are dropped when an include is set); excludes always subtract. - `staleManifestEntries(manifest, discovered)` — surfaces patterns that match no discovered suite, for the validation warnings the user wanted in the build summary. ProjectGlobs gets a `testTagsMap` member: union of every `testTags` key across all build projects, in the shape decline's `Argument.fromMap` wants for tab-completion + value validation. 12 unit tests covering all glob/filter/validation paths. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * Test tags: wire --only-tag/--exclude-tag through CLI + BSP + list-tests Adds the user-facing surface for the testTags manifest already declared on model.Project. Flags work for any test framework because filtering happens at bleep's suite-dispatch boundary in MultiWorkspaceBspServer, not via framework- native tags. - BleepBspProtocol.TestOptions gains includeTags/excludeTags fields - ReactiveBsp threads them through; runOnce prunes candidate projects whose testTags declare none of the requested includes (saves compile work) - MultiWorkspaceBspServer.discoverHandler applies TestTagFilter.filter on discovered suites against the project's testTags manifest - Main.scala adds --only-tag/--exclude-tag with Argument.fromMap over ProjectGlobs.testTagsMap: strict validation + tab-completion - ListTests annotates each discovered suite with matching tags and warns about stale manifest entries Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * Tag *IT as slow; exclude from native-image test runs - bleep.yaml: bleep-tests gets `testTags.slow: ["**IT"]`. Every IT-suffixed test in this project extends IntegrationTestHarness and spins up an in-process bleep-bsp running real builds end-to-end. 32 classes total. - schema.json: hand-add testTags property under Project (yaml-ls-check reads schema.json, so failing to update it would warn on the new field). - .github/workflows/build.yml: native-image jobs (ubuntu x86_64 + windows) now pass `--exclude-tag slow` to skip the IT bracket. Those jobs exist to validate that the produced binary runs, not to re-exercise the test surface. The `build` job is the canonical full-suite gate and continues to run everything. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * Tag filter: integration tests + crystal-clear error messages When a tag-related filter is misconfigured, the user used to get either no feedback (silent project drop) or a one-liner that lied about "Available suites" (it listed everything, ignoring what the tag filter had already removed). Now the error walks through the pipeline so you can tell exactly which stage emptied the set. Sample error for `--only-tag slow` against a project whose only suite is untagged: --only-tag matched no test suites in mytest (--only-tag slow): 1 discovered → 0 after tag filter. Tags declared in mytest: slow Suites that survived --only/--exclude (none matched the tag filter): example.FastTest The CLI also logs a one-line "pre-filtered N project(s)" notice when `--only-tag` drops projects before BSP dispatch, so users notice why their explicitly-listed project was skipped. Tests: - TestTagsIT (new, 5 cases): --only-tag runs only tagged; --exclude-tag drops tagged while keeping untagged; --only + --only-tag = AND semantics; empty-result error wording; project pre-filter doesn't throw, surfaces as info log. - Commands.test API extended with includeTags/excludeTags (no defaults); all 12 existing callers updated to pass None. - JCommands (Java surface) also updated. - Error path: tag-side empty triggers the same TaskResult.Failure path --only used to own, with a richer message; --exclude-tag emptying the set is intentional and stays silent. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * Always show filter accounting in test summary When a filter (--only, --exclude, --only-tag, --exclude-tag) is active OR when --only-tag pre-filtered any project, the summary now ends with two new lines under the existing Tests/Suites/Duration block: Projects: 1/2 selected (1 pre-filtered by --only-tag slow: bleep-bsp-tests) Filters active: --only NoSuchTest · --only-tag slow "N/M selected" is in CrossProjectName terms — i.e. post-glob-expansion — because that's the layer ReactiveBsp lives at. The user's typed globs (jvm3, prefixes) are resolved by ProjectGlobs upstream, so they're not preserved at this layer; the documentation on FilterContext spells this out. Plumbing: - New FilterContext case class in BuildDisplay.scala. - BuildSummary gains `filterContext: Option[FilterContext]` (required field, defaults to None at every construction site per the no-defaults rule). - BuildDisplay.printSummary signature changes to take `Option[FilterContext]`; both real impls plus the legacy ReactiveTestRunner path updated. - ReactiveBsp builds the context in runOnce and threads it through runInProcess / runWithBleepBsp / printFinalSummary. - BuildSummary.formatSummary renders the two new lines only when the filter did something the user might want to see. Tests: TestTagsIT gains "summary reports projects-selected ratio..." plus log assertions on the new lines for existing scenarios. Renamed one earlier IT to drop a `/` that broke Files.createTempDirectory. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * docs: add test-tags usage page Covers the testTags manifest syntax (glob semantics, single vs array values), CLI surface (--only-tag / --exclude-tag with union/subtractive rules + strict validation), project pre-filter optimization, list-tests inspection, summary diagnostics, the multi-stage pipeline error wording, the CI recipe that bleep itself uses for fast per-arch native-image validation, and a comparison table against framework-native tagging. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * Pass testTags to Project(...) in importer/generator call sites The model.Project case class gained a `testTags: JsonMap[String, JsonSet[String]]` field in 3d68163. The model file and the bleep.yaml-driven test projects compiled clean locally because Zinc cached the importer/generator translation units. CI cold-builds, surfacing four sites that construct Project explicitly: - bleep-cli/src/scala/bleep/mavenimport/buildFromMavenPom.scala (main + test) - bleep-cli/src/scala/bleep/mavenimport/generateBuildFromMaven.scala (scripts) - bleep-cli/src/scala/bleep/sbtimport/generateBuild.scala (scripts) - bleep-cli/src/scala/bleep/sbtimport/buildFromBloopFiles.scala (per-cross) All four now pass `testTags = model.JsonMap.empty` in the correct position. While here, type-annotate the bare `JsonSet.empty` calls in two of the same files — without an inferrable expected type the Ordering instance was ambiguous (Short vs Int both match Ordering[Any]) once shifted by the new field's position. * BuildCreateNew: pass testTags + type-annotate JsonSet.empty calls Same fix as the importer/generator commit (8265f9d) for the two `model.Project(...)` call sites in BuildCreateNew (empty + main proj). * GenNativeImage: add -Ob quick-build for non-release builds GraalVM's `-Ob` (alias `-O0`) skips advanced inlining / escape-analysis / etc., trading runtime performance for 30-50% faster build. This is the right trade for every non-release native-image invocation: PR / master matrix runs (binary gets thrown away after the test step) and local `bleep native-image` (testing, not benchmarking). Release tag builds keep full `-O2` (default). Signal: `GITHUB_REF` env var startswith `refs/tags/v`, same condition the `release` job in build.yml uses to gate itself. The chosen mode is logged at the top of each build so a reviewer can confirm which mode produced a given artifact: native-image build mode [GITHUB_REF => refs/heads/master, mode => -Ob (quick build, snapshot/PR/local)] Targets the macos-latest (arm64, 3 cpu / 7 GB) runner which was spending ~17 min in `native-image` proper. With -Ob that should drop closer to ~10-12 min; full job time from 35 min toward ~25. Local: `bleep compile` clean, `bleep test` 793/793 pass. --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
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.
Summary
Windows support (primary)
"file://" + pathstring concatenation withPath.toUri(). The old pattern produced illegal URIs on Windows (backslashes). Fixed in BuildLoader (4 sites), BspServer, MultiWorkspaceBspServer, and CoursierResolver.PlainVirtualFile.id()so Zinc's javac pipeline can match class names to filenames..bleep-lockfromtarget/classes/totarget/— Windows mandatory file locks blocked Zinc from scanning class files in the same directory.ProjectLockretries with backoff when another process holds the lock file.-source 8 -target 8: bleep-test-runner no longer targets ancient Java, uses-proc:nonelike other projects.Compile progress & TUI
CompilationProgressAPI, giving per-file progress and cooperative cancellation for Java compilation.Thread.interrupt()ECJ threads — Java NIO closes channels on interrupt, poisoning JDK-levelZipFileSystemcache. UseCompilationProgress.isCancelled()instead.[client => N]vialogger.withContextso multi-client log interleaving is distinguishable.Interrupted compilation detection
Test plan
EcjCompilationProgressBridgeTest)ClosedChannelException🤖 Generated with Claude Code