diff --git a/.github/actions/chen-from-main/action.yml b/.github/actions/chen-from-main/action.yml index 80ad6f53..72bb14a7 100644 --- a/.github/actions/chen-from-main/action.yml +++ b/.github/actions/chen-from-main/action.yml @@ -45,8 +45,8 @@ runs: set -euo pipefail git clone --quiet --depth 1 --branch main https://github.com/AppThreat/chen.git "$CHEN_DIR" cd "$CHEN_DIR" - sbt ${IVY_HOME:+"-Dsbt.ivy.home=$IVY_HOME"} -batch \ - "set ThisBuild / Compile / packageDoc / publishArtifact := false" publishLocal + sbt --server ${IVY_HOME:+"-Dsbt.ivy.home=$IVY_HOME"} -batch \ + "set ThisBuild / Compile / packageDoc / publishArtifact := false; publishLocal" cd "$RUNNER_TEMP" rm -rf "$CHEN_DIR" - name: Publish chen main locally @@ -59,7 +59,7 @@ runs: git clone --quiet --depth 1 --branch main https://github.com/AppThreat/chen.git "$env:CHEN_DIR" if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } Push-Location "$env:CHEN_DIR" - sbt -batch "set ThisBuild / Compile / packageDoc / publishArtifact := false" publishLocal + sbt --server -batch "set ThisBuild / Compile / packageDoc / publishArtifact := false; publishLocal" if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } Pop-Location Remove-Item -Recurse -Force "$env:CHEN_DIR" diff --git a/.github/workflows/containers.yml b/.github/workflows/containers.yml index d006200c..cd9b44ab 100644 --- a/.github/workflows/containers.yml +++ b/.github/workflows/containers.yml @@ -108,7 +108,7 @@ jobs: lookup-only: true - uses: ./.github/actions/chen-from-main # temporary: remove once chen 4.0.0 is published - run: | - sbt stage createDistribution + sbt --server "stage; createDistribution" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Set up QEMU diff --git a/.github/workflows/nodejstests.yml b/.github/workflows/nodejstests.yml index 5785b40e..09393e8a 100644 --- a/.github/workflows/nodejstests.yml +++ b/.github/workflows/nodejstests.yml @@ -113,7 +113,7 @@ jobs: - uses: ./.github/actions/chen-from-main # temporary: remove once chen 4.0.0 is published - name: atom node tests run: | - sbt stage createDistribution + sbt --server "stage; createDistribution" python -m pip install atom-tools cd wrapper/nodejs bash build.sh @@ -204,7 +204,7 @@ jobs: - name: build shell: pwsh run: | - sbt stage createDistribution + sbt --server "stage; createDistribution" python -m pip install atom-tools cd wrapper\\nodejs .\build.ps1 diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 7e572002..d1cb2307 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -50,7 +50,7 @@ jobs: # Before `sbt test`: the workflow tests probe for the AST generators and cancel without # them, so a post-test install would silently skip the JavaScript (and Ruby) fixtures. - run: npm install -g @appthreat/atom-parsetools - - run: sbt -batch scalafmtCheck test stage createDistribution + - run: sbt --server -batch "scalafmtCheck; testFull; stage; createDistribution" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} JAVA_TOOL_OPTIONS: "-Dfile.encoding=UTF-8" @@ -127,7 +127,7 @@ jobs: # workflow tests probe for them and cancel without them, so a post-test install would # silently skip the JavaScript (and Ruby) reachables fixtures. npm install -g @appthreat/atom-parsetools - sbt scalafmtCheck test stage createDistribution + sbt --server "scalafmtCheck; testFull; stage; createDistribution" cd wrapper/nodejs bash build.sh npm install -g . diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 737f779c..260f0fea 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -48,8 +48,8 @@ jobs: - run: | Invoke-WebRequest -Uri https://github.com/upx/upx/releases/download/v5.0.1/upx-5.0.1-win64.zip -UseBasicParsing -OutFile upx-5.0.1-win64.zip Expand-Archive -Path upx-5.0.1-win64.zip -DestinationPath . -Force - sbt stage createDistribution - sbt "GraalVMNativeImage / packageBin" + sbt --server "stage; createDistribution" + sbt --server "GraalVMNativeImage / packageBin" .\target\graalvm-native-image\atom.exe --help cd target\graalvm-native-image (Get-FileHash -Algorithm SHA512 .\atom.exe).hash | Out-File -FilePath .\atom.exe.sha512 @@ -100,8 +100,8 @@ jobs: - run: | Invoke-WebRequest -Uri https://github.com/upx/upx/releases/download/v5.0.1/upx-5.0.1-win64.zip -UseBasicParsing -OutFile upx-5.0.1-win64.zip Expand-Archive -Path upx-5.0.1-win64.zip -DestinationPath . -Force - sbt stage createDistribution - sbt "GraalVMNativeImage / packageBin" + sbt --server "stage; createDistribution" + sbt --server "GraalVMNativeImage / packageBin" .\target\graalvm-native-image\atom.exe --help mv .\target\graalvm-native-image\atom.exe .\target\graalvm-native-image\atom-arm64.exe cd target\graalvm-native-image @@ -147,7 +147,7 @@ jobs: tar -xvf upx-5.0.1-amd64_linux.tar.xz chmod +x upx-5.0.1-amd64_linux/upx sudo cp upx-5.0.1-amd64_linux/upx /usr/local/bin/ - sbt stage createDistribution + sbt --server "stage; createDistribution" sha512sum target/atom.zip > target/atom.zip.sha512 bash ci/native-image.sh cp target/graalvm-native-image/atom target/graalvm-native-image/atom-amd64 @@ -157,7 +157,7 @@ jobs: sha512sum target/graalvm-native-image/atom-amd64 > target/graalvm-native-image/atom-amd64.sha512 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - run: sbt publish + - run: sbt --server publish if: startsWith(github.ref, 'refs/tags/') env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -231,7 +231,7 @@ jobs: tar -xvf upx-5.0.1-arm64_linux.tar.xz chmod +x upx-5.0.1-arm64_linux/upx sudo cp upx-5.0.1-arm64_linux/upx /usr/local/bin/ - sbt stage createDistribution + sbt --server "stage; createDistribution" bash ci/native-image.sh cp target/graalvm-native-image/atom target/graalvm-native-image/atom-arm64 /usr/local/bin/upx -9 --lzma target/graalvm-native-image/atom-arm64 @@ -294,7 +294,7 @@ jobs: - uses: ./.github/actions/chen-from-main # temporary: remove once chen 4.0.0 is published - run: | brew install coreutils - sbt stage createDistribution + sbt --server "stage; createDistribution" bash ci/native-image.sh cp target/graalvm-native-image/atom target/graalvm-native-image/atom-darwin-arm64 bash ci/native-smoke.sh target/graalvm-native-image/atom-darwin-arm64 @@ -464,7 +464,7 @@ jobs: sudo apt install -y zlib1g php-zip - name: Assemble JAR packages run: | - sbt stage createDistribution + sbt --server "stage; createDistribution" cd wrapper/nodejs # Unzips target/atom.zip and stamps the universal jar + jar-fallback packages. bash build.sh diff --git a/.github/workflows/repotests.yml b/.github/workflows/repotests.yml index e1ed540c..ec437a27 100644 --- a/.github/workflows/repotests.yml +++ b/.github/workflows/repotests.yml @@ -152,7 +152,7 @@ jobs: if: runner.os == 'macOS' - uses: ./.github/actions/chen-from-main # temporary: remove once chen 4.0.0 is published - run: | - sbt stage createDistribution + sbt --server "stage; createDistribution" python -m pip install atom-tools env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.scalafmt.conf b/.scalafmt.conf index 7abe433b..2cc2494b 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -17,12 +17,12 @@ rewrite.rules = [AvoidInfix] rewrite.avoidInfix.excludeFilters."+" = [ "map" ] rewrite.avoidInfix.excludePlaceholderArg = false -# sbt 1.x compiles build definitions with Scala 2.12 and Scala 3 syntax for imports and varargs +# sbt 2.x compiles build definitions with Scala 3 fileOverride { "glob:**/*.sbt" { - runner.dialect = scala212source3 + runner.dialect = scala3 } "glob:**/project/*.scala" { - runner.dialect = scala212source3 + runner.dialect = scala3 } } diff --git a/README.md b/README.md index 129239c9..65f25893 100644 --- a/README.md +++ b/README.md @@ -607,7 +607,7 @@ Install Java 21 Node.js > 21 ```shell -sbt clean stage scalafmt test createDistribution +sbt "clean; stage; scalafmt; testFull; createDistribution" cd wrapper/nodejs bash build.sh && sudo npm install -g . ``` diff --git a/build.sbt b/build.sbt index 3d03d458..38a7e740 100644 --- a/build.sbt +++ b/build.sbt @@ -1,7 +1,7 @@ name := "atom" ThisBuild / organization := "io.appthreat" ThisBuild / version := "4.0.0" -ThisBuild / scalaVersion := "3.9.0" +ThisBuild / scalaVersion := "3.10.0" val chenVersion = "4.0.0" @@ -97,7 +97,12 @@ Universal / mappings := (Universal / mappings).value.filterNot { enablePlugins(JavaAppPackaging, ClasspathJarPlugin, GraalVMNativeImagePlugin) -ThisBuild / licenses := List("MIT" -> url("https://opensource.org/license/MIT")) +// sbt 2 moves `target` to target/out/jvm/scala-/atom; atom.sh, CI and the release +// scripts expect the staged app and the native image where sbt 1 put them +Universal / UniversalPlugin.autoImport.stagingDirectory := baseDirectory.value / "target" / "universal" / "stage" +GraalVMNativeImage / target := baseDirectory.value / "target" / "graalvm-native-image" + +ThisBuild / licenses := List("MIT" -> uri("https://opensource.org/license/MIT")) Global / onChangedBuildSource := ReloadOnSourceChanges @@ -108,17 +113,18 @@ debianPackageDependencies := Seq("java21-runtime-headless") rpmVendor := "AppThreat" lazy val createDistribution = taskKey[File]("Create a complete atom distribution") -createDistribution := { +createDistribution := Def.uncached { val distributionFile = file("target/atom.zip") - val zip = (atom / Universal / packageBin).value - IO.copyFile(zip, distributionFile) + val zip = (atom / (Universal / packageBin)).value + // sbt 2 packages to virtual-file refs; materialize via the file converter + IO.copyFile(fileConverter.value.toPath(zip).toFile, distributionFile) println(s"created distribution - resulting files: $distributionFile") distributionFile } ThisBuild / resolvers ++= Seq( Resolver.mavenLocal, - Resolver.githubPackages("appthreat/chen"), + githubPackagesResolver("appthreat", "chen"), "Sonatype OSS".at("https://oss.sonatype.org/content/repositories/public"), "Atlassian".at("https://packages.atlassian.com/mvn/maven-atlassian-external"), "Gradle Releases".at("https://repo.gradle.org/gradle/libs-releases/") @@ -127,6 +133,14 @@ ThisBuild / resolvers ++= Seq( ThisBuild / versionScheme := Some("semver-spec") ThisBuild / Test / fork := true +// sbt 2 runs the suites of a forked test JVM in parallel by default; the chen frontends keep +// JVM-global state (soot's Scene, shared AST caches) that concurrent suites corrupt +ThisBuild / Test / testForkedParallel := false +// executeTests reads it through a dynamic task, which lintUnused cannot see +Global / excludeLintKeys += testForkedParallel +// sbt 2 packs test classes+resources into jars (exportJars := true); keep exploded dirs so +// tests can read their fixtures as plain files +ThisBuild / Test / exportJars := false // The PHP/Ruby frontends run in-process inside the forked test JVM and resolve their generator // binary from the environment, so propagate the generator overrides from the launching shell. ThisBuild / Test / envVars ++= @@ -146,9 +160,8 @@ wartremoverWarnings ++= Seq( Wart.TryPartial ) -githubOwner := "appthreat" -githubRepository := "atom" -githubSuppressPublicationWarning := true +githubOwner := "appthreat" +githubRepository := "atom" credentials += Credentials( "GitHub Package Registry", diff --git a/ci/native-image.sh b/ci/native-image.sh index 10fe104b..a0613473 100755 --- a/ci/native-image.sh +++ b/ci/native-image.sh @@ -3,7 +3,7 @@ # sdk use java 25.0.2-graalce echo "About to build the native image. This would take a few minutes ..." -sbt "GraalVMNativeImage / packageBin" +sbt --server "GraalVMNativeImage / packageBin" if [ -f "target/graalvm-native-image/atom" ]; then chmod +x target/graalvm-native-image/atom diff --git a/docs/docs/development.md b/docs/docs/development.md index ed5ccaad..898a1e43 100644 --- a/docs/docs/development.md +++ b/docs/docs/development.md @@ -9,7 +9,7 @@ Install Java 21 Node.js > 21 ```shell -sbt clean stage scalafmt test createDistribution +sbt "clean; stage; scalafmt; testFull; createDistribution" cd wrapper/nodejs bash build.sh && sudo npm install -g . ``` diff --git a/project/GithubPackages.scala b/project/GithubPackages.scala new file mode 100644 index 00000000..b9dcb8d0 --- /dev/null +++ b/project/GithubPackages.scala @@ -0,0 +1,44 @@ +import sbt.* +import sbt.Keys.* + +/** Publishes to and resolves from GitHub Packages, replacing the unmaintained + * `com.codecommit:sbt-github-packages` plugin, which has no sbt 2.x build. + * + * Keeps the same `githubOwner` / `githubRepository` settings and the same project settings the + * plugin applied: the publish target, the owner's package registry as a resolver, and the POM + * metadata. Credentials for "GitHub Package Registry" / maven.pkg.github.com are still supplied by + * build.sbt. + */ +object GithubPackages extends AutoPlugin { + + object autoImport { + val githubOwner = settingKey[String]("GitHub user or organization owning the repository") + val githubRepository = settingKey[String]("GitHub repository to publish to") + + /** The package registry of a GitHub owner, or of one of its repositories. */ + def githubPackagesResolver(owner: String, repository: String = "_"): MavenRepository = + s"GitHub Package Registry ($owner/$repository)" + .at(s"https://maven.pkg.github.com/$owner/$repository") + } + import autoImport.* + + override def requires: Plugins = plugins.JvmPlugin + override def trigger: PluginTrigger = allRequirements + + override def projectSettings: Seq[Setting[?]] = Seq( + publishTo := Some( + "GitHub Package Registry" + .at(s"https://maven.pkg.github.com/${githubOwner.value}/${githubRepository.value}") + ), + resolvers += githubPackagesResolver(githubOwner.value), + scmInfo := Some( + ScmInfo( + uri(s"https://github.com/${githubOwner.value}/${githubRepository.value}"), + s"scm:git@github.com:${githubOwner.value}/${githubRepository.value}.git" + ) + ), + homepage := Some(uri(s"https://github.com/${githubOwner.value}/${githubRepository.value}")), + pomIncludeRepository := (_ => false), + publishMavenStyle := true + ) +} diff --git a/project/build.properties b/project/build.properties index f693be1b..e9c24d71 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.13.0 \ No newline at end of file +sbt.version=2.0.10 \ No newline at end of file diff --git a/project/plugins.sbt b/project/plugins.sbt index 07bc8f60..d6a65abe 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,4 +1,5 @@ -addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.6.1") -addSbtPlugin("com.github.sbt" % "sbt-native-packager" % "1.11.3") -addSbtPlugin("com.codecommit" % "sbt-github-packages" % "0.5.3") -addSbtPlugin("org.wartremover" % "sbt-wartremover" % "3.6.2") +addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.6.2") +addSbtPlugin("com.github.sbt" % "sbt-native-packager" % "1.13.0") +addSbtPlugin("org.wartremover" % "sbt-wartremover" % "3.6.3") + +// sbt-github-packages has no sbt 2.x build; project/GithubPackages.scala covers it instead. diff --git a/wrapper/nodejs/build.ps1 b/wrapper/nodejs/build.ps1 index b8c87469..fac68348 100644 --- a/wrapper/nodejs/build.ps1 +++ b/wrapper/nodejs/build.ps1 @@ -1,13 +1,13 @@ # Assemble the local @appthreat/atom JAR packages from a freshly built distribution. # -# Prerequisite: run `sbt stage createDistribution` from the repo root first so that +# Prerequisite: run `sbt "stage; createDistribution"` from the repo root first so that # target/atom.zip exists. Native-binary packages are assembled separately in the # release workflow (see scripts/assemble.mjs). $ErrorActionPreference = "Stop" Set-Location $PSScriptRoot if (-Not (Test-Path ..\..\target\atom.zip)) { - Write-Error "Build the atom project using 'sbt stage createDistribution' before running this script" + Write-Error "Build the atom project using 'sbt `"stage; createDistribution`"' before running this script" exit 1 } diff --git a/wrapper/nodejs/build.sh b/wrapper/nodejs/build.sh index eaf9cd8b..20a3d18a 100755 --- a/wrapper/nodejs/build.sh +++ b/wrapper/nodejs/build.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash # Assemble the local @appthreat/atom JAR packages from a freshly built distribution. # -# Prerequisite: run `sbt stage createDistribution` from the repo root first so that +# Prerequisite: run `sbt "stage; createDistribution"` from the repo root first so that # target/atom.zip exists. This script unzips that distribution and stamps the # universal JAR package (@appthreat/atom-jar) plus the JAR-fallback platform # packages (darwin-amd64, windows-arm64, linux-arm64-musl). @@ -17,7 +17,7 @@ DIST_ZIP="../../target/atom.zip" PLUGINS_DIR="plugins" if [ ! -e "${DIST_ZIP}" ]; then - echo "Build the atom project using 'sbt stage createDistribution' before running this script" >&2 + echo "Build the atom project using 'sbt \"stage; createDistribution\"' before running this script" >&2 exit 1 fi