Skip to content

2.18.4: udp:// receive thread at the audio priority (#253) #934

2.18.4: udp:// receive thread at the audio priority (#253)

2.18.4: udp:// receive thread at the audio priority (#253) #934

Workflow file for this run

name: Build
on:
push:
pull_request:
workflow_dispatch:
inputs:
commit_hash:
description: 'Specific commit SHA to build (leave empty for latest branch commit)'
required: false
type: string
# One run per branch (and event). On working branches a newer push cancels the older run;
# on basic / v2 it waits instead (only the newest waits), so "latest" still ends with the
# build of the newest commit (#90) and a publish is never cut off halfway. A manual run of the
# branch head shares that group (so each branch has one publish at a time and the shared
# release-latest group below never holds more than one waiting job); a manual run of an older
# commit (commit_hash) has a group of its own and does not publish.
concurrency:
group: ${{ github.event_name == 'workflow_dispatch' && inputs.commit_hash != '' && format('manual-{0}', github.run_id) || format('build-{0}-{1}', github.event_name == 'pull_request' && 'pull_request' || 'push', github.ref) }}
cancel-in-progress: ${{ !(github.event_name == 'workflow_dispatch' && inputs.commit_hash != '') && github.ref != 'refs/heads/v2' && github.ref != 'refs/heads/basic' }}
# Read-only by default; only the publish job writes the release
permissions:
contents: read
jobs:
# The version check of pull requests is .github/workflows/version.yml (#244).
# Unit tests and lint; also runs for pull requests from forks (no secrets needed)
test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Switch to specified commit (keep latest workflow files)
if: inputs.commit_hash != ''
run: |
git fetch --unshallow
git checkout ${{ inputs.commit_hash }}
git checkout ${{ github.ref_name }} -- .github/
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17
cache: gradle
- name: Unit tests and lint
working-directory: android
run: |
./gradlew testDebugUnitTest
# Commits from before the lint baseline would fail on known findings
if [ -f app/lint-baseline.xml ]; then
./gradlew lintDebug
else
echo "No lint baseline in this commit, lint skipped"
fi
- name: Upload reports
if: failure()
uses: actions/upload-artifact@v4
with:
name: test-and-lint-reports
path: |
android/app/build/reports/
android/app/build/test-results/
# Signed release build; needs secrets, so it does not run for pull requests
build:
needs: test
if: github.event_name != 'pull_request'
runs-on: ubuntu-latest
outputs:
mapping: ${{ steps.apk.outputs.mapping }} # 1 when the build has an R8 mapping
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Switch to specified commit (keep latest workflow files)
if: inputs.commit_hash != ''
run: |
git fetch --unshallow
git checkout ${{ inputs.commit_hash }}
git checkout ${{ github.ref_name }} -- .github/
- name: Set artifact name
id: vars
run: |
case "${{ github.ref_name }}" in
basic) echo "name=decoder" ;;
v2) echo "name=decoder-v2" ;;
*) echo "name=decoder-$(echo '${{ github.ref_name }}' | tr '/' '-')" ;;
esac >> $GITHUB_OUTPUT
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17
cache: gradle
- name: Build
id: apk
working-directory: android
env:
KEYSTORE_PASS: ${{ secrets.KEYSTORE_PASS }}
KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
KEY_PASS: ${{ secrets.KEY_PASS }}
run: |
echo "${{ secrets.KEY }}" | base64 -d > key.jks
# APK only while in development; the .aab (bundleRelease) is for store uploads
./gradlew assembleRelease
mv app/build/outputs/apk/release/app-release.apk ../${{ steps.vars.outputs.name }}.apk
# R8 mapping of this APK, to retrace obfuscated stack traces (#181). A build without
# minify has none: warn instead of failing
MAPPING=app/build/outputs/mapping/release/mapping.txt
if [ -f "$MAPPING" ]; then
cp "$MAPPING" ../${{ steps.vars.outputs.name }}-mapping.txt
echo "mapping=1" >> "$GITHUB_OUTPUT"
else
echo "::warning::No R8 mapping.txt at $MAPPING"
fi
# Every build keeps its R8 mapping as a workflow artifact (#181)
- name: Upload mapping
uses: actions/upload-artifact@v4
with:
name: ${{ steps.vars.outputs.name }}-mapping
path: ${{ steps.vars.outputs.name }}-mapping.txt
if-no-files-found: warn
# Every build is a workflow artifact; on basic / v2 the publish job takes it from here
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: ${{ steps.vars.outputs.name }}
path: ${{ steps.vars.outputs.name }}.apk
# The one release, "latest" (#194, #229): updated in place by v2 and basic, each with its
# own files; v2 moves the tag to its commit and sets the title "Decoder <version>".
# A new version (not every build) goes to Telegram. The
# concurrency group is shared with basic's workflow: one publish at a time.
publish:
needs: build
# basic publishes from its own workflow (same script, same concurrency group); a manual
# run of an older commit (commit_hash) builds but does not publish
if: github.ref_name == 'v2' && (github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.commit_hash == ''))
runs-on: ubuntu-latest
permissions:
contents: write # update the release and move its tag
concurrency:
group: release-latest
cancel-in-progress: false
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Download the build
uses: actions/download-artifact@v4
with:
name: decoder-v2
path: dist
# only when the build has one (a build without minify has none, #181); then it must come
- name: Download the mapping
if: needs.build.outputs.mapping == '1'
uses: actions/download-artifact@v4
with:
name: decoder-v2-mapping
path: dist
- name: Publish
id: publish
env:
GH_TOKEN: ${{ github.token }}
run: |
VER=$(sed -n 's/^[[:space:]]*versionName[[:space:]]*"\([^"]*\)"[[:space:]]*$/\1/p' android/app/build.gradle)
[ -n "$VER" ] || { echo "::error::no versionName in android/app/build.gradle"; exit 1; }
echo "VER=$VER" >> "$GITHUB_ENV"
files=(dist/decoder-v2.apk)
[ -f dist/decoder-v2-mapping.txt ] && files+=(dist/decoder-v2-mapping.txt)
.github/publish-latest.sh v2 "$VER" "${files[@]}"
# Organization secrets; a failed upload is a warning, not a failed release
- name: Telegram
if: steps.publish.outputs.new == 'true'
env:
TG_TOKEN: ${{ secrets.TELEGRAM_TOKEN_BOT_OPENIPC }}
TG_CHANNEL: ${{ secrets.TELEGRAM_CHANNEL_OPENIPC_DEV }}
run: |
if [ -z "$TG_TOKEN" ] || [ -z "$TG_CHANNEL" ]; then
echo "::warning::Telegram secrets are not available, version not announced"; exit 0
fi
CAPTION=$(printf 'Decoder %s\nCommit: %s\nBranch: %s\nTime: %s\n\n%s' "$VER" "${GITHUB_SHA::7}" \
"${GITHUB_REF_NAME}" "$(date -u '+%Y-%m-%d %H:%M:%S UTC')" \
"${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/releases/latest")
HTTP=$(curl -sS -o tg.json -w '%{http_code}' "https://api.telegram.org/bot${TG_TOKEN}/sendDocument" \
-F chat_id="$TG_CHANNEL" -F caption="$CAPTION" -F document=@dist/decoder-v2.apk) || HTTP=000
echo "Telegram response: $HTTP"
[ "$HTTP" = 200 ] || echo "::warning::Telegram upload failed (HTTP $HTTP)"