13 Commits

Author SHA1 Message Date
Hermes
438d8e22b4 ci: install Githug native build prerequisites
All checks were successful
Android build / build (push) Successful in 33m18s
Android build / build (release) Successful in 27m50s
2026-09-01 17:28:19 -05:00
Hermes
553c512082 ci: route Android builds through project tooling
Some checks failed
Android build / build (push) Failing after 1m48s
2026-09-01 17:16:48 -05:00
Hermes
0bf7f6b387 fix: cross-compile bundled Android git libs with Rust
All checks were successful
Android build / build (push) Successful in 14m1s
Android build / build (release) Successful in 24m0s
2026-08-31 20:40:02 -05:00
Hermes
1ac5f0d7fa ci: build and verify bundled Android git libs
Some checks failed
Android build / build (push) Failing after 4m53s
2026-08-31 20:33:40 -05:00
Hermes
052ea8de4c ci: verify Android bundles ship native git
Some checks failed
Android build / build (push) Failing after 38s
Android build / build (release) Failing after 53s
2026-08-31 18:53:02 -05:00
Hermes
9c77cdc3a3 ci: compile bundled git for Android builds
Some checks failed
Android build / build (push) Failing after 1m13s
2026-08-31 18:51:08 -05:00
Hermes
b5fea9e010 ci: prefer github token for release asset upload
All checks were successful
Android build / build (push) Successful in 9m6s
Android build / build (release) Successful in 11m31s
2026-08-31 17:52:41 -05:00
Hermes
df07409e48 ci: broaden release asset upload token fallback
Some checks failed
Android build / build (push) Has been cancelled
2026-08-31 16:12:17 -05:00
Hermes
6604b5b94a ci: bump APK versionCode and timestamp AAB names
Some checks failed
Android build / build (push) Successful in 11m49s
Android build / build (release) Failing after 9m55s
2026-08-31 15:05:53 -05:00
Hermes
56eddb424a fix: repair AGP upgrade file corruption
All checks were successful
Android build / build (push) Successful in 7m48s
2026-08-31 13:49:47 -05:00
Hermes
98faa8b6f0 build: upgrade AGP for Android 16 support
Some checks failed
Android build / build (push) Has been cancelled
2026-08-31 13:30:52 -05:00
Hermes
ee21751e03 build: target Android 16 / API 36
All checks were successful
Android build / build (push) Successful in 17m7s
2026-08-31 12:18:29 -05:00
Hermes
0b719dcc36 ci: visible-file push trigger test
All checks were successful
Android build / build (push) Successful in 6m50s
2026-08-30 10:01:44 -05:00
7 changed files with 180 additions and 103 deletions

View File

