Implement CI workflow for Gitea. Include provision scripts for Gitea runners.
This commit is contained in:
Executable
+291
@@ -0,0 +1,291 @@
|
||||
#!/usr/bin/env bash
|
||||
# Provisions a macOS host (Apple Silicon, macOS 14+) as a Gitea Actions runner
|
||||
# for RustDesk desktop (.dmg) builds. Idempotent: safe to re-run.
|
||||
#
|
||||
# Versions are pinned to .gitea/workflows/build-macos.yml. Bump them there and
|
||||
# here together.
|
||||
#
|
||||
# Usage:
|
||||
# sudo ./provision.sh \
|
||||
# --gitea-url https://gitea.example.com \
|
||||
# --runner-token <token>
|
||||
#
|
||||
# Toolchains land in /opt/* (chowned to the runner user). Service is installed
|
||||
# as a LaunchDaemon running as that user.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# ---- pinned versions (mirror .gitea/workflows/build-macos.yml env block) ----
|
||||
RUST_VERSION="1.81.0" # MAC_RUST_VERSION upstream (cidre crate needs >=1.81)
|
||||
FLUTTER_VERSION="3.24.5" # used for `flutter build macos`
|
||||
FLUTTER_BRIDGE_VERSION="3.22.3" # used for `flutter pub get` + flutter_rust_bridge_codegen
|
||||
VCPKG_COMMIT="120deac3062162151622ca4860575a33844ba10b"
|
||||
NASM_VERSION="2.16.03" # 3.x has incompatible CLI; aom/dav1d need 2.x
|
||||
RUNNER_VERSION="0.2.11"
|
||||
|
||||
# ---- defaults ----
|
||||
RUNNER_NAME="$(hostname -s)-rustdesk"
|
||||
RUNNER_LABELS=""
|
||||
SERVICE_USER="gitea-runner"
|
||||
GITEA_URL=""
|
||||
RUNNER_TOKEN=""
|
||||
|
||||
# ---- arg parse ----
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--gitea-url) GITEA_URL="$2"; shift 2 ;;
|
||||
--runner-token) RUNNER_TOKEN="$2"; shift 2 ;;
|
||||
--runner-name) RUNNER_NAME="$2"; shift 2 ;;
|
||||
--runner-labels) RUNNER_LABELS="$2"; shift 2 ;;
|
||||
--service-user) SERVICE_USER="$2"; shift 2 ;;
|
||||
-h|--help)
|
||||
sed -n '2,15p' "$0"
|
||||
exit 0 ;;
|
||||
*) echo "Unknown arg: $1" >&2; exit 2 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
[[ "$EUID" -eq 0 ]] || { echo "Run as root (use sudo)." >&2; exit 1; }
|
||||
[[ -n "$GITEA_URL" && -n "$RUNNER_TOKEN" ]] \
|
||||
|| { echo "Missing --gitea-url or --runner-token" >&2; exit 2; }
|
||||
|
||||
# ---- arch + macOS version detection ----
|
||||
ARCH="$(uname -m)"
|
||||
case "$ARCH" in
|
||||
arm64) HOMEBREW_PREFIX="/opt/homebrew"; ARCH_LABEL="ARM64" ;;
|
||||
x86_64) HOMEBREW_PREFIX="/usr/local"; ARCH_LABEL="X64" ;;
|
||||
*) echo "Unsupported arch: $ARCH" >&2; exit 1 ;;
|
||||
esac
|
||||
|
||||
OS_MAJOR="$(sw_vers -productVersion | cut -d. -f1)"
|
||||
[[ "$OS_MAJOR" -ge 14 ]] || {
|
||||
echo "WARNING: tested only on macOS 14+. You're on $(sw_vers -productVersion)."
|
||||
sleep 3
|
||||
}
|
||||
DISTRO_LABEL="macos-${OS_MAJOR}"
|
||||
|
||||
if [[ -z "$RUNNER_LABELS" ]]; then
|
||||
RUNNER_LABELS="${DISTRO_LABEL},self-hosted,${ARCH_LABEL},macOS"
|
||||
fi
|
||||
|
||||
log() { printf '\n==> %s\n' "$*"; }
|
||||
|
||||
# ---- 1. Xcode Command Line Tools ----
|
||||
log "Verifying Xcode Command Line Tools"
|
||||
if ! /usr/bin/xcode-select -p >/dev/null 2>&1; then
|
||||
echo "Xcode Command Line Tools not installed. Run:" >&2
|
||||
echo " xcode-select --install" >&2
|
||||
echo "Then re-run this script." >&2
|
||||
exit 1
|
||||
fi
|
||||
echo " $(xcode-select -p)"
|
||||
|
||||
# ---- 2. Homebrew (machine-wide) ----
|
||||
# Homebrew refuses to install under root (its installer aborts with
|
||||
# "Don't run this as root!"). It must be installed manually by a regular
|
||||
# user before this script runs.
|
||||
log "Verifying Homebrew"
|
||||
if [[ ! -x "$HOMEBREW_PREFIX/bin/brew" ]]; then
|
||||
echo "Homebrew not installed at $HOMEBREW_PREFIX." >&2
|
||||
echo "Install it as your regular user (NOT root), then re-run this script:" >&2
|
||||
echo " /bin/bash -c \"\$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\"" >&2
|
||||
exit 1
|
||||
fi
|
||||
export PATH="$HOMEBREW_PREFIX/bin:$PATH"
|
||||
echo " $(brew --version | head -1)"
|
||||
|
||||
# brew install must also run as a non-root user. Determine which user invoked
|
||||
# sudo so we can drop privileges for brew commands below.
|
||||
BREW_USER="${SUDO_USER:-}"
|
||||
if [[ -z "$BREW_USER" || "$BREW_USER" == "root" ]]; then
|
||||
echo "Could not determine the non-root user that ran sudo (SUDO_USER unset)." >&2
|
||||
echo "Re-run with: sudo ./provision.sh ..." >&2
|
||||
exit 1
|
||||
fi
|
||||
brew_as_user() { sudo -u "$BREW_USER" -H "$HOMEBREW_PREFIX/bin/brew" "$@"; }
|
||||
|
||||
# ---- 3. brew packages ----
|
||||
log "Installing brew packages"
|
||||
brew_pkgs=(node cocoapods llvm create-dmg pkg-config cmake ninja yasm autoconf automake libtool wget)
|
||||
for p in "${brew_pkgs[@]}"; do
|
||||
if brew_as_user list --versions "$p" >/dev/null 2>&1; then
|
||||
echo " $p (already installed)"
|
||||
else
|
||||
brew_as_user install "$p"
|
||||
fi
|
||||
done
|
||||
|
||||
# ---- 4. NASM 2.16.x (NOT brew's nasm 3.x; aom/dav1d need 2.x) ----
|
||||
if ! /usr/local/bin/nasm --version 2>/dev/null | grep -q "version $NASM_VERSION"; then
|
||||
log "Installing NASM $NASM_VERSION"
|
||||
tmp="$(mktemp -d)"
|
||||
curl -fsSL -o "$tmp/nasm.zip" \
|
||||
"https://www.nasm.us/pub/nasm/releasebuilds/${NASM_VERSION}/macosx/nasm-${NASM_VERSION}-macosx.zip"
|
||||
unzip -q "$tmp/nasm.zip" -d "$tmp"
|
||||
install -m 0755 "$tmp/nasm-${NASM_VERSION}/nasm" /usr/local/bin/nasm
|
||||
rm -rf "$tmp"
|
||||
fi
|
||||
/usr/local/bin/nasm --version | head -1
|
||||
|
||||
# ---- 5. dedicated runner user ----
|
||||
if ! /usr/bin/id -u "$SERVICE_USER" >/dev/null 2>&1; then
|
||||
log "Creating user $SERVICE_USER"
|
||||
# Find an unused UID >= 600
|
||||
uid=600
|
||||
while dscl . -list /Users UniqueID | awk '{print $2}' | grep -qx "$uid"; do
|
||||
uid=$((uid + 1))
|
||||
done
|
||||
dscl . -create "/Users/$SERVICE_USER"
|
||||
dscl . -create "/Users/$SERVICE_USER" UserShell /bin/bash
|
||||
dscl . -create "/Users/$SERVICE_USER" RealName "Gitea Runner"
|
||||
dscl . -create "/Users/$SERVICE_USER" UniqueID "$uid"
|
||||
dscl . -create "/Users/$SERVICE_USER" PrimaryGroupID 20
|
||||
dscl . -create "/Users/$SERVICE_USER" NFSHomeDirectory "/Users/$SERVICE_USER"
|
||||
mkdir -p "/Users/$SERVICE_USER"
|
||||
chown "$SERVICE_USER:staff" "/Users/$SERVICE_USER"
|
||||
fi
|
||||
RUNNER_HOME="/Users/$SERVICE_USER"
|
||||
|
||||
# ---- 6. Rust (machine-wide) ----
|
||||
export RUSTUP_HOME=/opt/rustup
|
||||
export CARGO_HOME=/opt/cargo
|
||||
mkdir -p "$RUSTUP_HOME" "$CARGO_HOME"
|
||||
|
||||
if [[ ! -x "$CARGO_HOME/bin/rustup" ]]; then
|
||||
log "Installing rustup at $RUSTUP_HOME / $CARGO_HOME"
|
||||
curl -fsSL https://sh.rustup.rs | RUSTUP_HOME="$RUSTUP_HOME" CARGO_HOME="$CARGO_HOME" \
|
||||
sh -s -- -y --default-toolchain none --profile minimal --no-modify-path
|
||||
fi
|
||||
"$CARGO_HOME/bin/rustup" toolchain install "$RUST_VERSION" --profile minimal --component rustfmt
|
||||
"$CARGO_HOME/bin/rustup" target add --toolchain "$RUST_VERSION" aarch64-apple-darwin x86_64-apple-darwin
|
||||
"$CARGO_HOME/bin/rustup" default "$RUST_VERSION"
|
||||
|
||||
# ---- 7. Flutter (two SDKs: 3.24.5 for build, 3.22.3 for bridge gen) ----
|
||||
# Same rationale as Linux: bridge codegen 1.80.1 + freezed produces broken Dart
|
||||
# under newer Flutter. Run codegen under 3.22.3, build under 3.24.5.
|
||||
install_flutter() {
|
||||
local ver="$1" dir="$2"
|
||||
if [[ ! -x "$dir/bin/flutter" ]]; then
|
||||
log "Installing Flutter $ver -> $dir"
|
||||
local tmp; tmp="$(mktemp -d)"
|
||||
local parent; parent="$(dirname "$dir")"
|
||||
# Flutter URL pattern differs between archs: Apple Silicon has an
|
||||
# `_arm64_` infix, Intel has no arch infix at all.
|
||||
local flutter_url_base="https://storage.googleapis.com/flutter_infra_release/releases/stable/macos/flutter_macos"
|
||||
local flutter_url
|
||||
case "$ARCH" in
|
||||
arm64) flutter_url="${flutter_url_base}_arm64_${ver}-stable.zip" ;;
|
||||
x86_64) flutter_url="${flutter_url_base}_${ver}-stable.zip" ;;
|
||||
esac
|
||||
curl -fsSL -o "$tmp/flutter.zip" "$flutter_url"
|
||||
mkdir -p "$parent"
|
||||
unzip -q "$tmp/flutter.zip" -d "$tmp"
|
||||
mv "$tmp/flutter" "$dir"
|
||||
rm -rf "$tmp"
|
||||
fi
|
||||
"$dir/bin/flutter" config --no-analytics >/dev/null
|
||||
"$dir/bin/flutter" precache --macos >/dev/null
|
||||
}
|
||||
install_flutter "$FLUTTER_VERSION" /opt/flutter
|
||||
install_flutter "$FLUTTER_BRIDGE_VERSION" /opt/flutter-bridge
|
||||
|
||||
# ---- 8. vcpkg ----
|
||||
VCPKG_DIR=/opt/vcpkg
|
||||
if [[ ! -d "$VCPKG_DIR/.git" ]]; then
|
||||
log "Cloning vcpkg"
|
||||
git clone https://github.com/microsoft/vcpkg.git "$VCPKG_DIR"
|
||||
fi
|
||||
git -C "$VCPKG_DIR" fetch --tags origin
|
||||
git -C "$VCPKG_DIR" -c advice.detachedHead=false checkout "$VCPKG_COMMIT"
|
||||
[[ -x "$VCPKG_DIR/vcpkg" ]] || "$VCPKG_DIR/bootstrap-vcpkg.sh" -disableMetrics
|
||||
|
||||
mkdir -p /var/cache/vcpkg
|
||||
chown -R "$SERVICE_USER:staff" /var/cache/vcpkg
|
||||
|
||||
# ---- 9. Permissions ----
|
||||
log "Setting up permissions for $SERVICE_USER"
|
||||
chown -R "$SERVICE_USER:staff" "$CARGO_HOME" "$RUSTUP_HOME" \
|
||||
/opt/flutter /opt/flutter-bridge "$VCPKG_DIR"
|
||||
mkdir -p /opt/cargo-tools
|
||||
chown -R "$SERVICE_USER:staff" /opt/cargo-tools
|
||||
|
||||
git config --system --add safe.directory '*' || true
|
||||
|
||||
# ---- 10. act_runner ----
|
||||
RUNNER_DIR="/usr/local/var/gitea-runner"
|
||||
mkdir -p "$RUNNER_DIR"
|
||||
chown -R "$SERVICE_USER:staff" "$RUNNER_DIR"
|
||||
|
||||
if [[ ! -x "$RUNNER_DIR/act_runner" ]]; then
|
||||
log "Downloading act_runner $RUNNER_VERSION"
|
||||
case "$ARCH" in
|
||||
arm64) rarch="arm64" ;;
|
||||
x86_64) rarch="amd64" ;;
|
||||
esac
|
||||
curl -fsSL -o "$RUNNER_DIR/act_runner" \
|
||||
"https://gitea.com/gitea/act_runner/releases/download/v${RUNNER_VERSION}/act_runner-${RUNNER_VERSION}-darwin-${rarch}"
|
||||
chmod +x "$RUNNER_DIR/act_runner"
|
||||
chown "$SERVICE_USER:staff" "$RUNNER_DIR/act_runner"
|
||||
fi
|
||||
|
||||
if [[ ! -f "$RUNNER_DIR/.runner" ]]; then
|
||||
log "Registering runner with $GITEA_URL"
|
||||
sudo -u "$SERVICE_USER" -H bash -c "
|
||||
cd '$RUNNER_DIR' && \
|
||||
./act_runner register --no-interactive \
|
||||
--instance '$GITEA_URL' \
|
||||
--token '$RUNNER_TOKEN' \
|
||||
--name '$RUNNER_NAME' \
|
||||
--labels '$RUNNER_LABELS'
|
||||
"
|
||||
fi
|
||||
|
||||
# ---- 11. launchd service ----
|
||||
log "Installing LaunchDaemon"
|
||||
PLIST=/Library/LaunchDaemons/com.rustdesk.gitea-runner.plist
|
||||
cat > "$PLIST" <<EOF
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>com.rustdesk.gitea-runner</string>
|
||||
<key>UserName</key>
|
||||
<string>${SERVICE_USER}</string>
|
||||
<key>WorkingDirectory</key>
|
||||
<string>${RUNNER_DIR}</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>${RUNNER_DIR}/act_runner</string>
|
||||
<string>daemon</string>
|
||||
</array>
|
||||
<key>EnvironmentVariables</key>
|
||||
<dict>
|
||||
<key>RUSTUP_HOME</key> <string>${RUSTUP_HOME}</string>
|
||||
<key>CARGO_HOME</key> <string>${CARGO_HOME}</string>
|
||||
<key>VCPKG_ROOT</key> <string>${VCPKG_DIR}</string>
|
||||
<key>HOMEBREW_PREFIX</key> <string>${HOMEBREW_PREFIX}</string>
|
||||
<key>PATH</key>
|
||||
<string>${CARGO_HOME}/bin:/opt/flutter/bin:/opt/cargo-tools/bin:${HOMEBREW_PREFIX}/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
|
||||
</dict>
|
||||
<key>RunAtLoad</key> <true/>
|
||||
<key>KeepAlive</key> <true/>
|
||||
<key>StandardOutPath</key><string>${RUNNER_DIR}/stdout.log</string>
|
||||
<key>StandardErrorPath</key><string>${RUNNER_DIR}/stderr.log</string>
|
||||
<key>SoftResourceLimits</key>
|
||||
<dict>
|
||||
<key>NumberOfFiles</key> <integer>65535</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
EOF
|
||||
chmod 0644 "$PLIST"
|
||||
|
||||
launchctl bootout system "$PLIST" 2>/dev/null || true
|
||||
launchctl bootstrap system "$PLIST"
|
||||
launchctl enable "system/com.rustdesk.gitea-runner"
|
||||
|
||||
log "Done."
|
||||
echo " Verify with: sudo launchctl print system/com.rustdesk.gitea-runner | head"
|
||||
echo " Tail logs with: tail -F $RUNNER_DIR/stderr.log"
|
||||
echo " Runner should appear (online) at $GITEA_URL > Site Admin > Actions > Runners"
|
||||
Reference in New Issue
Block a user