name: "Java SDK Tests" on: workflow_dispatch: workflow_call: permissions: contents: read env: MAVEN_OPTS: >- -Daether.connector.http.retryHandler.count=3 -Daether.connector.http.retryHandler.serviceUnavailable=429,502,503 jobs: java-sdk-inprocess: name: "Java SDK InProcess Tests (${{ matrix.classifier }})" if: github.event.repository.fork == false strategy: fail-fast: false matrix: include: - os: ubuntu-latest classifier: linux-x64 - os: ubuntu-24.04-arm classifier: linux-arm64 maven-args: -Dcopilot.native.libc=glibc - os: windows-latest classifier: win32-x64 - os: windows-11-arm classifier: win32-arm64 - os: macos-26 classifier: darwin-arm64 runs-on: ${{ matrix.os }} defaults: run: working-directory: ./java steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5 with: java-version: "25" distribution: "microsoft" cache: "maven" - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 with: node-version: 22 - name: Validate native host run: node copilot-native/scripts/validate-native-host.mjs ${{ matrix.classifier }} - name: Run Java SDK tests (InProcess) env: CI: "true" run: mvn clean verify -Pinprocess ${{ matrix.maven-args }} - name: Generate Test Report Summary if: failure() uses: ./.github/actions/java-test-report with: title: "Copilot Java SDK :: Test Results InProcess" - name: Upload test results on failure if: failure() uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: java-test-results-inprocess-${{ matrix.classifier }} path: | java/sdk/target/surefire-reports/ java/sdk/target/surefire-reports-isolated/ java/sdk/target/failsafe-reports/ retention-days: 7 java-native-publication-linux-arm64: name: "Java Native Publication Input (linux-arm64)" if: github.event.repository.fork == false runs-on: ubuntu-24.04-arm permissions: contents: read outputs: source_sha: ${{ steps.build.outputs.source_sha }} version: ${{ steps.build.outputs.version }} defaults: run: shell: bash working-directory: ./java steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5 with: java-version: "25" distribution: "microsoft" cache: "maven" - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 with: node-version: 22 - name: Build and validate linux-arm64 classifier id: build run: | set -euo pipefail node copilot-native/scripts/validate-native-host.mjs linux-arm64 mvn -B -pl copilot-native package -DskipTests -Dcopilot.native.libc=glibc VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout) JAR="copilot-native/target/copilot-sdk-java-runtime-$VERSION-linux-arm64.jar" PRIMARY_JAR="copilot-native/target/copilot-sdk-java-runtime-$VERSION.jar" test -f "$JAR" node copilot-native/scripts/validate-native-artifact.mjs \ classifier linux-arm64 "$JAR" "$(basename "$JAR")" .. node copilot-native/scripts/validate-native-artifact.mjs placeholder "$PRIMARY_JAR" MANIFEST="copilot-native/target/linux-arm64-$VERSION.sha256" HASH=$(sha256sum "$JAR" | cut -d ' ' -f 1) printf '%s %s' "$HASH" "$(basename "$JAR")" > "$MANIFEST" node copilot-native/scripts/validate-native-artifact.mjs \ checksum "$JAR" "$MANIFEST" "$(basename "$JAR")" echo "source_sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT" echo "version=$VERSION" >> "$GITHUB_OUTPUT" - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: java-native-publication-linux-arm64-${{ github.run_id }} path: | java/copilot-native/target/copilot-sdk-java-runtime-${{ steps.build.outputs.version }}-linux-arm64.jar java/copilot-native/target/linux-arm64-${{ steps.build.outputs.version }}.sha256 if-no-files-found: error overwrite: true retention-days: 1 java-native-publication-windows: name: "Java Native Publication Input (win32-x64)" if: github.event.repository.fork == false runs-on: windows-latest permissions: contents: read outputs: source_sha: ${{ steps.build.outputs.source_sha }} version: ${{ steps.build.outputs.version }} defaults: run: shell: pwsh working-directory: ./java steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5 with: java-version: "25" distribution: "microsoft" cache: "maven" - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 with: node-version: 22 - name: Build and validate win32-x64 classifier id: build run: | node copilot-native/scripts/validate-native-host.mjs win32-x64 mvn -B -pl copilot-native package -DskipTests $version = mvn help:evaluate "-Dexpression=project.version" -q "-DforceStdout" $jar = "copilot-native/target/copilot-sdk-java-runtime-$version-win32-x64.jar" $primaryJar = "copilot-native/target/copilot-sdk-java-runtime-$version.jar" if (-not (Test-Path -LiteralPath $jar -PathType Leaf)) { throw "Expected Windows classifier was not produced: $jar" } node copilot-native/scripts/validate-native-artifact.mjs classifier win32-x64 $jar ([IO.Path]::GetFileName($jar)) .. node copilot-native/scripts/validate-native-artifact.mjs placeholder $primaryJar $manifest = "copilot-native/target/win32-x64-$version.sha256" $hash = (Get-FileHash -Algorithm SHA256 -LiteralPath $jar).Hash.ToLowerInvariant() "$hash $([IO.Path]::GetFileName($jar))" | Set-Content -NoNewline -Encoding ascii $manifest node copilot-native/scripts/validate-native-artifact.mjs checksum $jar $manifest ([IO.Path]::GetFileName($jar)) echo "source_sha=$(git rev-parse HEAD)" >> $env:GITHUB_OUTPUT echo "version=$version" >> $env:GITHUB_OUTPUT - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: java-native-publication-win32-x64-${{ github.run_id }} path: | java/copilot-native/target/copilot-sdk-java-runtime-${{ steps.build.outputs.version }}-win32-x64.jar java/copilot-native/target/win32-x64-${{ steps.build.outputs.version }}.sha256 if-no-files-found: error overwrite: true retention-days: 1 java-native-publication-windows-arm64: name: "Java Native Publication Input (win32-arm64)" if: github.event.repository.fork == false runs-on: windows-11-arm permissions: contents: read outputs: source_sha: ${{ steps.build.outputs.source_sha }} version: ${{ steps.build.outputs.version }} defaults: run: shell: pwsh working-directory: ./java steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5 with: java-version: "25" distribution: "microsoft" cache: "maven" - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 with: node-version: 22 - name: Build and validate win32-arm64 classifier id: build run: | node copilot-native/scripts/validate-native-host.mjs win32-arm64 mvn -B -pl copilot-native package -DskipTests $version = mvn help:evaluate "-Dexpression=project.version" -q "-DforceStdout" $jar = "copilot-native/target/copilot-sdk-java-runtime-$version-win32-arm64.jar" $primaryJar = "copilot-native/target/copilot-sdk-java-runtime-$version.jar" if (-not (Test-Path -LiteralPath $jar -PathType Leaf)) { throw "Expected Windows ARM64 classifier was not produced: $jar" } node copilot-native/scripts/validate-native-artifact.mjs classifier win32-arm64 $jar ([IO.Path]::GetFileName($jar)) .. node copilot-native/scripts/validate-native-artifact.mjs placeholder $primaryJar $manifest = "copilot-native/target/win32-arm64-$version.sha256" $hash = (Get-FileHash -Algorithm SHA256 -LiteralPath $jar).Hash.ToLowerInvariant() "$hash $([IO.Path]::GetFileName($jar))" | Set-Content -NoNewline -Encoding ascii $manifest node copilot-native/scripts/validate-native-artifact.mjs checksum $jar $manifest ([IO.Path]::GetFileName($jar)) echo "source_sha=$(git rev-parse HEAD)" >> $env:GITHUB_OUTPUT echo "version=$version" >> $env:GITHUB_OUTPUT - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: java-native-publication-win32-arm64-${{ github.run_id }} path: | java/copilot-native/target/copilot-sdk-java-runtime-${{ steps.build.outputs.version }}-win32-arm64.jar java/copilot-native/target/win32-arm64-${{ steps.build.outputs.version }}.sha256 if-no-files-found: error overwrite: true retention-days: 1 java-native-publication-darwin: name: "Java Native Publication Input (darwin-arm64)" if: github.event.repository.fork == false runs-on: macos-26 permissions: contents: read outputs: source_sha: ${{ steps.build.outputs.source_sha }} version: ${{ steps.build.outputs.version }} defaults: run: shell: bash working-directory: ./java steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5 with: java-version: "25" distribution: "microsoft" cache: "maven" - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 with: node-version: 22 - name: Build and validate darwin-arm64 classifier id: build run: | set -euo pipefail node copilot-native/scripts/validate-native-host.mjs darwin-arm64 mvn -B -pl copilot-native package -DskipTests VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout) JAR="copilot-native/target/copilot-sdk-java-runtime-$VERSION-darwin-arm64.jar" PRIMARY_JAR="copilot-native/target/copilot-sdk-java-runtime-$VERSION.jar" test -f "$JAR" node copilot-native/scripts/validate-native-artifact.mjs \ classifier darwin-arm64 "$JAR" "$(basename "$JAR")" .. node copilot-native/scripts/validate-native-artifact.mjs placeholder "$PRIMARY_JAR" MANIFEST="copilot-native/target/darwin-arm64-$VERSION.sha256" HASH=$(shasum -a 256 "$JAR" | cut -d ' ' -f 1) printf '%s %s' "$HASH" "$(basename "$JAR")" > "$MANIFEST" node copilot-native/scripts/validate-native-artifact.mjs \ checksum "$JAR" "$MANIFEST" "$(basename "$JAR")" echo "source_sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT" echo "version=$VERSION" >> "$GITHUB_OUTPUT" - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: java-native-publication-darwin-arm64-${{ github.run_id }} path: | java/copilot-native/target/copilot-sdk-java-runtime-${{ steps.build.outputs.version }}-darwin-arm64.jar java/copilot-native/target/darwin-arm64-${{ steps.build.outputs.version }}.sha256 if-no-files-found: error overwrite: true retention-days: 1 java-native-publication-assembly: name: "Java Native Publication Assembly" if: github.event.repository.fork == false needs: [ java-native-publication-linux-arm64, java-native-publication-windows, java-native-publication-windows-arm64, java-native-publication-darwin, ] runs-on: ubuntu-latest defaults: run: shell: bash working-directory: ./java steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: ref: ${{ github.sha }} persist-credentials: false - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5 with: java-version: "25" distribution: "microsoft" cache: "maven" - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 with: node-version: 22 - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: name: java-native-publication-linux-arm64-${{ github.run_id }} path: ${{ github.workspace }}/java/native-publication-input/linux-arm64 - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: name: java-native-publication-win32-x64-${{ github.run_id }} path: ${{ github.workspace }}/java/native-publication-input/windows - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: name: java-native-publication-win32-arm64-${{ github.run_id }} path: ${{ github.workspace }}/java/native-publication-input/windows-arm64 - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: name: java-native-publication-darwin-arm64-${{ github.run_id }} path: ${{ github.workspace }}/java/native-publication-input/darwin - name: Verify native inputs and deploy the complete local release run: | set -euo pipefail test "$(git rev-parse HEAD)" = "${{ needs.java-native-publication-linux-arm64.outputs.source_sha }}" test "$(git rev-parse HEAD)" = "${{ needs.java-native-publication-windows.outputs.source_sha }}" test "$(git rev-parse HEAD)" = "${{ needs.java-native-publication-windows-arm64.outputs.source_sha }}" test "$(git rev-parse HEAD)" = "${{ needs.java-native-publication-darwin.outputs.source_sha }}" VERSION="${{ needs.java-native-publication-windows.outputs.version }}" test "$VERSION" = "${{ needs.java-native-publication-linux-arm64.outputs.version }}" test "$VERSION" = "${{ needs.java-native-publication-windows-arm64.outputs.version }}" test "$VERSION" = "${{ needs.java-native-publication-darwin.outputs.version }}" LINUX_ARM64_DIRECTORY="$GITHUB_WORKSPACE/java/native-publication-input/linux-arm64" WINDOWS_DIRECTORY="$GITHUB_WORKSPACE/java/native-publication-input/windows" WINDOWS_ARM64_DIRECTORY="$GITHUB_WORKSPACE/java/native-publication-input/windows-arm64" DARWIN_DIRECTORY="$GITHUB_WORKSPACE/java/native-publication-input/darwin" LINUX_ARM64_JAR="$LINUX_ARM64_DIRECTORY/copilot-sdk-java-runtime-$VERSION-linux-arm64.jar" LINUX_ARM64_MANIFEST="$LINUX_ARM64_DIRECTORY/linux-arm64-$VERSION.sha256" WINDOWS_JAR="$WINDOWS_DIRECTORY/copilot-sdk-java-runtime-$VERSION-win32-x64.jar" WINDOWS_MANIFEST="$WINDOWS_DIRECTORY/win32-x64-$VERSION.sha256" WINDOWS_ARM64_JAR="$WINDOWS_ARM64_DIRECTORY/copilot-sdk-java-runtime-$VERSION-win32-arm64.jar" WINDOWS_ARM64_MANIFEST="$WINDOWS_ARM64_DIRECTORY/win32-arm64-$VERSION.sha256" DARWIN_JAR="$DARWIN_DIRECTORY/copilot-sdk-java-runtime-$VERSION-darwin-arm64.jar" DARWIN_MANIFEST="$DARWIN_DIRECTORY/darwin-arm64-$VERSION.sha256" node copilot-native/scripts/validate-native-artifact.mjs \ checksum "$LINUX_ARM64_JAR" "$LINUX_ARM64_MANIFEST" "$(basename "$LINUX_ARM64_JAR")" node copilot-native/scripts/validate-native-artifact.mjs \ classifier linux-arm64 "$LINUX_ARM64_JAR" "$(basename "$LINUX_ARM64_JAR")" .. node copilot-native/scripts/validate-native-artifact.mjs \ checksum "$WINDOWS_JAR" "$WINDOWS_MANIFEST" "$(basename "$WINDOWS_JAR")" node copilot-native/scripts/validate-native-artifact.mjs \ classifier win32-x64 "$WINDOWS_JAR" "$(basename "$WINDOWS_JAR")" .. node copilot-native/scripts/validate-native-artifact.mjs \ checksum "$WINDOWS_ARM64_JAR" "$WINDOWS_ARM64_MANIFEST" "$(basename "$WINDOWS_ARM64_JAR")" node copilot-native/scripts/validate-native-artifact.mjs \ classifier win32-arm64 "$WINDOWS_ARM64_JAR" "$(basename "$WINDOWS_ARM64_JAR")" .. node copilot-native/scripts/validate-native-artifact.mjs \ checksum "$DARWIN_JAR" "$DARWIN_MANIFEST" "$(basename "$DARWIN_JAR")" node copilot-native/scripts/validate-native-artifact.mjs \ classifier darwin-arm64 "$DARWIN_JAR" "$(basename "$DARWIN_JAR")" .. export GNUPGHOME="$GITHUB_WORKSPACE/java/copilot-native/target/local-publication-gpg" rm -rf "$GNUPGHOME" mkdir -p "$GNUPGHOME" chmod 700 "$GNUPGHOME" gpg --batch --pinentry-mode loopback --passphrase '' \ --quick-generate-key 'Copilot SDK local validation ' rsa2048 sign 1d LOCAL_REPOSITORY="$GITHUB_WORKSPACE/java/copilot-native/target/local-publication-repository" rm -rf "$LOCAL_REPOSITORY" mvn -B -pl copilot-native deploy -Prelease -DskipTests \ -Dcopilot.native.libc=glibc \ -Dcopilot.native.test.local.publication=true \ -DskipPublishing=true \ "-Dcopilot.native.external.linux.arm64.classifier.path=$LINUX_ARM64_JAR" \ "-Dcopilot.native.external.win32.classifier.path=$WINDOWS_JAR" \ "-Dcopilot.native.external.win32.arm64.classifier.path=$WINDOWS_ARM64_JAR" \ "-Dcopilot.native.external.darwin.classifier.path=$DARWIN_JAR" \ "-Dmaven.repo.local=$LOCAL_REPOSITORY" node copilot-native/scripts/validate-local-publication.mjs \ "$LOCAL_REPOSITORY" copilot-sdk-java-runtime "$VERSION" .. --signatures java-sdk: name: "Java SDK Tests (JDK ${{ matrix.test-jdk }})" if: github.event.repository.fork == false runs-on: ubuntu-latest strategy: fail-fast: false matrix: test-jdk: ["25", "17"] defaults: run: shell: bash working-directory: ./java steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5 with: java-version: "25" distribution: "microsoft" cache: "maven" - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 with: node-version: 22 - name: Test documentation version updater if: matrix.test-jdk == '25' run: ./scripts/test-update-documentation-versions.sh - name: Build SDK and set up test harness run: mvn test-compile jar:jar - name: Verify Javadoc generation if: matrix.test-jdk == '25' run: mvn javadoc:javadoc -q - name: Verify CLI works run: | npm --prefix ../nodejs ci --ignore-scripts cli_path=$(npm --prefix ../nodejs run --silent prepare:runtime -- --print-path) test -x "$cli_path" legacy_cli=$(npm --prefix ../nodejs run --silent prepare:runtime -- --print-legacy-path) node "$legacy_cli" --version - name: Run spotless check if: matrix.test-jdk == '25' run: | max_attempts=3 for ((attempt=1; attempt<=max_attempts; attempt++)); do if mvn spotless:check; then echo "✅ spotless:check passed" exit 0 fi if [ "$attempt" -lt "$max_attempts" ]; then echo "⚠️ spotless:check failed (attempt $attempt/$max_attempts), retrying in 10s..." sleep 10 fi done echo "❌ spotless:check failed after $max_attempts attempts. Please run 'mvn spotless:apply' in java/" exit 1 - name: Run Java SDK tests (JDK 25) if: matrix.test-jdk == '25' env: CI: "true" # Native artifacts are built and exercised by every classifier job. run: mvn -pl sdk verify -Dskip.test.harness=true - name: Switch to JDK 17 if: matrix.test-jdk == '17' uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5 with: java-version: "17" distribution: "microsoft" - name: Run Java SDK tests (JDK 17, no recompilation) if: matrix.test-jdk == '17' env: CI: "true" run: | echo "Running tests against JDK 25-built classes using JDK 17 runtime..." java -version mvn -pl sdk jacoco:prepare-agent@wire-up-coverage-instrumentation antrun:run@print-test-jdk-banner surefire:test failsafe:integration-test failsafe:verify jacoco:report@build-coverage-report-from-tests -Denforcer.skip=true - name: Upload test results for site generation if: success() && github.event_name == 'merge_group' && matrix.test-jdk == '25' uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: test-results-for-site path: | java/sdk/target/jacoco-test-results/sdk-tests.exec java/sdk/target/surefire-reports/ java/sdk/target/surefire-reports-isolated/ retention-days: 1 - name: Generate Test Report Summary if: always() uses: ./.github/actions/java-test-report with: title: "Copilot Java SDK :: Test Results JDK ${{ matrix.test-jdk }}" - name: Upload test results on failure if: failure() uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: java-test-results-jdk-${{ matrix.test-jdk }} path: | java/sdk/target/surefire-reports/ java/sdk/target/surefire-reports-isolated/ java/sdk/target/failsafe-reports/ retention-days: 7