@@ -1,7 +1,7 @@
name: Android build name: Android build
permissions: permissions:
contents: read contents: write
releases: write releases: write
on: on:
@@ -29,90 +29,101 @@ jobs:
distribution: temurin distribution: temurin
java-version: '17' java-version: '17'
- name: Install Android SDK command-line tools and packages - name: Install native build prerequisites
shell: bash shell: bash
run: | run: |
set -euxo pipefail set -euxo pipefail
export ANDROID_SDK_ROOT="$HOME/.android/sdk" sudo apt-get update
export ANDROID_HOME="$ANDROID_SDK_ROOT" sudo apt-get install -y clang make perl pkg-config file binutils
mkdir -p "$ANDROID_SDK_ROOT/cmdline-tools"
if [ ! -x "$ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager" ]; then
tools_url="$(curl -fsSL https://developer.android.com/studio | grep -o 'https://dl.google.com/android/repository/commandlinetools-linux-[0-9][0-9]*_latest.zip' | head -n 1)"
test -n "$tools_url"
curl -fsSL -o /tmp/commandlinetools.zip "$tools_url"
rm -rf "$ANDROID_SDK_ROOT/cmdline-tools/latest" "$ANDROID_SDK_ROOT/cmdline-tools/cmdline-tools"
unzip -q /tmp/commandlinetools.zip -d "$ANDROID_SDK_ROOT/cmdline-tools"
mv "$ANDROID_SDK_ROOT/cmdline-tools/cmdline-tools" "$ANDROID_SDK_ROOT/cmdline-tools/latest"
fi
export PATH="$ANDROID_SDK_ROOT/cmdline-tools/latest/bin:$ANDROID_SDK_ROOT/platform-tools:$PATH"
set +o pipefail
yes | sdkmanager --licenses >/dev/null
set -o pipefail
sdkmanager \
"platform-tools" \
"platforms;android-35" \
"build-tools;35.0.0" \
"ndk;27.2.12479018" \
"cmake;3.22.1"
- name: Prepare optional release signing - name: Install Rust toolchain
if: github.event_name == 'release' shell: bash
continue-on-error: true run: |
set -euxo pipefail
if ! command -v cargo >/dev/null 2>&1; then
curl https://sh.rustup.rs -sSf | sh -s -- -y --profile minimal
fi
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
export PATH="$HOME/.cargo/bin:$PATH"
cargo --version
rustc --version
rustup target add aarch64-linux-android armv7-linux-androideabi i686-linux-android x86_64-linux-android
- name: Run project build tooling for debug APK
if: github.event_name != 'release'
shell: bash
env: env:
ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }} CI_VERSION_CODE: ${{ github.run_number }}
ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }} CI_ARTIFACT_TIMESTAMP: ${{ github.run_id }}
ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }}
shell: bash
run: |
set -euo pipefail
missing=()
for key in ANDROID_KEYSTORE_BASE64 ANDROID_KEYSTORE_PASSWORD ANDROID_KEY_ALIAS ANDROID_KEY_PASSWORD; do
if [ -z "${!key:-}" ]; then
missing+=("$key")
fi
done
if [ ${#missing[@]} -gt 0 ]; then
printf -v missing_csv '%s, ' "${missing[@]}"
missing_csv="${missing_csv%, }"
echo "::error::Release signing secrets missing: ${missing_csv}. Continuing with unsigned/default-signed release AAB."
exit 1
fi
mkdir -p .ci-secrets
printf '%s' "$ANDROID_KEYSTORE_BASE64" | base64 -d > .ci-secrets/release-keystore.jks
cat > keystore.properties <<EOF
storeFile=.ci-secrets/release-keystore.jks
storePassword=$ANDROID_KEYSTORE_PASSWORD
keyAlias=$ANDROID_KEY_ALIAS
keyPassword=$ANDROID_KEY_PASSWORD
EOF
- name: Make Gradle wrapper executable
run: chmod +x gradlew
- name: Write Android SDK location
shell: bash
run: | run: |
set -euxo pipefail set -euxo pipefail
printf 'sdk.dir=%s/.android/sdk\n' "$HOME" > local.properties export PATH="$HOME/.cargo/bin:$PATH"
chmod +x ./AndroidProjectTooling.sh
bash ./AndroidProjectTooling.sh --build --no-commit
- name: Build debug APK - name: Verify debug APK bundles native Git
if: github.event_name != 'release' if: github.event_name != 'release'
shell: bash shell: bash
run: | run: |
set -euxo pipefail set -euxo pipefail
export ANDROID_SDK_ROOT="$HOME/.android/sdk" python3 - <<'PY'
export ANDROID_HOME="$ANDROID_SDK_ROOT" from pathlib import Path
./gradlew --no-daemon clean assembleDebug import zipfile
apk = next(Path('app/build/outputs/apk/debug').glob('*.apk'))
with zipfile.ZipFile(apk) as zf:
names = zf.namelist()
required = {
'lib/arm64-v8a/libgit.so',
'lib/armeabi-v7a/libgit.so',
'lib/x86/libgit.so',
'lib/x86_64/libgit.so',
}
found = {name for name in names if name in required}
print('APK_NATIVE_GIT', sorted(found))
missing = sorted(required - found)
if missing:
raise SystemExit(f'Missing native Git libraries in {apk}: {missing}')
PY
- name: Build release AAB - name: Run project build tooling for release AAB
if: github.event_name == 'release'
shell: bash
env:
CI_VERSION_CODE: ${{ github.run_number }}
CI_ARTIFACT_TIMESTAMP: ${{ github.run_id }}
ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }}
ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }}
run: |
set -euxo pipefail
export PATH="$HOME/.cargo/bin:$PATH"
chmod +x ./AndroidProjectTooling.sh
bash ./AndroidProjectTooling.sh --build-release-aab --no-commit
- name: Verify release AAB bundles native Git
if: github.event_name == 'release' if: github.event_name == 'release'
shell: bash shell: bash
run: | run: |
set -euxo pipefail set -euxo pipefail
export ANDROID_SDK_ROOT="$HOME/.android/sdk" python3 - <<'PY'
export ANDROID_HOME="$ANDROID_SDK_ROOT" from pathlib import Path
./gradlew --no-daemon bundleRelease import zipfile
aab = next(Path('app/build/outputs/bundle/release').glob('*.aab'))
with zipfile.ZipFile(aab) as zf:
names = zf.namelist()
required = {
'base/lib/arm64-v8a/libgit.so',
'base/lib/armeabi-v7a/libgit.so',
'base/lib/x86/libgit.so',
'base/lib/x86_64/libgit.so',
}
found = {name for name in names if name in required}
print('AAB_NATIVE_GIT', sorted(found))
missing = sorted(required - found)
if missing:
raise SystemExit(f'Missing native Git libraries in {aab}: {missing}')
PY
- name: Upload debug APK - name: Upload debug APK
if: github.event_name != 'release' if: github.event_name != 'release'
@@ -126,13 +137,19 @@ jobs:
if: github.event_name == 'release' if: github.event_name == 'release'
env: env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
GITHUB_TOKEN: ${{ github.token }}
shell: bash shell: bash
run: | run: |
set -euxo pipefail set -euxo pipefail
token="${GITHUB_TOKEN:-${GITEA_TOKEN:-}}"
if [ -z "$token" ]; then
echo "::error::No release upload token is available from secrets.GITEA_TOKEN or github.token"
exit 1
fi
release_id="$(python3 -c 'import json, os; print(json.load(open(os.environ["GITHUB_EVENT_PATH"], encoding="utf-8"))["release"]["id"])')" release_id="$(python3 -c 'import json, os; print(json.load(open(os.environ["GITHUB_EVENT_PATH"], encoding="utf-8"))["release"]["id"])')"
aab="$(find app/build/outputs/bundle/release -name '*.aab' | head -n 1)" aab="$(find app/build/outputs/bundle/release -name '*.aab' | head -n 1)"
curl --fail-with-body \ curl --fail-with-body \
--request POST \ --request POST \
--header "Authorization: token ${GITEA_TOKEN}" \ --header "Authorization: token ${token}" \
--form "attachment=@${aab}" \ --form "attachment=@${aab}" \
"${GITHUB_SERVER_URL}/api/v1/repos/${GITHUB_REPOSITORY}/releases/${release_id}/assets?name=$(basename "$aab")" "${GITHUB_SERVER_URL}/api/v1/repos/${GITHUB_REPOSITORY}/releases/${release_id}/assets?name=$(basename "$aab")"

