main landed 25 commits while this branch was open, including a third @FailsOnEmulatorApi37 on Media3EngineTest.cancellingARunningExportStopsIt and a batch of new instrumented tests. Every number this branch touches moved with them. Re-derived rather than adjusted, and cross-checked against run 34020234606: the API 34 leg (no filter) reports 68 tests and the API 37 gating leg 64, which is 68 minus main's four markers. With the picker test marked that is five markers, baseline 5, and 63 on the gating leg. The conflict in FailsOnEmulatorApi37.kt is resolved main's way: it had replaced the hardcoded "grows by two" with a reference to the constant, which is the same drift this file exists to prevent and a better fix than the number I put there. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
518 lines
26 KiB
YAML
518 lines
26 KiB
YAML
name: Status check
|
|
|
|
on:
|
|
pull_request:
|
|
branches: [main]
|
|
|
|
# A newer push to the same PR makes the in-flight run obsolete. An emulator matrix is
|
|
# expensive, so cancel rather than let runs pile up.
|
|
concurrency:
|
|
group: status-check-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
# Third-party actions are pinned to a commit rather than a tag. A tag is mutable: the
|
|
# owner can repoint v4 at new code, so a tag reference is an open invitation to run
|
|
# whatever that repository contains tomorrow. The trailing comment records which
|
|
# release each hash corresponds to, since a bare hash is unreadable.
|
|
# Nothing here writes: these jobs read the code, build it and attach reports. Declared
|
|
# explicitly rather than inherited from the repository default, for the same reason the
|
|
# action SHAs above are pinned -- the token's reach should be readable here, and a default
|
|
# that widens later should not silently widen these jobs with it. build.yml's release job
|
|
# makes the opposite declaration for the same reason.
|
|
permissions:
|
|
contents: read
|
|
|
|
env:
|
|
GRADLE_CACHE_PATHS: |
|
|
~/.gradle/caches
|
|
~/.gradle/wrapper
|
|
|
|
jobs:
|
|
# ---------------------------------------------------------------------------
|
|
# Validates the committed FFmpeg archive. It does not build anything: the whole
|
|
# point of checking the binary in is that a red run means broken code rather than
|
|
# a cross-compile that hiccuped.
|
|
#
|
|
# Its own job so a bad archive reports once, clearly, instead of surfacing as five
|
|
# confusing emulator failures. It takes seconds, so gating the matrix on it costs
|
|
# almost nothing.
|
|
# ---------------------------------------------------------------------------
|
|
ffmpeg:
|
|
name: FFmpeg binary
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 10
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
|
|
- name: Verify the committed archive
|
|
run: |
|
|
AAR=bin/ffmpeg-kit-next-8.1.1.aar
|
|
test -f "$AAR" || { echo "::error::$AAR is missing"; exit 1; }
|
|
|
|
# A truncated file, or a Git LFS pointer checked out without LFS, would pass
|
|
# a file-exists check and then surface much later as a confusing linker
|
|
# error. Assert the archive actually carries native libraries for both ABIs.
|
|
for abi in arm64-v8a x86_64; do
|
|
n=$(unzip -l "$AAR" | grep -c "jni/$abi/.*\.so$" || true)
|
|
echo " $abi: $n shared libraries"
|
|
test "$n" -gt 0 || { echo "::error::AAR has no $abi libraries"; exit 1; }
|
|
done
|
|
|
|
# 16 KB alignment is a Play requirement and is easy to lose in a rebuild,
|
|
# so it is checked here rather than discovered at submission.
|
|
unzip -q -o "$AAR" 'jni/*' -d /tmp/aarcheck
|
|
bad=0
|
|
for f in /tmp/aarcheck/jni/*/*.so; do
|
|
align=$(readelf -lW "$f" | awk '$1=="LOAD"{print $NF}' | sort -u)
|
|
if [ "$align" != "0x4000" ]; then
|
|
echo "::error::$(basename "$f") is $align, not 16 KB aligned"; bad=1
|
|
fi
|
|
done
|
|
test "$bad" -eq 0 || exit 1
|
|
echo " all libraries are 16 KB aligned"
|
|
|
|
# Record what shipped, so a failing run elsewhere can be tied to a version.
|
|
echo " sha256: $(sha256sum "$AAR" | cut -d' ' -f1)"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# JVM tests: the routing matrix, the FFmpeg argument builder, the concat planner
|
|
# and the retry rule. No device needed, so this is the fastest signal on a PR.
|
|
# ---------------------------------------------------------------------------
|
|
unit:
|
|
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 is invoked 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
|
|
|
|
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
if: always()
|
|
with:
|
|
name: unit-test-report
|
|
path: app/build/reports/tests/
|
|
|
|
# Reported, not gated. A coverage floor is only meaningful against a measured
|
|
# baseline, and this is the thing that measures it -- currently 31% of lines. Once
|
|
# that number has settled, a jacocoTestCoverageVerification task can hold it.
|
|
- name: Coverage report
|
|
run: ./gradlew :app:jacocoTestReport
|
|
|
|
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
if: always()
|
|
with:
|
|
name: coverage-report
|
|
path: app/build/reports/jacoco/jacocoTestReport/
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Three tools, one job, because they answer three different questions and a
|
|
# developer wants all three answers at once rather than one per push.
|
|
#
|
|
# ktlint -- formatting. Owns it outright; detekt's formatting ruleset is off,
|
|
# so the two can never disagree about the same line.
|
|
# detekt -- static analysis. Its config lives in config/detekt/detekt.yml and
|
|
# overrides only the rules this codebase legitimately breaks.
|
|
# lint -- the Android-specific things neither of the others can see: opt-in
|
|
# markers, API-level misuse, manifest and resource problems.
|
|
#
|
|
# --continue is what makes it one round trip: a ktlint failure still lets detekt
|
|
# and lint report, so a red run hands over the whole list rather than the first
|
|
# item on it.
|
|
#
|
|
# No emulator and no FFmpeg archive needed, so this is the cheapest gate here and
|
|
# deliberately does not depend on the ffmpeg job.
|
|
# ---------------------------------------------------------------------------
|
|
static-analysis:
|
|
name: Static analysis
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 20
|
|
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 }}-
|
|
|
|
# Shell is the other language in this repo -- four scripts, one of them the CI
|
|
# entry point itself -- and nothing was checking it. `git ls-files` rather than a
|
|
# fixed list, so a script added later is covered without editing this workflow.
|
|
#
|
|
# Full severity, `info` included. The findings it raises today are answered with
|
|
# targeted `disable` directives carrying their reason, the same way
|
|
# config/detekt/detekt.yml carries only the rules this codebase legitimately
|
|
# breaks. A blanket --severity=warning would have hidden them and the next real
|
|
# one alike.
|
|
#
|
|
# PINNED BY DIGEST, for the reason CLAUDE.md already gives for pinning ktlint,
|
|
# detekt and JaCoCo: a new rule in a linter makes files nobody touched stop
|
|
# passing, so CI goes red on a PR whose diff cannot explain it. That is not
|
|
# hypothetical here. The first cut of this step used the runner's ambient
|
|
# shellcheck, which is 0.9.0, and 0.9.0 reports a trap handler as seven
|
|
# unreachable commands (SC2317) where 0.11.0 reports it once on the declaration
|
|
# (SC2329) -- same script, same directive, different answer, and a red build on
|
|
# the PR that introduced the step. The version is printed so a finding that
|
|
# appears out of nowhere can be tied to a bump of this line.
|
|
- name: shellcheck
|
|
env:
|
|
SHELLCHECK: koalaman/shellcheck@sha256:61862eba1fcf09a484ebcc6feea46f1782532571a34ed51fedf90dd25f925a8d
|
|
run: |
|
|
docker run --rm "$SHELLCHECK" --version
|
|
git ls-files -z '*.sh' | xargs -0 -r docker run --rm -v "$PWD:/mnt" "$SHELLCHECK"
|
|
|
|
# actionlint closes the half shellcheck cannot see. The step above reads .sh files;
|
|
# a good deal of this repo's bash lives in inline `run:` blocks instead -- the release
|
|
# verification here, the emulator setup and teardown in this file and in
|
|
# api37-debug.yml. actionlint parses each workflow and runs shellcheck over every
|
|
# `run:`, on top of its own checks for expression syntax, `needs:` references, matrix
|
|
# keys and action input names.
|
|
#
|
|
# Pinned by digest for the same reason shellcheck is, and with a second reason of its
|
|
# own: actionlint's documented install is `bash <(curl -s .../download-actionlint.bash)`
|
|
# off a moving branch, which would sit badly in a repo that pins every action by SHA.
|
|
- name: actionlint
|
|
env:
|
|
ACTIONLINT: rhysd/actionlint@sha256:9d36088643581e728c969f35141f88139fec77280b2be23c1f66f8e40e1025e7
|
|
run: |
|
|
docker run --rm "$ACTIONLINT" -version
|
|
docker run --rm -v "$PWD:/repo" -w /repo "$ACTIONLINT" -color
|
|
|
|
# `!cancelled()` rather than a plain sequence: a shellcheck failure above must not
|
|
# cost the ktlint/detekt/lint lists. Same reason this step passes --continue -- one
|
|
# round trip should produce every list, not stop at the first.
|
|
- name: ktlint, detekt and Android lint
|
|
if: '!cancelled()'
|
|
run: ./gradlew :app:ktlintCheck :app:detekt :app:lintDebug --continue --stacktrace
|
|
|
|
# The XML matters as much as the HTML: it is the one that can be diffed between
|
|
# runs to see what a change actually moved.
|
|
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
if: always()
|
|
with:
|
|
name: static-analysis-reports
|
|
path: |
|
|
app/build/reports/ktlint/
|
|
app/build/reports/detekt/
|
|
app/build/reports/lint-results-debug.html
|
|
app/build/reports/lint-results-debug.xml
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# One runner per API level, across the whole supported range.
|
|
#
|
|
# The range is the point: minSdk is 33, and the foreground service type differs
|
|
# across it -- none below 34, dataSync at 34, mediaProcessing from 35. Testing a
|
|
# single level would leave two thirds of that branch unexercised.
|
|
#
|
|
# It reaches targetSdk 37, but the API 37 row is not like the other four and the
|
|
# comment on it says how. Two tests are excluded there and run in their own
|
|
# advisory job below. See docs/api-37-emulator-crash.md.
|
|
#
|
|
# FFmpeg is not built here. The AAR is committed under bin/, so a red run means the
|
|
# code is broken rather than that a cross-compile hiccuped.
|
|
# ---------------------------------------------------------------------------
|
|
e2e:
|
|
name: E2E API ${{ matrix.label }}
|
|
runs-on: ubuntu-latest
|
|
needs: ffmpeg
|
|
timeout-minutes: 60
|
|
strategy:
|
|
# Report every API level rather than stopping at the first red one. Knowing
|
|
# whether a failure is universal or specific to one level is most of the
|
|
# diagnosis.
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- label: "33"
|
|
api-level: "33"
|
|
- label: "34"
|
|
api-level: "34"
|
|
- label: "35"
|
|
api-level: "35"
|
|
- label: "36"
|
|
api-level: "36"
|
|
# API 37, and it is NOT the same device as the four rows above it.
|
|
#
|
|
# THE CAVEAT THAT USED TO BE HERE IS WITHDRAWN, 2026-09-05, and the
|
|
# withdrawal is good news. It said this leg "runs with SystemUI disabled
|
|
# and the framework restarted under it", that no other leg or Pixel run
|
|
# uses that configuration, and that anything depending on system UI must
|
|
# not trust this row. **None of that was ever true.** Measured: the
|
|
# framework restart is two root-only adb commands that answered `Must be
|
|
# root` on every leg ever run, and `pm disable-user` does not stop SystemUI
|
|
# starting on this image anyway -- in run 34006456986 the package is
|
|
# verified disabled at 02:29:33 and SystemUI (pid 4275) is up from 02:28:52
|
|
# for the whole run. So this row's device configuration is the same as the
|
|
# other four's, and a green here means what a green on 33-36 means.
|
|
#
|
|
# E2E_DISABLE_SYSTEM_UI still exists and still runs, because what it
|
|
# actually buys is a 45-second window with no new gralloc aborts before the
|
|
# suite starts -- the boot-time ones land close together and instrumentation
|
|
# has to begin after them, not between them. The name is stale and kept:
|
|
# read .github/scripts/e2e-run.sh's header, which carries the measurements.
|
|
#
|
|
# notAnnotation below keeps five tests off this row, and one of
|
|
# them is new. SafPickerRoundTripTest's PICKER test was measured on
|
|
# 2026-08-24 as passing here and was left on the leg; four gating logcats
|
|
# read on 2026-09-05 show it aborting system_server from the task-snapshot
|
|
# path on every single run, pass or fail, which is what had been failing
|
|
# unrelated PRs (#108). Both of that class's tests now carry the marker.
|
|
# docs/api-37-emulator-crash.md has the timings and the correction.
|
|
#
|
|
# api-level must be a POINT release. A bare 37 is not an SDK package and
|
|
# fails during setup, which cost a run to discover. `37.0` is the choice
|
|
# here rather than the only option: `37.1` and `37.2-beta*` exist and
|
|
# abort the same way, and api37-debug.yml's inputs document both, with
|
|
# the wrinkle that above 37.0 they ship only as google_apis_ps16k.
|
|
# docs/api-37-emulator-crash.md measures 37.0 rev 6 and 37.1 rev 8 side
|
|
# by side, so pinning 37.0 is a decision, not a constraint.
|
|
#
|
|
# notAnnotation removes the three tests that do not pass on this image; they
|
|
# run in the advisory job below, off the same marker so they cannot end up
|
|
# in both or neither. docs/api-37-emulator-crash.md has the measurements.
|
|
- label: "37"
|
|
api-level: "37.0"
|
|
disable-system-ui: "1"
|
|
gradle-args: "-Pandroid.testInstrumentationRunnerArguments.notAnnotation=org.libremediaconverter.FailsOnEmulatorApi37"
|
|
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 }}-
|
|
|
|
# Without this the emulator falls back to software rendering and takes minutes
|
|
# longer to boot, when it boots at all.
|
|
- name: Enable KVM
|
|
run: |
|
|
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' \
|
|
| sudo tee /etc/udev/rules.d/99-kvm4all.rules
|
|
sudo udevadm control --reload-rules
|
|
sudo udevadm trigger --name-match=kvm
|
|
|
|
- name: Instrumented tests
|
|
uses: reactivecircus/android-emulator-runner@a421e43855164a8197daf9d8d40fe71c6996bb0d # v2.38.0
|
|
# Both of these are empty on every row but 37, and both are read with a
|
|
# `:-` default in e2e-run.sh, so the four legs below 37 run the identical
|
|
# gradle command they always have.
|
|
env:
|
|
E2E_DISABLE_SYSTEM_UI: ${{ matrix.disable-system-ui }}
|
|
E2E_EXTRA_GRADLE_ARGS: ${{ matrix.gradle-args }}
|
|
with:
|
|
api-level: ${{ matrix.api-level }}
|
|
target: google_apis
|
|
arch: x86_64
|
|
profile: pixel_6
|
|
# swiftshader_indirect is correct here only because runners have no GPU to
|
|
# pass through. On a workstation the same setting routes through
|
|
# SwiftShader's JIT, which is a known crash source.
|
|
emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
|
|
disable-animations: true
|
|
# The default userdata partition is not big enough for this APK once the
|
|
# FFmpeg libraries are in it. One level failed outright with "Requested
|
|
# internal only, but not enough space", and the margin was thin everywhere
|
|
# else, so give them all room.
|
|
disk-size: 8G
|
|
# Pinned because the emulator's own default is not uniform: it raises an
|
|
# undersized guest to a floor that varies by API level -- 2048M at 33, 2560M
|
|
# at 34 through 36 -- and skips levels it does not recognise entirely. 2560M
|
|
# is the highest of those floors, so no level gets less memory than it
|
|
# already had, and none of them depend on that heuristic any more.
|
|
ram-size: 2560M
|
|
# Build only the ABI the emulator can execute. FFmpeg's native libraries
|
|
# dominate the APK, so shipping arm64 to an x86_64 emulator doubles the
|
|
# install for code that can never run: 114 MB against 80 MB.
|
|
#
|
|
# Diagnostics live in .github/scripts/e2e-run.sh, not here. This action splits
|
|
# `script` on newlines and runs each line as its own `sh -c`, so a handler written
|
|
# inline has to fit on ONE line -- which is how the previous version ended up as an
|
|
# unreadable chain of semicolons. One line invokes the script; the script can use
|
|
# functions, and captures a hang as well as a failure. See its header.
|
|
script: bash .github/scripts/e2e-run.sh ${{ matrix.label }}
|
|
|
|
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
if: always()
|
|
with:
|
|
name: e2e-report-api${{ matrix.label }}
|
|
path: |
|
|
app/build/reports/androidTests/
|
|
app/build/outputs/androidTest-results/
|
|
if-no-files-found: warn
|
|
|
|
# The streamed logcat and the failure dump. Uploaded always, because a leg that goes red
|
|
# once and green on re-run is exactly the one worth reading afterwards, and by then the
|
|
# emulator is long gone.
|
|
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
if: always()
|
|
with:
|
|
name: e2e-diagnostics-api${{ matrix.label }}
|
|
path: |
|
|
${{ runner.temp }}/logcat-api${{ matrix.label }}.txt
|
|
${{ runner.temp }}/diagnostics-api${{ matrix.label }}.txt
|
|
${{ runner.temp }}/gradle-api${{ matrix.label }}.txt
|
|
if-no-files-found: warn
|
|
|
|
# Only exists when the wrapper timeout tripped, so `ignore` keeps healthy runs quiet
|
|
# instead of warning on every green leg.
|
|
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
if: always()
|
|
with:
|
|
name: e2e-wedge-api${{ matrix.label }}
|
|
path: ${{ runner.temp }}/wedge-diagnostics-api${{ matrix.label }}.txt
|
|
if-no-files-found: ignore
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# The three API 37 tests the gating row above excludes, run on their own so they
|
|
# stay visible instead of disappearing behind a notAnnotation.
|
|
#
|
|
# continue-on-error: it reports, it never blocks. That is the whole reason it is
|
|
# a separate job rather than a sixth matrix row: a row would share the gating
|
|
# job's `E2E API <label>` name, and a check cannot be both required and advisory
|
|
# under one name.
|
|
#
|
|
# It was named for WHAT IT RUNS, and that is now APPROXIMATE rather than exact.
|
|
# When this job was created it held two tests, both driving a full H.264 -> H.265
|
|
# hardware transcode through Media3Engine -- which is exactly what separated them
|
|
# from the two Media3EngineTest cases that pass here, since those two never decode
|
|
# video. Since 2026-08-25 it also holds SafPickerRoundTripTest's rotation case,
|
|
# which drives no transcode at all: a real rotation rebuilds every surface at once
|
|
# and takes the framework down on this image (INSTRUMENTATION_ABORTED), which is a
|
|
# different failure from the decoder one below.
|
|
#
|
|
# The name is kept anyway, and that is a decision rather than an oversight. This is
|
|
# not a required context, it is red on every PR by design, and it is one people
|
|
# have learned to look for -- renaming a check costs more than the imprecision
|
|
# does. **The marker is the definition, not the name:** what this job holds is the
|
|
# tests that cannot pass on the API 37 emulator image, whatever their subject. The
|
|
# theory about the Media3 pair is in the next paragraph, where it can be corrected
|
|
# without touching the name.
|
|
#
|
|
# THEORY, NOT SETTLED: the exception surfaces at `dequeueOutputBuffer` on
|
|
# `c2.goldfish.h264.decoder`, the emulator's own codec, which gets its frames out
|
|
# of a host-side colour buffer -- the same readback machinery that aborts
|
|
# surfaceflinger on this image. It is about the MEDIA3 PAIR only; the rotation
|
|
# case above fails for its own reason. What is MEASURED is narrower: those two
|
|
# fail on
|
|
# the API 37 emulator image; pass at API 36 on this runner under the same renderer
|
|
# AND the same SystemUI-disable path; pass at API 33-36 without that path at all,
|
|
# since nothing below 37 needs it; and pass on a physical Pixel 10 Pro XL at 37. That the decoder is the culprit rather than something else
|
|
# the decode path touches is inference. docs/api-37-emulator-crash.md separates
|
|
# the two, and the images also differ on the encoder side, which is why "broken
|
|
# h264 decoder" is not written into this job's name.
|
|
#
|
|
# WHEN THIS GOES GREEN, delete the annotation rather than this job: the gating
|
|
# row picks the tests back up automatically, and this job goes empty and can go
|
|
# with it.
|
|
# ---------------------------------------------------------------------------
|
|
e2e-api37-advisory:
|
|
name: E2E API 37 Media3 hardware transcode (advisory)
|
|
runs-on: ubuntu-latest
|
|
needs: ffmpeg
|
|
timeout-minutes: 60
|
|
continue-on-error: true
|
|
env:
|
|
E2E_LABEL: "37-media3-transcode"
|
|
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 }}-
|
|
|
|
- name: Enable KVM
|
|
run: |
|
|
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' \
|
|
| sudo tee /etc/udev/rules.d/99-kvm4all.rules
|
|
sudo udevadm control --reload-rules
|
|
sudo udevadm trigger --name-match=kvm
|
|
|
|
- name: Instrumented tests
|
|
uses: reactivecircus/android-emulator-runner@a421e43855164a8197daf9d8d40fe71c6996bb0d # v2.38.0
|
|
env:
|
|
E2E_DISABLE_SYSTEM_UI: "1"
|
|
# The complement of the gating row's notAnnotation, off the same marker,
|
|
# so a test can never be excluded from both jobs or run in both.
|
|
E2E_EXTRA_GRADLE_ARGS: "-Pandroid.testInstrumentationRunnerArguments.annotation=org.libremediaconverter.FailsOnEmulatorApi37"
|
|
# Turns on the baseline comparison in the run-shape report, and only here. Every leg
|
|
# prints the shape; this is the one that also says whether it matches
|
|
# FAILS_ON_EMULATOR_API37_BASELINE, because this is the one whose test list is the
|
|
# marker. A deviation is a `::notice::` -- this job stays continue-on-error and stays
|
|
# out of the required contexts, so nothing the report finds can change a conclusion.
|
|
E2E_ADVISORY: "1"
|
|
with:
|
|
# Every device pin below matches the gating row exactly, so a difference
|
|
# between the two jobs is the test selection and nothing else.
|
|
api-level: "37.0"
|
|
target: google_apis
|
|
arch: x86_64
|
|
profile: pixel_6
|
|
emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
|
|
disable-animations: true
|
|
disk-size: 8G
|
|
ram-size: 2560M
|
|
script: bash .github/scripts/e2e-run.sh ${{ env.E2E_LABEL }}
|
|
|
|
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
if: always()
|
|
with:
|
|
name: e2e-report-api${{ env.E2E_LABEL }}
|
|
path: |
|
|
app/build/reports/androidTests/
|
|
app/build/outputs/androidTest-results/
|
|
if-no-files-found: warn
|
|
|
|
# Uploaded always, and here it matters more than anywhere else in this file:
|
|
# this job is EXPECTED to be red, so the logcat is the only thing that says
|
|
# whether it is red for the known reason or for a new one.
|
|
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
if: always()
|
|
with:
|
|
name: e2e-diagnostics-api${{ env.E2E_LABEL }}
|
|
path: |
|
|
${{ runner.temp }}/logcat-api${{ env.E2E_LABEL }}.txt
|
|
${{ runner.temp }}/diagnostics-api${{ env.E2E_LABEL }}.txt
|
|
${{ runner.temp }}/gradle-api${{ env.E2E_LABEL }}.txt
|
|
if-no-files-found: warn
|
|
|
|
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
if: always()
|
|
with:
|
|
name: e2e-wedge-api${{ env.E2E_LABEL }}
|
|
path: ${{ runner.temp }}/wedge-diagnostics-api${{ env.E2E_LABEL }}.txt
|
|
if-no-files-found: ignore
|