259 lines
7.6 KiB
YAML
259 lines
7.6 KiB
YAML
name: Build Android Release
|
|
|
|
on:
|
|
push:
|
|
branches:
|
|
- main
|
|
- master
|
|
tags:
|
|
- "*"
|
|
workflow_dispatch:
|
|
|
|
permissions:
|
|
actions: read
|
|
contents: read
|
|
releases: write
|
|
|
|
jobs:
|
|
android:
|
|
name: Build Android
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
- name: Preflight disk cleanup
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
run_sudo() {
|
|
if command -v sudo >/dev/null 2>&1; then
|
|
sudo "$@"
|
|
else
|
|
"$@"
|
|
fi
|
|
}
|
|
|
|
free_mb() {
|
|
df -Pm "${1:-/}" | awk 'NR==2 {print $4}'
|
|
}
|
|
|
|
echo "Disk usage before cleanup:"
|
|
df -h
|
|
|
|
if command -v docker >/dev/null 2>&1; then
|
|
docker system prune -af --volumes || true
|
|
docker builder prune -af || true
|
|
fi
|
|
|
|
run_sudo rm -rf /tmp/* /var/tmp/* || true
|
|
|
|
if [ "$(free_mb /)" -lt 8192 ]; then
|
|
echo "Free disk space is below 8GB. Cleaning user build caches..."
|
|
rm -rf "$HOME/.gradle/caches" "$HOME/.gradle/wrapper/dists" "$HOME/.pub-cache/_temp" || true
|
|
fi
|
|
|
|
echo "Disk usage after cleanup:"
|
|
df -h
|
|
|
|
if [ "$(free_mb /)" -lt 4096 ]; then
|
|
echo "Free disk space is still below 4GB after cleanup. Runner disk is effectively full."
|
|
exit 1
|
|
fi
|
|
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
with:
|
|
repository: gongyun/app
|
|
ref: ${{ github.ref }}
|
|
token: ${{ secrets.GITEA_TOKEN }}
|
|
github-server-url: https://git.saont.net
|
|
|
|
- name: Check build environment
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
df -h
|
|
java -version
|
|
flutter --version
|
|
flutter doctor -v
|
|
|
|
- name: Install dependencies
|
|
run: flutter pub get
|
|
|
|
- name: Restore Android signing files
|
|
shell: bash
|
|
env:
|
|
ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }}
|
|
ANDROID_STORE_PASSWORD: ${{ secrets.ANDROID_STORE_PASSWORD }}
|
|
ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
|
|
ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }}
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
if [ -z "${ANDROID_KEYSTORE_BASE64:-}" ] || [ -z "${ANDROID_STORE_PASSWORD:-}" ] || [ -z "${ANDROID_KEY_ALIAS:-}" ] || [ -z "${ANDROID_KEY_PASSWORD:-}" ]; then
|
|
echo "Android signing secrets are required: ANDROID_KEYSTORE_BASE64, ANDROID_STORE_PASSWORD, ANDROID_KEY_ALIAS, ANDROID_KEY_PASSWORD"
|
|
exit 1
|
|
fi
|
|
|
|
printf "%s" "$ANDROID_KEYSTORE_BASE64" | base64 -d > android/app-release.jks
|
|
{
|
|
printf "storeFile=../app-release.jks\n"
|
|
printf "storePassword=%s\n" "$ANDROID_STORE_PASSWORD"
|
|
printf "keyAlias=%s\n" "$ANDROID_KEY_ALIAS"
|
|
printf "keyPassword=%s\n" "$ANDROID_KEY_PASSWORD"
|
|
} > android/key.properties
|
|
|
|
- name: Build Android release APK
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
rm -rf build dist .dart_tool android/.gradle
|
|
|
|
pkg_dir="$PWD/dist/android"
|
|
if [ -d "$pkg_dir" ]; then
|
|
echo "Cleaning old Android build artifacts: $pkg_dir"
|
|
rm -rf "$pkg_dir"
|
|
fi
|
|
|
|
echo "Building Flutter Android release APK..."
|
|
flutter build apk -v --release
|
|
|
|
mkdir -p "$pkg_dir"
|
|
apk_path="$(find "$PWD/build/app/outputs" -type f -name '*release*.apk' | head -n 1)"
|
|
if [ -z "$apk_path" ]; then
|
|
echo "Release APK not found under build/app/outputs"
|
|
exit 1
|
|
fi
|
|
|
|
cp "$apk_path" "$pkg_dir/gongyun-app-release.apk"
|
|
ls -alh "$pkg_dir/gongyun-app-release.apk"
|
|
|
|
- name: Rename Android APK
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
apk="dist/android/gongyun-app-release.apk"
|
|
if [ ! -f "$apk" ]; then
|
|
echo "Release APK was not found at $apk."
|
|
exit 1
|
|
fi
|
|
|
|
cp "$apk" gongyun-app-release.apk
|
|
ls -alh gongyun-app-release.apk
|
|
|
|
- name: Upload Android APK artifact
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: gongyun-app-release.apk
|
|
path: gongyun-app-release.apk
|
|
|
|
- name: Publish Gitea release
|
|
if: startsWith(github.ref, 'refs/tags/')
|
|
shell: bash
|
|
env:
|
|
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
|
GITEA_API_URL: https://git.saont.net/api/v1
|
|
GITEA_OWNER: gongyun
|
|
GITEA_REPO: app
|
|
TAG_NAME: ${{ github.ref_name }}
|
|
TARGET_COMMITISH: ${{ github.sha }}
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
if [ -z "${GITEA_TOKEN:-}" ]; then
|
|
echo "GITEA_TOKEN is required to publish release assets."
|
|
exit 1
|
|
fi
|
|
|
|
releases_url="$GITEA_API_URL/repos/$GITEA_OWNER/$GITEA_REPO/releases"
|
|
release_by_tag_url="$releases_url/tags/$TAG_NAME"
|
|
|
|
status="$(curl -sS -o release.json -w "%{http_code}" \
|
|
-H "Authorization: token $GITEA_TOKEN" \
|
|
"$release_by_tag_url")"
|
|
|
|
if [ "$status" = "404" ]; then
|
|
release_payload="$(python3 - <<'PY'
|
|
import json
|
|
import os
|
|
|
|
tag = os.environ["TAG_NAME"]
|
|
print(json.dumps({
|
|
"tag_name": tag,
|
|
"target_commitish": os.environ.get("TARGET_COMMITISH", ""),
|
|
"name": tag,
|
|
"body": f"Automated release for {tag}.",
|
|
"draft": False,
|
|
"prerelease": False,
|
|
}))
|
|
PY
|
|
)"
|
|
|
|
status="$(curl -sS -o release.json -w "%{http_code}" \
|
|
-X POST \
|
|
-H "Authorization: token $GITEA_TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d "$release_payload" \
|
|
"$releases_url")"
|
|
fi
|
|
|
|
if [ "$status" != "200" ] && [ "$status" != "201" ]; then
|
|
echo "Failed to create or load release. HTTP status: $status"
|
|
cat release.json
|
|
exit 1
|
|
fi
|
|
|
|
release_id="$(python3 - <<'PY'
|
|
import json
|
|
|
|
with open("release.json", encoding="utf-8") as f:
|
|
print(json.load(f)["id"])
|
|
PY
|
|
)"
|
|
|
|
assets_url="$releases_url/$release_id/assets"
|
|
|
|
curl -sS -f \
|
|
-H "Authorization: token $GITEA_TOKEN" \
|
|
"$assets_url" \
|
|
-o assets.json
|
|
|
|
python3 - <<'PY' > asset-ids-to-delete.txt
|
|
import json
|
|
|
|
names = {"gongyun-app-release.apk"}
|
|
with open("assets.json", encoding="utf-8") as f:
|
|
for asset in json.load(f):
|
|
if asset.get("name") in names:
|
|
print(asset["id"])
|
|
PY
|
|
|
|
while IFS= read -r asset_id; do
|
|
if [ -n "$asset_id" ]; then
|
|
curl -sS -f \
|
|
-X DELETE \
|
|
-H "Authorization: token $GITEA_TOKEN" \
|
|
"$assets_url/$asset_id"
|
|
fi
|
|
done < asset-ids-to-delete.txt
|
|
|
|
curl -sS -f \
|
|
-X POST \
|
|
-H "Authorization: token $GITEA_TOKEN" \
|
|
-F "attachment=@gongyun-app-release.apk" \
|
|
"$assets_url?name=gongyun-app-release.apk"
|
|
|
|
- name: Post-build disk cleanup
|
|
if: always()
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
rm -rf build dist .dart_tool android/.gradle android/app-release.jks android/key.properties || true
|
|
if command -v docker >/dev/null 2>&1; then
|
|
docker system prune -af --volumes || true
|
|
docker builder prune -af || true
|
|
fi
|
|
df -h
|