diff --git a/.github/actions/build-macos-x86_64/action.yml b/.github/actions/build-macos-x86_64/action.yml
index 816ac11f..3315021d 100644
--- a/.github/actions/build-macos-x86_64/action.yml
+++ b/.github/actions/build-macos-x86_64/action.yml
@@ -27,8 +27,13 @@ runs:
run: echo "WEBRTC_CACHE_BRANCH=$(sed -n 's|.*branch-heads/\([^<]*\).*|\1|p' webrtc-jni/pom.xml)" >> "$GITHUB_ENV"
shell: bash
- - name: Set up WebRTC cache
- uses: actions/cache@v6
+ # 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') }}
@@ -38,8 +43,9 @@ runs:
run: echo "FFMPEG_VERSION=$(sed -n 's|.*\([^<]*\).*|\1|p' webrtc-java-media/pom.xml)" >> "$GITHUB_ENV"
shell: bash
- - name: Set up FFmpeg cache
- uses: actions/cache@v6
+ - 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') }}
@@ -80,10 +86,34 @@ runs:
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
+ 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:
diff --git a/.github/actions/build/action.yml b/.github/actions/build/action.yml
index 887b1aa4..7baeb547 100644
--- a/.github/actions/build/action.yml
+++ b/.github/actions/build/action.yml
@@ -27,8 +27,13 @@ runs:
run: echo "WEBRTC_CACHE_BRANCH=$(sed -n 's|.*branch-heads/\([^<]*\).*|\1|p' webrtc-jni/pom.xml)" >> "$GITHUB_ENV"
shell: bash
- - name: Set up WebRTC cache
- uses: actions/cache@v6
+ # 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') }}
@@ -38,8 +43,9 @@ runs:
run: echo "FFMPEG_VERSION=$(sed -n 's|.*\([^<]*\).*|\1|p' webrtc-java-media/pom.xml)" >> "$GITHUB_ENV"
shell: bash
- - name: Set up FFmpeg cache
- uses: actions/cache@v6
+ - 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') }}
@@ -74,11 +80,35 @@ runs:
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
+ 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
+
- name: Deploy
if: ${{ github.event_name != 'pull_request' && github.repository == 'devopvoid/webrtc-java' }}
env:
diff --git a/.github/actions/prepare-linux/action.yml b/.github/actions/prepare-linux/action.yml
index 9fc88bfc..4a36699b 100644
--- a/.github/actions/prepare-linux/action.yml
+++ b/.github/actions/prepare-linux/action.yml
@@ -30,20 +30,35 @@ runs:
- name: Install required packages
run: |
- sudo apt update
+ sudo apt-get update -q
# nasm is what FFmpeg assembles its x86 code with.
- sudo apt install -y binutils cmake git locales lsb-release nasm ninja-build pipewire pipewire-pulse pkg-config python3 python3-setuptools rsync unzip wget xz-utils
+ sudo apt-get install -y -q binutils cmake git locales lsb-release nasm ninja-build pipewire pipewire-pulse pkg-config python3 python3-setuptools rsync unzip wget xz-utils
+ shell: bash
+
+ # Chromium Clang to be used with the clang toolchain file. The JNI code
+ # compiles against the libc++ headers of the WebRTC build, which only
+ # support the Clang that WebRTC branch ships with, so this must be the
+ # package pinned by CLANG_REVISION and CLANG_SUB_REVISION in
+ # tools/clang/scripts/update.py of the webrtc.branch set in
+ # webrtc-jni/pom.xml. Update it whenever that branch changes.
+ - name: Select the Chromium Clang package
+ run: echo "CLANG_PACKAGE=clang-llvmorg-23-init-19482-g53d18800-1.tar.xz" >> "$GITHUB_ENV"
+ shell: bash
- # Chromium Clang to be used with the clang toolchain file. The JNI code
- # compiles against the libc++ headers of the WebRTC build, which only
- # support the Clang that WebRTC branch ships with, so this must be the
- # package pinned by CLANG_REVISION and CLANG_SUB_REVISION in
- # tools/clang/scripts/update.py of the webrtc.branch set in
- # webrtc-jni/pom.xml. Update it whenever that branch changes.
- CLANG_PACKAGE=clang-llvmorg-23-init-19482-g53d18800-1.tar.xz
+ - name: Cache the Chromium Clang package
+ uses: actions/cache@v6
+ with:
+ path: ~/.cache/chromium-clang
+ key: chromium-clang-${{ env.CLANG_PACKAGE }}
+
+ - name: Install Chromium Clang
+ run: |
+ mkdir -p ~/.cache/chromium-clang
+ if [ ! -f ~/.cache/chromium-clang/$CLANG_PACKAGE ]; then
+ wget -q -O ~/.cache/chromium-clang/$CLANG_PACKAGE https://commondatastorage.googleapis.com/chromium-browser-clang/Linux_x64/$CLANG_PACKAGE
+ fi
sudo mkdir -p /opt/clang
- wget https://commondatastorage.googleapis.com/chromium-browser-clang/Linux_x64/$CLANG_PACKAGE
- sudo tar -xvf $CLANG_PACKAGE -C /opt/clang
+ sudo tar -xf ~/.cache/chromium-clang/$CLANG_PACKAGE -C /opt/clang
shell: bash
- name: Install required packages for x86-64
diff --git a/.github/actions/prepare-macos/action.yml b/.github/actions/prepare-macos/action.yml
index 5ef69300..cc07285e 100644
--- a/.github/actions/prepare-macos/action.yml
+++ b/.github/actions/prepare-macos/action.yml
@@ -5,7 +5,11 @@ description: 'Installs required packages for macOS builds.'
runs:
using: "composite"
steps:
+ # No Homebrew self-update: it takes minutes and neither package needs it.
- name: Install required packages
+ env:
+ HOMEBREW_NO_AUTO_UPDATE: '1'
+ HOMEBREW_NO_INSTALL_CLEANUP: '1'
run: |
# Required on macos-14
brew install python-setuptools
diff --git a/.github/actions/prepare-windows/action.yml b/.github/actions/prepare-windows/action.yml
index 692cf2bf..98e9c1f7 100644
--- a/.github/actions/prepare-windows/action.yml
+++ b/.github/actions/prepare-windows/action.yml
@@ -5,35 +5,6 @@ description: 'Frees up disk space and installs required packages for Windows bui
runs:
using: "composite"
steps:
- - name: Set up Python 3.11
- if: false
- uses: actions/setup-python@v7
- with:
- python-version: "3.11"
-
- - name: Disk cleanup
- if: false
- run: |
- Get-PSDrive
- # Docker Images
- docker rmi $(docker images -q -a)
- # Android SDK
- if ($Env:ANDROID_HOME) {
- Remove-Item -Recurse -Force $Env:ANDROID_HOME -ErrorAction Ignore
- }
- if ($Env:ANDROID_NDK_HOME) {
- Remove-Item -Recurse -Force $Env:ANDROID_NDK_HOME -ErrorAction Ignore
- }
- # JVM
- if ($Env:JAVA_HOME_11_X64) {
- Remove-Item -Recurse -Force $Env:JAVA_HOME_11_X64 -ErrorAction Ignore
- }
- if ($Env:JAVA_HOME_8_X64) {
- Remove-Item -Recurse -Force $Env:JAVA_HOME_8_X64 -ErrorAction Ignore
- }
- Get-PSDrive
- shell: powershell
-
- name: Install required packages
run: |
choco install ninja
diff --git a/.github/actions/release-macos-x86_64/action.yml b/.github/actions/release-macos-x86_64/action.yml
index cae846a1..c0ac1510 100644
--- a/.github/actions/release-macos-x86_64/action.yml
+++ b/.github/actions/release-macos-x86_64/action.yml
@@ -19,8 +19,13 @@ runs:
run: echo "WEBRTC_CACHE_BRANCH=$(sed -n 's|.*branch-heads/\([^<]*\).*|\1|p' webrtc-jni/pom.xml)" >> "$GITHUB_ENV"
shell: bash
- - name: Set up WebRTC cache
- uses: actions/cache@v6
+ # 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') }}
@@ -30,8 +35,9 @@ runs:
run: echo "FFMPEG_VERSION=$(sed -n 's|.*\([^<]*\).*|\1|p' webrtc-java-media/pom.xml)" >> "$GITHUB_ENV"
shell: bash
- - name: Set up FFmpeg cache
- uses: actions/cache@v6
+ - 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') }}
@@ -67,10 +73,34 @@ runs:
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
+ 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.
diff --git a/.github/actions/release/action.yml b/.github/actions/release/action.yml
index 460b365d..27c73883 100644
--- a/.github/actions/release/action.yml
+++ b/.github/actions/release/action.yml
@@ -18,8 +18,13 @@ runs:
run: echo "WEBRTC_CACHE_BRANCH=$(sed -n 's|.*branch-heads/\([^<]*\).*|\1|p' webrtc-jni/pom.xml)" >> "$GITHUB_ENV"
shell: bash
- - name: Set up WebRTC cache
- uses: actions/cache@v6
+ # 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') }}
@@ -29,8 +34,9 @@ runs:
run: echo "FFMPEG_VERSION=$(sed -n 's|.*\([^<]*\).*|\1|p' webrtc-java-media/pom.xml)" >> "$GITHUB_ENV"
shell: bash
- - name: Set up FFmpeg cache
- uses: actions/cache@v6
+ - 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') }}
@@ -62,11 +68,35 @@ runs:
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
+ 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.
diff --git a/.github/actions/test-natives/action.yml b/.github/actions/test-natives/action.yml
index 6a09796d..26c1d035 100644
--- a/.github/actions/test-natives/action.yml
+++ b/.github/actions/test-natives/action.yml
@@ -121,5 +121,15 @@ runs:
# The native build is off: these natives were cross compiled by another
# job, and this runner is here to run them, not to build them again.
- name: Test
- run: mvn -B -pl webrtc,webrtc-java-media test -DskipNativeBuild -P${{ inputs.profile }}
+ run: mvn -B -pl webrtc,webrtc-java-media test -DskipNativeBuild -P${{ inputs.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-native-${{ inputs.platform-name }}
+ path: '**/target/surefire-reports/'
+ if-no-files-found: ignore
+ retention-days: 7
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 1a195411..e630046d 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -4,17 +4,38 @@ on:
push:
branches:
- main
- paths:
- - "**.cpp"
- - "**.h"
- - "**.java"
-
+ # Everything that can change a build runs here: poms, CMake files, the FFmpeg
+ # submodule and this directory too, not only sources. A PR cannot read the
+ # caches of another PR, only those of main, so a build change that main does
+ # not rebuild leaves every following PR to build WebRTC from scratch.
+ paths-ignore:
+ - "docs/**"
+ - "**.md"
+ - ".github/ISSUE_TEMPLATE/**"
+ - ".github/workflows/pages.yml"
+
+ # A change that only touches docs cannot affect the native build. The docs
+ # site has its own check in pages.yml.
pull_request:
branches:
- main
+ paths-ignore:
+ - "docs/**"
+ - "**.md"
+ - ".github/ISSUE_TEMPLATE/**"
+ - ".github/workflows/pages.yml"
workflow_dispatch:
+permissions:
+ contents: read
+
+# A new push to a PR supersedes its running build. On main every run is kept,
+# since each one deploys a snapshot and refreshes the caches.
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: ${{ github.event_name == 'pull_request' }}
+
env:
WEBRTC_CHECKOUT_FOLDER: webrtc
WEBRTC_INSTALL_FOLDER: webrtc/build
@@ -148,6 +169,7 @@ jobs:
test-natives:
needs: [build-windows, build-linux]
+ timeout-minutes: 30
strategy:
fail-fast: false
matrix:
diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml
index e4a23ee7..efb5db32 100644
--- a/.github/workflows/pages.yml
+++ b/.github/workflows/pages.yml
@@ -6,6 +6,13 @@ on:
paths:
- 'docs/**'
+ # PRs only build the site, so that a broken build shows up before the merge.
+ pull_request:
+ branches: [main]
+ paths:
+ - 'docs/**'
+ - '.github/workflows/pages.yml'
+
workflow_dispatch:
permissions:
@@ -14,8 +21,8 @@ permissions:
id-token: write
concurrency:
- group: pages
- cancel-in-progress: false
+ group: pages-${{ github.event_name == 'pull_request' && github.ref || 'deploy' }}
+ cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
build:
@@ -32,6 +39,7 @@ jobs:
cache-dependency-path: docs/package-lock.json
- name: Setup Pages
+ if: github.event_name != 'pull_request'
uses: actions/configure-pages@v6
- name: Install dependencies
@@ -45,11 +53,13 @@ jobs:
npm run build
- name: Upload artifact
+ if: github.event_name != 'pull_request'
uses: actions/upload-pages-artifact@v5
with:
path: docs/.vitepress/dist
deploy:
+ if: github.event_name != 'pull_request'
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 5b62d411..433eb998 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -17,125 +17,146 @@ 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
+
+# Two releases at once would race on the pushed commits and tags.
+concurrency:
+ group: release
+ cancel-in-progress: false
+
jobs:
- changelog:
- name: Generate changelog
- runs-on: ubuntu-latest
+ # Nothing reaches main before release:prepare has succeeded: the changelog
+ # commit is made locally, release:prepare adds its two commits and the tag on
+ # top, and all of it is pushed in one atomic push at the end. A failure on the
+ # way leaves main untouched, so the release can simply be dispatched again.
+ prepare-release:
+ name: Prepare release
+ runs-on: ubuntu-22.04
+ permissions:
+ contents: write
outputs:
+ release_tag: ${{ steps.release-version.outputs.tag }}
release_body: ${{ steps.git-cliff.outputs.content }}
- release_version: ${{ steps.git-cliff.outputs.version }}
-
steps:
- - name: Checkout
+ # The full history, for git-cliff.
+ - name: Checkout code
uses: actions/checkout@v6
with:
+ ref: main
fetch-depth: 0
- name: Git config
run: |
- git config user.name "github-actions[bot]"
- git config user.email "github-actions[bot]@users.noreply.github.com"
+ git config --global user.name "${{ github.actor }}"
+ git config --global user.email "${{ github.actor_id }}+${{ github.actor }}@users.noreply.github.com"
+
+ # The version is the one release:prepare will tag: the pom's version without
+ # -SNAPSHOT. git-cliff is told it rather than bumping from the commit types, so
+ # that the changelog, the Maven tag and the GitHub release always agree.
+ - name: Determine and check the versions
+ id: release-version
+ env:
+ DEVELOPMENT_VERSION: ${{ inputs.developmentVersion }}
+ run: |
+ version=$(sed -n '0,//s|.*\([^<]*\).*|\1|p' pom.xml)
+ version="${version%-SNAPSHOT}"
+ echo "Release version: $version, next development version: $DEVELOPMENT_VERSION"
+
+ if ! [[ "$DEVELOPMENT_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+-SNAPSHOT$ ]]; then
+ echo "::error::developmentVersion must look like 1.2.3-SNAPSHOT, got '$DEVELOPMENT_VERSION'"
+ exit 1
+ fi
+ if [ "${DEVELOPMENT_VERSION%-SNAPSHOT}" == "$version" ]; then
+ echo "::error::developmentVersion must differ from the release version $version"
+ exit 1
+ fi
+ if git rev-parse -q --verify "refs/tags/v$version" >/dev/null; then
+ echo "::error::Tag v$version already exists"
+ exit 1
+ fi
- - name: Generate changelog for the current build
+ echo "version=$version" >> "$GITHUB_OUTPUT"
+ echo "tag=v$version" >> "$GITHUB_OUTPUT"
+
+ # Written outside the checkout, which release:prepare requires to be clean.
+ - name: Generate the release notes
uses: orhun/git-cliff-action@v4
id: git-cliff
with:
config: .github/changelog/cliff-release.toml
- args: -v -u --strip footer --bump --use-branch-tags
+ args: -v -u --strip footer --tag ${{ steps.release-version.outputs.tag }} --use-branch-tags
+ env:
+ OUTPUT: ${{ runner.temp }}/release-notes.md
- name: Update CHANGELOG.md
uses: orhun/git-cliff-action@v4
with:
config: .github/changelog/cliff.toml
- args: -v --bump --use-branch-tags
+ args: -v --tag ${{ steps.release-version.outputs.tag }} --use-branch-tags
env:
OUTPUT: CHANGELOG.md
- name: Commit CHANGELOG.md
- if: ${{ !inputs.dryRun }}
+ env:
+ RELEASE_TAG: ${{ steps.release-version.outputs.tag }}
run: |
git add CHANGELOG.md
- git commit -m "chore(release): Update CHANGELOG.md for ${{ steps.git-cliff.outputs.version }}"
- git push
-
- prepare-release:
- name: Prepare release
- needs: changelog
- outputs:
- release_body: ${{ needs.changelog.outputs.release_body }}
- release_version: ${{ needs.changelog.outputs.release_version }}
- strategy:
- fail-fast: false
- matrix:
- platform:
- - name: linux_x86-64
- runs-on: ubuntu-22.04
- runs-on: ${{ matrix.platform.runs-on }}
- steps:
- - name: Checkout code
- uses: actions/checkout@v6
- with:
- ref: main
- - run: |
- git config --global user.name "${{ github.actor }}"
- git config --global user.email "${{ github.actor_id }}+${{ github.actor }}@users.noreply.github.com"
-
- - id: prepare
- name: Prepare release build
- uses: ./.github/actions/prepare-linux
+ git commit -m "chore(release): Update CHANGELOG.md for $RELEASE_TAG"
- name: Set up Java
uses: actions/setup-java@v5
with:
- java-version: '21'
+ java-version: '17'
distribution: 'temurin'
- server-id: central
- server-username: MAVEN_USERNAME
- server-password: MAVEN_TOKEN
- gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }}
- gpg-passphrase: MAVEN_GPG_PASSPHRASE
-
- # release:prepare runs "clean verify" over the whole reactor, and the media
- # module in it builds FFmpeg from its third-party submodule.
- - name: Update development version
- uses: actions/checkout@v6
- with:
- ref: main
- submodules: true
+ # preparationGoals is "clean validate" instead of the default "clean verify":
+ # verify would compile WebRTC and FFmpeg here, on a runner without their
+ # caches, only for the platform jobs below to build the tagged tree again.
+ #
# A dry run transforms the poms and writes release.properties, but creates no
# commit and no tag, so there is nothing to amend or push below.
- name: Prepare release
+ env:
+ DEVELOPMENT_VERSION: ${{ inputs.developmentVersion }}
+ EXPECTED_VERSION: ${{ steps.release-version.outputs.version }}
run: |
- mvn release:prepare -DskipTests -DpushChanges=false \
+ mvn -B release:prepare -DpushChanges=false \
+ -DpreparationGoals="clean validate" \
-DdryRun=${{ inputs.dryRun }} \
- -DdevelopmentVersion=${{ github.event.inputs.developmentVersion }}
+ -DdevelopmentVersion="$DEVELOPMENT_VERSION"
# Get the release version from the release.properties file
RELEASE_VERSION=$(grep "project.rel.dev.onvoid.webrtc\\\:webrtc-java=" release.properties 2>/dev/null | cut -d'=' -f2 || true)
echo "Extracted release version from release.properties: ${RELEASE_VERSION:-}"
+
+ if [ "$RELEASE_VERSION" != "$EXPECTED_VERSION" ]; then
+ echo "::error::release:prepare chose version '$RELEASE_VERSION', expected '$EXPECTED_VERSION'"
+ exit 1
+ fi
echo "RELEASE_VERSION=$RELEASE_VERSION" >> "$GITHUB_ENV"
- - name: Push release commit and tag
+ - name: Push release commits and tag
if: ${{ !inputs.dryRun }}
+ env:
+ DEVELOPMENT_VERSION: ${{ inputs.developmentVersion }}
+ RELEASE_TAG: ${{ steps.release-version.outputs.tag }}
run: |
# Update versions.ts file
- echo "Updating versions.ts with release version: $RELEASE_VERSION and development version: ${{ github.event.inputs.developmentVersion }}"
+ echo "Updating versions.ts with release version: $RELEASE_VERSION and development version: $DEVELOPMENT_VERSION"
sed -i "s/VERSION: '.*'/VERSION: '$RELEASE_VERSION'/g" docs/.vitepress/versions.ts
- sed -i "s/VERSION_SNAPSHOT: '.*'/VERSION_SNAPSHOT: '${{ github.event.inputs.developmentVersion }}'/g" docs/.vitepress/versions.ts
+ sed -i "s/VERSION_SNAPSHOT: '.*'/VERSION_SNAPSHOT: '$DEVELOPMENT_VERSION'/g" docs/.vitepress/versions.ts
# Add the updated file to the existing commit
git add docs/.vitepress/versions.ts
git commit --amend --no-edit
- git push
- git push --tags
+ # 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
- outputs:
- release_body: ${{ needs.prepare-release.outputs.release_body }}
- release_version: ${{ needs.prepare-release.outputs.release_version }}
strategy:
fail-fast: false
matrix:
@@ -147,23 +168,15 @@ jobs:
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:
- fetch-tags: true
+ ref: ${{ !inputs.dryRun && needs.prepare-release.outputs.release_tag || '' }}
# The media module builds FFmpeg from its third-party submodule.
submodules: true
- - name: Get tag from current branch
- id: tag-selector
- if: ${{ !inputs.dryRun }}
- shell: bash
- run: |
- git fetch -a
- tag=$(git describe --tags `git rev-list --tags --max-count=1`)
- echo "tag=$tag" >> "$GITHUB_OUTPUT"
- git checkout $tag
-
- id: prepare
name: Prepare release build
uses: ./.github/actions/prepare-windows
@@ -190,22 +203,15 @@ jobs:
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:
- fetch-tags: true
+ ref: ${{ !inputs.dryRun && needs.prepare-release.outputs.release_tag || '' }}
# The media module builds FFmpeg from its third-party submodule.
submodules: true
- - name: Get tag from current branch
- id: tag-selector
- if: ${{ !inputs.dryRun }}
- run: |
- git fetch -a
- tag=$(git describe --tags `git rev-list --tags --max-count=1`)
- echo "tag=$tag" >> "$GITHUB_OUTPUT"
- git checkout $tag
-
- id: prepare-build
name: Prepare release build
uses: ./.github/actions/prepare-linux
@@ -230,22 +236,15 @@ jobs:
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:
- fetch-tags: true
+ ref: ${{ !inputs.dryRun && needs.prepare-release.outputs.release_tag || '' }}
# The media module builds FFmpeg from its third-party submodule.
submodules: true
- - name: Get tag from current branch
- id: tag-selector
- if: ${{ !inputs.dryRun }}
- run: |
- git fetch -a
- tag=$(git describe --tags `git rev-list --tags --max-count=1`)
- echo "tag=$tag" >> "$GITHUB_OUTPUT"
- git checkout $tag
-
- id: prepare-build
name: Prepare release build
uses: ./.github/actions/prepare-macos
@@ -268,17 +267,14 @@ jobs:
publish-central:
name: Publish to Maven Central
- needs: [build-windows, build-linux, build-macos]
- outputs:
- release_body: ${{ needs.build-windows.outputs.release_body }}
- release_version: ${{ needs.build-windows.outputs.release_version }}
+ needs: [prepare-release, build-windows, build-linux, build-macos]
runs-on: ubuntu-22.04
steps:
- name: Checkout code
uses: actions/checkout@v6
with:
- fetch-tags: true
+ ref: ${{ !inputs.dryRun && needs.prepare-release.outputs.release_tag || '' }}
- name: Set up Maven cache
uses: actions/cache@v6
@@ -300,14 +296,13 @@ jobs:
- name: Determine the version to publish
id: release-version
+ env:
+ RELEASE_TAG: ${{ needs.prepare-release.outputs.release_tag }}
run: |
if [ "${{ inputs.dryRun }}" == "true" ]; then
version=$(mvn -B -q -N help:evaluate -Dexpression=project.version -DforceStdout)
else
- git fetch -a
- tag=$(git describe --tags `git rev-list --tags --max-count=1`)
- git checkout "$tag"
- version="${tag#v}"
+ version="${RELEASE_TAG#v}"
fi
echo "Version to publish: $version"
@@ -406,19 +401,25 @@ jobs:
publish-release:
name: Publish GitHub release
- needs: publish-central
+ needs: [prepare-release, publish-central]
if: ${{ !inputs.dryRun }}
runs-on: ubuntu-latest
+ permissions:
+ contents: write
steps:
- name: Checkout code
uses: actions/checkout@v6
+ # The notes are commit subjects, so they go through the environment and a file
+ # rather than into the script, where a quote or a backtick would be run.
+ # --verify-tag fails instead of creating a tag that release:prepare did not.
- name: Publish
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ RELEASE_VERSION: ${{ needs.prepare-release.outputs.release_tag }}
+ RELEASE_BODY: ${{ needs.prepare-release.outputs.release_body }}
run: |
- version="${{ needs.publish-central.outputs.release_version }}"
- body="${{ needs.publish-central.outputs.release_body }}"
-
- gh release create $version -d -t "Release $version" -n "$body"
\ No newline at end of file
+ printf '%s\n' "$RELEASE_BODY" > release-notes.md
+ gh release create "$RELEASE_VERSION" --draft --verify-tag \
+ -t "Release $RELEASE_VERSION" -F release-notes.md
\ No newline at end of file