The layouts are C's names, not Java's #17
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
| name: CI | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| env: | |
| MAVEN_ARGS: -B -ntp | |
| jobs: | |
| # The API artifact is what a caller compiles against, it has no native | |
| # code in it, and it is the one thing that has to build on every JDK | |
| # this client claims to support. It needs no engine, so it answers in | |
| # under a minute and it answers first. | |
| api: | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| java: ["17", "21", "25", "26-ea"] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - uses: actions/setup-java@v5 | |
| with: | |
| distribution: temurin | |
| java-version: ${{ matrix.java }} | |
| cache: maven | |
| # Only the API module, because the FFM provider compiles to release | |
| # 25 and a JDK 17 compiler cannot be asked for that. A caller on 17 | |
| # gets exactly this artifact and the JNI provider beside it. | |
| - run: mvn $MAVEN_ARGS -pl zudb -am test | |
| # The whole client against the engine at its own HEAD, which is what | |
| # makes a red job here mean the binding is wrong about the ABI rather | |
| # than that a checked-in copy of something is stale. | |
| engine: | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, macos-latest] | |
| java: ["25", "26-ea"] | |
| runs-on: ${{ matrix.os }} | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - uses: actions/checkout@v5 | |
| with: | |
| repository: tamnd/zu | |
| path: engine | |
| - uses: actions/setup-java@v5 | |
| with: | |
| distribution: temurin | |
| java-version: ${{ matrix.java }} | |
| cache: maven | |
| - uses: Swatinem/rust-cache@v2 | |
| with: | |
| workspaces: engine | |
| # ZU_ABI_VERSION is a header macro rather than a symbol, so a | |
| # binding with no C compile step has nowhere to read it from and | |
| # has to write it down. This is the step that stops the written | |
| # down copy from drifting. | |
| - name: The ABI this client speaks is the ABI the engine offers | |
| run: | | |
| set -eu | |
| engine_abi="$(sed -n 's/^#define ZU_ABI_VERSION "\(.*\)"$/\1/p' \ | |
| engine/crates/zu-capi/include/zu.h)" | |
| client_abi="$(sed -n 's/.*ABI_VERSION = "\(.*\)";.*/\1/p' \ | |
| zudb/src/main/java/dev/zudb/Zu.java)" | |
| test -n "$engine_abi" | |
| test -n "$client_abi" | |
| echo "engine $engine_abi, client $client_abi" | |
| test "$engine_abi" = "$client_abi" | |
| - name: Build libzu | |
| working-directory: engine | |
| run: cargo build --release -p zu-capi | |
| - name: Where the library landed | |
| run: | | |
| set -eu | |
| lib="$(ls engine/target/release/libzu.dylib engine/target/release/libzu.so 2>/dev/null | head -1)" | |
| test -n "$lib" | |
| echo "ZU_LIBRARY=$GITHUB_WORKSPACE/$lib" >> "$GITHUB_ENV" | |
| - run: mvn $MAVEN_ARGS test | |
| # The suite again with assertions on everywhere, including the ones | |
| # in the JDK itself. The bounds checks a MemorySegment does are the | |
| # difference between a wrong offset failing and a wrong offset | |
| # reading somebody else's memory. | |
| - run: mvn $MAVEN_ARGS test -Dzu.test.args="-ea -esa" | |
| # Not for the numbers, which mean nothing on a shared runner, but | |
| # because a benchmark is code that nothing else compiles and | |
| # nothing else runs. One iteration is enough to say it still works. | |
| - run: mvn $MAVEN_ARGS -DskipTests package | |
| - run: java -jar zudb-bench/target/benchmarks.jar -f 1 -wi 1 -i 1 -r 1s -w 1s | |
| # The claim the zudb-native artifact makes is that a user who added a | |
| # dependency and installed nothing has an engine. Nothing in the test | |
| # suite can check that, because the suite is told where the library is | |
| # so that it tests the binding rather than the search. So it is | |
| # checked here, once, the way a user meets it: a classpath, no | |
| # property, no environment variable, and a statement. | |
| natives: | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, macos-latest] | |
| runs-on: ${{ matrix.os }} | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - uses: actions/checkout@v5 | |
| with: | |
| repository: tamnd/zu | |
| path: engine | |
| - uses: actions/setup-java@v5 | |
| with: | |
| distribution: temurin | |
| java-version: "25" | |
| cache: maven | |
| - uses: Swatinem/rust-cache@v2 | |
| with: | |
| workspaces: engine | |
| - name: Build libzu | |
| working-directory: engine | |
| run: cargo build --release -p zu-capi | |
| # One platform rather than seven, because this runner can only | |
| # build the one it is, so the rule that every platform is staged | |
| # is stood down here and holds where it matters, in the release. | |
| - name: Stage the one platform this runner is | |
| run: | | |
| set -eu | |
| case "$RUNNER_OS" in | |
| Linux) flavour=linux-amd64; library=libzu.so ;; | |
| macOS) flavour=darwin-arm64; library=libzu.dylib ;; | |
| *) echo "no row for $RUNNER_OS"; exit 1 ;; | |
| esac | |
| mkdir -p "zudb-native/lib/$flavour" | |
| cp "engine/target/release/$library" "zudb-native/lib/$flavour/$library" | |
| - run: mvn $MAVEN_ARGS -Pnatives -DskipTests -Denforcer.skip=true package | |
| - name: A classpath, and nothing else | |
| run: | | |
| set -eu | |
| mkdir -p "$RUNNER_TEMP/user" | |
| cat > "$RUNNER_TEMP/user/Main.java" <<'EOF' | |
| import dev.zudb.Connection; | |
| import dev.zudb.Result; | |
| import dev.zudb.Zu; | |
| public class Main { | |
| public static void main(String[] args) { | |
| System.out.println("found " + Zu.library() + " through " + Zu.source()); | |
| try (Connection conn = Connection.memory(); | |
| Result r = conn.query("RETURN 1 AS one")) { | |
| if (r.row(0).getLong(0) != 1L) { | |
| throw new AssertionError("the engine answered something else"); | |
| } | |
| } | |
| System.out.println("the engine came out of the jar and answered"); | |
| } | |
| } | |
| EOF | |
| cp=$(ls zudb/target/zudb-*.jar zudb-ffm/target/zudb-ffm-*.jar \ | |
| zudb-native/target/zudb-native-*.jar | grep -v sources | tr '\n' ':') | |
| javac -cp "$cp" -d "$RUNNER_TEMP/user" "$RUNNER_TEMP/user/Main.java" | |
| env -u ZU_LIBRARY java --enable-native-access=ALL-UNNAMED \ | |
| -cp "$cp$RUNNER_TEMP/user" Main | |
| # An image has no linker in it. Every downcall stub is machine code | |
| # written while the image is built, from a file that says which | |
| # signatures to write, and a file that is wrong produces an image that | |
| # builds clean and dies on the first query. The unit test checks that | |
| # file against what the binding binds; only an image can check that the | |
| # file is the file the builder wanted, so one gets built here and run. | |
| native: | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, macos-latest] | |
| runs-on: ${{ matrix.os }} | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - uses: actions/checkout@v5 | |
| with: | |
| repository: tamnd/zu | |
| path: engine | |
| - uses: graalvm/setup-graalvm@v1 | |
| with: | |
| java-version: "25" | |
| distribution: graalvm | |
| cache: maven | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| - uses: Swatinem/rust-cache@v2 | |
| with: | |
| workspaces: engine | |
| - name: Build libzu | |
| working-directory: engine | |
| run: cargo build --release -p zu-capi | |
| - name: Stage the one platform this runner is | |
| run: | | |
| set -eu | |
| case "$RUNNER_OS" in | |
| Linux) flavour=linux-amd64; library=libzu.so ;; | |
| macOS) flavour=darwin-arm64; library=libzu.dylib ;; | |
| *) echo "no row for $RUNNER_OS"; exit 1 ;; | |
| esac | |
| mkdir -p "zudb-native/lib/$flavour" | |
| cp "engine/target/release/$library" "zudb-native/lib/$flavour/$library" | |
| - run: mvn $MAVEN_ARGS -Pnatives -DskipTests -Denforcer.skip=true package | |
| # The same program the natives job runs on a JVM, compiled to a | |
| # binary instead. No property, no environment variable, and the | |
| # library comes out of the image rather than off the disk. | |
| - name: An image, and nothing else | |
| run: | | |
| set -eu | |
| mkdir -p "$RUNNER_TEMP/user" | |
| cat > "$RUNNER_TEMP/user/Main.java" <<'EOF' | |
| import dev.zudb.Connection; | |
| import dev.zudb.Result; | |
| import dev.zudb.Zu; | |
| public class Main { | |
| public static void main(String[] args) { | |
| System.out.println("found " + Zu.library() + " through " + Zu.source()); | |
| try (Connection conn = Connection.memory(); | |
| Result r = conn.query("UNWIND [1, 2, 3] AS n RETURN sum(n) AS total")) { | |
| if (r.row(0).getLong(0) != 6L) { | |
| throw new AssertionError("the image answered something else"); | |
| } | |
| } | |
| System.out.println("the engine came out of the image and answered"); | |
| } | |
| } | |
| EOF | |
| cp=$(ls zudb/target/zudb-*.jar zudb-ffm/target/zudb-ffm-*.jar \ | |
| zudb-native/target/zudb-native-*.jar | grep -v sources | tr '\n' ':') | |
| javac -cp "$cp" -d "$RUNNER_TEMP/user" "$RUNNER_TEMP/user/Main.java" | |
| native-image -cp "$cp$RUNNER_TEMP/user" \ | |
| --no-fallback -o "$RUNNER_TEMP/user/main" Main | |
| env -u ZU_LIBRARY "$RUNNER_TEMP/user/main" | |
| # What Maven Central will run over the artifacts, run here instead so | |
| # that a release is not the first time anyone sees it. | |
| javadoc: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - uses: actions/setup-java@v5 | |
| with: | |
| distribution: temurin | |
| java-version: "25" | |
| cache: maven | |
| - run: mvn $MAVEN_ARGS -P release -DskipTests package |