From 79b01a01c7d63ae37785968d65acebbe93dcc27e Mon Sep 17 00:00:00 2001 From: Alex Andres Date: Mon, 28 Sep 2026 23:56:59 +0200 Subject: [PATCH 1/3] ci: share one platform matrix and deploy snapshots once The seven platform builds were defined twice, in build.yml and in release.yml, and ran through four composite actions that were copies of each other: build and release, each with a macOS Intel variant. A cache key or runner change had to be made in up to six places. Move the matrix into the reusable platforms.yml, which both workflows call, and fold the four actions into one build action. The macOS Intel cross build becomes a matrix entry with its own JDK architectures, and the if/elif chains that mapped platforms to profiles become a matrix column. Releases now also run the ARM tests in test-natives before publishing. Every platform uploads its natives, and the build no longer deploys. On main, one deploy-snapshot job attaches the natives of all platforms to a single deployment once every platform has been built and tested, the way release.yml publishes a release. The seven jobs that each deployed the whole reactor raced on the snapshot metadata. Snapshots are deployed only from main, no longer from a manually dispatched build of another branch. The download, check and deploy steps shared by both publishing jobs move into a publish action. --- .github/actions/build-macos-x86_64/action.yml | 128 ----------- .github/actions/build/action.yml | 123 +++++++---- .github/actions/publish/action.yml | 84 +++++++ .../actions/release-macos-x86_64/action.yml | 135 ----------- .github/actions/release/action.yml | 131 ----------- .github/actions/test-natives/action.yml | 16 +- .github/workflows/build.yml | 209 ++++-------------- .github/workflows/platforms.yml | 143 ++++++++++++ .github/workflows/release.yml | 176 ++------------- 9 files changed, 382 insertions(+), 763 deletions(-) delete mode 100644 .github/actions/build-macos-x86_64/action.yml create mode 100644 .github/actions/publish/action.yml delete mode 100644 .github/actions/release-macos-x86_64/action.yml delete mode 100644 .github/actions/release/action.yml create mode 100644 .github/workflows/platforms.yml diff --git a/.github/actions/build-macos-x86_64/action.yml b/.github/actions/build-macos-x86_64/action.yml deleted file mode 100644 index 6ee6d9e7..00000000 --- a/.github/actions/build-macos-x86_64/action.yml +++ /dev/null @@ -1,128 +0,0 @@ -name: 'Maven Build' - -description: 'Build the platform dependent Java library' - -inputs: - java-version: - description: 'The Java build version.' - required: true - default: '17' - - platform-name: - description: 'The target platform.' - required: true - - maven-username: - description: 'The Maven username.' - required: true - - maven-password: - description: 'The Maven password.' - required: true - -runs: - using: "composite" - steps: - - name: Derive the WebRTC cache branch from the pom - run: echo "WEBRTC_CACHE_BRANCH=$(sed -n 's|.*branch-heads/\([^<]*\).*|\1|p' webrtc-jni/pom.xml)" >> "$GITHUB_ENV" - shell: bash - - # Restored here, saved right after the build below: the post step of - # actions/cache only saves when the whole job succeeds, so a failing test - # would otherwise throw away a WebRTC build that took the better part of an - # hour. - - id: webrtc-cache - name: Restore WebRTC cache - uses: actions/cache/restore@v6 - with: - path: ~/${{ env.WEBRTC_INSTALL_FOLDER }} - key: webrtc-${{ env.WEBRTC_CACHE_BRANCH }}-${{ inputs.platform-name }}-${{ hashFiles('webrtc-jni/src/main/cpp/dependencies/webrtc/CMakeLists.txt') }}-${{ hashFiles('webrtc-jni/pom.xml') }} - restore-keys: webrtc-${{ env.WEBRTC_CACHE_BRANCH }}-${{ inputs.platform-name }}-${{ hashFiles('webrtc-jni/src/main/cpp/dependencies/webrtc/CMakeLists.txt') }}- - - - name: Derive the FFmpeg version from the pom - run: echo "FFMPEG_VERSION=$(sed -n 's|.*\([^<]*\).*|\1|p' webrtc-java-media/pom.xml)" >> "$GITHUB_ENV" - shell: bash - - - id: ffmpeg-cache - name: Restore FFmpeg cache - uses: actions/cache/restore@v6 - with: - path: ~/ffmpeg - key: ffmpeg-${{ env.FFMPEG_VERSION }}-${{ inputs.platform-name }}-${{ hashFiles('webrtc-java-media/src/main/cpp/dependencies/ffmpeg/CMakeLists.txt') }}-${{ hashFiles('webrtc-java-media/pom.xml') }} - restore-keys: ffmpeg-${{ env.FFMPEG_VERSION }}-${{ inputs.platform-name }}-${{ hashFiles('webrtc-java-media/src/main/cpp/dependencies/ffmpeg/CMakeLists.txt') }}- - - # One cache per OS: the dependencies do not differ between the platforms of - # an OS. The project's own artifacts, which mvn deploy installs, change with - # every build and stay out of it. - - name: Set up Maven cache - uses: actions/cache@v6 - with: - path: | - ~/.m2/repository - !~/.m2/repository/dev/onvoid/webrtc - key: maven-${{ runner.os }}-${{ hashFiles('**/pom.xml') }} - restore-keys: maven-${{ runner.os }}- - - # The runner is Apple Silicon. The build runs natively and cross compiles - # for Intel; only the tests need an Intel JVM, to load what was built, and - # that one runs under Rosetta. - - id: jdk-x64 - name: Set up JDK (x64, for the tests) - uses: actions/setup-java@v5 - with: - architecture: 'x64' - java-version: ${{ inputs.java-version }} - distribution: 'temurin' - overwrite-settings: false - - # Set up last, so that it is the JAVA_HOME the build runs with and the one - # whose settings.xml carries the deploy credentials. - - name: Set up JDK (arm64, for the build) - uses: actions/setup-java@v5 - with: - architecture: 'aarch64' - java-version: ${{ inputs.java-version }} - distribution: 'temurin' - server-id: central - server-username: MAVEN_USERNAME - server-password: MAVEN_TOKEN - - - name: Build - run: mvn package -DskipTests -Pmacos-cross-x86_64 - shell: bash - - - name: Save WebRTC cache - if: steps.webrtc-cache.outputs.cache-hit != 'true' - uses: actions/cache/save@v6 - with: - path: ~/${{ env.WEBRTC_INSTALL_FOLDER }} - key: ${{ steps.webrtc-cache.outputs.cache-primary-key }} - - - name: Save FFmpeg cache - if: steps.ffmpeg-cache.outputs.cache-hit != 'true' - uses: actions/cache/save@v6 - with: - path: ~/ffmpeg - key: ${{ steps.ffmpeg-cache.outputs.cache-primary-key }} - - - name: Test - run: JAVA_HOME="${{ steps.jdk-x64.outputs.path }}" mvn -B jar:jar surefire:test -Pmacos-cross-x86_64 -Dsurefire.timeout=1800 - shell: bash - - # What failed, for runners that cannot be reproduced locally. - - name: Upload test reports - if: failure() - uses: actions/upload-artifact@v7 - with: - name: test-reports-${{ inputs.platform-name }} - path: '**/target/surefire-reports/' - if-no-files-found: ignore - retention-days: 7 - - - name: Deploy - if: ${{ github.event_name != 'pull_request' && github.repository == 'devopvoid/webrtc-java' }} - env: - MAVEN_USERNAME: ${{ inputs.maven-username }} - MAVEN_TOKEN: ${{ inputs.maven-password }} - run: mvn deploy -DskipTests -Pmacos-cross-x86_64 - shell: bash diff --git a/.github/actions/build/action.yml b/.github/actions/build/action.yml index 6c5463e5..cf132adc 100644 --- a/.github/actions/build/action.yml +++ b/.github/actions/build/action.yml @@ -1,24 +1,41 @@ name: 'Maven Build' -description: 'Build the platform dependent Java library' +description: 'Build and test the native libraries of one platform, and upload them as artifacts' inputs: + platform-name: + description: 'The target platform.' + required: true + + profile: + description: 'The Maven profile that selects a cross compiled classifier. Empty for the runner''s own.' + required: false + default: '' + + test: + description: 'Whether to run the tests. Cross compiled natives that the runner cannot load are tested elsewhere.' + required: false + default: 'true' + java-version: description: 'The Java build version.' - required: true + required: false default: '17' - platform-name: - description: 'The target platform.' - required: true + jdk-architecture: + description: 'The architecture of the JDK the build runs with. Empty for the runner''s own.' + required: false + default: '' - maven-username: - description: 'The Maven username.' - required: true + test-jdk-architecture: + description: 'The architecture of a second JDK the tests run with, when it differs from the build JDK.' + required: false + default: '' - maven-password: - description: 'The Maven password.' - required: true + retention-days: + description: 'How long the natives artifacts are kept.' + required: false + default: '1' runs: using: "composite" @@ -52,8 +69,8 @@ runs: restore-keys: ffmpeg-${{ env.FFMPEG_VERSION }}-${{ inputs.platform-name }}-${{ hashFiles('webrtc-java-media/src/main/cpp/dependencies/ffmpeg/CMakeLists.txt') }}- # One cache per OS: the dependencies do not differ between the platforms of - # an OS. The project's own artifacts, which mvn deploy installs, change with - # every build and stay out of it. + # an OS. The project's own artifacts change with every build and stay out + # of it. - name: Set up Maven cache uses: actions/cache@v6 with: @@ -63,26 +80,27 @@ runs: key: maven-${{ runner.os }}-${{ hashFiles('**/pom.xml') }} restore-keys: maven-${{ runner.os }}- + - id: test-jdk + name: Set up JDK ${{ inputs.java-version }} (${{ inputs.test-jdk-architecture }}, for the tests) + if: inputs.test-jdk-architecture != '' + uses: actions/setup-java@v5 + with: + architecture: ${{ inputs.test-jdk-architecture }} + java-version: ${{ inputs.java-version }} + distribution: 'temurin' + + # Set up last, so that it is the JAVA_HOME the build runs with. - name: Set up JDK ${{ inputs.java-version }} uses: actions/setup-java@v5 with: + architecture: ${{ inputs.jdk-architecture }} java-version: ${{ inputs.java-version }} distribution: 'temurin' - server-id: central - server-username: MAVEN_USERNAME - server-password: MAVEN_TOKEN - name: Build - run: | - if [ "${{ inputs.platform-name }}" == "linux_arm" ]; then - mvn package -DskipTests -Plinux-aarch32 - elif [ "${{ inputs.platform-name }}" == "linux_arm64" ]; then - mvn package -DskipTests -Plinux-aarch64 - elif [ "${{ inputs.platform-name }}" == "windows_arm64" ]; then - mvn package -DskipTests -Pwindows-aarch64 - else - mvn package -DskipTests - fi + env: + PROFILE: ${{ inputs.profile }} + run: mvn -B package -DskipTests ${PROFILE:+-P$PROFILE} shell: bash - name: Save WebRTC cache @@ -100,8 +118,15 @@ runs: key: ${{ steps.ffmpeg-cache.outputs.cache-primary-key }} - name: Test - if: ${{ inputs.platform-name != 'linux_arm' && inputs.platform-name != 'linux_arm64' && inputs.platform-name != 'windows_arm64' }} - run: mvn -B jar:jar surefire:test -Dsurefire.timeout=1800 + if: inputs.test == 'true' + env: + PROFILE: ${{ inputs.profile }} + TEST_JAVA_HOME: ${{ steps.test-jdk.outputs.path }} + run: | + if [ -n "$TEST_JAVA_HOME" ]; then + export JAVA_HOME="$TEST_JAVA_HOME" + fi + mvn -B jar:jar surefire:test ${PROFILE:+-P$PROFILE} -Dsurefire.timeout=1800 shell: bash # What failed, for runners that cannot be reproduced locally. @@ -114,19 +139,29 @@ runs: if-no-files-found: ignore retention-days: 7 - - name: Deploy - if: ${{ github.event_name != 'pull_request' && github.repository == 'devopvoid/webrtc-java' }} - env: - MAVEN_USERNAME: ${{ inputs.maven-username }} - MAVEN_TOKEN: ${{ inputs.maven-password }} - run: | - if [ "${{ inputs.platform-name }}" == "linux_arm" ]; then - mvn deploy -DskipTests -Plinux-aarch32 - elif [ "${{ inputs.platform-name }}" == "linux_arm64" ]; then - mvn deploy -DskipTests -Plinux-aarch64 - elif [ "${{ inputs.platform-name }}" == "windows_arm64" ]; then - mvn deploy -DskipTests -Pwindows-aarch64 - else - mvn deploy -DskipTests - fi - shell: bash + # The natives of every platform go to the callers' publishing job, which + # attaches all of them to a single deployment, and the cross compiled ones + # to test-natives as well. Both artifacts hold one flat jar each, so that a + # natives-* download with merge-multiple puts every jar into one directory. + - name: Upload native library jar + uses: actions/upload-artifact@v7 + with: + name: natives-${{ inputs.platform-name }} + path: webrtc-jni/target/webrtc-java-*.jar + if-no-files-found: error + retention-days: ${{ inputs.retention-days }} + overwrite: true + + # Only the classifier jar: the main jar is platform independent and the + # publishing job builds it itself. + - name: Upload media native library jar + uses: actions/upload-artifact@v7 + with: + name: natives-media-${{ inputs.platform-name }} + path: | + webrtc-java-media/target/webrtc-java-media-*-windows-*.jar + webrtc-java-media/target/webrtc-java-media-*-linux-*.jar + webrtc-java-media/target/webrtc-java-media-*-macos-*.jar + if-no-files-found: error + retention-days: ${{ inputs.retention-days }} + overwrite: true diff --git a/.github/actions/publish/action.yml b/.github/actions/publish/action.yml new file mode 100644 index 00000000..2182705c --- /dev/null +++ b/.github/actions/publish/action.yml @@ -0,0 +1,84 @@ +name: 'Maven Publish' + +description: 'Deploy one version with the native libraries of every platform attached, as a single deployment' + +# Expects the checkout of the version to deploy, a JDK whose settings.xml has +# the "central" server, and MAVEN_USERNAME and MAVEN_TOKEN (plus +# MAVEN_GPG_PASSPHRASE for a release) in the environment of the calling step. + +inputs: + version: + description: 'The version to deploy, as the natives jars are named.' + required: true + + profiles: + description: 'Maven profiles to activate, comma separated. "release" adds sources, javadoc and signatures.' + required: false + default: '' + + skip-publishing: + description: 'Build, sign and bundle everything, but upload nothing.' + required: false + default: 'false' + +runs: + using: "composite" + steps: + - name: Download the native library jars of all platforms + uses: actions/download-artifact@v8 + with: + pattern: natives-* + path: natives + merge-multiple: true + + - name: Verify that every platform is present + env: + VERSION: ${{ inputs.version }} + run: | + status=0 + + for classifier in windows-x86_64 windows-aarch64 linux-x86_64 linux-aarch64 \ + linux-aarch32 macos-x86_64 macos-aarch64; do + if [ ! -f "natives/webrtc-java-$VERSION-$classifier.jar" ]; then + echo "::error::Missing native library jar for $classifier" + status=1 + fi + if [ ! -f "natives/webrtc-java-media-$VERSION-$classifier.jar" ]; then + echo "::error::Missing media native library jar for $classifier" + status=1 + fi + done + + exit $status + shell: bash + + # The webrtc module depends on its own native library jar for the host + # platform. That dependency is normally installed by webrtc-jni, which is kept + # out of the reactor here to avoid rebuilding the native libraries. + - name: Seed the local repository with the host native library + env: + VERSION: ${{ inputs.version }} + run: | + mvn -B install:install-file \ + -Dfile="natives/webrtc-java-$VERSION-linux-x86_64.jar" \ + -DgroupId=dev.onvoid.webrtc \ + -DartifactId=webrtc-java \ + -Dversion="$VERSION" \ + -Dclassifier=linux-x86_64 \ + -Dpackaging=jar \ + -DgeneratePom=false + shell: bash + + # natives.dir makes webrtc and webrtc-java-media attach the jars of all + # platforms instead of the host's. skipPublishing suppresses both the + # bundling and the upload. + - name: Deploy + env: + PROFILES: ${{ inputs.profiles }} + SKIP_PUBLISHING: ${{ inputs.skip-publishing }} + run: > + mvn -B deploy -pl .,webrtc,webrtc-java-media -DskipTests + ${PROFILES:+-P$PROFILES} + -Dnatives.dir="$PWD/natives" + -DskipPublishing="$SKIP_PUBLISHING" + shell: bash diff --git a/.github/actions/release-macos-x86_64/action.yml b/.github/actions/release-macos-x86_64/action.yml deleted file mode 100644 index 42656994..00000000 --- a/.github/actions/release-macos-x86_64/action.yml +++ /dev/null @@ -1,135 +0,0 @@ -name: 'Maven Release' - -description: 'Release the platform dependent Java library' - -inputs: - java-version: - description: 'The Java build version.' - required: true - default: '17' - - platform-name: - description: 'The target platform.' - required: true - -runs: - using: "composite" - steps: - - name: Derive the WebRTC cache branch from the pom - run: echo "WEBRTC_CACHE_BRANCH=$(sed -n 's|.*branch-heads/\([^<]*\).*|\1|p' webrtc-jni/pom.xml)" >> "$GITHUB_ENV" - shell: bash - - # Restored here, saved right after the build below: the post step of - # actions/cache only saves when the whole job succeeds, so a failing test - # would otherwise throw away a WebRTC build that took the better part of an - # hour. - - id: webrtc-cache - name: Restore WebRTC cache - uses: actions/cache/restore@v6 - with: - path: ~/${{ env.WEBRTC_INSTALL_FOLDER }} - key: webrtc-${{ env.WEBRTC_CACHE_BRANCH }}-${{ inputs.platform-name }}-${{ hashFiles('webrtc-jni/src/main/cpp/dependencies/webrtc/CMakeLists.txt') }}-${{ hashFiles('webrtc-jni/pom.xml') }} - restore-keys: webrtc-${{ env.WEBRTC_CACHE_BRANCH }}-${{ inputs.platform-name }}-${{ hashFiles('webrtc-jni/src/main/cpp/dependencies/webrtc/CMakeLists.txt') }}- - - - name: Derive the FFmpeg version from the pom - run: echo "FFMPEG_VERSION=$(sed -n 's|.*\([^<]*\).*|\1|p' webrtc-java-media/pom.xml)" >> "$GITHUB_ENV" - shell: bash - - - id: ffmpeg-cache - name: Restore FFmpeg cache - uses: actions/cache/restore@v6 - with: - path: ~/ffmpeg - key: ffmpeg-${{ env.FFMPEG_VERSION }}-${{ inputs.platform-name }}-${{ hashFiles('webrtc-java-media/src/main/cpp/dependencies/ffmpeg/CMakeLists.txt') }}-${{ hashFiles('webrtc-java-media/pom.xml') }} - restore-keys: ffmpeg-${{ env.FFMPEG_VERSION }}-${{ inputs.platform-name }}-${{ hashFiles('webrtc-java-media/src/main/cpp/dependencies/ffmpeg/CMakeLists.txt') }}- - - # One cache per OS: the dependencies do not differ between the platforms of - # an OS. The project's own artifacts, which mvn deploy installs, change with - # every build and stay out of it. - - name: Set up Maven cache - uses: actions/cache@v6 - with: - path: | - ~/.m2/repository - !~/.m2/repository/dev/onvoid/webrtc - key: maven-${{ runner.os }}-${{ hashFiles('**/pom.xml') }} - restore-keys: maven-${{ runner.os }}- - - # The runner is Apple Silicon. The build runs natively and cross compiles - # for Intel; only the tests need an Intel JVM, to load what was built, and - # that one runs under Rosetta. - - id: jdk-x64 - name: Set up JDK ${{ inputs.java-version }} (x64, for the tests) - uses: actions/setup-java@v5 - with: - architecture: 'x64' - java-version: ${{ inputs.java-version }} - distribution: 'temurin' - - # Set up last, so that it is the JAVA_HOME the build runs with. - - name: Set up JDK ${{ inputs.java-version }} (arm64, for the build) - uses: actions/setup-java@v5 - with: - architecture: 'aarch64' - java-version: ${{ inputs.java-version }} - distribution: 'temurin' - - - name: Build - run: mvn package -DskipTests -Pmacos-cross-x86_64 - shell: bash - - - name: Save WebRTC cache - if: steps.webrtc-cache.outputs.cache-hit != 'true' - uses: actions/cache/save@v6 - with: - path: ~/${{ env.WEBRTC_INSTALL_FOLDER }} - key: ${{ steps.webrtc-cache.outputs.cache-primary-key }} - - - name: Save FFmpeg cache - if: steps.ffmpeg-cache.outputs.cache-hit != 'true' - uses: actions/cache/save@v6 - with: - path: ~/ffmpeg - key: ${{ steps.ffmpeg-cache.outputs.cache-primary-key }} - - - name: Test - run: JAVA_HOME="${{ steps.jdk-x64.outputs.path }}" mvn -B jar:jar surefire:test -Pmacos-cross-x86_64 -Dsurefire.timeout=1800 - shell: bash - - # What failed, for runners that cannot be reproduced locally. - - name: Upload test reports - if: failure() - uses: actions/upload-artifact@v7 - with: - name: test-reports-${{ inputs.platform-name }} - path: '**/target/surefire-reports/' - if-no-files-found: ignore - retention-days: 7 - - # Maven Central publishes a version as one atomic bundle, so this job must not - # deploy. The native library jar is handed to the aggregating publish-central - # job instead, which attaches every platform to a single deployment. - - name: Upload native library jar - uses: actions/upload-artifact@v7 - with: - name: natives-${{ inputs.platform-name }} - path: webrtc-jni/target/webrtc-java-*.jar - if-no-files-found: error - retention-days: 7 - overwrite: true - - # The media module's natives go the same way. Only the classifier jar: the - # main jar is platform independent and publish-central builds it itself. The - # name matches publish-central's natives-* download pattern, which merges - # both uploads into one flat directory. - - name: Upload media native library jar - uses: actions/upload-artifact@v7 - with: - name: natives-media-${{ inputs.platform-name }} - path: | - webrtc-java-media/target/webrtc-java-media-*-windows-*.jar - webrtc-java-media/target/webrtc-java-media-*-linux-*.jar - webrtc-java-media/target/webrtc-java-media-*-macos-*.jar - if-no-files-found: error - retention-days: 7 - overwrite: true diff --git a/.github/actions/release/action.yml b/.github/actions/release/action.yml deleted file mode 100644 index 45bba012..00000000 --- a/.github/actions/release/action.yml +++ /dev/null @@ -1,131 +0,0 @@ -name: 'Maven Release' - -description: 'Release the platform dependent Java library' - -inputs: - java-version: - description: 'The Java build version.' - required: true - default: '17' - - platform-name: - description: 'The target platform.' - required: true -runs: - using: "composite" - steps: - - name: Derive the WebRTC cache branch from the pom - run: echo "WEBRTC_CACHE_BRANCH=$(sed -n 's|.*branch-heads/\([^<]*\).*|\1|p' webrtc-jni/pom.xml)" >> "$GITHUB_ENV" - shell: bash - - # Restored here, saved right after the build below: the post step of - # actions/cache only saves when the whole job succeeds, so a failing test - # would otherwise throw away a WebRTC build that took the better part of an - # hour. - - id: webrtc-cache - name: Restore WebRTC cache - uses: actions/cache/restore@v6 - with: - path: ~/${{ env.WEBRTC_INSTALL_FOLDER }} - key: webrtc-${{ env.WEBRTC_CACHE_BRANCH }}-${{ inputs.platform-name }}-${{ hashFiles('webrtc-jni/src/main/cpp/dependencies/webrtc/CMakeLists.txt') }}-${{ hashFiles('webrtc-jni/pom.xml') }} - restore-keys: webrtc-${{ env.WEBRTC_CACHE_BRANCH }}-${{ inputs.platform-name }}-${{ hashFiles('webrtc-jni/src/main/cpp/dependencies/webrtc/CMakeLists.txt') }}- - - - name: Derive the FFmpeg version from the pom - run: echo "FFMPEG_VERSION=$(sed -n 's|.*\([^<]*\).*|\1|p' webrtc-java-media/pom.xml)" >> "$GITHUB_ENV" - shell: bash - - - id: ffmpeg-cache - name: Restore FFmpeg cache - uses: actions/cache/restore@v6 - with: - path: ~/ffmpeg - key: ffmpeg-${{ env.FFMPEG_VERSION }}-${{ inputs.platform-name }}-${{ hashFiles('webrtc-java-media/src/main/cpp/dependencies/ffmpeg/CMakeLists.txt') }}-${{ hashFiles('webrtc-java-media/pom.xml') }} - restore-keys: ffmpeg-${{ env.FFMPEG_VERSION }}-${{ inputs.platform-name }}-${{ hashFiles('webrtc-java-media/src/main/cpp/dependencies/ffmpeg/CMakeLists.txt') }}- - - # One cache per OS: the dependencies do not differ between the platforms of - # an OS. The project's own artifacts, which mvn deploy installs, change with - # every build and stay out of it. - - name: Set up Maven cache - uses: actions/cache@v6 - with: - path: | - ~/.m2/repository - !~/.m2/repository/dev/onvoid/webrtc - key: maven-${{ runner.os }}-${{ hashFiles('**/pom.xml') }} - restore-keys: maven-${{ runner.os }}- - - - name: Set up JDK ${{ inputs.java-version }} - uses: actions/setup-java@v5 - with: - java-version: ${{ inputs.java-version }} - distribution: 'temurin' - - - name: Build - run: | - if [ "${{ inputs.platform-name }}" == "linux_arm" ]; then - mvn package -DskipTests -Plinux-aarch32 - elif [ "${{ inputs.platform-name }}" == "linux_arm64" ]; then - mvn package -DskipTests -Plinux-aarch64 - elif [ "${{ inputs.platform-name }}" == "windows_arm64" ]; then - mvn package -DskipTests -Pwindows-aarch64 - else - mvn package -DskipTests - fi - shell: bash - - - name: Save WebRTC cache - if: steps.webrtc-cache.outputs.cache-hit != 'true' - uses: actions/cache/save@v6 - with: - path: ~/${{ env.WEBRTC_INSTALL_FOLDER }} - key: ${{ steps.webrtc-cache.outputs.cache-primary-key }} - - - name: Save FFmpeg cache - if: steps.ffmpeg-cache.outputs.cache-hit != 'true' - uses: actions/cache/save@v6 - with: - path: ~/ffmpeg - key: ${{ steps.ffmpeg-cache.outputs.cache-primary-key }} - - - name: Test - if: ${{ inputs.platform-name != 'linux_arm' && inputs.platform-name != 'linux_arm64' && inputs.platform-name != 'windows_arm64' }} - run: mvn -B jar:jar surefire:test -Dsurefire.timeout=1800 - shell: bash - - # What failed, for runners that cannot be reproduced locally. - - name: Upload test reports - if: failure() - uses: actions/upload-artifact@v7 - with: - name: test-reports-${{ inputs.platform-name }} - path: '**/target/surefire-reports/' - if-no-files-found: ignore - retention-days: 7 - - # Maven Central publishes a version as one atomic bundle, so this job must not - # deploy. The native library jar is handed to the aggregating publish-central - # job instead, which attaches every platform to a single deployment. - - name: Upload native library jar - uses: actions/upload-artifact@v7 - with: - name: natives-${{ inputs.platform-name }} - path: webrtc-jni/target/webrtc-java-*.jar - if-no-files-found: error - retention-days: 7 - overwrite: true - - # The media module's natives go the same way. Only the classifier jar: the - # main jar is platform independent and publish-central builds it itself. The - # name matches publish-central's natives-* download pattern, which merges - # both uploads into one flat directory. - - name: Upload media native library jar - uses: actions/upload-artifact@v7 - with: - name: natives-media-${{ inputs.platform-name }} - path: | - webrtc-java-media/target/webrtc-java-media-*-windows-*.jar - webrtc-java-media/target/webrtc-java-media-*-linux-*.jar - webrtc-java-media/target/webrtc-java-media-*-macos-*.jar - if-no-files-found: error - retention-days: 7 - overwrite: true diff --git a/.github/actions/test-natives/action.yml b/.github/actions/test-natives/action.yml index 490fd10c..91eccda8 100644 --- a/.github/actions/test-natives/action.yml +++ b/.github/actions/test-natives/action.yml @@ -33,12 +33,20 @@ inputs: runs: using: "composite" steps: + # The build uploads each platform's two native jars as separate artifacts, + # one flat jar each. - name: Download natives uses: actions/download-artifact@v8 with: name: natives-${{ inputs.platform-name }} path: natives + - name: Download media natives + uses: actions/download-artifact@v8 + with: + name: natives-media-${{ inputs.platform-name }} + path: natives + # PulseAudio, libudev and libdbus are deliberately not installed here: the # natives open them at runtime, and the armhf lane, whose image has none of # them, proves that they load without them. @@ -78,7 +86,11 @@ runs: - name: Install the natives into the local repository run: | VERSION=$(sed -n '0,//s|.*\([^<]*\).*|\1|p' pom.xml) - JAR=$(find natives -path '*webrtc-jni*' -name 'webrtc-java-*.jar' | head -n 1) + JAR=$(find natives -name 'webrtc-java-*-${{ inputs.classifier }}.jar' ! -name 'webrtc-java-media-*' | head -n 1) + if [ -z "$JAR" ]; then + echo "No webrtc-java natives for ${{ inputs.classifier }} in the artifact" >&2 + exit 1 + fi echo "Installing $JAR as webrtc-java:$VERSION:${{ inputs.classifier }}" mvn -B -q install:install-file -Dfile="$JAR" -DgroupId=dev.onvoid.webrtc \ -DartifactId=webrtc-java -Dversion="$VERSION" -Dpackaging=jar \ @@ -95,7 +107,7 @@ runs: - name: Unpack the natives where the tests look for them run: | MEDIA_JAR=$(find natives -name 'webrtc-java-media-*-${{ inputs.classifier }}.jar' | head -n 1) - WEBRTC_JAR=$(find natives -path '*webrtc-jni*' -name 'webrtc-java-*.jar' | head -n 1) + WEBRTC_JAR=$(find natives -name 'webrtc-java-*-${{ inputs.classifier }}.jar' ! -name 'webrtc-java-media-*' | head -n 1) if [ -z "$MEDIA_JAR" ]; then echo "No webrtc-java-media natives for ${{ inputs.classifier }} in the artifact" >&2 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e2f38542..c9c1c95f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -36,176 +36,59 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: ${{ github.event_name == 'pull_request' }} -env: - WEBRTC_CHECKOUT_FOLDER: webrtc - WEBRTC_INSTALL_FOLDER: webrtc/build - jobs: - build-windows: - strategy: - fail-fast: false - matrix: - platform: - - name: windows_x86_64 - runs-on: windows-2022 - - name: windows_arm64 - runs-on: windows-2022 - java: [17] - runs-on: ${{ matrix.platform.runs-on }} + platforms: + uses: ./.github/workflows/platforms.yml + with: + # Only the deploy-snapshot job of this same run reads them. + retention-days: 1 + + # One deployment with the natives of every platform attached, the way + # release.yml publishes a release, instead of seven jobs each deploying the + # whole reactor and racing on the snapshot metadata. It runs only once every + # platform has been built and tested. + deploy-snapshot: + name: Deploy snapshot + needs: platforms + if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main' && github.repository == 'devopvoid/webrtc-java' + runs-on: ubuntu-22.04 steps: - name: Checkout code uses: actions/checkout@v6 - with: - # The media module builds FFmpeg from its third-party submodule. - submodules: true - - - id: prepare - name: Prepare build - uses: ./.github/actions/prepare-windows - - - id: maven-build - name: Maven build - uses: ./.github/actions/build - with: - java-version: ${{ matrix.java }} - platform-name: ${{ matrix.platform.name }} - maven-username: ${{ secrets.MAVEN_USERNAME }} - maven-password: ${{ secrets.MAVEN_TOKEN }} - - name: Upload natives for native testing - if: matrix.platform.name == 'windows_arm64' - uses: actions/upload-artifact@v7 + - name: Set up Maven cache + uses: actions/cache@v6 with: - name: natives-${{ matrix.platform.name }} path: | - webrtc-jni/target/webrtc-java-*.jar - webrtc-java-media/target/webrtc-java-media-*.jar - if-no-files-found: error - # Only test-natives of this same run reads them. - retention-days: 1 + ~/.m2/repository + !~/.m2/repository/dev/onvoid/webrtc + key: maven-publish-${{ hashFiles('**/pom.xml') }} + restore-keys: maven-publish- - build-linux: - strategy: - fail-fast: false - matrix: - platform: - - name: linux_arm - runs-on: ubuntu-22.04 - - name: linux_arm64 - runs-on: ubuntu-22.04 - - name: linux_x86-64 - runs-on: ubuntu-22.04 - java: [17] - runs-on: ${{ matrix.platform.runs-on }} - steps: - - name: Checkout code - uses: actions/checkout@v6 + - name: Set up JDK 17 + uses: actions/setup-java@v5 with: - # The media module builds FFmpeg from its third-party submodule. - submodules: true - - - id: prepare - name: Prepare build - uses: ./.github/actions/prepare-linux - - - id: maven-build - name: Maven build - uses: ./.github/actions/build - with: - java-version: ${{ matrix.java }} - platform-name: ${{ matrix.platform.name }} - maven-username: ${{ secrets.MAVEN_USERNAME }} - maven-password: ${{ secrets.MAVEN_TOKEN }} - - - name: Upload natives for native testing - if: matrix.platform.name == 'linux_arm' || matrix.platform.name == 'linux_arm64' - uses: actions/upload-artifact@v7 - with: - name: natives-${{ matrix.platform.name }} - path: | - webrtc-jni/target/webrtc-java-*.jar - webrtc-java-media/target/webrtc-java-media-*.jar - if-no-files-found: error - # Only test-natives of this same run reads them. - retention-days: 1 - - build-macos: - strategy: - fail-fast: false - matrix: - platform: - - name: macos_x86-64 - runs-on: macos-14 - - name: macos_arm64 - runs-on: macos-14 - java: [17] - runs-on: ${{ matrix.platform.runs-on }} - steps: - - name: Checkout code - uses: actions/checkout@v6 - with: - # The media module builds FFmpeg from its third-party submodule. - submodules: true - - - id: prepare-build - name: Prepare build - uses: ./.github/actions/prepare-macos - - - id: maven-build-arm64 - name: Maven build - Apple Silicon - if: matrix.platform.name == 'macos_arm64' - uses: ./.github/actions/build - with: - java-version: ${{ matrix.java }} - platform-name: ${{ matrix.platform.name }} - maven-username: ${{ secrets.MAVEN_USERNAME }} - maven-password: ${{ secrets.MAVEN_TOKEN }} - - - id: maven-build-x86_64 - name: Maven build - Intel - if: matrix.platform.name == 'macos_x86-64' - uses: ./.github/actions/build-macos-x86_64 - with: - java-version: ${{ matrix.java }} - platform-name: ${{ matrix.platform.name }} - maven-username: ${{ secrets.MAVEN_USERNAME }} - maven-password: ${{ secrets.MAVEN_TOKEN }} - - test-natives: - needs: [build-windows, build-linux] - timeout-minutes: 30 - strategy: - fail-fast: false - matrix: - platform: - - name: windows_arm64 - runs-on: windows-11-arm - classifier: windows-aarch64 - profile: windows-aarch64 - java-distribution: microsoft - java-architecture: aarch64 - - name: linux_arm64 - runs-on: ubuntu-22.04-arm - classifier: linux-aarch64 - profile: linux-aarch64 - java-distribution: temurin - java-architecture: '' - - name: linux_arm - runs-on: ubuntu-22.04-arm - classifier: linux-aarch32 - profile: linux-aarch32 - java-distribution: liberica - java-architecture: armv7 - runs-on: ${{ matrix.platform.runs-on }} - steps: - - name: Checkout code - uses: actions/checkout@v6 - - - name: Test natives - uses: ./.github/actions/test-natives + java-version: '17' + distribution: 'temurin' + server-id: central + server-username: MAVEN_USERNAME + server-password: MAVEN_TOKEN + + - name: Determine the version to deploy + id: version + run: | + version=$(mvn -B -q -N help:evaluate -Dexpression=project.version -DforceStdout) + echo "Version to deploy: $version" + if [[ "$version" != *-SNAPSHOT ]]; then + echo "::error::main is at $version, which is not a snapshot; releases are published by release.yml" + exit 1 + fi + echo "version=$version" >> "$GITHUB_OUTPUT" + + - name: Deploy + uses: ./.github/actions/publish + env: + MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }} + MAVEN_TOKEN: ${{ secrets.MAVEN_TOKEN }} with: - platform-name: ${{ matrix.platform.name }} - classifier: ${{ matrix.platform.classifier }} - profile: ${{ matrix.platform.profile }} - java-distribution: ${{ matrix.platform.java-distribution }} - java-architecture: ${{ matrix.platform.java-architecture }} + version: ${{ steps.version.outputs.version }} diff --git a/.github/workflows/platforms.yml b/.github/workflows/platforms.yml new file mode 100644 index 00000000..215e92bc --- /dev/null +++ b/.github/workflows/platforms.yml @@ -0,0 +1,143 @@ +name: Platforms + +# Builds and tests the native libraries of every supported platform, and hands +# them on as artifacts: natives- holds the webrtc-java native jar, +# natives-media- the webrtc-java-media one. Nothing is deployed here; +# the callers do that once, from all platforms together, because Maven Central +# publishes a version as one bundle. +# +# Called by build.yml for every push and PR, and by release.yml for the tag it +# releases, so that both build exactly the same way. + +on: + workflow_call: + inputs: + ref: + description: "The commit, branch or tag to build. Empty for the one that triggered the caller." + type: string + default: '' + retention-days: + description: "How long the natives artifacts are kept." + type: number + default: 1 + +env: + # The default webrtc.install.dir of webrtc-jni/pom.xml, below the home directory. + WEBRTC_INSTALL_FOLDER: webrtc/build + +jobs: + build: + name: build (${{ matrix.platform.name }}) + strategy: + fail-fast: false + matrix: + # profile: the Maven profile that selects a cross compiled classifier; + # empty when the classifier is the runner's own. + # test: whether the runner can run what was built. The ARM builds are + # cross compiled and are tested by test-natives below instead. + # jdk-architecture, test-jdk-architecture: for the macOS Intel build, + # which runs on Apple Silicon: an arm64 JDK builds, an x64 JDK under + # Rosetta loads the Intel natives for the tests. + platform: + - name: windows_x86_64 + runs-on: windows-2022 + profile: '' + test: true + - name: windows_arm64 + runs-on: windows-2022 + profile: windows-aarch64 + test: false + - name: linux_x86-64 + runs-on: ubuntu-22.04 + profile: '' + test: true + - name: linux_arm64 + runs-on: ubuntu-22.04 + profile: linux-aarch64 + test: false + - name: linux_arm + runs-on: ubuntu-22.04 + profile: linux-aarch32 + test: false + - name: macos_arm64 + runs-on: macos-14 + profile: '' + test: true + - name: macos_x86-64 + runs-on: macos-14 + profile: macos-cross-x86_64 + test: true + jdk-architecture: aarch64 + test-jdk-architecture: x64 + runs-on: ${{ matrix.platform.runs-on }} + steps: + - name: Checkout code + uses: actions/checkout@v6 + with: + ref: ${{ inputs.ref }} + # The media module builds FFmpeg from its third-party submodule. + submodules: true + + - name: Prepare build + if: runner.os == 'Windows' + uses: ./.github/actions/prepare-windows + + - name: Prepare build + if: runner.os == 'Linux' + uses: ./.github/actions/prepare-linux + + - name: Prepare build + if: runner.os == 'macOS' + uses: ./.github/actions/prepare-macos + + - name: Maven build + uses: ./.github/actions/build + with: + platform-name: ${{ matrix.platform.name }} + profile: ${{ matrix.platform.profile }} + test: ${{ matrix.platform.test }} + jdk-architecture: ${{ matrix.platform.jdk-architecture || '' }} + test-jdk-architecture: ${{ matrix.platform.test-jdk-architecture || '' }} + retention-days: ${{ inputs.retention-days }} + + test-natives: + name: test-natives (${{ matrix.platform.name }}) + needs: build + timeout-minutes: 30 + strategy: + fail-fast: false + matrix: + platform: + - name: windows_arm64 + runs-on: windows-11-arm + classifier: windows-aarch64 + profile: windows-aarch64 + java-distribution: microsoft + java-architecture: aarch64 + - name: linux_arm64 + runs-on: ubuntu-22.04-arm + classifier: linux-aarch64 + profile: linux-aarch64 + java-distribution: temurin + java-architecture: '' + - name: linux_arm + runs-on: ubuntu-22.04-arm + classifier: linux-aarch32 + profile: linux-aarch32 + java-distribution: liberica + java-architecture: armv7 + runs-on: ${{ matrix.platform.runs-on }} + steps: + - name: Checkout code + uses: actions/checkout@v6 + with: + ref: ${{ inputs.ref }} + + - name: Test natives + uses: ./.github/actions/test-natives + with: + platform-name: ${{ matrix.platform.name }} + classifier: ${{ matrix.platform.classifier }} + profile: ${{ matrix.platform.profile }} + java-distribution: ${{ matrix.platform.java-distribution }} + java-architecture: ${{ matrix.platform.java-architecture }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 433eb998..6a7237b2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,10 +13,6 @@ on: type: boolean default: false -env: - WEBRTC_CHECKOUT_FOLDER: webrtc - WEBRTC_INSTALL_FOLDER: webrtc/build - # Only the jobs that push commits, tags or the GitHub release get write access. permissions: contents: read @@ -155,119 +151,18 @@ jobs: # The branch and the tag land together or not at all. git push --atomic origin HEAD:main "refs/tags/$RELEASE_TAG" - build-windows: - needs: prepare-release - strategy: - fail-fast: false - matrix: - platform: - - name: windows_x86_64 - runs-on: windows-2022 - - name: windows_arm64 - runs-on: windows-2022 - java: [17] - runs-on: ${{ matrix.platform.runs-on }} - steps: - # The tag prepare-release pushed. A dry run pushes none and builds the - # dispatched commit instead. - - name: Checkout code - uses: actions/checkout@v6 - with: - ref: ${{ !inputs.dryRun && needs.prepare-release.outputs.release_tag || '' }} - # The media module builds FFmpeg from its third-party submodule. - submodules: true - - - id: prepare - name: Prepare release build - uses: ./.github/actions/prepare-windows - - - id: maven-build - name: Maven build - uses: ./.github/actions/release - with: - java-version: ${{ matrix.java }} - platform-name: ${{ matrix.platform.name }} - - build-linux: - needs: prepare-release - strategy: - fail-fast: false - matrix: - platform: - - name: linux_arm - runs-on: ubuntu-22.04 - - name: linux_arm64 - runs-on: ubuntu-22.04 - - name: linux_x86-64 - runs-on: ubuntu-22.04 - java: [17] - runs-on: ${{ matrix.platform.runs-on }} - steps: - # The tag prepare-release pushed. A dry run pushes none and builds the - # dispatched commit instead. - - name: Checkout code - uses: actions/checkout@v6 - with: - ref: ${{ !inputs.dryRun && needs.prepare-release.outputs.release_tag || '' }} - # The media module builds FFmpeg from its third-party submodule. - submodules: true - - - id: prepare-build - name: Prepare release build - uses: ./.github/actions/prepare-linux - - - id: maven-build - name: Maven build - uses: ./.github/actions/release - with: - java-version: ${{ matrix.java }} - platform-name: ${{ matrix.platform.name }} - - build-macos: + # The tag prepare-release pushed. A dry run pushes none and builds the + # dispatched commit instead. + platforms: needs: prepare-release - strategy: - fail-fast: false - matrix: - platform: - - name: macos_x86-64 - runs-on: macos-14 - - name: macos_arm64 - runs-on: macos-14 - java: [17] - runs-on: ${{ matrix.platform.runs-on }} - steps: - # The tag prepare-release pushed. A dry run pushes none and builds the - # dispatched commit instead. - - name: Checkout code - uses: actions/checkout@v6 - with: - ref: ${{ !inputs.dryRun && needs.prepare-release.outputs.release_tag || '' }} - # The media module builds FFmpeg from its third-party submodule. - submodules: true - - - id: prepare-build - name: Prepare release build - uses: ./.github/actions/prepare-macos - - - id: maven-build-arm64 - name: Maven build - Apple Silicon - if: matrix.platform.name == 'macos_arm64' - uses: ./.github/actions/release - with: - java-version: ${{ matrix.java }} - platform-name: ${{ matrix.platform.name }} - - - id: maven-build-x86_64 - name: Maven build - Intel - if: matrix.platform.name == 'macos_x86-64' - uses: ./.github/actions/release-macos-x86_64 - with: - java-version: ${{ matrix.java }} - platform-name: ${{ matrix.platform.name }} + uses: ./.github/workflows/platforms.yml + with: + ref: ${{ !inputs.dryRun && needs.prepare-release.outputs.release_tag || '' }} + retention-days: 7 publish-central: name: Publish to Maven Central - needs: [prepare-release, build-windows, build-linux, build-macos] + needs: [prepare-release, platforms] runs-on: ubuntu-22.04 steps: @@ -279,7 +174,9 @@ jobs: - name: Set up Maven cache uses: actions/cache@v6 with: - path: ~/.m2/repository + path: | + ~/.m2/repository + !~/.m2/repository/dev/onvoid/webrtc key: maven-publish-${{ hashFiles('**/pom.xml') }} restore-keys: maven-publish- @@ -308,48 +205,6 @@ jobs: echo "Version to publish: $version" echo "version=$version" >> "$GITHUB_OUTPUT" - - name: Download the native library jars of all platforms - uses: actions/download-artifact@v8 - with: - pattern: natives-* - path: natives - merge-multiple: true - - - name: Verify that every platform is present - run: | - version="${{ steps.release-version.outputs.version }}" - status=0 - - for classifier in windows-x86_64 windows-aarch64 linux-x86_64 linux-aarch64 \ - linux-aarch32 macos-x86_64 macos-aarch64; do - if [ ! -f "natives/webrtc-java-$version-$classifier.jar" ]; then - echo "::error::Missing native library jar for $classifier" - status=1 - fi - if [ ! -f "natives/webrtc-java-media-$version-$classifier.jar" ]; then - echo "::error::Missing media native library jar for $classifier" - status=1 - fi - done - - exit $status - - # The webrtc module depends on its own native library jar for the host - # platform. That dependency is normally installed by webrtc-jni, which is kept - # out of the reactor here to avoid rebuilding the native libraries. - - name: Seed the local repository with the host native library - run: | - version="${{ steps.release-version.outputs.version }}" - - mvn -B install:install-file \ - -Dfile="natives/webrtc-java-$version-linux-x86_64.jar" \ - -DgroupId=dev.onvoid.webrtc \ - -DartifactId=webrtc-java \ - -Dversion="$version" \ - -Dclassifier=linux-x86_64 \ - -Dpackaging=jar \ - -DgeneratePom=false - # skipPublishing suppresses both the bundling and the upload, so a dry run # still builds, signs and attaches everything without anything leaving the # runner. As a second line of defence the Central credentials are replaced by @@ -357,14 +212,15 @@ jobs: # fails on authentication instead of publishing a release. Signing does run, so # the GPG passphrase stays intact. - name: Deploy + uses: ./.github/actions/publish env: MAVEN_USERNAME: ${{ inputs.dryRun && 'dry-run-must-not-upload' || secrets.MAVEN_USERNAME }} MAVEN_TOKEN: ${{ inputs.dryRun && 'dry-run-must-not-upload' || secrets.MAVEN_TOKEN }} MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }} - run: > - mvn -B deploy -pl .,webrtc,webrtc-java-media -Prelease -DskipTests - -Dnatives.dir="$PWD/natives" - -DskipPublishing=${{ inputs.dryRun }} + with: + version: ${{ steps.release-version.outputs.version }} + profiles: release + skip-publishing: ${{ inputs.dryRun }} - name: Summarize what would have been published if: ${{ inputs.dryRun }} From 822f5b13419f15fed5d956cdc021a04e1b8c2b2f Mon Sep 17 00:00:00 2001 From: Alex Andres Date: Tue, 29 Sep 2026 00:14:09 +0200 Subject: [PATCH 2/3] ci: test every platform on its own hardware test-natives tested only the three ARM platforms, the ones cross compiled for a runner that could not load them. The other four ran their tests in the build job, and the macOS Intel natives only under Rosetta, on the Apple Silicon runner that cross compiled them. Test all seven platforms in test-natives instead, each on a runner of its own OS and architecture and against the natives the build job uploaded, which are the ones that get published. The macOS Intel natives are now tested on an Intel runner. The build job only builds, so it no longer sets up a second JDK or runs the tests. --- .github/actions/build/action.yml | 65 ++++--------------------- .github/actions/test-natives/action.yml | 2 +- .github/workflows/platforms.yml | 55 ++++++++++++--------- 3 files changed, 41 insertions(+), 81 deletions(-) diff --git a/.github/actions/build/action.yml b/.github/actions/build/action.yml index cf132adc..585754e1 100644 --- a/.github/actions/build/action.yml +++ b/.github/actions/build/action.yml @@ -1,6 +1,6 @@ name: 'Maven Build' -description: 'Build and test the native libraries of one platform, and upload them as artifacts' +description: 'Build the native libraries of one platform and upload them as artifacts' inputs: platform-name: @@ -12,26 +12,11 @@ inputs: required: false default: '' - test: - description: 'Whether to run the tests. Cross compiled natives that the runner cannot load are tested elsewhere.' - required: false - default: 'true' - java-version: description: 'The Java build version.' required: false default: '17' - jdk-architecture: - description: 'The architecture of the JDK the build runs with. Empty for the runner''s own.' - required: false - default: '' - - test-jdk-architecture: - description: 'The architecture of a second JDK the tests run with, when it differs from the build JDK.' - required: false - default: '' - retention-days: description: 'How long the natives artifacts are kept.' required: false @@ -45,9 +30,9 @@ runs: shell: bash # Restored here, saved right after the build below: the post step of - # actions/cache only saves when the whole job succeeds, so a failing test - # would otherwise throw away a WebRTC build that took the better part of an - # hour. + # actions/cache only saves when the whole job succeeds, so a failure in a + # later step would otherwise throw away a WebRTC build that took the better + # part of an hour. - id: webrtc-cache name: Restore WebRTC cache uses: actions/cache/restore@v6 @@ -80,20 +65,9 @@ runs: key: maven-${{ runner.os }}-${{ hashFiles('**/pom.xml') }} restore-keys: maven-${{ runner.os }}- - - id: test-jdk - name: Set up JDK ${{ inputs.java-version }} (${{ inputs.test-jdk-architecture }}, for the tests) - if: inputs.test-jdk-architecture != '' - uses: actions/setup-java@v5 - with: - architecture: ${{ inputs.test-jdk-architecture }} - java-version: ${{ inputs.java-version }} - distribution: 'temurin' - - # Set up last, so that it is the JAVA_HOME the build runs with. - name: Set up JDK ${{ inputs.java-version }} uses: actions/setup-java@v5 with: - architecture: ${{ inputs.jdk-architecture }} java-version: ${{ inputs.java-version }} distribution: 'temurin' @@ -117,32 +91,11 @@ runs: path: ~/ffmpeg key: ${{ steps.ffmpeg-cache.outputs.cache-primary-key }} - - name: Test - if: inputs.test == 'true' - env: - PROFILE: ${{ inputs.profile }} - TEST_JAVA_HOME: ${{ steps.test-jdk.outputs.path }} - run: | - if [ -n "$TEST_JAVA_HOME" ]; then - export JAVA_HOME="$TEST_JAVA_HOME" - fi - mvn -B jar:jar surefire:test ${PROFILE:+-P$PROFILE} -Dsurefire.timeout=1800 - shell: bash - - # What failed, for runners that cannot be reproduced locally. - - name: Upload test reports - if: failure() - uses: actions/upload-artifact@v7 - with: - name: test-reports-${{ inputs.platform-name }} - path: '**/target/surefire-reports/' - if-no-files-found: ignore - retention-days: 7 - - # The natives of every platform go to the callers' publishing job, which - # attaches all of them to a single deployment, and the cross compiled ones - # to test-natives as well. Both artifacts hold one flat jar each, so that a - # natives-* download with merge-multiple puts every jar into one directory. + # The natives of every platform go to test-natives, which tests them on a + # runner of their own OS and architecture, and to the callers' publishing + # job, which attaches all of them to a single deployment. Both artifacts + # hold one flat jar each, so that a natives-* download with merge-multiple + # puts every jar into one directory. - name: Upload native library jar uses: actions/upload-artifact@v7 with: diff --git a/.github/actions/test-natives/action.yml b/.github/actions/test-natives/action.yml index 91eccda8..7703bf71 100644 --- a/.github/actions/test-natives/action.yml +++ b/.github/actions/test-natives/action.yml @@ -1,6 +1,6 @@ name: 'Test Natives' -description: 'Run the test suite on a native runner against natives that a cross compiling lane built' +description: 'Run the test suite on a runner of the platform''s own OS and architecture, against the natives the build job uploaded' inputs: platform-name: diff --git a/.github/workflows/platforms.yml b/.github/workflows/platforms.yml index 215e92bc..4edb0350 100644 --- a/.github/workflows/platforms.yml +++ b/.github/workflows/platforms.yml @@ -1,7 +1,7 @@ name: Platforms -# Builds and tests the native libraries of every supported platform, and hands -# them on as artifacts: natives- holds the webrtc-java native jar, +# Builds the native libraries of every supported platform, tests each of them on +# a runner of its own OS and architecture, and hands them on as artifacts: natives- holds the webrtc-java native jar, # natives-media- the webrtc-java-media one. Nothing is deployed here; # the callers do that once, from all platforms together, because Maven Central # publishes a version as one bundle. @@ -32,43 +32,30 @@ jobs: fail-fast: false matrix: # profile: the Maven profile that selects a cross compiled classifier; - # empty when the classifier is the runner's own. - # test: whether the runner can run what was built. The ARM builds are - # cross compiled and are tested by test-natives below instead. - # jdk-architecture, test-jdk-architecture: for the macOS Intel build, - # which runs on Apple Silicon: an arm64 JDK builds, an x64 JDK under - # Rosetta loads the Intel natives for the tests. + # empty when the classifier is the runner's own. The macOS Intel + # build runs on Apple Silicon and cross compiles. platform: - name: windows_x86_64 runs-on: windows-2022 profile: '' - test: true - name: windows_arm64 runs-on: windows-2022 profile: windows-aarch64 - test: false - name: linux_x86-64 runs-on: ubuntu-22.04 profile: '' - test: true - name: linux_arm64 runs-on: ubuntu-22.04 profile: linux-aarch64 - test: false - name: linux_arm runs-on: ubuntu-22.04 profile: linux-aarch32 - test: false - name: macos_arm64 runs-on: macos-14 profile: '' - test: true - name: macos_x86-64 runs-on: macos-14 profile: macos-cross-x86_64 - test: true - jdk-architecture: aarch64 - test-jdk-architecture: x64 runs-on: ${{ matrix.platform.runs-on }} steps: - name: Checkout code @@ -95,11 +82,12 @@ jobs: with: platform-name: ${{ matrix.platform.name }} profile: ${{ matrix.platform.profile }} - test: ${{ matrix.platform.test }} - jdk-architecture: ${{ matrix.platform.jdk-architecture || '' }} - test-jdk-architecture: ${{ matrix.platform.test-jdk-architecture || '' }} retention-days: ${{ inputs.retention-days }} + # Every platform is tested on a runner of its own OS and architecture, + # against the natives the build job uploaded, so that what is tested is + # exactly what gets published. Most of them are cross compiled and could not + # be loaded on the runner that built them. test-natives: name: test-natives (${{ matrix.platform.name }}) needs: build @@ -107,25 +95,44 @@ jobs: strategy: fail-fast: false matrix: + # java-architecture: the JDK architecture, when it differs from the + # runner's. linux_arm runs a 32-bit ARM JDK on an arm64 runner. platform: + - name: windows_x86_64 + runs-on: windows-2022 + classifier: windows-x86_64 + java-distribution: temurin + java-architecture: '' - name: windows_arm64 runs-on: windows-11-arm classifier: windows-aarch64 - profile: windows-aarch64 java-distribution: microsoft java-architecture: aarch64 + - name: linux_x86-64 + runs-on: ubuntu-22.04 + classifier: linux-x86_64 + java-distribution: temurin + java-architecture: '' - name: linux_arm64 runs-on: ubuntu-22.04-arm classifier: linux-aarch64 - profile: linux-aarch64 java-distribution: temurin java-architecture: '' - name: linux_arm runs-on: ubuntu-22.04-arm classifier: linux-aarch32 - profile: linux-aarch32 java-distribution: liberica java-architecture: armv7 + - name: macos_arm64 + runs-on: macos-14 + classifier: macos-aarch64 + java-distribution: temurin + java-architecture: '' + - name: macos_x86-64 + runs-on: macos-15-intel + classifier: macos-x86_64 + java-distribution: temurin + java-architecture: '' runs-on: ${{ matrix.platform.runs-on }} steps: - name: Checkout code @@ -138,6 +145,6 @@ jobs: with: platform-name: ${{ matrix.platform.name }} classifier: ${{ matrix.platform.classifier }} - profile: ${{ matrix.platform.profile }} + profile: ${{ matrix.platform.classifier }} java-distribution: ${{ matrix.platform.java-distribution }} java-architecture: ${{ matrix.platform.java-architecture }} From fbeba306321c1c3591a4e2a75d8a9617c49e55a1 Mon Sep 17 00:00:00 2001 From: Alex Andres Date: Tue, 29 Sep 2026 08:07:46 +0200 Subject: [PATCH 3/3] ci: read the project version portably in test-natives The macOS test lanes installed the natives as webrtc-java::, without a version, and then could not resolve them. The version came from sed's 0,/re/ address, which only GNU sed knows; the Linux and Windows runners have GNU sed, macOS has BSD sed. Take the first of the root pom with plain sed and head instead, and fail right there when it comes out empty. Also drop the step that downloaded Maven when a runner had none. Every runner test-natives uses ships with Maven, the ARM partner images included, and none of them took that branch. --- .github/actions/test-natives/action.yml | 19 +++++++------------ .github/workflows/platforms.yml | 9 +++++---- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/.github/actions/test-natives/action.yml b/.github/actions/test-natives/action.yml index 7703bf71..4ae794c9 100644 --- a/.github/actions/test-natives/action.yml +++ b/.github/actions/test-natives/action.yml @@ -72,20 +72,15 @@ runs: distribution: ${{ inputs.java-distribution }} architecture: ${{ inputs.java-architecture }} - - name: Ensure Maven - run: | - if ! command -v mvn >/dev/null 2>&1; then - url=https://archive.apache.org/dist/maven/maven-3/3.9.9/binaries/apache-maven-3.9.9-bin.zip - curl -sSfLo maven.zip "$url" - echo "$(curl -sSfL "$url.sha512" | cut -d' ' -f1) maven.zip" | sha512sum -c - - unzip -q maven.zip -d "$RUNNER_TEMP/maven" - echo "$RUNNER_TEMP/maven/apache-maven-3.9.9/bin" >> "$GITHUB_PATH" - fi - shell: bash - - name: Install the natives into the local repository run: | - VERSION=$(sed -n '0,//s|.*\([^<]*\).*|\1|p' pom.xml) + # The root pom has no parent, so its first is the project's. + # Not sed's 0,/re/ address: that is GNU only, and macOS has BSD sed. + VERSION=$(sed -n 's|.*\([^<]*\).*|\1|p' pom.xml | head -n 1) + if [ -z "$VERSION" ]; then + echo "Could not read the project version from pom.xml" >&2 + exit 1 + fi JAR=$(find natives -name 'webrtc-java-*-${{ inputs.classifier }}.jar' ! -name 'webrtc-java-media-*' | head -n 1) if [ -z "$JAR" ]; then echo "No webrtc-java natives for ${{ inputs.classifier }} in the artifact" >&2 diff --git a/.github/workflows/platforms.yml b/.github/workflows/platforms.yml index 4edb0350..ecf44bdc 100644 --- a/.github/workflows/platforms.yml +++ b/.github/workflows/platforms.yml @@ -1,10 +1,11 @@ name: Platforms # Builds the native libraries of every supported platform, tests each of them on -# a runner of its own OS and architecture, and hands them on as artifacts: natives- holds the webrtc-java native jar, -# natives-media- the webrtc-java-media one. Nothing is deployed here; -# the callers do that once, from all platforms together, because Maven Central -# publishes a version as one bundle. +# a runner of its own OS and architecture, and hands them on as artifacts: +# natives- holds the webrtc-java native jar, natives-media- +# the webrtc-java-media one. Nothing is deployed here; the callers do that once, +# from all platforms together, because Maven Central publishes a version as one +# bundle. # # Called by build.yml for every push and PR, and by release.yml for the tag it # releases, so that both build exactly the same way.