View File

@@ -30,14 +30,17 @@ GRADLE_DIST_URL="https://services.gradle.org/distributions/gradle-8.7-bin.zip"
JDK_DIST_URL="https://api.adoptium.net/v3/binary/latest/17/ga/linux/x64/jdk/hotspot/normal/eclipse" JDK_DIST_URL="https://api.adoptium.net/v3/binary/latest/17/ga/linux/x64/jdk/hotspot/normal/eclipse"
ANDROID_NDK_PACKAGE="ndk;27.2.12479018" ANDROID_NDK_PACKAGE="ndk;27.2.12479018"
ANDROID_CMAKE_PACKAGE="cmake;3.22.1" ANDROID_CMAKE_PACKAGE="cmake;3.22.1"
ANDROID_EMULATOR_SYSTEM_IMAGE="system-images;android-35;google_apis;x86_64" ANDROID_EMULATOR_SYSTEM_IMAGE="system-images;android-36;google_apis;x86_64"
ANDROID_TEST_AVD_NAME="githug_android_api35" ANDROID_TEST_AVD_NAME="githug_android_api36"
ANDROID_NDK_DIR="$SDK_DIR/ndk/27.2.12479018" ANDROID_NDK_DIR="$SDK_DIR/ndk/27.2.12479018"
ANDROID_CMAKE_DIR="$SDK_DIR/cmake/3.22.1" ANDROID_CMAKE_DIR="$SDK_DIR/cmake/3.22.1"
ANDROID_TOOLBIN="$ANDROID_NDK_DIR/toolchains/llvm/prebuilt/linux-x86_64/bin" ANDROID_TOOLBIN="$ANDROID_NDK_DIR/toolchains/llvm/prebuilt/linux-x86_64/bin"
STATE_TTL_SECONDS=86400 STATE_TTL_SECONDS=86400
HIDE_EMULATOR_WINDOW="false" HIDE_EMULATOR_WINDOW="false"
QUIET_LOG_DIR="$PROJECT_DIR/build/reports/android-project-tooling" QUIET_LOG_DIR="$PROJECT_DIR/build/reports/android-project-tooling"
NO_COMMIT="false"
CI_VERSION_CODE="${CI_VERSION_CODE:-}"
CI_ARTIFACT_TIMESTAMP="${CI_ARTIFACT_TIMESTAMP:-}"
log() { log() {
printf '\n[%s] %s\n' "tooling" "$1" printf '\n[%s] %s\n' "tooling" "$1"
@@ -48,7 +51,7 @@ quiet_log_name() {
local arg local arg
for arg in "$@"; do for arg in "$@"; do
case "$arg" in case "$arg" in
--build|--build-release-aab|--test|--clean-test|--test-emulator|--compile-git) --build|--build-release-aab|--test|--clean-test|--test-emulator|--compile-git|--compile-android-git)
mode="${arg#--}" mode="${arg#--}"
;; ;;
esac esac
@@ -139,8 +142,8 @@ mark_successful_check() {
required_sdk_packages_present() { required_sdk_packages_present() {
[ -d "$SDK_DIR/platform-tools" ] \ [ -d "$SDK_DIR/platform-tools" ] \
&& [ -d "$SDK_DIR/platforms/android-35" ] \ && [ -d "$SDK_DIR/platforms/android-36" ] \
&& [ -d "$SDK_DIR/build-tools/35.0.0" ] \ && [ -d "$SDK_DIR/build-tools/36.0.0" ] \
&& [ -d "$ANDROID_NDK_DIR" ] \ && [ -d "$ANDROID_NDK_DIR" ] \
&& [ -d "$ANDROID_CMAKE_DIR" ] && [ -d "$ANDROID_CMAKE_DIR" ]
} }
@@ -148,7 +151,7 @@ required_sdk_packages_present() {
required_emulator_packages_present() { required_emulator_packages_present() {
required_sdk_packages_present \ required_sdk_packages_present \
&& [ -x "$SDK_DIR/emulator/emulator" ] \ && [ -x "$SDK_DIR/emulator/emulator" ] \
&& [ -d "$SDK_DIR/system-images/android-35/google_apis/x86_64" ] && [ -d "$SDK_DIR/system-images/android-36/google_apis/x86_64" ]
} }
auto_commit_if_needed() { auto_commit_if_needed() {
@@ -299,6 +302,7 @@ import re
path = Path(r'''$gradle_file''') path = Path(r'''$gradle_file''')
text = path.read_text() text = path.read_text()
ci_version_code = r'''$CI_VERSION_CODE'''.strip()
version_code_match = re.search(r'versionCode\s*=\s*(\d+)', text) version_code_match = re.search(r'versionCode\s*=\s*(\d+)', text)
version_name_match = re.search(r'versionName\s*=\s*"(\d+)\.(\d+)\.(\d+)"', text) version_name_match = re.search(r'versionName\s*=\s*"(\d+)\.(\d+)\.(\d+)"', text)
@@ -309,14 +313,15 @@ if not version_code_match or not version_name_match:
current_code = int(version_code_match.group(1)) current_code = int(version_code_match.group(1))
major, minor, patch = map(int, version_name_match.groups()) major, minor, patch = map(int, version_name_match.groups())
new_code = current_code + 1 new_code = int(ci_version_code) if ci_version_code else current_code + 1
new_name = f'{major}.{minor}.{patch + 1}' new_name = f'{major}.{minor}.{patch + 1}'
text = re.sub(r'versionCode\s*=\s*\d+', f'versionCode = {new_code}', text, count=1) text = re.sub(r'versionCode\s*=\s*\d+', f'versionCode = {new_code}', text, count=1)
text = re.sub(r'versionName\s*=\s*"\d+\.\d+\.\d+"', f'versionName = "{new_name}"', text, count=1) if not ci_version_code:
text = re.sub(r'versionName\s*=\s*"\d+\.\d+\.\d+"', f'versionName = "{new_name}"', text, count=1)
path.write_text(text) path.write_text(text)
print(f'Updated versionCode to {new_code} and versionName to {new_name}') print(f'Updated versionCode to {new_code}' + (f' and versionName to {new_name}' if not ci_version_code else ''))
PY PY
} }
@@ -352,6 +357,34 @@ upload_build_artifact_if_possible() {
bash "$UPLOAD_SCRIPT" "$artifact_path" bash "$UPLOAD_SCRIPT" "$artifact_path"
} }
prepare_optional_release_signing() {
local required=(ANDROID_KEYSTORE_BASE64 ANDROID_KEYSTORE_PASSWORD ANDROID_KEY_ALIAS ANDROID_KEY_PASSWORD)
local missing=()
local key
for key in "${required[@]}"; do
if [ -z "${!key:-}" ]; then
missing+=("$key")
fi
done
if [ ${#missing[@]} -eq ${#required[@]} ]; then
return
fi
if [ ${#missing[@]} -gt 0 ]; then
printf 'Release signing secrets missing: %s\n' "${missing[*]}" >&2
exit 1
fi
mkdir -p "$PROJECT_DIR/.ci-secrets"
printf '%s' "$ANDROID_KEYSTORE_BASE64" | base64 -d > "$PROJECT_DIR/.ci-secrets/release-keystore.jks"
cat > "$PROJECT_DIR/keystore.properties" <<EOF_INNER
storeFile=.ci-secrets/release-keystore.jks
storePassword=$ANDROID_KEYSTORE_PASSWORD
keyAlias=$ANDROID_KEY_ALIAS
keyPassword=$ANDROID_KEY_PASSWORD
EOF_INNER
}
setup_env() { setup_env() {
setup_java_env setup_java_env
export ANDROID_HOME="$SDK_DIR" export ANDROID_HOME="$SDK_DIR"
@@ -502,10 +535,11 @@ build_host_git() {
build_android_git_for_abi() { build_android_git_for_abi() {
local abi="$1" local abi="$1"
local cc="$2" local cc="$2"
local rust_target="$3"
local output_dir="$ANDROID_JNI_DIR/$abi" local output_dir="$ANDROID_JNI_DIR/$abi"
local output_binary="$output_dir/libgit.so" local output_binary="$output_dir/libgit.so"
local stamp="$output_dir/.source-fingerprint" local stamp="$output_dir/.source-fingerprint"
local fingerprint="$3:android:$abi:$cc:$ANDROID_API:githug-embedded-main" local fingerprint="$4:android:$abi:$cc:$rust_target:$ANDROID_API:githug-embedded-main"
require_path "$ANDROID_TOOLBIN/$cc" require_path "$ANDROID_TOOLBIN/$cc"
@@ -530,6 +564,7 @@ build_android_git_for_abi() {
AR=llvm-ar \ AR=llvm-ar \
RANLIB=llvm-ranlib \ RANLIB=llvm-ranlib \
STRIP=llvm-strip \ STRIP=llvm-strip \
RUST_TARGETS="$rust_target" \
"${make_args[@]}" \ "${make_args[@]}" \
git git
@@ -554,10 +589,10 @@ build_android_git() {
local fingerprint local fingerprint
fingerprint="$(git_source_fingerprint)" fingerprint="$(git_source_fingerprint)"
build_android_git_for_abi "arm64-v8a" "aarch64-linux-android${ANDROID_API}-clang" "$fingerprint" build_android_git_for_abi "arm64-v8a" "aarch64-linux-android${ANDROID_API}-clang" "aarch64-linux-android" "$fingerprint"
build_android_git_for_abi "armeabi-v7a" "armv7a-linux-androideabi${ANDROID_API}-clang" "$fingerprint" build_android_git_for_abi "armeabi-v7a" "armv7a-linux-androideabi${ANDROID_API}-clang" "armv7-linux-androideabi" "$fingerprint"
build_android_git_for_abi "x86" "i686-linux-android${ANDROID_API}-clang" "$fingerprint" build_android_git_for_abi "x86" "i686-linux-android${ANDROID_API}-clang" "i686-linux-android" "$fingerprint"
build_android_git_for_abi "x86_64" "x86_64-linux-android${ANDROID_API}-clang" "$fingerprint" build_android_git_for_abi "x86_64" "x86_64-linux-android${ANDROID_API}-clang" "x86_64-linux-android" "$fingerprint"
} }
build_all_git_targets() { build_all_git_targets() {
@@ -598,8 +633,8 @@ ensure_sdk_packages() {
log "Installing required Android SDK packages" log "Installing required Android SDK packages"
"$CMDLINE_TOOLS_LATEST_DIR/bin/sdkmanager" --sdk_root="$SDK_DIR" \ "$CMDLINE_TOOLS_LATEST_DIR/bin/sdkmanager" --sdk_root="$SDK_DIR" \
"platform-tools" \ "platform-tools" \
"platforms;android-35" \ "platforms;android-36" \
"build-tools;35.0.0" \ "build-tools;36.0.0" \
"$ANDROID_NDK_PACKAGE" \ "$ANDROID_NDK_PACKAGE" \
"$ANDROID_CMAKE_PACKAGE" "$ANDROID_CMAKE_PACKAGE"
@@ -629,8 +664,8 @@ ensure_emulator_sdk_packages() {
log "Installing Android emulator SDK packages" log "Installing Android emulator SDK packages"
"$CMDLINE_TOOLS_LATEST_DIR/bin/sdkmanager" --sdk_root="$SDK_DIR" \ "$CMDLINE_TOOLS_LATEST_DIR/bin/sdkmanager" --sdk_root="$SDK_DIR" \
"platform-tools" \ "platform-tools" \
"platforms;android-35" \ "platforms;android-36" \
"build-tools;35.0.0" \ "build-tools;36.0.0" \
"$ANDROID_NDK_PACKAGE" \ "$ANDROID_NDK_PACKAGE" \
"$ANDROID_CMAKE_PACKAGE" \ "$ANDROID_CMAKE_PACKAGE" \
"emulator" \ "emulator" \
@@ -786,6 +821,11 @@ maybe_run_operation() {
build_all_git_targets build_all_git_targets
return return
;; ;;
--compile-android-git)
setup_env
build_android_git
return
;;
*) *)
return return
;; ;;
@@ -803,7 +843,11 @@ maybe_run_operation() {
artifact_target="$PROJECT_DIR/app/build/outputs/apk/debug/githug-android-debug-v${version_code}.apk" artifact_target="$PROJECT_DIR/app/build/outputs/apk/debug/githug-android-debug-v${version_code}.apk"
;; ;;
--build-release-aab) --build-release-aab)
if [ -n "$CI_ARTIFACT_TIMESTAMP" ]; then
artifact_target="$PROJECT_DIR/app/build/outputs/bundle/release/Githug-Android-${CI_ARTIFACT_TIMESTAMP}-release.aab"
else
artifact_target="$PROJECT_DIR/app/build/outputs/bundle/release/githug-android-release-v${version_code}.aab" artifact_target="$PROJECT_DIR/app/build/outputs/bundle/release/githug-android-release-v${version_code}.aab"
fi
;; ;;
esac esac
fi fi
@@ -811,6 +855,9 @@ maybe_run_operation() {
build_host_git build_host_git
export GITHUG_TEST_GIT_BINARY="$HOST_GIT_BINARY" export GITHUG_TEST_GIT_BINARY="$HOST_GIT_BINARY"
fi fi
if [ "$mode" = "--build-release-aab" ]; then
prepare_optional_release_signing
fi
if [ "$should_compile_android_git" = "true" ]; then if [ "$should_compile_android_git" = "true" ]; then
build_android_git build_android_git
fi fi
@@ -838,7 +885,7 @@ maybe_run_operation() {
log "Expected build output not found for rename: ${artifact_source#$PROJECT_DIR/}" log "Expected build output not found for rename: ${artifact_source#$PROJECT_DIR/}"
fi fi
if [ "$should_auto_commit" = "true" ]; then if [ "$should_auto_commit" = "true" ] && [ "$NO_COMMIT" != "true" ]; then
auto_commit_if_needed auto_commit_if_needed
fi fi
@@ -850,7 +897,7 @@ maybe_run_operation() {
print_usage() { print_usage() {
cat <<EOF_USAGE cat <<EOF_USAGE
Usage: bash ./AndroidProjectTooling.sh [--quiet] [--build | --build-release-aab | --test | --clean-test | --test-emulator [--hide-emulator-window] | --compile-git] Usage: bash ./AndroidProjectTooling.sh [--quiet] [--build | --build-release-aab | --test | --clean-test | --test-emulator [--hide-emulator-window] | --compile-git | --compile-android-git]
--build Set up the environment and build the debug APK --build Set up the environment and build the debug APK
--build-release-aab Set up the environment and build a release Android App Bundle (AAB) --build-release-aab Set up the environment and build a release Android App Bundle (AAB)
@@ -859,6 +906,7 @@ Usage: bash ./AndroidProjectTooling.sh [--quiet] [--build | --build-release-aab
--test-emulator Set up a visible Android emulator and run debug instrumentation tests on it --test-emulator Set up a visible Android emulator and run debug instrumentation tests on it
--hide-emulator-window Run --test-emulator with the emulator window hidden --hide-emulator-window Run --test-emulator with the emulator window hidden
--compile-git Compile Git for the development host and all Android target ABIs --compile-git Compile Git for the development host and all Android target ABIs
--compile-android-git Compile Git only for the Android target ABIs used by the app
--quiet Write full output to build/reports/android-project-tooling/ and print only a concise result --quiet Write full output to build/reports/android-project-tooling/ and print only a concise result
EOF_USAGE EOF_USAGE
} }
@@ -872,7 +920,7 @@ validate_args() {
shift || true shift || true
case "$mode" in case "$mode" in
""|--build|--build-release-aab|--test|--clean-test|--test-emulator|--compile-git) ""|--build|--build-release-aab|--test|--clean-test|--test-emulator|--compile-git|--compile-android-git)
;; ;;
*) *)
echo "Unknown argument: $mode" >&2 echo "Unknown argument: $mode" >&2
@@ -885,6 +933,9 @@ validate_args() {
case "$1" in case "$1" in
--quiet) --quiet)
;; ;;
--no-commit)
NO_COMMIT="true"
;;
--hide-emulator-window) --hide-emulator-window)
if [ "$mode" != "--test-emulator" ]; then if [ "$mode" != "--test-emulator" ]; then
echo "--hide-emulator-window can only be used with --test-emulator" >&2 echo "--hide-emulator-window can only be used with --test-emulator" >&2
@@ -913,11 +964,18 @@ main() {
require_tool git require_tool git
require_tool perl require_tool perl
require_tool make require_tool make
require_tool clang
require_tool pkg-config require_tool pkg-config
require_tool readelf require_tool readelf
require_tool file require_tool file
local mode="${1:-}"
if [ "$mode" = "--build" ] || [ "$mode" = "--build-release-aab" ] || [ "$mode" = "--test" ] || [ "$mode" = "--clean-test" ] || [ "$mode" = "--compile-git" ] || [ "$mode" = "--test-emulator" ] || [ "$mode" = "--compile-android-git" ]; then
require_tool cargo
fi
if [ "$mode" = "--build" ] || [ "$mode" = "--build-release-aab" ] || [ "$mode" = "--test" ] || [ "$mode" = "--clean-test" ] || [ "$mode" = "--compile-git" ] || [ "$mode" = "--test-emulator" ]; then
require_tool clang
fi
ensure_dir "$TMP_DIR" ensure_dir "$TMP_DIR"
ensure_dir "$SDK_DIR" ensure_dir "$SDK_DIR"
ensure_dir "$GRADLE_USER_HOME_DIR" ensure_dir "$GRADLE_USER_HOME_DIR"
@@ -936,6 +994,7 @@ main() {
log "NDK dir: $ANDROID_NDK_DIR" log "NDK dir: $ANDROID_NDK_DIR"
log "CMake dir: $ANDROID_CMAKE_DIR" log "CMake dir: $ANDROID_CMAKE_DIR"
log "To compile Git for host and Android ABIs: bash ./AndroidProjectTooling.sh --compile-git" log "To compile Git for host and Android ABIs: bash ./AndroidProjectTooling.sh --compile-git"
log "To compile Git only for Android ABIs: bash ./AndroidProjectTooling.sh --compile-android-git"
log "To build without a background Gradle daemon: ./gradlew --no-daemon assembleDebug" log "To build without a background Gradle daemon: ./gradlew --no-daemon assembleDebug"
log "To set up and build in one step: bash ./AndroidProjectTooling.sh --build" log "To set up and build in one step: bash ./AndroidProjectTooling.sh --build"
log "To set up and build a release AAB in one step: bash ./AndroidProjectTooling.sh --build-release-aab" log "To set up and build a release AAB in one step: bash ./AndroidProjectTooling.sh --build-release-aab"

View File

@@ -0,0 +1 @@
trigger test 2026-08-30T10:01:44-05:00

View File

@@ -21,7 +21,7 @@ The UI supports a terminal-centered workflow with optional inspection panes:
## Development Workflow ## Development Workflow
Development tasks should be run through the project tooling script. It provisions the local toolchain, keeps paths project-relative, and runs Gradle with the project configuration expected by this repository. Development tasks should be run through the project tooling script. Local developers and Gitea Actions both use this same script so the compile path stays aligned.
While implementing changes, keep `commit-summary.txt` updated as you go. This file is intentionally ignored by git and excluded from automatic commits so it can be edited manually too; the build tooling uses it as the commit message when it exists and is non-empty. While implementing changes, keep `commit-summary.txt` updated as you go. This file is intentionally ignored by git and excluded from automatic commits so it can be edited manually too; the build tooling uses it as the commit message when it exists and is non-empty.
@@ -50,8 +50,8 @@ Available commands:
| `bash ./AndroidProjectTooling.sh --clean-test` | Compile host Git, clean Gradle outputs, set `GITHUG_TEST_GIT_BINARY`, and run JVM unit tests. | Fresh test reports under `app/build/reports/` | | `bash ./AndroidProjectTooling.sh --clean-test` | Compile host Git, clean Gradle outputs, set `GITHUG_TEST_GIT_BINARY`, and run JVM unit tests. | Fresh test reports under `app/build/reports/` |
| `bash ./AndroidProjectTooling.sh --test-emulator` | Install emulator packages if needed, create/start the visible project test AVD, compile Android Git, and run debug instrumentation tests. | Instrumentation reports under `app/build/reports/androidTests/` | | `bash ./AndroidProjectTooling.sh --test-emulator` | Install emulator packages if needed, create/start the visible project test AVD, compile Android Git, and run debug instrumentation tests. | Instrumentation reports under `app/build/reports/androidTests/` |
| `bash ./AndroidProjectTooling.sh --test-emulator --hide-emulator-window` | Run the same emulator instrumentation tests without showing the emulator window. | Instrumentation reports under `app/build/reports/androidTests/` | | `bash ./AndroidProjectTooling.sh --test-emulator --hide-emulator-window` | Run the same emulator instrumentation tests without showing the emulator window. | Instrumentation reports under `app/build/reports/androidTests/` |
| `bash ./AndroidProjectTooling.sh --build` | Build the debug APK. | `app/build/outputs/apk/debug/githug-android-debug-v<versionCode>.apk` | | `bash ./AndroidProjectTooling.sh --build` | Build the debug APK. Add `--no-commit` to skip the post-build commit. | `app/build/outputs/apk/debug/githug-android-debug-v<versionCode>.apk` |
| `bash ./AndroidProjectTooling.sh --build-release-aab` | Build the release Android App Bundle. | `app/build/outputs/bundle/release/githug-android-release-v<versionCode>.aab` | | `bash ./AndroidProjectTooling.sh --build-release-aab` | Build the release Android App Bundle. Add `--no-commit` to skip the post-build commit. | `app/build/outputs/bundle/release/githug-android-release-v<versionCode>.aab` or `Githug-Android-<timestamp>-release.aab` when `CI_ARTIFACT_TIMESTAMP` is set |
| `bash ./AndroidProjectTooling.sh --compile-git` | Compile Git for the development host and all Android target ABIs. | Host and Android `libgit.so` binaries | | `bash ./AndroidProjectTooling.sh --compile-git` | Compile Git for the development host and all Android target ABIs. | Host and Android `libgit.so` binaries |
Add `--quiet` before any tooling command when running through an AI or other log-sensitive automation: Add `--quiet` before any tooling command when running through an AI or other log-sensitive automation:
@@ -120,13 +120,13 @@ If all required components were verified successfully, the script will skip SDK
When `--build` or `--build-release-aab` is used, the script also: When `--build` or `--build-release-aab` is used, the script also:
- increments `versionCode` by 1 - increments `versionCode` by 1 for local builds, or honors `CI_VERSION_CODE` when provided
- increments the patch component of `versionName`, for example `0.1.0` to `0.1.1` - increments the patch component of `versionName` for local builds
- compiles the generated Android `libgit.so` binaries when they are missing or stale - compiles the generated Android `libgit.so` binaries when they are missing or stale
- bundles full Git manpage source files from Git's `Documentation/` directory into app assets - bundles full Git manpage source files from Git's `Documentation/` directory into app assets
- renames the generated artifact to a `githug-android-*` filename that includes the post-bump `versionCode` - renames the generated artifact to a `githug-android-*` filename that includes the post-bump `versionCode`, or to `Githug-Android-<timestamp>-release.aab` when `CI_ARTIFACT_TIMESTAMP` is set for CI release builds
- uploads the renamed APK/AAB with local `./upload2DL.sh` when that script exists - uploads the renamed APK/AAB with local `./upload2DL.sh` when that script exists
- attempts to create a git commit after a successful build if there are source changes - attempts to create a git commit after a successful build unless `--no-commit` is passed
The build commands currently run these Gradle tasks: The build commands currently run these Gradle tasks:

View File

@@ -19,13 +19,13 @@ plugins {
android { android {
namespace = "solutions.tretter.githugandroid" namespace = "solutions.tretter.githugandroid"
compileSdk = 35 compileSdk = 36
ndkVersion = "27.2.12479018" ndkVersion = "27.2.12479018"
defaultConfig { defaultConfig {
applicationId = "solutions.tretter.githugandroid" applicationId = "solutions.tretter.githugandroid"
minSdk = 26 minSdk = 26
targetSdk = 35 targetSdk = 36
versionCode = 184 versionCode = 184
versionName = "0.1.183" versionName = "0.1.183"

View File

@@ -1,4 +1,4 @@
plugins { plugins {
id("com.android.application") version "8.6.1" apply false id("com.android.application") version "8.10.0" apply false
id("org.jetbrains.kotlin.android") version "1.9.24" apply false id("org.jetbrains.kotlin.android") version "1.9.24" apply false
} }

View File

@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
networkTimeout=10000 networkTimeout=10000
validateDistributionUrl=true validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME