From 9dd237288d8ecb304e27ce0ce9febbe62af881de Mon Sep 17 00:00:00 2001 From: Giacomo Debidda Date: Mon, 7 Oct 2024 22:55:12 +0200 Subject: [PATCH 1/4] add script to register pod on local registry --- bb.edn | 4 +++ examples/jsoup.bb | 80 +++++++----------------------------------- examples/jsoup_repl.bb | 38 ++++++++++++++++++++ script/register.sh | 22 ++++++++++++ 4 files changed, 76 insertions(+), 68 deletions(-) create mode 100644 examples/jsoup_repl.bb create mode 100755 script/register.sh diff --git a/bb.edn b/bb.edn index 2c24409..d372345 100644 --- a/bb.edn +++ b/bb.edn @@ -95,6 +95,10 @@ :task (tasks/release! {:dry-run false :prerelease-type "RC"})} + register + {:doc "Download manifest.edn from GitHub Releases, then copy manifest.edn and examples to my local pod registry" + :task (shell "./script/register.sh")} + -resources {:task (shell "mkdir -p resources/img")} diff --git a/examples/jsoup.bb b/examples/jsoup.bb index d76750d..f5cb9c6 100755 --- a/examples/jsoup.bb +++ b/examples/jsoup.bb @@ -1,76 +1,20 @@ #!/usr/bin/env bb -(ns jsoup - (:require - [babashka.pods :as pods] - [cheshire.core :as json] - [clojure.edn :as edn] - [clojure.string :as str])) -;; Run this script with `bb -f examples/jsoup.bb` -;; Or make it executable with `chmod +x examples/jsoup.bb` and run it with `./examples/jsoup.bb` +(require '[babashka.http-client :as http]) +(require '[babashka.pods :as pods]) -(def project (-> (edn/read-string (slurp "deps.edn")) :aliases :neil :project)) -(def pod-spec (:name project)) -(def pod-id (name pod-spec)) -(def pod-name (str/replace pod-id #"\." "-")) -(def pod-version (:version project)) -;; (def pod-version "0.1.10") +;; Test me by running bb -f examples/jsoup.bb when registering this pod, then delete me. +;; (pods/load-pod "/home/jack/repos/pod-jackdbd-jsoup/target/pod-jackdbd-jsoup") -(def exe-file (format "target/%s" pod-name)) - -(pods/load-pod exe-file) -;; (pods/load-pod 'pod.jackdbd.jsoup "0.1.1") +;; Uncomment me when registering this pod. +;; (pods/load-pod 'com.github.jackdbd/jsoup "0.4.0") (require '[pod.jackdbd.jsoup :as jsoup]) -(def html (str/join "" ["" - "" - "" - " " - " Hello world" - "" - "" - "

Test world

" - "

This is foo

" - "

This is bar

" - "

This is another foo

