The step added in the previous commit went red on its own PR, and the reason is the one
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." Here it was not even a new rule, just a different version of the same tool.
The runner's ambient shellcheck is 0.9.0. The container used to check locally was 0.11.0.
They disagree about how to report `on_signal`, which is installed as the INT and TERM trap
eleven lines below its declaration and so is never called by name:
0.11.0 SC2329, once, on the function declaration -- "never invoked"
0.9.0 SC2317, seven times, one per command in the body -- "appears to be unreachable"
The disable directive named SC2329, so 0.11.0 was silent and 0.9.0 reported seven findings.
Nothing about the script was wrong; the local check simply was not the check CI ran.
Two changes, because either alone still leaves a way to be surprised:
- CI runs shellcheck from an image pinned by digest, so an upgrade is a line in this
file that someone chose, not something that arrives on a Tuesday. The version is
still printed, so a finding out of nowhere can be tied to that line.
- The directive names SC2317 and SC2329 both, so a contributor whose distro ships 0.9.0
gets the same answer locally as CI gives. Verified against both images: clean under
0.9.0 and clean under 0.11.0.
CLAUDE.md now says to check with the pinned digest rather than with whatever is installed,
which is what would have caught this before the push.
460 lines
22 KiB
YAML
460 lines
22 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"
|
|
|
|
# `!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.
|
|
#
|
|
# CAVEAT, read this before trusting a green here: this leg runs with
|
|
# SystemUI disabled and the framework restarted under it. No other leg
|
|
# and no Pixel run uses that configuration. It is defensible only because
|
|
# nothing in this suite touches system UI -- these are Media3, FFmpeg and
|
|
# WorkManager tests -- and because the alternative is no CI coverage of
|
|
# the level this app targets. **Anything that ever does depend on system
|
|
# UI must not trust this row.** E2E_DISABLE_SYSTEM_UI is what does it;
|
|
# .github/scripts/e2e-run.sh explains the mechanism and why every step of
|
|
# it is verified rather than assumed.
|
|
#
|
|
# api-level must be "37.0". A bare 37 is not an SDK package and fails
|
|
# during setup, which cost a run to discover.
|
|
#
|
|
# notAnnotation removes the two 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
|
|
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 two 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 is named for WHAT IT RUNS, deliberately. Both tests drive a full H.264 ->
|
|
# H.265 hardware transcode through Media3Engine -- which is exactly what
|
|
# separates them from the two Media3EngineTest cases that pass here, since those
|
|
# two never decode video. The current theory about why they fail is in the next
|
|
# paragraph, where it can be corrected without renaming a check that people have
|
|
# already learned to look for.
|
|
#
|
|
# 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. What is MEASURED is narrower: these 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"
|
|
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
|
|
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
|