Files
LibreMediaConverter/.github/workflows/build.yml
T
JMR-devandClaude Opus 5 3841f58c74 Put the whole toolchain on Java 24, and take Gradle to 9.7.1
Java was scattered across four numbers that nobody had chosen together: the
daemon ran on 25 (pinned in gradle-daemon-jvm.properties), CI installed 17, the
IDE was set to 25, and the app compiled to 17 bytecode. Now all four say 24.

24 rather than 25 because 25 is not reachable end to end. Kotlin 2.2.10 refuses
jvmTarget 25 outright -- "available targets are 1.8 ... 23, 24" -- so the app's
bytecode could never have joined a 25 toolchain, and "everything on the same
version" would have stayed false in the one place it is hardest to notice. 24 is
the highest number all four can actually hold. Checked, not assumed: D8 dexes
Java 24 class files, and R8 full mode minifies them, so the shipped artifact
builds on this too.

Floating where floating is native:

  - java-version: '24' -- setup-java resolves the newest 24.x at run time.
  - toolchainVersion=24 -- Gradle reports it as "Compatible with Java 24, any
    vendor", and provisions whatever 24.x it finds or downloads.

The Gradle wrapper deliberately does NOT float, because it cannot: distributionUrl
names one archive and distributionSha256Sum is the checksum of that exact file.
That pairing is the wrapper's integrity check, and it is the same reasoning the
workflows already apply to action SHAs. Set via `./gradlew wrapper`, not by hand,
so the checksum matches the URL.

Dependencies were audited against Google Maven and Maven Central rather than
guessed at, and almost everything was already current: AGP, the Compose BOM,
core-ktx, activity, lifecycle, navigation, work, datastore, media3, room,
documentfile, annotation, espresso, androidx-junit, junit and ktlint are all at
their newest stable. Only two had moved -- detekt to 2.0.0-alpha.6 and JaCoCo to
0.8.15 -- and both are here.

Kotlin stays at 2.2.10 and that is now recorded as a verified fact rather than a
warning: the AGP 9.3.1 POM declares kotlin-gradle-plugin 2.2.10 at runtime scope,
which is what AGP's built-in Kotlin actually compiles with. Android lint suggests
2.4.10 and taking that suggestion breaks the build unless KGP is also forced onto
the root buildscript classpath. agp, kotlin and ksp move together or not at all.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-22 14:42:41 -05:00

131 lines
5.5 KiB
YAML

name: Build
# Pull requests are covered by status_check.yml, which runs the unit tests and the
# instrumented suite across API 33-37. This workflow keeps the post-merge and release
# duties and does not duplicate PR validation.
on:
push:
branches: [main]
tags: ['v*']
# Actions are pinned to a commit rather than a tag, with the release in a trailing
# comment. A tag is mutable -- the owner can repoint it at new code -- so a tag
# reference amounts to running whatever that repository contains tomorrow. This matters
# more here than on pull requests: these jobs sign nothing today, but they do publish
# the artifacts people install.
env:
GRADLE_CACHE_PATHS: |
~/.gradle/caches
~/.gradle/wrapper
jobs:
test:
name: Unit tests
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5.7.0
with:
distribution: temurin
java-version: '24' # Matches the daemon JVM pinned in gradle/gradle-daemon-jvm.properties
# Gradle runs through the committed wrapper rather than a setup action. The
# wrapper verifies its own distribution against distributionSha256Sum, and
# caching is a handful of lines, so the action earned little here.
- uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ${{ env.GRADLE_CACHE_PATHS }}
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle.kts', 'gradle/libs.versions.toml', 'gradle/wrapper/gradle-wrapper.properties') }}
restore-keys: gradle-${{ runner.os }}-
- name: Unit tests
run: ./gradlew :app:testDebugUnitTest
- name: Upload test report
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: unit-test-report
path: app/build/reports/tests/
release:
name: Release
needs: [test]
runs-on: ubuntu-latest
timeout-minutes: 60
if: startsWith(github.ref, 'refs/tags/v')
permissions:
# Needed to create the release. Declared explicitly rather than relying on the
# repository default, so the token's reach is visible here.
contents: write
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5.7.0
with:
distribution: temurin
java-version: '24'
- uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ${{ env.GRADLE_CACHE_PATHS }}
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle.kts', 'gradle/libs.versions.toml', 'gradle/wrapper/gradle-wrapper.properties') }}
restore-keys: gradle-${{ runner.os }}-
# No -PabiFilters here: released artifacts must carry every ABI. That override
# exists only so emulator jobs skip libraries they cannot execute.
- name: Build release artifacts
run: ./gradlew :app:assembleRelease :app:bundleRelease
- name: Verify the released artifacts
run: |
APK=$(ls app/build/outputs/apk/release/*.apk | head -1)
# A release that shipped one ABI, or lost 16 KB alignment, would install
# fine on a test device and fail for users or at Play submission. Both are
# cheap to check and expensive to discover later.
for abi in arm64-v8a x86_64; do
n=$(unzip -l "$APK" | grep -c "lib/$abi/.*\.so$" || true)
echo " $abi: $n shared libraries"
test "$n" -gt 0 || { echo "::error::release APK is missing $abi"; exit 1; }
done
unzip -q -o "$APK" 'lib/*' -d /tmp/relcheck
bad=0
for f in /tmp/relcheck/lib/*/*.so; do
align=$(readelf -lW "$f" | awk '$1=="LOAD"{print $NF}' | sort -u)
[ "$align" = "0x4000" ] || { echo "::error::$(basename "$f") is $align"; bad=1; }
done
test "$bad" -eq 0 || exit 1
echo " all libraries are 16 KB aligned"
# GPL-3.0 requires that complete corresponding source accompany the binary.
# FFmpeg's guidance says to host it on the same server as the binary; for a Play
# listing that is impossible, so it is attached to the GitHub release next to the
# APK and linked from both the store listing and the in-app About screen.
- name: Assemble corresponding source
run: |
mkdir -p release-source
cp -r tools/ffmpeg release-source/
cp bin/README.md release-source/PREBUILT.md
{
echo "FFmpeg corresponding source for ${GITHUB_REF_NAME}"
echo
echo "Upstream: https://github.com/arthenica/ffmpeg-kit-next"
echo "Tag: v8.1.1 (FFmpeg 8.1.2)"
echo
echo "tools/ffmpeg reproduces the binary shipped in this release."
echo "PREBUILT.md records its provenance, including the SHA-256 and the"
echo "configure line read back out of the shipped libavutil."
} > release-source/README.txt
tar czf ffmpeg-corresponding-source.tar.gz release-source
- uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3.0.2
with:
files: |
app/build/outputs/apk/release/*.apk
app/build/outputs/bundle/release/*.aab
ffmpeg-corresponding-source.tar.gz
LICENSE
LICENSES/README.md