mirror of
git://f0xx.org/ac/ac-scripts
synced 2026-07-29 03:37:48 +03:00
feat(scripts): docker CI image, runner submodule seed, OTA browser apk
Signed-off-by: Anton Afanasyeu <a.afanasieff@gmail.com>
This commit is contained in:
42
Dockerfile.androidcast-ci
Normal file
42
Dockerfile.androidcast-ci
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
# Android Cast CI image — Gradle + NDK + native codec build deps.
|
||||||
|
# Build: docker build -f ac-scripts/Dockerfile.androidcast-ci -t androidcast-ci:latest ac-scripts
|
||||||
|
FROM ubuntu:22.04
|
||||||
|
|
||||||
|
ARG ANDROIDCAST_CI_VERSION=00.01.00.1000
|
||||||
|
ENV DEBIAN_FRONTEND=noninteractive \
|
||||||
|
ANDROID_HOME=/opt/android-sdk \
|
||||||
|
ANDROID_SDK_ROOT=/opt/android-sdk \
|
||||||
|
JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64 \
|
||||||
|
GRADLE_USER_HOME=/root/.gradle \
|
||||||
|
ANDROIDCAST_CI_VERSION=${ANDROIDCAST_CI_VERSION}
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
openjdk-21-jdk-headless \
|
||||||
|
git bash curl unzip wget ca-certificates \
|
||||||
|
autoconf automake libtool pkg-config make g++ python3 \
|
||||||
|
ccache \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
RUN mkdir -p "${ANDROID_HOME}/cmdline-tools" \
|
||||||
|
&& curl -fsSL https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip -o /tmp/cmdline-tools.zip \
|
||||||
|
&& unzip -q /tmp/cmdline-tools.zip -d "${ANDROID_HOME}/cmdline-tools" \
|
||||||
|
&& mv "${ANDROID_HOME}/cmdline-tools/cmdline-tools" "${ANDROID_HOME}/cmdline-tools/latest" \
|
||||||
|
&& rm /tmp/cmdline-tools.zip
|
||||||
|
|
||||||
|
ENV PATH="${ANDROID_HOME}/cmdline-tools/latest/bin:${ANDROID_HOME}/platform-tools:${PATH}"
|
||||||
|
|
||||||
|
RUN yes | sdkmanager --licenses >/dev/null \
|
||||||
|
&& sdkmanager --install \
|
||||||
|
"platform-tools" \
|
||||||
|
"platforms;android-34" \
|
||||||
|
"build-tools;34.0.0" \
|
||||||
|
"ndk;29.0.14206865" \
|
||||||
|
"cmake;3.22.1"
|
||||||
|
|
||||||
|
ENV ANDROID_NDK_HOME="${ANDROID_HOME}/ndk/29.0.14206865" \
|
||||||
|
ANDROID_NDK_ROOT="${ANDROID_HOME}/ndk/29.0.14206865"
|
||||||
|
|
||||||
|
WORKDIR /workspace
|
||||||
|
LABEL org.androidcast.ci.version="${ANDROIDCAST_CI_VERSION}"
|
||||||
|
|
||||||
|
CMD ["./scripts/ci-build-and-publish-ota.sh"]
|
||||||
20
build.config.yml
Normal file
20
build.config.yml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# Canonical CI pipeline for ac-ms-build / docker-build-runner.sh (cluster lab).
|
||||||
|
# Referenced from compose-lab-backend.php → build.pipeline_config
|
||||||
|
version: 2.1
|
||||||
|
parameters:
|
||||||
|
git_ref: next
|
||||||
|
gradle_task: assembleDebug
|
||||||
|
run_tests: true
|
||||||
|
run_native: true
|
||||||
|
run_apk: true
|
||||||
|
auto_ota: true
|
||||||
|
ota_channel: staging
|
||||||
|
jobs:
|
||||||
|
android-build:
|
||||||
|
docker:
|
||||||
|
- image: androidcast-ci:00.01.00.1000
|
||||||
|
steps:
|
||||||
|
- checkout
|
||||||
|
- run:
|
||||||
|
name: Gradle pipeline
|
||||||
|
command: ./scripts/ci-build-and-publish-ota.sh
|
||||||
@@ -13,6 +13,7 @@
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
SCRIPTS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
IMAGE="${ANDROIDCAST_CI_IMAGE:-androidcast-ci:latest}"
|
IMAGE="${ANDROIDCAST_CI_IMAGE:-androidcast-ci:latest}"
|
||||||
CI_VERSION="${ANDROIDCAST_CI_VERSION:-00.01.00.1000}"
|
CI_VERSION="${ANDROIDCAST_CI_VERSION:-00.01.00.1000}"
|
||||||
BUILD_ID="${BUILD_ID:-local}"
|
BUILD_ID="${BUILD_ID:-local}"
|
||||||
@@ -22,6 +23,9 @@ OUT_DIR="${BUILD_OUT_DIR:-${WORK_DIR}/out/builds/${BUILD_ID}}"
|
|||||||
LOG_STDOUT_ONLY="${BUILD_LOG_STDOUT_ONLY:-0}"
|
LOG_STDOUT_ONLY="${BUILD_LOG_STDOUT_ONLY:-0}"
|
||||||
ISOLATE_SOURCE="${BUILD_ISOLATE_SOURCE:-1}"
|
ISOLATE_SOURCE="${BUILD_ISOLATE_SOURCE:-1}"
|
||||||
CLONE_DEPTH="${BUILD_GIT_DEPTH:-1}"
|
CLONE_DEPTH="${BUILD_GIT_DEPTH:-1}"
|
||||||
|
MOBILE_SUBDIR="${BUILD_MOBILE_SUBDIR:-ac-mobile-android}"
|
||||||
|
HOST_SCRIPTS_DIR="${BUILD_SCRIPTS_DIR:-${SCRIPTS_DIR}}"
|
||||||
|
DOCKERFILE_PATH="${BUILD_DOCKERFILE:-}"
|
||||||
SOURCE_DIR="${OUT_DIR}/src"
|
SOURCE_DIR="${OUT_DIR}/src"
|
||||||
DOCKER_WORKSPACE="${WORK_DIR}"
|
DOCKER_WORKSPACE="${WORK_DIR}"
|
||||||
CONTAINER_NAME="androidcast-bld-${BUILD_ID}"
|
CONTAINER_NAME="androidcast-bld-${BUILD_ID}"
|
||||||
@@ -93,6 +97,93 @@ resolve_git_remote() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
host_mobile_tree() {
|
||||||
|
if [[ -d "${WORK_DIR}/${MOBILE_SUBDIR}/app" ]]; then
|
||||||
|
echo "${WORK_DIR}/${MOBILE_SUBDIR}"
|
||||||
|
elif [[ -d "${WORK_DIR}/app" ]]; then
|
||||||
|
echo "${WORK_DIR}"
|
||||||
|
else
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
isolated_mobile_tree() {
|
||||||
|
local base="$1"
|
||||||
|
if [[ -d "${base}/${MOBILE_SUBDIR}/app" ]]; then
|
||||||
|
echo "${base}/${MOBILE_SUBDIR}"
|
||||||
|
elif [[ -d "${base}/app" ]]; then
|
||||||
|
echo "${base}"
|
||||||
|
else
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
third_party_incomplete() {
|
||||||
|
local tree="$1"
|
||||||
|
local p="$2"
|
||||||
|
local dir="${tree}/third-party/${p}"
|
||||||
|
if [[ ! -d "$dir" ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
case "$p" in
|
||||||
|
wireguard-android)
|
||||||
|
[[ ! -d "${dir}/tunnel/src/main/java" ]]
|
||||||
|
;;
|
||||||
|
libvpx)
|
||||||
|
[[ ! -d "${dir}/vp8" && ! -f "${dir}/configure" ]]
|
||||||
|
;;
|
||||||
|
opus|speex)
|
||||||
|
[[ ! -f "${dir}/configure" && ! -f "${dir}/CMakeLists.txt" && ! -d "${dir}/include" ]]
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
[[ -z "$(ls -A "${dir}" 2>/dev/null)" ]]
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
seed_third_party_from_host() {
|
||||||
|
local host_tree="$1"
|
||||||
|
local iso_tree="$2"
|
||||||
|
if [[ -z "$host_tree" || -z "$iso_tree" || ! -d "$host_tree/third-party" ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
mkdir -p "${iso_tree}/third-party"
|
||||||
|
local p
|
||||||
|
for p in libvpx opus speex wireguard-android; do
|
||||||
|
if [[ -d "${host_tree}/third-party/${p}" ]] && third_party_incomplete "$iso_tree" "$p"; then
|
||||||
|
log "[runner] seed third-party/${p} from host checkout"
|
||||||
|
rm -rf "${iso_tree}/third-party/${p}"
|
||||||
|
cp -r "${host_tree}/third-party/${p}" "${iso_tree}/third-party/"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
stage_ci_scripts() {
|
||||||
|
local iso_tree="$1"
|
||||||
|
if [[ -z "$iso_tree" || ! -d "$HOST_SCRIPTS_DIR" ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
mkdir -p "${iso_tree}/scripts"
|
||||||
|
local f
|
||||||
|
for f in ci-build-and-publish-ota.sh init-third-party-submodules.sh build-native-codecs.sh android-ndk.sh generate-ota-v0.sh native-build-cache.sh; do
|
||||||
|
if [[ -f "${HOST_SCRIPTS_DIR}/${f}" ]]; then
|
||||||
|
cp -f "${HOST_SCRIPTS_DIR}/${f}" "${iso_tree}/scripts/${f}"
|
||||||
|
chmod +x "${iso_tree}/scripts/${f}" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
init_mobile_submodule_only() {
|
||||||
|
local base="$1"
|
||||||
|
if [[ ! -d "${base}/.git" ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if git -C "$base" config -f .gitmodules --get "submodule.${MOBILE_SUBDIR}.path" >/dev/null 2>&1; then
|
||||||
|
log "[runner] isolate: init workspace submodule ${MOBILE_SUBDIR} (no third-party recurse)"
|
||||||
|
run_step git-submodule-mobile git -c safe.directory="${base}" -C "${base}" submodule update --init "${MOBILE_SUBDIR}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
prepare_isolated_source() {
|
prepare_isolated_source() {
|
||||||
local ref="${GIT_REF:-}"
|
local ref="${GIT_REF:-}"
|
||||||
local remote sha
|
local remote sha
|
||||||
@@ -105,14 +196,13 @@ prepare_isolated_source() {
|
|||||||
rm -rf "${SOURCE_DIR}"
|
rm -rf "${SOURCE_DIR}"
|
||||||
mkdir -p "${SOURCE_DIR}"
|
mkdir -p "${SOURCE_DIR}"
|
||||||
|
|
||||||
log "[runner] isolate: shallow clone depth=${CLONE_DEPTH} ref=${ref} remote=${remote} -> ${SOURCE_DIR}"
|
log "[runner] isolate: shallow clone depth=${CLONE_DEPTH} ref=${ref} remote=*** -> ${SOURCE_DIR}"
|
||||||
if git clone --depth "${CLONE_DEPTH}" --recurse-submodules --shallow-submodules \
|
if git clone --depth "${CLONE_DEPTH}" \
|
||||||
--single-branch --branch "${ref}" "${remote}" "${SOURCE_DIR}"; then
|
--single-branch --branch "${ref}" "${remote}" "${SOURCE_DIR}"; then
|
||||||
:
|
:
|
||||||
else
|
else
|
||||||
log "[runner] isolate: branch clone failed; clone default branch then checkout ${ref}"
|
log "[runner] isolate: branch clone failed; clone default branch then checkout ${ref}"
|
||||||
run_step git-clone git clone --depth "${CLONE_DEPTH}" --recurse-submodules --shallow-submodules \
|
run_step git-clone git clone --depth "${CLONE_DEPTH}" "${remote}" "${SOURCE_DIR}"
|
||||||
"${remote}" "${SOURCE_DIR}"
|
|
||||||
run_step git-fetch git -c safe.directory="${SOURCE_DIR}" -C "${SOURCE_DIR}" fetch --depth "${CLONE_DEPTH}" origin "${ref}"
|
run_step git-fetch git -c safe.directory="${SOURCE_DIR}" -C "${SOURCE_DIR}" fetch --depth "${CLONE_DEPTH}" origin "${ref}"
|
||||||
run_step git-checkout git -c safe.directory="${SOURCE_DIR}" -C "${SOURCE_DIR}" checkout "${ref}"
|
run_step git-checkout git -c safe.directory="${SOURCE_DIR}" -C "${SOURCE_DIR}" checkout "${ref}"
|
||||||
fi
|
fi
|
||||||
@@ -122,8 +212,20 @@ prepare_isolated_source() {
|
|||||||
run_step git-pin git -c safe.directory="${SOURCE_DIR}" -C "${SOURCE_DIR}" checkout "${GIT_SHA}"
|
run_step git-pin git -c safe.directory="${SOURCE_DIR}" -C "${SOURCE_DIR}" checkout "${GIT_SHA}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
run_step git-rev-parse git -c safe.directory="${SOURCE_DIR}" -C "${SOURCE_DIR}" rev-parse HEAD
|
init_mobile_submodule_only "${SOURCE_DIR}"
|
||||||
|
|
||||||
|
local host_tree iso_tree
|
||||||
|
host_tree="$(host_mobile_tree)"
|
||||||
|
iso_tree="$(isolated_mobile_tree "${SOURCE_DIR}")"
|
||||||
|
if [[ -n "$iso_tree" ]]; then
|
||||||
|
seed_third_party_from_host "$host_tree" "$iso_tree"
|
||||||
|
stage_ci_scripts "$iso_tree"
|
||||||
|
DOCKER_WORKSPACE="${iso_tree}"
|
||||||
|
else
|
||||||
DOCKER_WORKSPACE="${SOURCE_DIR}"
|
DOCKER_WORKSPACE="${SOURCE_DIR}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
run_step git-rev-parse git -c safe.directory="${SOURCE_DIR}" -C "${SOURCE_DIR}" rev-parse HEAD
|
||||||
}
|
}
|
||||||
|
|
||||||
sync_shared_checkout() {
|
sync_shared_checkout() {
|
||||||
@@ -212,11 +314,31 @@ log "[runner] docker workspace=${DOCKER_WORKSPACE}"
|
|||||||
if should_skip_docker_build; then
|
if should_skip_docker_build; then
|
||||||
log "[runner] resume: skipped docker-build (image ${IMAGE} exists)"
|
log "[runner] resume: skipped docker-build (image ${IMAGE} exists)"
|
||||||
else
|
else
|
||||||
|
dockerfile="${DOCKERFILE_PATH}"
|
||||||
|
if [[ -z "$dockerfile" || ! -f "$dockerfile" ]]; then
|
||||||
|
for candidate in \
|
||||||
|
"${HOST_SCRIPTS_DIR}/Dockerfile.androidcast-ci" \
|
||||||
|
"${DOCKER_WORKSPACE}/Dockerfile" \
|
||||||
|
"${ROOT}/Dockerfile"; do
|
||||||
|
if [[ -f "$candidate" ]]; then
|
||||||
|
dockerfile="$candidate"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
if [[ -z "$dockerfile" || ! -f "$dockerfile" ]]; then
|
||||||
|
log "[runner] ERROR: CI Dockerfile not found (set BUILD_DOCKERFILE or add Dockerfile.androidcast-ci under ac-scripts)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
docker_ctx="${DOCKER_WORKSPACE}"
|
||||||
|
if [[ "$(basename "$dockerfile")" == "Dockerfile.androidcast-ci" ]]; then
|
||||||
|
docker_ctx="$(dirname "$dockerfile")"
|
||||||
|
fi
|
||||||
run_step docker-build docker build \
|
run_step docker-build docker build \
|
||||||
--build-arg ANDROIDCAST_CI_VERSION="${CI_VERSION}" \
|
--build-arg ANDROIDCAST_CI_VERSION="${CI_VERSION}" \
|
||||||
-t "$IMAGE" \
|
-t "$IMAGE" \
|
||||||
-f "${ROOT}/Dockerfile" \
|
-f "${dockerfile}" \
|
||||||
"${ROOT}"
|
"${docker_ctx}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "$SSH_DEBUG" == "1" ]]; then
|
if [[ "$SSH_DEBUG" == "1" ]]; then
|
||||||
@@ -225,6 +347,7 @@ if [[ "$SSH_DEBUG" == "1" ]]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
run_step docker-run docker run --rm --name "${CONTAINER_NAME}" \
|
run_step docker-run docker run --rm --name "${CONTAINER_NAME}" \
|
||||||
|
--network host \
|
||||||
-v "${DOCKER_WORKSPACE}:/workspace" \
|
-v "${DOCKER_WORKSPACE}:/workspace" \
|
||||||
-v "${ROOT}/out:/workspace/out" \
|
-v "${ROOT}/out:/workspace/out" \
|
||||||
-w /workspace \
|
-w /workspace \
|
||||||
|
|||||||
@@ -76,7 +76,10 @@ rel_dir="${rel_root}/00/${maj_p}/${ver_p}"
|
|||||||
mkdir -p "${rel_dir}" "${rel_root}/channel"
|
mkdir -p "${rel_dir}" "${rel_root}/channel"
|
||||||
|
|
||||||
pkg_name="android_cast_${ver_p}.${bld_p}.otapkg"
|
pkg_name="android_cast_${ver_p}.${bld_p}.otapkg"
|
||||||
|
browser_pkg_name="android_cast_${ver_p}.${bld_p}.apk"
|
||||||
|
browser_apk_url="${artifact_base}.apk"
|
||||||
cp -f "$apk" "${rel_dir}/${pkg_name}"
|
cp -f "$apk" "${rel_dir}/${pkg_name}"
|
||||||
|
cp -f "$apk" "${rel_dir}/${browser_pkg_name}"
|
||||||
|
|
||||||
sign_name="android_cast_${ver_p}.${bld_p}_sign.json"
|
sign_name="android_cast_${ver_p}.${bld_p}_sign.json"
|
||||||
manifest_name="android_cast_${ver_p}.${bld_p}_manifest.json"
|
manifest_name="android_cast_${ver_p}.${bld_p}_manifest.json"
|
||||||
@@ -123,6 +126,7 @@ cat >"${rel_dir}/${manifest_name}" <<EOF
|
|||||||
"build": ${build},
|
"build": ${build},
|
||||||
"versionName": "${version_name:-${major}.${minor}.${build}}",
|
"versionName": "${version_name:-${major}.${minor}.${build}}",
|
||||||
"apkUrl": "${apk_url}",
|
"apkUrl": "${apk_url}",
|
||||||
|
"browserApkUrl": "${browser_apk_url}",
|
||||||
"signUrl": "${sign_url}",
|
"signUrl": "${sign_url}",
|
||||||
"sizeBytes": ${apk_size},
|
"sizeBytes": ${apk_size},
|
||||||
"bundleUrl": "${bundle_url}",
|
"bundleUrl": "${bundle_url}",
|
||||||
|
|||||||
Reference in New Issue
Block a user