" - "" - ""])) - -(def filepath "target/test-html.json") -(def parsed (jsoup/select html "div.foo")) -(spit filepath (json/generate-string {:html html :parsed parsed})) -(println (str "wrote " filepath)) - -(comment - ;; Run these commands in a Babashka REPL - (require '[babashka.pods :as pods]) - - (def project (-> (edn/read-string (slurp "deps.edn")) :aliases :neil :project)) - (def pod-spec (:name project)) - (def pod-id (name pod-spec)) - (def pod-name (str/replace pod-id #"\." "-")) - (def pod-version (:version project)) - - ;; Example 1: load the pod compiled as an uberjar - (def uber-file (format "target/%s-%s-standalone.jar" pod-id pod-version)) - (pods/load-pod ["java" "-jar" uber-file]) - - ;; Example 2: load the pod compiled as an executable with GraalVM native-image - (def exe-file (format "target/%s" pod-name)) - (pods/load-pod exe-file) - - ;; Example 3: load a pod that was published to the Babashka pod registry - ;; https://github.com/babashka/pod-registry - ;; https://clojars.org/com.github.jackdbd/pod.jackdbd.jsoup - (pods/load-pod pod-spec "0.1.10") - - (require '[pod.jackdbd.jsoup :as jsoup]) - (require '[babashka.http-client :as http]) +(def text (-> (http/get "https://clojure.org") + :body + (jsoup/select "div p") + first + :text)) - (-> (http/get "https://clojure.org") - :body - (jsoup/select "div p") - first - :text) - ) +(println text) diff --git a/examples/jsoup_repl.bb b/examples/jsoup_repl.bb new file mode 100644 index 0000000..ade8f60 --- /dev/null +++ b/examples/jsoup_repl.bb @@ -0,0 +1,38 @@ +#!/usr/bin/env bb +(ns jsoup-repl + (:require + [babashka.pods :as pods] + [clojure.edn :as edn] + [clojure.string :as str])) + +(comment + ;; Run these commands in a Babashka REPL + (require '[babashka.pods :as pods]) + + (def project (-> (edn/read-string (slurp "deps.edn")) :aliases :neil :project)) + (def pod-spec (:name project)) + (def pod-id (name pod-spec)) + (def pod-name (str/replace pod-id #"\." "-")) + (def pod-version (:version project)) + + ;; Example 1: load the pod compiled as an uberjar + (def uber-file (format "target/%s-%s-standalone.jar" pod-id pod-version)) + (pods/load-pod ["java" "-jar" uber-file]) + + ;; Example 2: load the pod compiled as an executable with GraalVM native-image + (def exe-file (format "target/%s" pod-name)) + (pods/load-pod exe-file) + + ;; Example 3: load a pod that was published to the Babashka pod registry + ;; https://github.com/babashka/pod-registry + ;; https://clojars.org/com.github.jackdbd/pod.jackdbd.jsoup + (pods/load-pod pod-spec "0.1.10") + + (require '[pod.jackdbd.jsoup :as jsoup]) + (require '[babashka.http-client :as http]) + + (-> (http/get "https://clojure.org") + :body + (jsoup/select "div p") + first + :text)) diff --git a/script/register.sh b/script/register.sh new file mode 100755 index 0000000..d1c3676 --- /dev/null +++ b/script/register.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +set -euo pipefail + +# https://github.com/jackdbd/pod-registry/tree/master?tab=readme-ov-file#registering-a-pod + +POD_REGISTRY="$HOME/repos/pod-registry" +ORG=com.github.jackdbd # Group ID +POD_NAME=jsoup +MANIFEST_DIR="$POD_REGISTRY/manifests/$ORG/$POD_NAME/$POD_VERSION" +EXAMPLES_DIR="$POD_REGISTRY/examples" + +echo "Download manifest.edn from GitHub release v$POD_VERSION" +gh release download "v$POD_VERSION" --clobber --pattern manifest.edn + +echo "Register pod $POD_NAME at $MANIFEST_DIR" +mkdir -p $MANIFEST_DIR +mv manifest.edn $MANIFEST_DIR + +echo "Copy examples/$POD_NAME.bb to $EXAMPLES_DIR" +cp "examples/$POD_NAME.bb" $EXAMPLES_DIR + +echo "TODO: commit to https://github.com/jackdbd/pod-registry/ and open a PR on https://github.com/babashka/pod-registry" From 8a1a0b92c7b2d31dec16928425a52210e9a7767e Mon Sep 17 00:00:00 2001 From: Giacomo Debidda Date: Tue, 8 Oct 2024 00:17:45 +0200 Subject: [PATCH 2/4] fix executable name in manifest.bb --- bb.edn | 4 ++++ bb/manifest.bb | 25 ++++++++++++++++--------- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/bb.edn b/bb.edn index d372345..0b37dd5 100644 --- a/bb.edn +++ b/bb.edn @@ -85,6 +85,10 @@ jar-path (format "target/%s-%s-standalone.jar" pod-name pod-version)] (shell "jar --file" jar-path "--list"))} + manifest + {:doc "Run the manifest.edn CLI" + :task (shell (into ["bb" "bb/manifest.bb"] *command-line-args*))} + prerelease {:doc "Increment current prerelease and publish it Clojars and GitHub Releases" :task (tasks/prerelease! {:dry-run false diff --git a/bb/manifest.bb b/bb/manifest.bb index d60fd7e..5891fa2 100644 --- a/bb/manifest.bb +++ b/bb/manifest.bb @@ -68,6 +68,11 @@ Babashka Pod registry manifest.edn generator Generate a manifest.edn to register your pod on the pod registry. + +WARNING: +If you simply need to update an existing manifest.edn, run the `upgrade-manifest.clj` script in the `pod-registry` repo instead! +bb script/upgrade-manifest.clj com.github.jackdbd/jsoup +https://github.com/babashka/pod-registry/pull/103#issuecomment-2397883424 Options: %s @@ -100,37 +105,39 @@ Examples: (let [opts (cli/parse-opts *command-line-args* {:spec spec :error-fn error-fn}) result (if (or (nil? *command-line-args*) (:help opts) (:h opts)) (help {:spec spec}) - (let [pod-id (:name opts) - pod-name (str/replace pod-id #"\." "-") + (let [pod-name (str/replace (:name opts) #"\." "-") + splits (str/split pod-name (re-pattern "/")) + bin-name (last splits) + version (:version opts) artifacts (cond-> [] (:linux-amd64 opts) (conj {:os/arch "amd64" :os/name "Linux.*" :artifact/url (:linux-amd64 opts) - :artifact/executable pod-name}) + :artifact/executable bin-name}) (:macos-aarch64 opts) (conj {:os/arch "aarch64" :os/name "Mac.*" :artifact/url (:macos-aarch64 opts) - :artifact/executable pod-name}) + :artifact/executable bin-name}) (:macos-x86_64 opts) (conj {:os/arch "x86_64" :os/name "Mac.*" :artifact/url (:macos-x86_64 opts) - :artifact/executable pod-name}) + :artifact/executable bin-name}) (:windows-amd64 opts) (conj {:os/arch "amd64" :os/name "Windows.*" :artifact/url (:windows-amd64 opts) - :artifact/executable (format "%s.exe" pod-name)}) + :artifact/executable (format "%s.exe" bin-name)}) (:uberjar opts) (conj {:artifact/url (:uberjar opts)})) - manifest-data {:pod/name (symbol pod-id) + manifest-data {:pod/name (:name opts) :pod/description (:description opts) :pod/example (:example opts) :pod/language (:language opts) :pod/license (:license opts) - :pod/version (:version opts) + :pod/version version :pod/artifacts artifacts} filepath "manifest.edn" edn-content (format-edn manifest-data)] (spit filepath edn-content) - {:exit-code 0 :stdout (format "Wrote %s" filepath)}))] + {:exit-code 0 :stdout (format "Wrote %s for pod %s v%s" filepath (:name opts) version)}))] (when-let [stdout (:stdout result)] (println stdout)))) From 79c31a89cbd3a578020a904838ed4df24455228e Mon Sep 17 00:00:00 2001 From: Giacomo Debidda Date: Tue, 8 Oct 2024 12:15:39 +0200 Subject: [PATCH 3/4] improve documentation in native-image compilation script --- examples/jsoup.bb | 2 +- script/compile.sh | 69 +++++++++++++++++++++++++++++++++++++---------- 2 files changed, 56 insertions(+), 15 deletions(-) diff --git a/examples/jsoup.bb b/examples/jsoup.bb index f5cb9c6..041e22d 100755 --- a/examples/jsoup.bb +++ b/examples/jsoup.bb @@ -4,7 +4,7 @@ (require '[babashka.pods :as pods]) ;; Test me by running bb -f examples/jsoup.bb when registering this pod, then delete me. -;; (pods/load-pod "/home/jack/repos/pod-jackdbd-jsoup/target/pod-jackdbd-jsoup") +(pods/load-pod "target/pod-jackdbd-jsoup") ;; Uncomment me when registering this pod. ;; (pods/load-pod 'com.github.jackdbd/jsoup "0.4.0") diff --git a/script/compile.sh b/script/compile.sh index c4c6b1a..492ceb9 100755 --- a/script/compile.sh +++ b/script/compile.sh @@ -1,16 +1,17 @@ #!/usr/bin/env bash set -euo pipefail -POD_ID=pod.jackdbd.jsoup -POD_NAME=pod-jackdbd-jsoup -echo "POD_VERSION is $POD_VERSION" +# See deps.edn and the pom.xml generated when building the uberjar. +GROUP_ID=com.github.jackdbd +ARTIFACT_ID=pod.jackdbd.jsoup +ARTIFACT_VERSION=$POD_VERSION # https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/store-information-in-variables#default-environment-variables if [ "${CI+x}" ]; then # running on GitHub actions - UBERJAR_PATH="$POD_ID-$POD_VERSION-standalone.jar" + UBERJAR_PATH="$ARTIFACT_ID-$ARTIFACT_VERSION-standalone.jar" else - UBERJAR_PATH="target/$POD_ID-$POD_VERSION-standalone.jar" + UBERJAR_PATH="target/$ARTIFACT_ID-$ARTIFACT_VERSION-standalone.jar" fi echo "UBERJAR_PATH is $UBERJAR_PATH" @@ -18,7 +19,29 @@ echo "UBERJAR_PATH is $UBERJAR_PATH" # https://www.graalvm.org/latest/reference-manual/native-image/ # https://www.graalvm.org/latest/reference-manual/native-image/overview/BuildOutput/ -HEAP_SIZE_AT_BUILD_TIME="-R:MaxHeapSize=1024m" +## Memory management ########################################################### + +# Epsilon GC is NOT a garbage collector. It NEVER allocates/frees memory. +# GARBAGE_COLLECTOR="--gc=epsilon" +# Serial GC is the only GC available in GraalVM Community Edition. +GARBAGE_COLLECTOR="--gc=serial" + +# If the Java heap is full and the GC is unable reclaim sufficient memory for a +# Java object allocation, the allocation will fail with the OutOfMemoryError. +# HEAP_SIZE_AT_BUILD_TIME="-R:MaxHeapSize=1m" # 1MB: not enough => OutOfMemoryError +# HEAP_SIZE_AT_BUILD_TIME="-R:MaxHeapSize=64m" # 64MB: ok => no OutOfMemoryError +# HEAP_SIZE_AT_BUILD_TIME="-R:MaxHeapSize=256m" # 256MB: ok => no OutOfMemoryError +# HEAP_SIZE_AT_BUILD_TIME="-R:MaxHeapSize=1024m" # 1GB: ok => no OutOfMemoryError +# We can also set a maximum heap size as a percentage% of the physical memory. +# https://www.graalvm.org/latest/reference-manual/native-image/optimizations-and-performance/MemoryManagement/#performance-tuning +HEAP_SIZE_AT_BUILD_TIME="-R:MaximumHeapSizePercent=25" +# Performance tuning for Serial GC is limited. More performance tuning options +# are available for G1 GC, but G1 is not available in GraalVM Community Edition. + +# DEBUG TIP: you can use these flags when RUNNING the binary (not when compiling it). +# https://www.graalvm.org/latest/reference-manual/native-image/optimizations-and-performance/MemoryManagement/#printing-garbage-collections + +# CPU optimizations ############################################################ # https://www.graalvm.org/latest/reference-manual/native-image/optimizations-and-performance/#optimization-levels # -Ob: quicker build time @@ -36,34 +59,52 @@ MACHINE_TYPE="-march=x86-64-v3" # native-image does NOT support cross-compilation. # https://github.com/oracle/graal/issues/407 -TARGET="linux-amd64" +ARCH=amd64 +OS=linux +TARGET="--target=$OS-$ARCH" + +APP_NAME=pod-jackdbd-jsoup +IMAGE_NAME=$APP_NAME +# IMAGE_NAME="$APP_NAME-$ARTIFACT_VERSION-$ARCH-$OS" +echo "IMAGE_NAME is $IMAGE_NAME" + +## Native Image Builder ######################################################## +# https://www.graalvm.org/22.0/reference-manual/native-image/Options/ +# https://docs.oracle.com/en/graalvm/enterprise/22/docs/reference-manual/native-image/overview/BuildOptions/ # I am not sure I need to add this flag. # -J-Dclojure.compiler.direct-linking=true # https://clojure.org/reference/compilation#directlinking +# Why do we need to trigger class initialization at build time in this project? +# https://www.graalvm.org/latest/reference-manual/native-image/basics/#build-time-vs-run-time +# --initialize-at-build-time + # When running on NixOS, this works only when the environment variables CPATH, # LIBRARY_PATH, NIX_LDFLAGS are set. -native-image -jar $UBERJAR_PATH \ +native-image -jar $UBERJAR_PATH $IMAGE_NAME \ -H:ReflectionConfigurationFiles=reflection.json \ -H:+ReportExceptionStackTraces \ -J-Dclojure.compiler.direct-linking=true \ + $GARBAGE_COLLECTOR \ $HEAP_SIZE_AT_BUILD_TIME \ $OPTIMIZATION_LEVEL \ $MACHINE_TYPE \ + $TARGET \ --initialize-at-build-time \ --native-image-info \ --no-fallback \ - --report-unsupported-elements-at-runtime \ --static --libc=musl \ - "--target=$TARGET" \ --verbose if [ "${CI+x}" ]; then # Avoid moving the artifact when running on GitHub actions (other steps in the # GitHub workflow expect the artifact to be here). - echo "Binary artifact is at $POD_ID-$POD_VERSION-standalone" + echo "Binary artifact is at $IMAGE_NAME" else - mv "$POD_ID-$POD_VERSION-standalone" "target/$POD_NAME" - echo "Binary artifact moved to target/$POD_NAME" -fi \ No newline at end of file + mv "$IMAGE_NAME" "target/$IMAGE_NAME" + echo "Binary artifact moved to target/$IMAGE_NAME" +fi + +# DEBUG TIP: you can use these flags when RUNNING the binary (not when compiling it). +# https://www.graalvm.org/latest/reference-manual/native-image/optimizations-and-performance/MemoryManagement/#printing-garbage-collections From 34a6cd51e5ffe03ce76d62e9974c658fb803c843 Mon Sep 17 00:00:00 2001 From: Giacomo Debidda Date: Tue, 8 Oct 2024 13:19:24 +0200 Subject: [PATCH 4/4] ci: use more descriptive names --- .github/workflows/ci-cd.yaml | 144 +++++++++++++++++++---------------- script/compile.sh | 2 +- 2 files changed, 79 insertions(+), 67 deletions(-) diff --git a/.github/workflows/ci-cd.yaml b/.github/workflows/ci-cd.yaml index f5aaff6..53a9f1e 100644 --- a/.github/workflows/ci-cd.yaml +++ b/.github/workflows/ci-cd.yaml @@ -18,17 +18,17 @@ env: HEAP_SIZE_AT_BUILD_TIME: '-R:MaxHeapSize=1024m' JAVA_VERSION: 21 OPTIMIZATION_LEVEL: '-O2' - POD_ID: pod.jackdbd.jsoup - POD_NAME: pod-jackdbd-jsoup + UBERJAR_ID: pod.jackdbd.jsoup # See deps.edn and the pom.xml generated when building the uberjar. + BINARY_NAME: pod-jackdbd-jsoup jobs: - set-shared-outputs: - name: Set shared outputs + shared-outputs: + name: Shared outputs runs-on: ubuntu-latest outputs: - pod_version: ${{ steps.set_outputs.outputs.pod_version }} is_prerelease: ${{ steps.set_outputs.outputs.is_prerelease }} + version: ${{ steps.set_outputs.outputs.version }} steps: - name: 🛎️ Checkout @@ -42,27 +42,28 @@ jobs: - name: Set job outputs id: set_outputs run: | - POD_VERSION=$(bb -e '(-> (slurp "deps.edn") edn/read-string :aliases :neil :project :version)' | tr -d '"') - echo "pod_version=$POD_VERSION" >> $GITHUB_OUTPUT - if [ "${{ github.ref }}" == "refs/heads/main" ]; then echo "is_prerelease=false" >> $GITHUB_OUTPUT else echo "is_prerelease=true" >> $GITHUB_OUTPUT fi + VERSION=$(bb -e '(-> (slurp "deps.edn") edn/read-string :aliases :neil :project :version)' | tr -d '"') + echo "version=$VERSION" >> $GITHUB_OUTPUT + + - name: Log job outputs run: | - echo "pod_version is ${{ steps.set_outputs.outputs.pod_version }}" echo "is_prerelease is ${{ steps.set_outputs.outputs.is_prerelease }}" + echo "version is ${{ steps.set_outputs.outputs.version }}" - build-uberjar: - name: Build uberjar + uberjar: + name: Uberjar runs-on: ubuntu-latest - needs: [set-shared-outputs] + needs: [shared-outputs] env: - POD_VERSION: ${{ needs.set-shared-outputs.outputs.pod_version }} + UBERJAR_VERSION: ${{ needs.shared-outputs.outputs.version }} steps: - name: 🛎️ Checkout @@ -98,22 +99,23 @@ jobs: key: cljdeps-${{ hashFiles('deps.edn', 'bb.edn') }} restore-keys: cljdeps- - - name: 📦 Compile pod into an uberjar + - name: 📦 Compile uberjar run: clojure -T:build uber - name: ⬆️ Upload uberjar uses: actions/upload-artifact@v4 with: name: uberjar - path: target/${{ env.POD_ID }}-${{ env.POD_VERSION }}-standalone.jar + path: target/${{ env.UBERJAR_ID }}-${{ env.UBERJAR_VERSION }}-standalone.jar + if-no-files-found: error - linux: - name: Compile Linux binary & Test + linux-amd64-binary: + name: Linux amd64 binary, Test runs-on: ubuntu-latest - needs: [set-shared-outputs, build-uberjar] + needs: [shared-outputs, uberjar] env: - POD_VERSION: ${{ needs.set-shared-outputs.outputs.pod_version }} + UBERJAR_VERSION: ${{ needs.shared-outputs.outputs.version }} steps: - name: 🛎️ Checkout @@ -160,28 +162,29 @@ jobs: run: ./script/compile.sh # The tests expect the uberjar and the binary to be in a directory called "target" - - name: Copy the uberjar and the binary to the target directory + - name: Copy uberjar and binary to target/ run: | mkdir target - cp ${{ env.POD_ID }}-${{ env.POD_VERSION }}-standalone.jar target/ - cp ${{ env.POD_ID }}-${{ env.POD_VERSION }}-standalone target/${{ env.POD_NAME }} + cp ${{ env.UBERJAR_ID }}-${{ env.UBERJAR_VERSION }}-standalone.jar target/ + cp ${{ env.BINARY_NAME }} target/ - name: ⬆️ Upload amd64 Linux binary uses: actions/upload-artifact@v4 with: name: ubuntu-latest-amd64-binary - path: target/${{ env.POD_NAME }} + path: target/${{ env.BINARY_NAME }} + if-no-files-found: error - name: 🔍 Run all tests run: clojure -X:test - macos: - name: Compile macos-latest-aarch64-binary, Test + macos-aarch64-binary: + name: macOS aarch64 binary, Test runs-on: macOS-latest - needs: [set-shared-outputs, build-uberjar] + needs: [shared-outputs, uberjar] env: - POD_VERSION: ${{ needs.set-shared-outputs.outputs.pod_version }} + UBERJAR_VERSION: ${{ needs.shared-outputs.outputs.version }} steps: - name: 🛎️ Checkout @@ -222,8 +225,7 @@ jobs: # gave me this error: # On AArch64, only 'ARMV8_A', 'ARMV8_1_A', 'COMPATIBILITY', 'NATIVE' are available. run: | - native-image \ - -jar ${{ env.POD_ID }}-${{ env.POD_VERSION }}-standalone.jar \ + native-image -jar ${{ env.UBERJAR_ID }}-${{ env.UBERJAR_VERSION }}-standalone.jar ${{ env.BINARY_NAME }} \ '-H:ReflectionConfigurationFiles=reflection.json' \ '-H:+ReportExceptionStackTraces' \ '-J-Dclojure.compiler.direct-linking=true' \ @@ -236,28 +238,29 @@ jobs: '--report-unsupported-elements-at-runtime' # The tests expect the uberjar and the binary to be in a directory called "target" - - name: Copy the uberjar and the binary to the target directory + - name: Copy uberjar and binary to target/ run: | mkdir target - cp ${{ env.POD_ID }}-${{ env.POD_VERSION }}-standalone.jar target/ - cp ${{ env.POD_ID }}-${{ env.POD_VERSION }}-standalone target/${{ env.POD_NAME }} + cp ${{ env.UBERJAR_ID }}-${{ env.UBERJAR_VERSION }}-standalone.jar target/ + cp ${{ env.BINARY_NAME }} target/ - - name: ⬆️ Upload the aarch64 macOS binary + - name: ⬆️ Upload aarch64 macOS binary uses: actions/upload-artifact@v4 with: name: macos-latest-aarch64-binary - path: target/${{ env.POD_NAME }} + path: target/${{ env.BINARY_NAME }} + if-no-files-found: error - name: 🔍 Run all tests run: clojure -X:test - windows: - name: Compile Windows binary & Test + windows-amd64-binary: + name: Windows amd64 binary, Test runs-on: windows-latest - needs: [set-shared-outputs, build-uberjar] + needs: [shared-outputs, uberjar] env: - POD_VERSION: ${{ needs.set-shared-outputs.outputs.pod_version }} + UBERJAR_VERSION: ${{ needs.shared-outputs.outputs.version }} steps: - name: 🛎️ Checkout @@ -293,11 +296,11 @@ jobs: with: name: uberjar + # When compiling a windows executable, native-image adds the `.exe` extension. # See: https://github.com/babashka/pod-babashka-buddy/blob/main/script/compile.bat - name: 📦 Compile uberjar to amd64-windows binary with GraalVM native-image run: > - native-image - -jar ${{ env.POD_ID }}-${{ env.POD_VERSION }}-standalone.jar + native-image -jar ${{ env.UBERJAR_ID }}-${{ env.UBERJAR_VERSION }}-standalone.jar ${{ env.BINARY_NAME }} '-H:ReflectionConfigurationFiles=reflection.json' '-H:+ReportExceptionStackTraces' '-J-Dclojure.compiler.direct-linking=true' @@ -309,30 +312,38 @@ jobs: '--no-fallback' '--report-unsupported-elements-at-runtime' - - name: Copy the uberjar and the binary to the target directory + - name: Copy uberjar and binary to target/ run: | mkdir target - move ${{ env.POD_ID }}-${{ env.POD_VERSION }}-standalone.jar target\\${{ env.POD_ID }}-${{ env.POD_VERSION }}-standalone.jar - move "${{ env.POD_ID }}-${{ env.POD_VERSION }}-standalone.exe" ".\\target\\${{ env.POD_NAME }}.exe" + move ${{ env.UBERJAR_ID }}-${{ env.UBERJAR_VERSION }}-standalone.jar target\\${{ env.UBERJAR_ID }}-${{ env.UBERJAR_VERSION }}-standalone.jar + move ${{ env.BINARY_NAME }}.exe target\\${{ env.BINARY_NAME }}.exe + shell: cmd + + # Troubleshooting: Windows command prompt equivalent for `ls -la` + - run: dir /A /Q shell: cmd - name: ⬆️ Upload amd64-windows binary uses: actions/upload-artifact@v4 with: name: windows-latest-amd64-binary - path: ".\\target\\${{ env.POD_NAME }}.exe" + path: ".\\target\\${{ env.BINARY_NAME }}.exe" + if-no-files-found: error - name: 🔍 Run all tests run: clojure -X:test - clojars: - name: Publish to Clojars + clojars-release: + name: Clojars release if: ${{ github.event_name != 'pull_request' }} - needs: [set-shared-outputs, linux, macos, windows] # publish only when all tests on all platforms pass + # Only the uberjar is published to Clojars, but since some tests require the + # native binary (for Linux/macOS/Windows), I have to wait for those tests to + # pass before publishing the uberjar to Clojars. + needs: [shared-outputs, linux-amd64-binary, macos-aarch64-binary, windows-amd64-binary] # publish only when all tests on all platforms pass runs-on: ubuntu-latest env: - ARTIFACT_VERSION: ${{ needs.set-shared-outputs.outputs.pod_version }} + ARTIFACT_VERSION: ${{ needs.shared-outputs.outputs.version }} permissions: contents: write @@ -346,7 +357,7 @@ jobs: with: cli: 'latest' - - name: 📦 Compile pod into an uberjar + - name: 📦 Compile uberjar run: clojure -T:build uber - name: 🌐 Publish version ${{ env.ARTIFACT_VERSION }} to Clojars @@ -369,12 +380,12 @@ jobs: github-release: name: GitHub release if: ${{ github.event_name != 'pull_request' }} - needs: [set-shared-outputs, build-uberjar, linux, macos, windows, clojars] + needs: [shared-outputs, uberjar, linux-amd64-binary, macos-aarch64-binary, windows-amd64-binary, clojars-release] runs-on: ubuntu-latest env: - IS_PRERELEASE: ${{ needs.set-shared-outputs.outputs.is_prerelease }} - POD_VERSION: ${{ needs.set-shared-outputs.outputs.pod_version }} + IS_PRERELEASE: ${{ needs.shared-outputs.outputs.is_prerelease }} + VERSION: ${{ needs.shared-outputs.outputs.version }} permissions: contents: write @@ -414,14 +425,15 @@ jobs: - name: 📦 Create archives for all assets to be included in the GitHub release run: | - pushd . && cd ubuntu-latest-amd64 && zip "${{ env.POD_NAME }}-${{ env.POD_VERSION }}-ubuntu-latest-amd64.zip" "pod-jackdbd-jsoup" && popd - pushd . && cd macos-latest-aarch64 && zip "${{ env.POD_NAME }}-${{ env.POD_VERSION }}-macos-latest-aarch64.zip" "pod-jackdbd-jsoup" && popd - pushd . && cd windows-latest-amd64 && zip "${{ env.POD_NAME }}-${{ env.POD_VERSION }}-windows-latest-amd64.zip" "pod-jackdbd-jsoup.exe" && popd - mv ubuntu-latest-amd64/${{ env.POD_NAME }}-${{ env.POD_VERSION }}-ubuntu-latest-amd64.zip . - mv macos-latest-aarch64/${{ env.POD_NAME }}-${{ env.POD_VERSION }}-macos-latest-aarch64.zip . - mv windows-latest-amd64/${{ env.POD_NAME }}-${{ env.POD_VERSION }}-windows-latest-amd64.zip . + pushd . && cd ubuntu-latest-amd64 && zip "${{ env.BINARY_NAME }}-${{ env.VERSION }}-ubuntu-latest-amd64.zip" "${{ env.BINARY_NAME }}" && popd + pushd . && cd macos-latest-aarch64 && zip "${{ env.BINARY_NAME }}-${{ env.VERSION }}-macos-latest-aarch64.zip" "${{ env.BINARY_NAME }}" && popd + pushd . && cd windows-latest-amd64 && zip "${{ env.BINARY_NAME }}-${{ env.VERSION }}-windows-latest-amd64.zip" "${{ env.BINARY_NAME }}.exe" && popd + mv ubuntu-latest-amd64/${{ env.BINARY_NAME }}-${{ env.VERSION }}-ubuntu-latest-amd64.zip . + mv macos-latest-aarch64/${{ env.BINARY_NAME }}-${{ env.VERSION }}-macos-latest-aarch64.zip . + mv windows-latest-amd64/${{ env.BINARY_NAME }}-${{ env.VERSION }}-windows-latest-amd64.zip . # Troubleshooting: do we have every assets we want to include in the GitHub release? + - run: ls -la # - run: ls -R # https://github.com/marketplace/actions/gh-release @@ -430,21 +442,21 @@ jobs: id: github_release with: body: | - 📦 **${{ env.POD_NAME }}** version `${{ env.POD_VERSION }}` is [available on Clojars](https://clojars.org/com.github.jackdbd/pod.jackdbd.jsoup/versions/${{ env.POD_VERSION }}). + 📦 **${{ env.BINARY_NAME }}** version `${{ env.VERSION }}` is [available on Clojars](https://clojars.org/com.github.jackdbd/pod.jackdbd.jsoup/versions/${{ env.VERSION }}). # draft: true fail_on_unmatched_files: true files: | - ${{ env.POD_ID }}-${{ env.POD_VERSION }}-standalone.jar - ${{ env.POD_NAME }}-${{ env.POD_VERSION }}-macos-latest-aarch64.zip - ${{ env.POD_NAME }}-${{ env.POD_VERSION }}-ubuntu-latest-amd64.zip - ${{ env.POD_NAME }}-${{ env.POD_VERSION }}-windows-latest-amd64.zip + ${{ env.UBERJAR_ID }}-${{ env.VERSION }}-standalone.jar + ${{ env.BINARY_NAME }}-${{ env.VERSION }}-macos-latest-aarch64.zip + ${{ env.BINARY_NAME }}-${{ env.VERSION }}-ubuntu-latest-amd64.zip + ${{ env.BINARY_NAME }}-${{ env.VERSION }}-windows-latest-amd64.zip # body is prepended to these automatically generated release notes. # See here for how to configure these release notes: # https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes#configuring-automatically-generated-release-notes generate_release_notes: true - name: v${{ env.POD_VERSION }} + name: v${{ env.VERSION }} prerelease: ${{ env.IS_PRERELEASE }} - tag_name: v${{ env.POD_VERSION }} + tag_name: v${{ env.VERSION }} # Troubleshooting: show help of manifest.edn CLI - run: bb bb/manifest.bb --help @@ -481,4 +493,4 @@ jobs: with: files: | manifest.edn - tag_name: v${{ env.POD_VERSION }} + tag_name: v${{ env.VERSION }} diff --git a/script/compile.sh b/script/compile.sh index 492ceb9..d8860fb 100755 --- a/script/compile.sh +++ b/script/compile.sh @@ -4,7 +4,7 @@ set -euo pipefail # See deps.edn and the pom.xml generated when building the uberjar. GROUP_ID=com.github.jackdbd ARTIFACT_ID=pod.jackdbd.jsoup -ARTIFACT_VERSION=$POD_VERSION +ARTIFACT_VERSION=$UBERJAR_VERSION # https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/store-information-in-variables#default-environment-variables if [ "${CI+x}" ]; then