Skip to content

Release

Release #55

Workflow file for this run

name: Release
on:
workflow_dispatch:
inputs:
developmentVersion:
description: "Default version to use for new local working copy."
required: true
default: "X.Y.Z-SNAPSHOT"
dryRun:
description: "Dry run: build every platform and assemble the deployment bundle, but push no commits or tags and publish nothing."
required: false
type: boolean
default: false
# 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:
# 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 }}
steps:
# 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 --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,/<version>/s|.*<version>\([^<]*\)</version>.*|\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
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 --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 --tag ${{ steps.release-version.outputs.tag }} --use-branch-tags
env:
OUTPUT: CHANGELOG.md
- name: Commit CHANGELOG.md
env:
RELEASE_TAG: ${{ steps.release-version.outputs.tag }}
run: |
git add CHANGELOG.md
git commit -m "chore(release): Update CHANGELOG.md for $RELEASE_TAG"
- name: Set up Java
uses: actions/setup-java@v5
with:
java-version: '17'
distribution: 'temurin'
# 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 -B release:prepare -DpushChanges=false \
-DpreparationGoals="clean validate" \
-DdryRun=${{ inputs.dryRun }} \
-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:-<none>}"
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 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: $DEVELOPMENT_VERSION"
sed -i "s/VERSION: '.*'/VERSION: '$RELEASE_VERSION'/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
# The branch and the tag land together or not at all.
git push --atomic origin HEAD:main "refs/tags/$RELEASE_TAG"
# The tag prepare-release pushed. A dry run pushes none and builds the
# dispatched commit instead.
platforms:
needs: prepare-release
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, platforms]
runs-on: ubuntu-22.04
steps:
- name: Checkout code
uses: actions/checkout@v6
with:
ref: ${{ !inputs.dryRun && needs.prepare-release.outputs.release_tag || '' }}
- name: Set up Maven cache
uses: actions/cache@v6
with:
path: |
~/.m2/repository
!~/.m2/repository/dev/onvoid/webrtc
key: maven-publish-${{ hashFiles('**/pom.xml') }}
restore-keys: maven-publish-
- name: Set up JDK 17
uses: actions/setup-java@v5
with:
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
- 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
version="${RELEASE_TAG#v}"
fi
echo "Version to publish: $version"
echo "version=$version" >> "$GITHUB_OUTPUT"
# 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
# a placeholder during a dry run: should the upload ever happen regardless, it
# 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 }}
with:
version: ${{ steps.release-version.outputs.version }}
profiles: release
skip-publishing: ${{ inputs.dryRun }}
- name: Summarize what would have been published
if: ${{ inputs.dryRun }}
run: |
{
echo "## Dry run — nothing was published"
echo
echo "Version: \`${{ steps.release-version.outputs.version }}\`"
echo
echo "Artifacts destined for the deployment bundle:"
echo '```'
ls -1 webrtc/target/*.jar webrtc/target/*.asc \
webrtc-java-media/target/*.jar webrtc-java-media/target/*.asc \
natives/*.asc 2>/dev/null || true
echo '```'
} >> "$GITHUB_STEP_SUMMARY"
- name: Upload the deployment bundle for inspection
if: ${{ inputs.dryRun }}
uses: actions/upload-artifact@v7
with:
name: deployment-bundle-dry-run
path: |
target/central-*/**
webrtc/target/central-*/**
webrtc/target/*.jar
webrtc/target/*.asc
webrtc-java-media/target/central-*/**
webrtc-java-media/target/*.jar
webrtc-java-media/target/*.asc
natives/*.asc
if-no-files-found: warn
retention-days: 7
publish-release:
name: Publish GitHub release
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: |
printf '%s\n' "$RELEASE_BODY" > release-notes.md
gh release create "$RELEASE_VERSION" --draft --verify-tag \
-t "Release $RELEASE_VERSION" -F release-notes.md