diff --git a/.github/scripts/bleep-version.sh b/.github/scripts/bleep-version.sh new file mode 100755 index 000000000..cb89c94b6 --- /dev/null +++ b/.github/scripts/bleep-version.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +# Print the version this build will bake into the client, i.e. `model.BleepVersion.current`. +# +# Every publish in build.yml has to name this exact version. The client asks Coursier for `build.bleep:bleep-bsp` at the +# version compiled into it, so publishing under any other coordinate produces a binary that resolves nothing — and +# nothing fails until someone runs it. +# +# It is read out of the sourcegen output rather than recomputed with dynver, because recomputing is how the two drift: +# dynver appends a timestamp on a dirty tree, so a second derivation of "the same" version need not agree with the one +# already compiled in. +# +# This lives in one place because it previously did not. Four steps each carried their own copy of the grep, all naming +# the pre-1.0.0-M11 layout (`.bleep/generated-sources//...`), and when the bootstrap moved to a bleep that +# writes the current layout (`.bleep/projects//generated-sources/...`) every one of them silently matched +# nothing at once. + +set -uo pipefail + +version_file=".bleep/projects/bleep-model/generated-sources/bleep.scripts.GenerateResources/bleep/model/BleepVersion.scala" + +if [ ! -f "$version_file" ]; then + echo "::error::$version_file does not exist — run 'bleep sourcegen' before this step. (If the layout moved again, this script is what needs updating.)" >&2 + exit 1 +fi + +version=$(grep 'val current' "$version_file" | sed 's/.*BleepVersion("\(.*\)").*/\1/') + +# An empty version is the dangerous case, not a loud one: passed to `--version ""` it publishes under whatever the +# fallback picks, and the mismatch only surfaces when a binary later fails to resolve its own server. +if [ -z "$version" ]; then + echo "::error::could not parse a version out of $version_file" >&2 + exit 1 +fi + +echo "$version" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f07d9028c..690820b60 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -45,7 +45,7 @@ jobs: bleep sourcegen bleep compile # publish locally so the dev script's BSP server uses our code - bleep publish-local --groupId build.bleep --version "$(grep 'val current' .bleep/generated-sources/bleep-model/bleep.scripts.GenerateResources/bleep/model/BleepVersion.scala | sed 's/.*BleepVersion("\(.*\)").*/\1/')" + bleep publish-local --groupId build.bleep --version "$(bash .github/scripts/bleep-version.sh)" bleep config compile-server stop-all bleep setup-dev-script bleep-cli @@ -78,7 +78,7 @@ jobs: # Without it the version comes from dynver at runtime, which appends a timestamp when the working tree is # dirty — and the artifact would then be published under a version no binary asks for. The jars are only # useful paired with a binary that names them, so this cannot be left to depend on the tree being clean. - version=$(grep 'val current' .bleep/generated-sources/bleep-model/bleep.scripts.GenerateResources/bleep/model/BleepVersion.scala | sed 's/.*BleepVersion("\(.*\)").*/\1/') + version=$(bash .github/scripts/bleep-version.sh) ./bleep-cli.sh --dev publish local-ivy --to dev-jars --version "$version" --no-tui echo "$version" > dev-jars/VERSION echo "version: $version" @@ -304,7 +304,7 @@ jobs: run: | bleep sourcegen bleep compile bleep-cli - bleep publish-local --groupId build.bleep --version "$(grep 'val current' .bleep/generated-sources/bleep-model/bleep.scripts.GenerateResources/bleep/model/BleepVersion.scala | sed 's/.*BleepVersion("\(.*\)").*/\1/')" + bleep publish-local --groupId build.bleep --version "$(bash .github/scripts/bleep-version.sh)" bleep config compile-server stop-all # Windows-only and genuinely so: mandatory file locks. `compile-server stop-all` can fail to remove socket directories while a JVM still holds them, @@ -425,7 +425,7 @@ jobs: run: | bleep sourcegen bleep compile bleep-cli - bleep publish-local --groupId build.bleep --version "$(grep 'val current' .bleep/generated-sources/bleep-model/bleep.scripts.GenerateResources/bleep/model/BleepVersion.scala | sed 's/.*BleepVersion("\(.*\)").*/\1/')" + bleep publish-local --groupId build.bleep --version "$(bash .github/scripts/bleep-version.sh)" bleep config compile-server stop-all - name: Download artifacts uses: actions/download-artifact@v8 diff --git a/bleep-model/src/scala/bleep/BuildPaths.scala b/bleep-model/src/scala/bleep/BuildPaths.scala index cbf4c8331..e6d1d221a 100644 --- a/bleep-model/src/scala/bleep/BuildPaths.scala +++ b/bleep-model/src/scala/bleep/BuildPaths.scala @@ -113,23 +113,6 @@ case class BuildPaths(cwd: Path, bleepYamlFile: Path, variant: model.BuildVarian case None => if (scalaVersion.isDefined) model.SourceLayout.Normal else model.SourceLayout.Java } - // Legacy v1 layout fallback for sourcegen outputs. A bleep build that's still on the released `build.bleep:bleep-core:` writes generated - // sources to `.bleep/generated-sources///`. The forked sourcegen subprocess fetches its bleep-core from Maven (per `BLEEP_VERSION` - // substitution), so during CI on a fresh checkout it gets the released M9 layout. The bleep-server in this PR uses v2 layout - // (`.bleep/projects//generated-sources//`). Without this fallback the v2-layout-aware source list misses the v1-written files and the - // compile fails with "Not found: type BleepVersion" or similar. - // - // Gated on `Files.isDirectory` so fresh builds (snapshot tests, `bleep new` workspaces) — which have no M9-generated content — don't see these phantom - // paths in their bloop.json. Once a v2-aware bleep is shipping everywhere and no v1 dirs survive bootstraps, this whole block can go. - def legacyGeneratedSourcesDir(folderName: String): Option[Path] = { - val p = dotBleepDir / "generated-sources" / crossName.value / folderName - if (java.nio.file.Files.isDirectory(p)) Some(p) else None - } - def legacyGeneratedResourcesDir(folderName: String): Option[Path] = { - val p = dotBleepDir / "generated-resources" / crossName.value / folderName - if (java.nio.file.Files.isDirectory(p)) Some(p) else None - } - val sources = { val fromSourceLayout = sourceLayout.sources(scalaVersion, maybePlatformId, p.`sbt-scope`).values.map(dir / _) val fromJson = p.sources.values.map(relPath => (relPath, dir / replacements.fill.relPath(relPath))).toMap @@ -143,10 +126,7 @@ case class BuildPaths(cwd: Path, bleepYamlFile: Path, variant: model.BuildVarian val base = generatedSourcesDir(crossName, "ksp") List(base / "kotlin", base / "java") } - // Append v1-layout sourcegen paths to ksp (which is just an opaque List[Path] in DirsByOrigin). Wrong field semantically, but it threads through .all - // without changing the ADT — the legacy fallback is temporary anyway. - val legacySourcegen = p.sourcegen.values.iterator.flatMap(s => legacyGeneratedSourcesDir(s.folderName)).toList - ProjectPaths.DirsByOrigin(fromSourceLayout, fromJson, generated, annotationProcessing, ksp ++ legacySourcegen) + ProjectPaths.DirsByOrigin(fromSourceLayout, fromJson, generated, annotationProcessing, ksp) } val resources = { @@ -156,8 +136,7 @@ case class BuildPaths(cwd: Path, bleepYamlFile: Path, variant: model.BuildVarian // KSP resources land at .bleep/projects//generated-sources/ksp/resources/; expose them so they're packaged like normal resources. val ksp: List[Path] = p.kotlin.filter(_.hasSymbolProcessing).toList.map(_ => generatedSourcesDir(crossName, "ksp") / "resources") - val legacySourcegenResources = p.sourcegen.values.iterator.flatMap(s => legacyGeneratedResourcesDir(s.folderName)).toList - ProjectPaths.DirsByOrigin(fromSourceLayout, fromJson, generated, None, ksp ++ legacySourcegenResources) + ProjectPaths.DirsByOrigin(fromSourceLayout, fromJson, generated, None, ksp) } ProjectPaths(dir = dir, targetDir = targetDir, sourcesDirs = sources, resourcesDirs = resources, isTestProject = p.isTestProject.getOrElse(false)) diff --git a/bleep.yaml b/bleep.yaml index 3be2026fb..11d989fad 100644 --- a/bleep.yaml +++ b/bleep.yaml @@ -1,5 +1,5 @@ $schema: https://raw.githubusercontent.com/oyvindberg/bleep/master/schema.json -$version: 1.0.0-M9 +$version: 1.0.0-M11 jvm: # TODO: graalvm-community:25.0.2 is not available for macos-15-intel (x86_64) in coursier's JVM index. # Need to either wait for index update, pin x86 macOS to 25.0.1, or drop x86 macOS CI. @@ -375,7 +375,18 @@ projects: enabled: false sources: ./src/main/java scripts-init: - dependencies: build.bleep::bleep-plugin-dynver:${BLEEP_VERSION} + # bleep-core is declared explicitly rather than arriving through the dynver plugin. Until 1.0.0-M11 it came for free, + # because bleep-plugin-dynver depended on bleep-core; #591 merged the sbt-pgp/sonatype/ci-release sources INTO + # bleep-core to break a cycle, which flipped that edge — bleep-core now depends on bleep-plugin-dynver. So the M11 + # dynver POM lists no bleep-core at all, and GenerateResources died at fork time with + # `NoClassDefFoundError: bleep/BleepCodegenScript$Target` while still compiling cleanly, because the script's compile + # classpath and the forked runtime classpath are built from different things. + # + # This project cannot `dependsOn: bleep-core` like every other script project: it sourcegens BleepVersion.scala FOR + # bleep-model, which bleep-core depends on, so an in-tree edge would be circular. It has to resolve a published one. + dependencies: + - build.bleep::bleep-plugin-dynver:${BLEEP_VERSION} + - build.bleep::bleep-core:${BLEEP_VERSION} extends: - template-common - template-scala-3