Make beta release artifacts reproducible on Linux and Android
Constraint: SRS-118 and SRS-119 require a Linux release package and an Android release AAB, and the current workspace also needs the sibling oboe-rs checkout for Cargo manifest loading. Rejected: Keep release packaging as ad-hoc local knowledge | CI and contributors would still miss the required artifacts and hit the missing oboe-rs prerequisite. Confidence: medium Scope-risk: moderate Directive: If the oboe-rs fork path changes or is vendored, update the helper scripts and workflow checkout steps together. Tested: bash -n tools/build-linux-deb.sh tools/build-android-aab.sh; python3 YAML parse for .github/workflows/ci.yml, .github/workflows/bench-advisory.yml, .github/workflows/bench-baseline-update.yml; git diff --check Not-tested: End-to-end flutter build linux --release; end-to-end flutter build appbundle --release; GitHub Actions runtime execution
This commit is contained in:
@@ -25,6 +25,8 @@ jobs:
|
|||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
- name: Checkout oboe-rs fork
|
||||||
|
run: git clone --depth 1 https://github.com/edisonjwa/oboe-rs.git ../oboe-rs
|
||||||
- name: System deps (cpal / Opus)
|
- name: System deps (cpal / Opus)
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
- name: Checkout oboe-rs fork
|
||||||
|
run: git clone --depth 1 https://github.com/edisonjwa/oboe-rs.git ../oboe-rs
|
||||||
- name: System deps (cpal / Opus)
|
- name: System deps (cpal / Opus)
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
- name: Checkout oboe-rs fork
|
||||||
|
run: git clone --depth 1 https://github.com/edisonjwa/oboe-rs.git ../oboe-rs
|
||||||
- name: System deps (cpal / Opus / SQLite)
|
- name: System deps (cpal / Opus / SQLite)
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
@@ -38,6 +40,8 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
- name: Checkout oboe-rs fork
|
||||||
|
run: git clone --depth 1 https://github.com/edisonjwa/oboe-rs.git ../oboe-rs
|
||||||
- uses: EmbarkStudios/cargo-deny-action@v2
|
- uses: EmbarkStudios/cargo-deny-action@v2
|
||||||
with:
|
with:
|
||||||
command: check
|
command: check
|
||||||
@@ -51,6 +55,8 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
- name: Checkout oboe-rs fork
|
||||||
|
run: git clone --depth 1 https://github.com/edisonjwa/oboe-rs.git ../oboe-rs
|
||||||
- uses: dtolnay/rust-toolchain@stable
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
- uses: Swatinem/rust-cache@v2
|
- uses: Swatinem/rust-cache@v2
|
||||||
- name: Install cargo-about
|
- name: Install cargo-about
|
||||||
@@ -113,12 +119,71 @@ jobs:
|
|||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
- name: Checkout oboe-rs fork
|
||||||
|
run: git clone --depth 1 https://github.com/edisonjwa/oboe-rs.git ../oboe-rs
|
||||||
- uses: subosito/flutter-action@v2
|
- uses: subosito/flutter-action@v2
|
||||||
with:
|
with:
|
||||||
channel: stable
|
channel: stable
|
||||||
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
|
- uses: Swatinem/rust-cache@v2
|
||||||
- name: flutter pub get
|
- name: flutter pub get
|
||||||
working-directory: apps/chanora_flutter
|
working-directory: apps/chanora_flutter
|
||||||
run: flutter pub get
|
run: flutter pub get
|
||||||
- name: flutter build ios --no-codesign
|
- name: flutter build ios --no-codesign
|
||||||
working-directory: apps/chanora_flutter
|
working-directory: apps/chanora_flutter
|
||||||
run: flutter build ios --release --no-codesign
|
run: flutter build ios --release --no-codesign
|
||||||
|
|
||||||
|
flutter-linux-release-package:
|
||||||
|
name: flutter Linux release package (.deb)
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Checkout oboe-rs fork
|
||||||
|
run: git clone --depth 1 https://github.com/edisonjwa/oboe-rs.git ../oboe-rs
|
||||||
|
- name: System deps (Flutter Linux + audio + packaging)
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y \
|
||||||
|
clang cmake ninja-build pkg-config libgtk-3-dev liblzma-dev \
|
||||||
|
libasound2-dev libpulse-dev libopus-dev libsdl2-dev
|
||||||
|
- uses: subosito/flutter-action@v2
|
||||||
|
with:
|
||||||
|
channel: stable
|
||||||
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
|
- uses: Swatinem/rust-cache@v2
|
||||||
|
- name: Build Linux .deb package
|
||||||
|
run: ./tools/build-linux-deb.sh
|
||||||
|
- name: Upload Linux package artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: chanora-linux-deb
|
||||||
|
path: dist/linux/*.deb
|
||||||
|
|
||||||
|
flutter-android-release-aab:
|
||||||
|
name: flutter Android release AAB
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Checkout oboe-rs fork
|
||||||
|
run: git clone --depth 1 https://github.com/edisonjwa/oboe-rs.git ../oboe-rs
|
||||||
|
- uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
distribution: temurin
|
||||||
|
java-version: '17'
|
||||||
|
- uses: android-actions/setup-android@v3
|
||||||
|
- uses: subosito/flutter-action@v2
|
||||||
|
with:
|
||||||
|
channel: stable
|
||||||
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
|
with:
|
||||||
|
targets: aarch64-linux-android,x86_64-linux-android
|
||||||
|
- uses: Swatinem/rust-cache@v2
|
||||||
|
- name: Install cargo-ndk
|
||||||
|
run: cargo install --locked cargo-ndk
|
||||||
|
- name: Build Android release AAB
|
||||||
|
run: ./tools/build-android-aab.sh
|
||||||
|
- name: Upload Android bundle artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: chanora-android-aab
|
||||||
|
path: dist/android/*.aab
|
||||||
|
|||||||
Executable
+116
@@ -0,0 +1,116 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||||
|
APP_DIR="$REPO_ROOT/apps/chanora_flutter"
|
||||||
|
PUBSPEC="$APP_DIR/pubspec.yaml"
|
||||||
|
OBOE_DIR="$(cd "$REPO_ROOT/.." && pwd)/oboe-rs"
|
||||||
|
DIST_DIR="$REPO_ROOT/dist/android"
|
||||||
|
TMP_DIR=""
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
if [[ -n "$TMP_DIR" && -d "$TMP_DIR" ]]; then
|
||||||
|
rm -rf "$TMP_DIR"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
require_cmd() {
|
||||||
|
local cmd=$1
|
||||||
|
if ! command -v "$cmd" >/dev/null 2>&1; then
|
||||||
|
echo "ERROR: required command '$cmd' is not on PATH." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
require_file() {
|
||||||
|
local path=$1
|
||||||
|
local label=$2
|
||||||
|
if [[ ! -f "$path" ]]; then
|
||||||
|
echo "ERROR: missing $label at $path" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_release_signing() {
|
||||||
|
if [[ -n "${CHANORA_RELEASE_STORE_FILE:-}" ]]; then
|
||||||
|
local missing=()
|
||||||
|
[[ -n "${CHANORA_RELEASE_STORE_PASSWORD:-}" ]] || missing+=("CHANORA_RELEASE_STORE_PASSWORD")
|
||||||
|
[[ -n "${CHANORA_RELEASE_KEY_ALIAS:-}" ]] || missing+=("CHANORA_RELEASE_KEY_ALIAS")
|
||||||
|
[[ -n "${CHANORA_RELEASE_KEY_PASSWORD:-}" ]] || missing+=("CHANORA_RELEASE_KEY_PASSWORD")
|
||||||
|
if (( ${#missing[@]} > 0 )); then
|
||||||
|
printf 'ERROR: release signing is partially configured; missing %s\n' "${missing[*]}" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
require_file "$CHANORA_RELEASE_STORE_FILE" "release keystore"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
require_cmd keytool
|
||||||
|
TMP_DIR="$(mktemp -d "${TMPDIR:-/tmp}/chanora-android-aab.XXXXXX")"
|
||||||
|
|
||||||
|
export CHANORA_RELEASE_STORE_FILE="$TMP_DIR/chanora-release.keystore"
|
||||||
|
export CHANORA_RELEASE_STORE_PASSWORD="${CHANORA_RELEASE_STORE_PASSWORD:-chanora-ci}"
|
||||||
|
export CHANORA_RELEASE_KEY_ALIAS="${CHANORA_RELEASE_KEY_ALIAS:-chanora-ci}"
|
||||||
|
export CHANORA_RELEASE_KEY_PASSWORD="${CHANORA_RELEASE_KEY_PASSWORD:-$CHANORA_RELEASE_STORE_PASSWORD}"
|
||||||
|
|
||||||
|
keytool -genkeypair \
|
||||||
|
-storetype PKCS12 \
|
||||||
|
-keystore "$CHANORA_RELEASE_STORE_FILE" \
|
||||||
|
-storepass "$CHANORA_RELEASE_STORE_PASSWORD" \
|
||||||
|
-keypass "$CHANORA_RELEASE_KEY_PASSWORD" \
|
||||||
|
-alias "$CHANORA_RELEASE_KEY_ALIAS" \
|
||||||
|
-keyalg RSA \
|
||||||
|
-keysize 2048 \
|
||||||
|
-validity 3650 \
|
||||||
|
-dname "CN=Chanora CI,O=Chanora,OU=Engineering,L=Seoul,S=Seoul,C=KR" \
|
||||||
|
-noprompt >/dev/null 2>&1
|
||||||
|
|
||||||
|
printf 'Generated ephemeral Android release keystore: %s\n' "$CHANORA_RELEASE_STORE_FILE"
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
require_cmd flutter
|
||||||
|
require_file "$PUBSPEC" "Flutter pubspec"
|
||||||
|
|
||||||
|
if [[ ! -f "$OBOE_DIR/Cargo.toml" ]]; then
|
||||||
|
cat >&2 <<EOF
|
||||||
|
ERROR: missing sibling oboe-rs checkout at:
|
||||||
|
$OBOE_DIR
|
||||||
|
|
||||||
|
This repository's Android-targeted Rust manifest currently depends on a local
|
||||||
|
oboe-rs fork. Clone it before running this script:
|
||||||
|
|
||||||
|
git clone https://github.com/edisonjwa/oboe-rs.git "$OBOE_DIR"
|
||||||
|
EOF
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
ensure_release_signing
|
||||||
|
|
||||||
|
local app_version
|
||||||
|
app_version="$(sed -n 's/^version:[[:space:]]*//p' "$PUBSPEC" | head -n1)"
|
||||||
|
if [[ -z "$app_version" ]]; then
|
||||||
|
echo "ERROR: could not read version from $PUBSPEC" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
(
|
||||||
|
cd "$APP_DIR"
|
||||||
|
flutter pub get
|
||||||
|
flutter build appbundle --release
|
||||||
|
)
|
||||||
|
|
||||||
|
local source_aab="$APP_DIR/build/app/outputs/bundle/release/app-release.aab"
|
||||||
|
require_file "$source_aab" "Android release app bundle"
|
||||||
|
|
||||||
|
mkdir -p "$DIST_DIR"
|
||||||
|
local output="$DIST_DIR/chanora-${app_version}-release.aab"
|
||||||
|
cp "$source_aab" "$output"
|
||||||
|
|
||||||
|
printf 'Built Android release bundle: %s\n' "$output"
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
Executable
+146
@@ -0,0 +1,146 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||||
|
APP_DIR="$REPO_ROOT/apps/chanora_flutter"
|
||||||
|
PUBSPEC="$APP_DIR/pubspec.yaml"
|
||||||
|
OBOE_DIR="$(cd "$REPO_ROOT/.." && pwd)/oboe-rs"
|
||||||
|
DIST_DIR="$REPO_ROOT/dist/linux"
|
||||||
|
STAGE_DIR="$(mktemp -d "${TMPDIR:-/tmp}/chanora-linux-deb.XXXXXX")"
|
||||||
|
PKG_ROOT="$STAGE_DIR/package"
|
||||||
|
INSTALL_ROOT="$PKG_ROOT/opt/chanora"
|
||||||
|
ICON_SRC="$APP_DIR/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png"
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
rm -rf "$STAGE_DIR"
|
||||||
|
}
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
require_cmd() {
|
||||||
|
local cmd=$1
|
||||||
|
if ! command -v "$cmd" >/dev/null 2>&1; then
|
||||||
|
echo "ERROR: required command '$cmd' is not on PATH." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
require_file() {
|
||||||
|
local path=$1
|
||||||
|
local label=$2
|
||||||
|
if [[ ! -f "$path" ]]; then
|
||||||
|
echo "ERROR: missing $label at $path" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve_arch() {
|
||||||
|
if command -v dpkg >/dev/null 2>&1; then
|
||||||
|
dpkg --print-architecture
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$(uname -m)" in
|
||||||
|
x86_64) echo "amd64" ;;
|
||||||
|
aarch64 | arm64) echo "arm64" ;;
|
||||||
|
*)
|
||||||
|
echo "ERROR: unsupported Linux architecture '$(uname -m)'" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
require_cmd flutter
|
||||||
|
require_cmd dpkg-deb
|
||||||
|
require_file "$PUBSPEC" "Flutter pubspec"
|
||||||
|
require_file "$ICON_SRC" "launcher icon"
|
||||||
|
|
||||||
|
if [[ ! -f "$OBOE_DIR/Cargo.toml" ]]; then
|
||||||
|
cat >&2 <<EOF
|
||||||
|
ERROR: missing sibling oboe-rs checkout at:
|
||||||
|
$OBOE_DIR
|
||||||
|
|
||||||
|
This repository's Android-targeted Rust manifest currently depends on a local
|
||||||
|
oboe-rs fork, so Cargo manifest loading fails until that sibling checkout
|
||||||
|
exists. Clone it before running this script:
|
||||||
|
|
||||||
|
git clone https://github.com/edisonjwa/oboe-rs.git "$OBOE_DIR"
|
||||||
|
EOF
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local app_version
|
||||||
|
app_version="$(sed -n 's/^version:[[:space:]]*//p' "$PUBSPEC" | head -n1)"
|
||||||
|
if [[ -z "$app_version" ]]; then
|
||||||
|
echo "ERROR: could not read version from $PUBSPEC" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local deb_version
|
||||||
|
deb_version="${app_version/-/~}"
|
||||||
|
|
||||||
|
local arch
|
||||||
|
arch="$(resolve_arch)"
|
||||||
|
|
||||||
|
(
|
||||||
|
cd "$APP_DIR"
|
||||||
|
flutter pub get
|
||||||
|
flutter build linux --release
|
||||||
|
)
|
||||||
|
|
||||||
|
local bundle_dir="$APP_DIR/build/linux/x64/release/bundle"
|
||||||
|
local app_binary="$bundle_dir/chanora_flutter"
|
||||||
|
require_file "$app_binary" "Linux release bundle binary"
|
||||||
|
|
||||||
|
mkdir -p \
|
||||||
|
"$PKG_ROOT/DEBIAN" \
|
||||||
|
"$INSTALL_ROOT" \
|
||||||
|
"$PKG_ROOT/usr/bin" \
|
||||||
|
"$PKG_ROOT/usr/share/applications" \
|
||||||
|
"$PKG_ROOT/usr/share/icons/hicolor/256x256/apps"
|
||||||
|
|
||||||
|
cp -R "$bundle_dir/." "$INSTALL_ROOT/"
|
||||||
|
|
||||||
|
cat >"$PKG_ROOT/DEBIAN/control" <<EOF
|
||||||
|
Package: chanora
|
||||||
|
Version: $deb_version
|
||||||
|
Section: net
|
||||||
|
Priority: optional
|
||||||
|
Architecture: $arch
|
||||||
|
Maintainer: Chanora Project Contributors
|
||||||
|
Depends: libasound2, libgtk-3-0, libpulse0, libsdl2-2.0-0, libstdc++6
|
||||||
|
Description: Chanora voice client for TeamSpeak-compatible servers
|
||||||
|
Chanora is a Flutter + Rust voice client for TeamSpeak-compatible servers.
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat >"$PKG_ROOT/usr/bin/chanora" <<'EOF'
|
||||||
|
#!/bin/sh
|
||||||
|
exec /opt/chanora/chanora_flutter "$@"
|
||||||
|
EOF
|
||||||
|
chmod 0755 "$PKG_ROOT/usr/bin/chanora"
|
||||||
|
|
||||||
|
cat >"$PKG_ROOT/usr/share/applications/chanora.desktop" <<'EOF'
|
||||||
|
[Desktop Entry]
|
||||||
|
Type=Application
|
||||||
|
Name=Chanora
|
||||||
|
GenericName=Voice Client
|
||||||
|
Comment=Voice client for TeamSpeak-compatible servers
|
||||||
|
Exec=/usr/bin/chanora
|
||||||
|
Icon=chanora
|
||||||
|
Terminal=false
|
||||||
|
Categories=Network;Chat;AudioVideo;
|
||||||
|
StartupNotify=true
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cp "$ICON_SRC" "$PKG_ROOT/usr/share/icons/hicolor/256x256/apps/chanora.png"
|
||||||
|
|
||||||
|
mkdir -p "$DIST_DIR"
|
||||||
|
local output="$DIST_DIR/chanora_${deb_version}_${arch}.deb"
|
||||||
|
dpkg-deb --build --root-owner-group "$PKG_ROOT" "$output" >/dev/null
|
||||||
|
|
||||||
|
printf 'Built Linux package: %s\n' "$output"
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
Reference in New Issue
Block a user