diff --git a/.forgejo/workflows/build_release.yml b/.forgejo/workflows/build_release.yml index 5257f26c0..061238bf1 100755 --- a/.forgejo/workflows/build_release.yml +++ b/.forgejo/workflows/build_release.yml @@ -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-.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"