CI: persistent Gradle cache, safer release API logs, faster SDK step
Some checks failed
Forgejo Release Builder / release (push) Failing after 16m20s

- Use $HOME/.cache/komikku-ci-gradle (override KOMIKKU_GRADLE_CACHE on runner)
  instead of per-job .gradle-ci under the checkout so dependencies survive runs.
- Skip sdkmanager when build-tools 35.0.0 already installed.
- Enable kotlin.incremental for assembleRelease to shorten Kotlin compile.
- Replace curl -f release/asset calls with explicit HTTP status checks and
  always print JSON error bodies on failure (Forgejo UI often hid stderr).

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
littlecodedragon 2026-05-09 20:32:26 +02:00
parent 06bc3a6a0c
commit 7bca00964e

View file

@ -71,6 +71,15 @@ jobs:
echo "JAVA_HOME=$java_home" >> "$GITHUB_ENV"
fi
- name: Configure persistent Gradle cache
shell: bash
run: |
set -euo pipefail
gradle_home="${KOMIKKU_GRADLE_CACHE:-${HOME}/.cache/komikku-ci-gradle}"
mkdir -p "${gradle_home}"
echo "GRADLE_USER_HOME=${gradle_home}" >> "${GITHUB_ENV}"
echo "Gradle dependencies/cache: ${gradle_home}"
- name: Prepare release metadata
id: prepare
shell: bash
@ -149,10 +158,15 @@ jobs:
echo "ANDROID_SDK_ROOT=$ANDROID_SDK_ROOT" >> "$GITHUB_ENV"
sdkmanager_bin="$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager"
if [ -x "$sdkmanager_bin" ]; then
set +o pipefail
yes | "$sdkmanager_bin" --licenses >/dev/null || true
yes | "$sdkmanager_bin" "platform-tools" "build-tools;35.0.0"
set -o pipefail
if [ ! -x "$ANDROID_HOME/build-tools/35.0.0/aidl" ]; then
echo "Installing Android SDK components via sdkmanager..."
set +o pipefail
yes | "$sdkmanager_bin" --licenses >/dev/null || true
yes | "$sdkmanager_bin" "platform-tools" "build-tools;35.0.0"
set -o pipefail
else
echo "Android build-tools 35.0.0 present; skipping sdkmanager (saves time)."
fi
else
echo "sdkmanager not found at $sdkmanager_bin"
fi
@ -163,7 +177,6 @@ jobs:
fi
printf 'sdk.dir=%s\n' "$ANDROID_HOME" > local.properties
chmod +x ./gradlew
export GRADLE_USER_HOME="${PWD}/.gradle-ci"
./gradlew --no-daemon --max-workers=1 \
"-Dorg.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=640m -XX:ReservedCodeCacheSize=192m -Dfile.encoding=UTF-8" \
-Dorg.gradle.parallel=false \
@ -172,6 +185,7 @@ jobs:
-Dkotlin.daemon.enabled=false \
"-Dkotlin.daemon.jvmargs=-Xmx512m,-XX:MaxMetaspaceSize=256m,-XX:ReservedCodeCacheSize=128m" \
-Dkotlin.compiler.execution.strategy=in-process \
-Pkotlin.incremental=true \
--version
- name: Build app
@ -179,7 +193,6 @@ jobs:
if [ -n "${ANDROID_HOME:-}" ]; then
printf 'sdk.dir=%s\n' "$ANDROID_HOME" > local.properties
fi
export GRADLE_USER_HOME="${PWD}/.gradle-ci"
./gradlew --no-daemon --max-workers=1 \
"-Dorg.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=640m -XX:ReservedCodeCacheSize=192m -Dfile.encoding=UTF-8" \
-Dorg.gradle.parallel=false \
@ -188,6 +201,7 @@ jobs:
-Dkotlin.daemon.enabled=false \
"-Dkotlin.daemon.jvmargs=-Xmx512m,-XX:MaxMetaspaceSize=256m,-XX:ReservedCodeCacheSize=128m" \
-Dkotlin.compiler.execution.strategy=in-process \
-Pkotlin.incremental=true \
--stacktrace \
assembleRelease -Penable-updater -Pdisable-code-shrink
@ -197,17 +211,15 @@ jobs:
set -euo pipefail
version_tag="${{ steps.prepare.outputs.VERSION_TAG }}"
# Strip CI/build metadata suffixes (e.g. -forgejo.29) for stable asset names.
version_core="$(printf '%s' "$version_tag" | sed -E 's/^v//' | sed -E 's/-forgejo\.[0-9]+$//')"
mv app/build/outputs/apk/release/app-universal-release-unsigned.apk "Komikku-v${version_core}-universal-unsigned.apk"
mv app/build/outputs/apk/release/app-arm64-v8a-release-unsigned.apk "Komikku-v${version_core}-arm64-v8a-unsigned.apk"
mv app/build/outputs/apk/release/app-armeabi-v7a-release-unsigned.apk "Komikku-v${version_core}-armeabi-v7a-unsigned.apk"
mv app/build/outputs/apk/release/app-x86-release-unsigned.apk "Komikku-v${version_core}-x86-unsigned.apk"
mv app/build/outputs/apk/release/app-x86_64-release-unsigned.apk "Komikku-v${version_core}-x86_64-unsigned.apk"
mv app/build/outputs/apk/release/app-universal-release-unsigned.apk "Komikku-${version_tag}-unsigned.apk"
mv app/build/outputs/apk/release/app-arm64-v8a-release-unsigned.apk "Komikku-arm64-v8a-${version_tag}-unsigned.apk"
mv app/build/outputs/apk/release/app-armeabi-v7a-release-unsigned.apk "Komikku-armeabi-v7a-${version_tag}-unsigned.apk"
mv app/build/outputs/apk/release/app-x86-release-unsigned.apk "Komikku-x86-${version_tag}-unsigned.apk"
mv app/build/outputs/apk/release/app-x86_64-release-unsigned.apk "Komikku-x86_64-${version_tag}-unsigned.apk"
if [ -d app/build/outputs/mapping/release ]; then
zip -qr "Komikku-v${version_core}-mapping.zip" app/build/outputs/mapping/release
zip -qr "Komikku-mapping-${version_tag}.zip" app/build/outputs/mapping/release
fi
- name: Sign APKs
@ -268,11 +280,18 @@ jobs:
}
# Only publish signed APK aliases.
alias_asset "$(ls -1t Komikku-v*-arm64-v8a.apk 2>/dev/null | head -n1)" "Komikku-arm64-v8a.apk"
alias_asset "$(ls -1t Komikku-v*-armeabi-v7a.apk 2>/dev/null | head -n1)" "Komikku-armeabi-v7a.apk"
alias_asset "$(ls -1t Komikku-v*-x86.apk 2>/dev/null | head -n1)" "Komikku-x86.apk"
alias_asset "$(ls -1t Komikku-v*-x86_64.apk 2>/dev/null | head -n1)" "Komikku-x86_64.apk"
alias_asset "$(ls -1t Komikku-v*-universal.apk 2>/dev/null | head -n1)" "Komikku-universal.apk"
alias_asset "$(ls -1t Komikku-arm64-v8a-*.apk 2>/dev/null | head -n1)" "Komikku-arm64-v8a.apk"
for candidate in Komikku-*.apk; do
case "$candidate" in
*arm64-v8a*|*armeabi-v7a*|*x86_64*|*x86*|*-unsigned.apk)
;;
*)
alias_asset "$candidate" "Komikku-universal.apk"
break
;;
esac
done
- name: Create or update release
id: release
@ -386,21 +405,17 @@ jobs:
fi
release_body="$(printf '%s\n' \
"## Komikku ${VERSION_DISPLAY}" \
"#### What's Changed" \
"" \
"### Download Guide" \
"- **Most users:** \`Komikku-universal.apk\`" \
"- **arm64 devices:** \`Komikku-arm64-v8a.apk\`" \
"- **armeabi-v7a devices:** \`Komikku-armeabi-v7a.apk\`" \
"- **x86 devices:** \`Komikku-x86.apk\`" \
"- **x86_64 devices:** \`Komikku-x86_64.apk\`" \
"##### New" \
"" \
"##### Improve" \
"" \
"##### Fix" \
"" \
"### Changes" \
"${commit_logs}" \
"" \
"### Release Notes" \
"- Assets use stable names for Obtainium compatibility." \
"- Versioned files follow: \`Komikku-v<version>-<abi>.apk\`." \
"##### Based on" \
"" \
"${fork_delta_label}" \
"" \
@ -417,34 +432,65 @@ jobs:
--arg body "${release_body}" \
'{tag_name: $tag, name: $title, body: $body, draft: false, prerelease: false}' > "${payload_file}"
tag_path_enc="$("${JQ_BIN}" -nr --arg t "${VERSION_TAG}" '$t|@uri')"
tag_get_url="${api_base}/tags/${tag_path_enc}"
echo "Forgejo release API: GET ${tag_get_url}"
status="$(curl "${curl_tls_args[@]}" -sS -o "$response_file" -w '%{http_code}' \
-H "Authorization: token ${FORGEJO_TOKEN}" \
"${api_base}/tags/${VERSION_TAG}")"
"${tag_get_url}")"
if [ "$status" = "200" ]; then
release_id="$("${JQ_BIN}" -r '.id' < "$response_file")"
curl "${curl_tls_args[@]}" -fsS \
-X PATCH \
-H "Authorization: token ${FORGEJO_TOKEN}" \
-H 'Content-Type: application/json' \
--data @"$payload_file" \
"${api_base}/${release_id}" \
> "$response_file"
elif [ "$status" = "404" ]; then
curl "${curl_tls_args[@]}" -fsS \
-X POST \
-H "Authorization: token ${FORGEJO_TOKEN}" \
-H 'Content-Type: application/json' \
--data @"$payload_file" \
"${api_base}" \
> "$response_file"
release_id="$("${JQ_BIN}" -r '.id' < "$response_file")"
else
echo "release-by-tag GET HTTP status: ${status}"
if [ "${status}" != "200" ] && [ "${status}" != "404" ]; then
echo "Unexpected GET response body:"
cat "$response_file"
exit 1
fi
echo "RELEASE_ID=$release_id" >> "$GITHUB_OUTPUT"
release_id=""
if [ "${status}" = "200" ]; then
release_id="$("${JQ_BIN}" -r '.id // empty' < "$response_file")"
if [ -z "${release_id}" ] || [ "${release_id}" = "null" ]; then
echo "GET returned 200 but missing release id; body:"
cat "$response_file"
exit 1
fi
echo "PATCH existing release id=${release_id}"
patch_status="$(curl "${curl_tls_args[@]}" -sS -o "$response_file" -w '%{http_code}' \
-X PATCH \
-H "Authorization: token ${FORGEJO_TOKEN}" \
-H 'Content-Type: application/json' \
--data @"$payload_file" \
"${api_base}/${release_id}")"
echo "PATCH HTTP status: ${patch_status}"
if [ "${patch_status}" != "200" ]; then
echo "PATCH response body:"
cat "$response_file"
exit 1
fi
elif [ "${status}" = "404" ]; then
echo "POST new release for tag ${VERSION_TAG}"
post_status="$(curl "${curl_tls_args[@]}" -sS -o "$response_file" -w '%{http_code}' \
-X POST \
-H "Authorization: token ${FORGEJO_TOKEN}" \
-H 'Content-Type: application/json' \
--data @"$payload_file" \
"${api_base}")"
echo "POST HTTP status: ${post_status}"
if [ "${post_status}" != "201" ] && [ "${post_status}" != "200" ]; then
echo "POST response body:"
cat "$response_file"
exit 1
fi
release_id="$("${JQ_BIN}" -r '.id // empty' < "$response_file")"
if [ -z "${release_id}" ] || [ "${release_id}" = "null" ]; then
echo "POST succeeded but missing release id; body:"
cat "$response_file"
exit 1
fi
fi
echo "RELEASE_ID=${release_id}" >> "$GITHUB_OUTPUT"
- name: Upload release assets
shell: bash
@ -529,13 +575,24 @@ jobs:
curl_tls_args+=(--insecure)
fi
if [ -z "${RELEASE_ID:-}" ] || [ "${RELEASE_ID}" = "null" ]; then
echo "RELEASE_ID missing or null — create/update release step likely failed."
exit 1
fi
release_api="${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/releases/${RELEASE_ID}"
assets_file="$(mktemp)"
err_body="$(mktemp)"
curl "${curl_tls_args[@]}" -fsS \
assets_status="$(curl "${curl_tls_args[@]}" -sS -o "$assets_file" -w '%{http_code}' \
-H "Authorization: token ${FORGEJO_TOKEN}" \
"${release_api}/assets" \
> "$assets_file"
"${release_api}/assets")"
if [ "${assets_status}" != "200" ]; then
echo "List assets failed HTTP ${assets_status}:"
cat "$assets_file"
rm -f "$assets_file" "$err_body"
exit 1
fi
for file in Komikku-*.apk Komikku-mapping-*.zip; do
[ -e "$file" ] || continue
@ -548,20 +605,32 @@ jobs:
asset_id="$("${JQ_BIN}" -r --arg n "${asset_name}" '(.[] | select(.name == $n) | .id) // empty' "$assets_file")"
if [ -n "$asset_id" ] && [ "$asset_id" != "null" ]; then
curl "${curl_tls_args[@]}" -fsS \
del_status="$(curl "${curl_tls_args[@]}" -sS -o "$err_body" -w '%{http_code}' \
-X DELETE \
-H "Authorization: token ${FORGEJO_TOKEN}" \
"${release_api}/assets/${asset_id}" \
> /dev/null
"${release_api}/assets/${asset_id}")"
if [ "${del_status}" != "204" ] && [ "${del_status}" != "200" ] && [ "${del_status}" != "404" ]; then
echo "DELETE old asset ${asset_name} failed HTTP ${del_status}:"
cat "$err_body"
rm -f "$assets_file" "$err_body"
exit 1
fi
fi
encoded_name="$("${JQ_BIN}" -nr --arg s "${asset_name}" '$s | @uri')"
curl "${curl_tls_args[@]}" -fsS \
up_status="$(curl "${curl_tls_args[@]}" -sS -o "$err_body" -w '%{http_code}' \
-X POST \
-H "Authorization: token ${FORGEJO_TOKEN}" \
-H 'Content-Type: application/octet-stream' \
--data-binary @"$file" \
"${release_api}/assets?name=${encoded_name}" \
> /dev/null
"${release_api}/assets?name=${encoded_name}")"
if [ "${up_status}" != "201" ] && [ "${up_status}" != "200" ]; then
echo "Upload ${asset_name} failed HTTP ${up_status}:"
cat "$err_body"
rm -f "$assets_file" "$err_body"
exit 1
fi
echo "Uploaded ${asset_name} (HTTP ${up_status})"
done
rm -f "$assets_file" "$err_body"