Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions .github/signing/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Termux App Signing Keys

This directory contains the keystores used for signing the Termux APK builds.

## Debug Keystore (`debug.jks`)

- **Alias:** `termux-debug`
- **Store Password:** `termux-debug-password`
- **Key Password:** `termux-debug-password`
- **Key Algorithm:** RSA 2048-bit
- **Validity:** 100 years

Used for debug builds in CI and local development.

## Release Keystore (`release.jks`)

- **Alias:** `termux-release`
- **Store Password:** Configure via `TERMUX_RELEASE_STORE_PASSWORD` GitHub Secret
- **Key Password:** Configure via `TERMUX_RELEASE_KEY_PASSWORD` GitHub Secret
- **Key Algorithm:** RSA 4096-bit
- **Validity:** 100 years

Used for release builds. Passwords must be configured as GitHub Secrets
(`TERMUX_RELEASE_STORE_PASSWORD` and `TERMUX_RELEASE_KEY_PASSWORD`) for CI builds.
For local development, set the corresponding environment variables.

## Workflow Integration

Both debug and release workflows reference these keystores. The `app/build.gradle`
signing configurations point to these files via relative paths.
Binary file added .github/signing/debug.jks
Binary file not shown.
Binary file added .github/signing/release.jks
Binary file not shown.
22 changes: 21 additions & 1 deletion .github/workflows/attach_debug_apks_to_release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ on:

jobs:
attach-apks:
runs-on: ubuntu-latest
runs-on: mp4
strategy:
fail-fast: false
matrix:
Expand All @@ -21,6 +21,26 @@ jobs:
with:
ref: ${{ env.GITHUB_REF }}

- name: Setup java 17
uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: '17'

- name: Install dependencies for self-hosted runner
run: |
sudo apt-get update -qq
sudo apt-get install -y unzip

- name: Setup Android SDK
uses: android-actions/setup-android@v3

- name: Verify signing keystores
run: |
echo "Verifying debug keystore"
keytool -list -keystore .github/signing/debug.jks -storepass termux-debug-password -alias termux-debug > /dev/null 2>&1
echo "Debug keystore OK"

- name: Build and attach APKs to release
shell: bash {0}
env:
Expand Down
28 changes: 21 additions & 7 deletions .github/workflows/debug_build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ on:

jobs:
build:
runs-on: ubuntu-latest
runs-on: mp4
strategy:
fail-fast: false
matrix:
Expand All @@ -27,6 +27,20 @@ jobs:
distribution: 'temurin'
java-version: '17'

- name: Install dependencies for self-hosted runner
run: |
sudo apt-get update -qq
sudo apt-get install -y unzip

- name: Setup Android SDK
uses: android-actions/setup-android@v3

- name: Verify signing keystores
run: |
echo "Verifying debug keystore"
keytool -list -keystore .github/signing/debug.jks -storepass termux-debug-password -alias termux-debug > /dev/null 2>&1
echo "Debug keystore OK"

- name: Build APKs
shell: bash {0}
env:
Expand Down Expand Up @@ -85,47 +99,47 @@ jobs:
fi

- name: Attach universal APK file
uses: actions/upload-artifact@v6
uses: actions/upload-artifact@v7
with:
name: ${{ env.APK_BASENAME_PREFIX }}_universal
path: |
${{ env.APK_DIR_PATH }}/${{ env.APK_BASENAME_PREFIX }}_universal.apk
${{ env.APK_DIR_PATH }}/output-metadata.json

- name: Attach arm64-v8a APK file
uses: actions/upload-artifact@v6
uses: actions/upload-artifact@v7
with:
name: ${{ env.APK_BASENAME_PREFIX }}_arm64-v8a
path: |
${{ env.APK_DIR_PATH }}/${{ env.APK_BASENAME_PREFIX }}_arm64-v8a.apk
${{ env.APK_DIR_PATH }}/output-metadata.json

- name: Attach armeabi-v7a APK file
uses: actions/upload-artifact@v6
uses: actions/upload-artifact@v7
with:
name: ${{ env.APK_BASENAME_PREFIX }}_armeabi-v7a
path: |
${{ env.APK_DIR_PATH }}/${{ env.APK_BASENAME_PREFIX }}_armeabi-v7a.apk
${{ env.APK_DIR_PATH }}/output-metadata.json

- name: Attach x86_64 APK file
uses: actions/upload-artifact@v6
uses: actions/upload-artifact@v7
with:
name: ${{ env.APK_BASENAME_PREFIX }}_x86_64
path: |
${{ env.APK_DIR_PATH }}/${{ env.APK_BASENAME_PREFIX }}_x86_64.apk
${{ env.APK_DIR_PATH }}/output-metadata.json

- name: Attach x86 APK file
uses: actions/upload-artifact@v6
uses: actions/upload-artifact@v7
with:
name: ${{ env.APK_BASENAME_PREFIX }}_x86
path: |
${{ env.APK_DIR_PATH }}/${{ env.APK_BASENAME_PREFIX }}_x86.apk
${{ env.APK_DIR_PATH }}/output-metadata.json

- name: Attach sha256sums file
uses: actions/upload-artifact@v6
uses: actions/upload-artifact@v7
with:
name: ${{ env.APK_BASENAME_PREFIX }}_sha256sums
path: |
Expand Down
8 changes: 7 additions & 1 deletion .github/workflows/dependency-submission.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ permissions:

jobs:
dependency-submission:
runs-on: ubuntu-latest
runs-on: mp4
steps:
- name: Checkout sources
uses: actions/checkout@v6
Expand All @@ -19,5 +19,11 @@ jobs:
with:
distribution: 'temurin'
java-version: 17
- name: Install dependencies for self-hosted runner
run: |
sudo apt-get update -qq
sudo apt-get install -y unzip
- name: Setup Android SDK
uses: android-actions/setup-android@v3
- name: Generate and submit dependency graph
uses: gradle/actions/dependency-submission@v5
2 changes: 1 addition & 1 deletion .github/workflows/gradle-wrapper-validation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ on:
jobs:
validation:
name: "Validation"
runs-on: ubuntu-latest
runs-on: mp4
steps:
- uses: actions/checkout@v6
- uses: gradle/actions/wrapper-validation@5
150 changes: 150 additions & 0 deletions .github/workflows/release_build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
name: Release Build

on:
push:
branches:
- 'github-releases/**'
tags:
- 'v*'
workflow_dispatch:

jobs:
build:
runs-on: mp4
strategy:
fail-fast: false
matrix:
package_variant: [ apt-android-7, apt-android-5 ]

steps:
- name: Clone repository
uses: actions/checkout@v6

- name: Setup java 17
uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: '17'

- name: Install dependencies for self-hosted runner
run: |
sudo apt-get update -qq
sudo apt-get install -y unzip

- name: Setup Android SDK
uses: android-actions/setup-android@v3

- name: Verify signing keystores
run: |
echo "Verifying release keystore"
keytool -list -keystore .github/signing/release.jks -storepass termux-release-password -alias termux-release > /dev/null 2>&1
echo "Release keystore OK"

- name: Build Release APKs
shell: bash {0}
env:
PACKAGE_VARIANT: ${{ matrix.package_variant }}
TERMUX_RELEASE_STORE_PASSWORD: ${{ secrets.TERMUX_RELEASE_STORE_PASSWORD }}
TERMUX_RELEASE_KEY_PASSWORD: ${{ secrets.TERMUX_RELEASE_KEY_PASSWORD }}
run: |
exit_on_error() { echo "$1"; exit 1; }

echo "Setting vars"

# Set RELEASE_VERSION_NAME from tag or build.gradle
if [[ "$GITHUB_REF" == refs/tags/v* ]]; then
RELEASE_VERSION_NAME="${GITHUB_REF/refs\/tags\//}"
else
CURRENT_VERSION_NAME_REGEX='\s+versionName "([^"]+)"$'
CURRENT_VERSION_NAME="$(grep -m 1 -E "$CURRENT_VERSION_NAME_REGEX" ./app/build.gradle | sed -r "s/$CURRENT_VERSION_NAME_REGEX/\1/")"
RELEASE_VERSION_NAME="v$CURRENT_VERSION_NAME+${GITHUB_SHA:0:7}"
fi

if ! printf "%s" "${RELEASE_VERSION_NAME/v/}" | grep -qP '^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$'; then
exit_on_error "The versionName '${RELEASE_VERSION_NAME/v/}' is not a valid version as per semantic version '2.0.0' spec in the format 'major.minor.patch(-prerelease)(+buildmetadata)'. https://semver.org/spec/v2.0.0.html."
fi

APK_DIR_PATH="./app/build/outputs/apk/release"
APK_VERSION_TAG="$RELEASE_VERSION_NAME-${{ env.PACKAGE_VARIANT }}-github-release"
APK_BASENAME_PREFIX="termux-app_$APK_VERSION_TAG"

# Used by attachment steps later
echo "APK_DIR_PATH=$APK_DIR_PATH" >> $GITHUB_ENV
echo "APK_VERSION_TAG=$APK_VERSION_TAG" >> $GITHUB_ENV
echo "APK_BASENAME_PREFIX=$APK_BASENAME_PREFIX" >> $GITHUB_ENV

echo "Building Release APKs for '$APK_VERSION_TAG' build"
export TERMUX_APP_VERSION_NAME="${RELEASE_VERSION_NAME/v/}"
export TERMUX_APK_VERSION_TAG="$APK_VERSION_TAG"
export TERMUX_PACKAGE_VARIANT="${{ env.PACKAGE_VARIANT }}"
export TERMUX_SPLIT_APKS_FOR_RELEASE_BUILDS="1"
if ! ./gradlew assembleRelease; then
exit_on_error "Build failed for '$APK_VERSION_TAG' build."
fi

echo "Validating APKs"
for abi in universal arm64-v8a armeabi-v7a x86_64 x86; do
if ! test -f "$APK_DIR_PATH/${APK_BASENAME_PREFIX}_$abi.apk"; then
files_found="$(ls "$APK_DIR_PATH")"
exit_on_error "Failed to find built APK at '$APK_DIR_PATH/${APK_BASENAME_PREFIX}_$abi.apk'. Files found: "$'\n'"$files_found"
fi
done

echo "Generating sha256sums file"
if ! (cd "$APK_DIR_PATH"; sha256sum \
"${APK_BASENAME_PREFIX}_universal.apk" \
"${APK_BASENAME_PREFIX}_arm64-v8a.apk" \
"${APK_BASENAME_PREFIX}_armeabi-v7a.apk" \
"${APK_BASENAME_PREFIX}_x86_64.apk" \
"${APK_BASENAME_PREFIX}_x86.apk" \
> "${APK_BASENAME_PREFIX}_sha256sums"); then
exit_on_error "Generate sha256sums failed for '$APK_VERSION_TAG' release."
fi

- name: Attach universal APK file
uses: actions/upload-artifact@v7
with:
name: ${{ env.APK_BASENAME_PREFIX }}_universal
path: |
${{ env.APK_DIR_PATH }}/${{ env.APK_BASENAME_PREFIX }}_universal.apk
${{ env.APK_DIR_PATH }}/output-metadata.json

- name: Attach arm64-v8a APK file
uses: actions/upload-artifact@v7
with:
name: ${{ env.APK_BASENAME_PREFIX }}_arm64-v8a
path: |
${{ env.APK_DIR_PATH }}/${{ env.APK_BASENAME_PREFIX }}_arm64-v8a.apk
${{ env.APK_DIR_PATH }}/output-metadata.json

- name: Attach armeabi-v7a APK file
uses: actions/upload-artifact@v7
with:
name: ${{ env.APK_BASENAME_PREFIX }}_armeabi-v7a
path: |
${{ env.APK_DIR_PATH }}/${{ env.APK_BASENAME_PREFIX }}_armeabi-v7a.apk
${{ env.APK_DIR_PATH }}/output-metadata.json

- name: Attach x86_64 APK file
uses: actions/upload-artifact@v7
with:
name: ${{ env.APK_BASENAME_PREFIX }}_x86_64
path: |
${{ env.APK_DIR_PATH }}/${{ env.APK_BASENAME_PREFIX }}_x86_64.apk
${{ env.APK_DIR_PATH }}/output-metadata.json

- name: Attach x86 APK file
uses: actions/upload-artifact@v7
with:
name: ${{ env.APK_BASENAME_PREFIX }}_x86
path: |
${{ env.APK_DIR_PATH }}/${{ env.APK_BASENAME_PREFIX }}_x86.apk
${{ env.APK_DIR_PATH }}/output-metadata.json

- name: Attach sha256sums file
uses: actions/upload-artifact@v7
with:
name: ${{ env.APK_BASENAME_PREFIX }}_sha256sums
path: |
${{ env.APK_DIR_PATH }}/${{ env.APK_BASENAME_PREFIX }}_sha256sums
${{ env.APK_DIR_PATH }}/output-metadata.json
8 changes: 7 additions & 1 deletion .github/workflows/run_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ on:

jobs:
testing:
runs-on: ubuntu-latest
runs-on: mp4
steps:
- name: Clone repository
uses: actions/checkout@v6
Expand All @@ -21,6 +21,12 @@ jobs:
with:
distribution: 'temurin'
java-version: '17'
- name: Install dependencies for self-hosted runner
run: |
sudo apt-get update -qq
sudo apt-get install -y unzip
- name: Setup Android SDK
uses: android-actions/setup-android@v3
- name: Execute tests
run: |
./gradlew test
2 changes: 1 addition & 1 deletion .github/workflows/trigger_library_builds_on_jitpack.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ on:

jobs:
trigger-termux-library-builds:
runs-on: ubuntu-latest
runs-on: mp4
steps:
- name: Set vars
run: echo "TERMUX_LIB_VERSION=${GITHUB_REF/refs\/tags\/v/}" >> $GITHUB_ENV # Do not include "v" prefix
Expand Down
Loading
Loading