The previous commit settled for Java 24 everywhere because Kotlin 2.2.10 refuses jvmTarget 25. That was the wrong constraint to accept, for two reasons. The first is that 24 turned out to be unbuyable. Adoptium's repository carries 8, 11, 17, 21, 25 and 26 -- no 24, because it is a non-LTS that went end of life in July 2025. The builds passed only because Gradle quietly auto-provisioned 24.0.2+12 through foojay, and .idea/misc.xml had been pointed at a temurin-24 that cannot be installed. A toolchain nobody can install is not pinned, it is lucky. The second is that the cap was never on the toolchain at all. Kotlin's ceiling applies to jvmTarget -- the bytecode -- and the JDK running the build is a separate axis. Conflating them is what steered this at 24 in the first place. So the fix is the one the sibling repo already uses: put KGP on the root buildscript classpath, where AGP's built-in Kotlin picks it up instead of the 2.2.10 it bundles. Kotlin 2.4.10 supports jvmTarget through 26, which lifts the ceiling above the toolchain rather than under it. The Compose compiler plugin is versioned in lockstep and reads the same catalog entry, so the two cannot drift, and the module now applies both by id() because they come from the classpath rather than from plugin resolution. Checked rather than assumed, since a silent downgrade would look identical to success: compiled classes report major version 69, which is Java 25. D8 dexes them, R8 minifies them, and ktlint, detekt, lint, the unit tests and the androidTest compile are all green on top. 25 is the right landing place independent of all this: it is LTS, it is in the Adoptium repository, and temurin-25-jdk is already installed here -- so the daemon runs on a real system JDK rather than a provisioned copy of an unpatched one. Two catalog plugin aliases went with it. android-application and kotlin-compose now resolve from the buildscript classpath, so leaving aliases behind would have left two entries that read like the source of truth and control nothing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
131 lines
5.5 KiB
YAML
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: '25' # 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: '25'
|
|
|
|
- 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
|