name: "Test Debug Release" on: workflow_dispatch: inputs: architecture: description: 'APK architecture to upload for manual test builds' required: true type: choice options: - arm64-v8a - armeabi-v7a - x86 - x86_64 - universal default: universal push: concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true permissions: contents: read jobs: build-debug: name: Build test debug APK runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 persist-credentials: false - name: Set up JDK 21 uses: actions/setup-java@03ad4de0992f5dab5e18fcb136590ce7c4a0ac95 # v5.6.0 with: distribution: 'temurin' java-version: '21' cache: 'gradle' verify-signature: true - name: Read latest dated version from CHANGELOG.md id: changelog shell: bash run: | set -euo pipefail if [[ ! -f CHANGELOG.md ]]; then echo "::error::CHANGELOG.md not found" exit 1 fi # Expected format (this repo's changelog uses a blockquoted heading): # > # 1.8.9.1 (2026-06) CHANGELOG_LINE="$( grep -m1 -E '^>[[:space:]]+#[[:space:]]+[^[:space:]]+[[:space:]]+\([0-9]{4}-[0-9]{2}\)[[:space:]]*$' CHANGELOG.md )" || { echo "::error::No dated version heading was found in CHANGELOG.md" echo "::error::Expected: > # 1.8.9.1 (YYYY-MM)" exit 1 } VERSION="$(sed -E 's/^>[[:space:]]+#[[:space:]]+([^[:space:]]+).*$/\1/' <<< "$CHANGELOG_LINE")" RELEASE_DATE="$(sed -E 's/^>[[:space:]]+#[[:space:]]+[^[:space:]]+[[:space:]]+\(([0-9]{4}-[0-9]{2})\).*$/\1/' <<< "$CHANGELOG_LINE")" # Extract the complete latest dated release section, excluding # any older releases. Stops at the next top-level version heading. RELEASE_SECTION="$( awk -v heading="$CHANGELOG_LINE" ' $0 == heading { found=1; print; next } found && /^>[[:space:]]+#[[:space:]]+/ { exit } found { print } ' CHANGELOG.md )" # Keep the values safe for filenames/tags. SAFE_VERSION="$(tr -cd '[:alnum:]._-v' <<< "$VERSION")" if [[ -z "$SAFE_VERSION" || -z "$RELEASE_DATE" || -z "$RELEASE_SECTION" ]]; then echo "::error::Could not extract the latest dated release section from CHANGELOG.md" exit 1 fi { echo "version=$SAFE_VERSION" echo "date=$RELEASE_DATE" echo "heading=$CHANGELOG_LINE" echo "section<> "$GITHUB_OUTPUT" echo "Latest dated changelog version: $SAFE_VERSION ($RELEASE_DATE)" - name: Generate debug keystore run: | if [[ -f app/debug.keystore ]]; then echo "Using the committed app/debug.keystore — signature stays the same across runs." else echo "::warning::app/debug.keystore not found in the repo — generating a temporary one for this run only. Commit the keystore this workflow uploads as a build artifact to app/debug.keystore so future test builds share one signature and can be installed as updates instead of reinstalls." keytool -genkeypair -v \ -keystore app/debug.keystore \ -storepass android \ -keypass android \ -alias androiddebugkey \ -keyalg RSA \ -keysize 2048 \ -validity 10000 \ -dname "CN=Android Debug,O=Android,C=US" fi # app/build.gradle only defines signingConfigs.debug when this # file exists and is non-empty — without it, the keystore above # is never actually referenced and the build silently falls # back to Gradle's own implicit debug signing config instead. cat > keystore.properties <> "$GITHUB_OUTPUT" echo "dir=dist" >> "$GITHUB_OUTPUT" SELECTED_APK="" SELECTED_ABI="" SELECTED_FLAVOR="" for APK_PATH in "${APK_PATHS[@]}"; do # Flavor is the directory two levels above the APK file # (.../apk//debug/.apk). FLAVOR="$(basename "$(dirname "$(dirname "$APK_PATH")")")" # Pull the ABI out of the filename by matching a known ABI # token instead of assuming the default "app--debug" # naming — this project's APKs are named "YTDLnis-...". ABI="$(basename "$APK_PATH" .apk | grep -oE 'arm64-v8a|armeabi-v7a|x86_64|x86|universal' || true)" if [[ -z "$ABI" ]]; then ABI="$(basename "$APK_PATH" .apk)" fi if [[ "$ABI" == "$TARGET_ARCH" ]]; then SELECTED_APK="$APK_PATH" SELECTED_ABI="$ABI" SELECTED_FLAVOR="$FLAVOR" break fi done if [[ -z "$SELECTED_APK" ]]; then echo "::error::No APK found for requested architecture: $TARGET_ARCH" echo "::error::Produced APKs:" printf ' %s\n' "${APK_PATHS[@]}" exit 1 fi OUTPUT_APK="dist/YTDLnis-debug-v${VERSION}-${RELEASE_DATE}-${SHORT_SHA}-${SELECTED_FLAVOR}-${SELECTED_ABI}.apk" cp "$SELECTED_APK" "$OUTPUT_APK" echo "architecture=$SELECTED_ABI" >> "$GITHUB_OUTPUT" echo "apk=$OUTPUT_APK" >> "$GITHUB_OUTPUT" echo "Selected architecture: $SELECTED_ABI" echo "Selected APK: $SELECTED_APK" - name: Create internal debug release notes id: notes shell: bash env: VERSION: ${{ steps.changelog.outputs.version }} RELEASE_DATE: ${{ steps.changelog.outputs.date }} CHANGELOG_HEADING: ${{ steps.changelog.outputs.heading }} CHANGELOG_SECTION: ${{ steps.changelog.outputs.section }} SHORT_SHA: ${{ steps.apk.outputs.short_sha }} ARCHITECTURE: ${{ steps.apk.outputs.architecture }} run: | cat > debug-release-notes.md <