diff --git a/.github/workflows/prep_release.yml b/.github/workflows/prep_release.yml index af1377997..94efb1936 100644 --- a/.github/workflows/prep_release.yml +++ b/.github/workflows/prep_release.yml @@ -2,17 +2,21 @@ name: Prepare Viash Release on: workflow_dispatch: - + jobs: - build-and-release: + build-jar: runs-on: ubuntu-latest permissions: - contents: write + contents: read + + outputs: + viash_version: ${{ steps.get_version.outputs.viash_version }} + changelog_section: ${{ steps.get_version.outputs.changelog_section }} steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Set up JDK 17 uses: actions/setup-java@v5 @@ -43,26 +47,142 @@ jobs: echo "Detected Viash version: $viash_version" echo "Detected Viash minor version: $viash_minor_version" echo "viash_version=$viash_version" >> "$GITHUB_OUTPUT" - + # fetch relevant changelog section changelog_section=$(awk "/# Viash ${viash_version}.*/{flag=1;print;next}/^# /{flag=0}flag" CHANGELOGS/CHANGELOG_${viash_minor_version}.md) - + echo "changelog_section<> "$GITHUB_OUTPUT" echo "$changelog_section" >> "$GITHUB_OUTPUT" echo "GITHUB_EOF" >> "$GITHUB_OUTPUT" + - name: Extract fat JAR + run: | + cp target/viash.jar viash.jar + + - name: Upload JAR artifact + uses: actions/upload-artifact@v4 + with: + name: fat-jar + path: viash.jar + retention-days: 1 + + - name: Upload release assets + uses: actions/upload-artifact@v4 + with: + name: release-assets + path: | + bin/viash + bin/schema.json + bin/viash_install + retention-days: 1 + + build-native: + needs: build-jar + strategy: + fail-fast: false + matrix: + include: + - os: macos-15-intel + label: macos-x86_64 + - os: macos-15 + label: macos-aarch64 + - os: ubuntu-latest + label: linux-x86_64 + - os: ubuntu-24.04-arm + label: linux-aarch64 + + runs-on: ${{ matrix.os }} + + permissions: + contents: read + + steps: + - name: Download JAR + uses: actions/download-artifact@v4 + with: + name: fat-jar + + - name: Set up GraalVM + uses: graalvm/setup-graalvm@v1 + with: + java-version: '21' + distribution: 'graalvm' + + - name: Build native image + run: | + native-image -jar viash.jar \ + --no-fallback \ + -H:+ReportExceptionStackTraces \ + --initialize-at-build-time=scala,org.rogach.scallop \ + --enable-url-protocols=https \ + -o viash + + - name: Smoke test + run: | + ./viash --version + + - name: Upload native binary + uses: actions/upload-artifact@v4 + with: + name: viash-${{ matrix.label }} + path: viash + retention-days: 1 + + create-release: + needs: [build-jar, build-native] + runs-on: ubuntu-latest + + permissions: + contents: write + + steps: + - name: Download release assets + uses: actions/download-artifact@v4 + with: + name: release-assets + path: release-assets + merge-multiple: true + + - name: Download native binaries + uses: actions/download-artifact@v4 + with: + pattern: viash-* + path: native-binaries + merge-multiple: false + + - name: Prepare release files + run: | + mkdir -p release + + # JAR-based executable (backward compatible) + cp release-assets/viash release/viash + cp release-assets/schema.json release/schema.json + cp release-assets/viash_install release/viash_install + + # Native binaries with platform suffixes + cp native-binaries/viash-linux-x86_64/viash release/viash-linux-x86_64 + cp native-binaries/viash-linux-aarch64/viash release/viash-linux-aarch64 + cp native-binaries/viash-macos-x86_64/viash release/viash-macos-x86_64 + cp native-binaries/viash-macos-aarch64/viash release/viash-macos-aarch64 + + chmod +x release/viash-* + - name: Create release uses: softprops/action-gh-release@v2 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - tag_name: ${{ steps.get_version.outputs.viash_version }} + tag_name: ${{ needs.build-jar.outputs.viash_version }} target_commitish: ${{ github.sha }} - name: Viash ${{ steps.get_version.outputs.viash_version }} - body: ${{ steps.get_version.outputs.changelog_section }} + name: Viash ${{ needs.build-jar.outputs.viash_version }} + body: ${{ needs.build-jar.outputs.changelog_section }} draft: true fail_on_unmatched_files: true files: | - bin/viash - bin/schema.json - bin/viash_install + release/viash + release/schema.json + release/viash_install + release/viash-linux-x86_64 + release/viash-linux-aarch64 + release/viash-macos-x86_64 + release/viash-macos-aarch64 diff --git a/build.sbt b/build.sbt index f6d96f08a..bfcc7d4d4 100644 --- a/build.sbt +++ b/build.sbt @@ -78,5 +78,41 @@ generateWorkflowHelper := { streams.value.log.info(s"Generated WorkflowHelper.nf at ${wfHelper.toAbsolutePath}") } +// Generate BuildInfo.scala with name and version baked in at compile time. +// The JAR manifest approach doesn't work in GraalVM native binaries. +Compile / sourceGenerators += Def.task { + val file = (Compile / sourceManaged).value / "io" / "viash" / "BuildInfo.scala" + IO.write(file, + s"""package io.viash + | + |object BuildInfo { + | val name: String = "${name.value}" + | val version: String = "${version.value}" + |} + |""".stripMargin) + Seq(file) +}.taskValue + assembly := ((assembly) dependsOn generateWorkflowHelper).value Test / testOptions := ((Test / testOptions) dependsOn generateWorkflowHelper).value + +// GraalVM native-image configuration +enablePlugins(NativeImagePlugin) + +Compile / mainClass := Some("io.viash.Main") + +nativeImageJvm := "graalvm-java21" +nativeImageVersion := "21.0.2" +Global / excludeLintKeys ++= Set(nativeImageJvm, nativeImageVersion) + +nativeImageOptions ++= Seq( + "--no-fallback", + "-H:+ReportExceptionStackTraces", + // Scala 3 lazy vals use reflection for bitmap fields (scala/scala3#13985). + // Initializing at build time lets reflection resolve during the build. + "--initialize-at-build-time=scala,org.rogach.scallop", + // viash downloads remote resources and version binaries over HTTPS + "--enable-url-protocols=https", +) + +nativeImage := ((nativeImage) dependsOn generateWorkflowHelper).value diff --git a/project/plugins.sbt b/project/plugins.sbt index ebefee87c..d92e40878 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,3 +1,4 @@ addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.1.1") addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.1.0") addSbtPlugin("de.heikoseeberger" % "sbt-header" % "5.9.0") +addSbtPlugin("org.scalameta" % "sbt-native-image" % "0.3.4")