179 lines
4.4 KiB
Bash
179 lines
4.4 KiB
Bash
|
|
#!/usr/bin/env bash
|
||
|
|
set -euo pipefail
|
||
|
|
|
||
|
|
ROOT_DIR="$(git rev-parse --show-toplevel)"
|
||
|
|
APPS_DIR="$ROOT_DIR/apps"
|
||
|
|
OUTPUT_APK="$APPS_DIR/build/app/outputs/flutter-apk/app-release.apk"
|
||
|
|
RELEASES_DIR="$ROOT_DIR/deploy/static/releases"
|
||
|
|
MANIFEST_FILE="$RELEASES_DIR/manifest.json"
|
||
|
|
|
||
|
|
BACKEND_HOST=""
|
||
|
|
CHANNEL="release"
|
||
|
|
RELEASE_NOTES=""
|
||
|
|
|
||
|
|
while [[ $# -gt 0 ]]; do
|
||
|
|
case "$1" in
|
||
|
|
--backend-host)
|
||
|
|
BACKEND_HOST="$2"
|
||
|
|
shift 2
|
||
|
|
;;
|
||
|
|
--channel)
|
||
|
|
CHANNEL="$2"
|
||
|
|
shift 2
|
||
|
|
;;
|
||
|
|
--release-notes)
|
||
|
|
RELEASE_NOTES="$2"
|
||
|
|
shift 2
|
||
|
|
;;
|
||
|
|
*)
|
||
|
|
printf 'Unknown arg: %s\n' "$1" >&2
|
||
|
|
exit 1
|
||
|
|
;;
|
||
|
|
esac
|
||
|
|
done
|
||
|
|
|
||
|
|
if [[ -z "$BACKEND_HOST" ]]; then
|
||
|
|
printf 'Usage: %s --backend-host <ip-or-domain> [--channel release] [--release-notes "..."]\n' "$0" >&2
|
||
|
|
exit 1
|
||
|
|
fi
|
||
|
|
|
||
|
|
if [[ "$BACKEND_HOST" == *":"* ]]; then
|
||
|
|
printf 'Invalid backend host: do not include port (%s)\n' "$BACKEND_HOST" >&2
|
||
|
|
exit 1
|
||
|
|
fi
|
||
|
|
|
||
|
|
if ! [[ "$CHANNEL" =~ ^[a-z0-9_-]+$ ]]; then
|
||
|
|
printf 'Invalid channel: %s\n' "$CHANNEL" >&2
|
||
|
|
exit 1
|
||
|
|
fi
|
||
|
|
|
||
|
|
BACKEND_URL="http://$BACKEND_HOST"
|
||
|
|
|
||
|
|
readarray -t VERSION_INFO < <(
|
||
|
|
python - <<'PY'
|
||
|
|
import re
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
text = Path("apps/pubspec.yaml").read_text(encoding="utf-8")
|
||
|
|
match = re.search(r"^version:\s*([0-9]+\.[0-9]+\.[0-9]+)\+([0-9]+)\s*$", text, re.MULTILINE)
|
||
|
|
if not match:
|
||
|
|
raise SystemExit("pubspec.yaml version format invalid")
|
||
|
|
print(match.group(1))
|
||
|
|
print(match.group(2))
|
||
|
|
PY
|
||
|
|
)
|
||
|
|
|
||
|
|
VERSION_NAME="${VERSION_INFO[0]}"
|
||
|
|
CURRENT_VERSION_CODE="${VERSION_INFO[1]}"
|
||
|
|
NEXT_VERSION_CODE="$((CURRENT_VERSION_CODE + 1))"
|
||
|
|
FILE_NAME="social-app-android-v${VERSION_NAME}+${NEXT_VERSION_CODE}-${CHANNEL}.apk"
|
||
|
|
TARGET_APK="$RELEASES_DIR/$FILE_NAME"
|
||
|
|
|
||
|
|
mkdir -p "$RELEASES_DIR"
|
||
|
|
|
||
|
|
pushd "$APPS_DIR" >/dev/null
|
||
|
|
flutter build apk --release \
|
||
|
|
--build-name="$VERSION_NAME" \
|
||
|
|
--build-number="$NEXT_VERSION_CODE" \
|
||
|
|
--dart-define="BACKEND_URL=$BACKEND_URL" \
|
||
|
|
--target-platform=android-arm64 \
|
||
|
|
--split-per-abi \
|
||
|
|
--target "lib/main.dart"
|
||
|
|
popd >/dev/null
|
||
|
|
|
||
|
|
SOURCE_APK="$APPS_DIR/build/app/outputs/flutter-apk/app-arm64-v8a-release.apk"
|
||
|
|
if [[ ! -f "$SOURCE_APK" ]]; then
|
||
|
|
SOURCE_APK="$OUTPUT_APK"
|
||
|
|
fi
|
||
|
|
|
||
|
|
cp "$SOURCE_APK" "$TARGET_APK"
|
||
|
|
|
||
|
|
FILE_SIZE="$(stat -c%s "$TARGET_APK")"
|
||
|
|
SHA256="$(sha256sum "$TARGET_APK" | cut -d' ' -f1)"
|
||
|
|
|
||
|
|
python - <<'PY' "$ROOT_DIR/apps/pubspec.yaml" "$VERSION_NAME" "$NEXT_VERSION_CODE"
|
||
|
|
import re
|
||
|
|
import sys
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
pubspec_path = Path(sys.argv[1])
|
||
|
|
version_name = sys.argv[2]
|
||
|
|
version_code = sys.argv[3]
|
||
|
|
|
||
|
|
content = pubspec_path.read_text(encoding="utf-8")
|
||
|
|
updated, count = re.subn(
|
||
|
|
r"^version:\s*[0-9]+\.[0-9]+\.[0-9]+\+[0-9]+\s*$",
|
||
|
|
f"version: {version_name}+{version_code}",
|
||
|
|
content,
|
||
|
|
count=1,
|
||
|
|
flags=re.MULTILINE,
|
||
|
|
)
|
||
|
|
if count != 1:
|
||
|
|
raise SystemExit("failed to update version in pubspec.yaml")
|
||
|
|
pubspec_path.write_text(updated, encoding="utf-8")
|
||
|
|
PY
|
||
|
|
|
||
|
|
RELEASE_NOTES="$RELEASE_NOTES" python - <<'PY' "$MANIFEST_FILE" "$FILE_NAME" "$VERSION_NAME" "$NEXT_VERSION_CODE" "$CHANNEL" "$FILE_SIZE" "$SHA256"
|
||
|
|
import json
|
||
|
|
import os
|
||
|
|
import sys
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
manifest_path = Path(sys.argv[1])
|
||
|
|
file_name = sys.argv[2]
|
||
|
|
version_name = sys.argv[3]
|
||
|
|
version_code = int(sys.argv[4])
|
||
|
|
channel = sys.argv[5]
|
||
|
|
file_size = int(sys.argv[6])
|
||
|
|
sha256 = sys.argv[7]
|
||
|
|
release_notes = os.environ.get("RELEASE_NOTES", "")
|
||
|
|
|
||
|
|
if manifest_path.is_file():
|
||
|
|
data = json.loads(manifest_path.read_text(encoding="utf-8"))
|
||
|
|
else:
|
||
|
|
data = {"releases": []}
|
||
|
|
|
||
|
|
releases = data.get("releases") or []
|
||
|
|
releases = [
|
||
|
|
item
|
||
|
|
for item in releases
|
||
|
|
if not (
|
||
|
|
item.get("platform") == "android"
|
||
|
|
and item.get("channel") == channel
|
||
|
|
and item.get("version_code") == version_code
|
||
|
|
)
|
||
|
|
]
|
||
|
|
releases.append(
|
||
|
|
{
|
||
|
|
"platform": "android",
|
||
|
|
"channel": channel,
|
||
|
|
"version_name": version_name,
|
||
|
|
"version_code": version_code,
|
||
|
|
"min_supported_version_code": version_code,
|
||
|
|
"file_name": file_name,
|
||
|
|
"release_notes": release_notes or None,
|
||
|
|
"file_size": file_size,
|
||
|
|
"sha256": sha256,
|
||
|
|
}
|
||
|
|
)
|
||
|
|
releases.sort(
|
||
|
|
key=lambda item: (
|
||
|
|
item.get("platform", ""),
|
||
|
|
item.get("channel", ""),
|
||
|
|
item.get("version_code", 0),
|
||
|
|
)
|
||
|
|
)
|
||
|
|
|
||
|
|
manifest_path.write_text(
|
||
|
|
json.dumps({"releases": releases}, indent=2, ensure_ascii=True) + "\n",
|
||
|
|
encoding="utf-8",
|
||
|
|
)
|
||
|
|
PY
|
||
|
|
|
||
|
|
printf 'Build completed\n'
|
||
|
|
printf 'Version: %s+%s\n' "$VERSION_NAME" "$NEXT_VERSION_CODE"
|
||
|
|
printf 'Previous buildNumber: %s\n' "$CURRENT_VERSION_CODE"
|
||
|
|
printf 'Backend URL: %s\n' "$BACKEND_URL"
|
||
|
|
printf 'Package: %s\n' "$TARGET_APK"
|
||
|
|
printf 'SHA256: %s\n' "$SHA256"
|