feat(devops): add Gitea CI (act_runner) to Azure VM setup

- Phase 2: install act_runner binary, register with Gitea, create systemd service
- Phase 3: push all 11 repos to VM Gitea after cloning from GitHub
- Expanded Gitea API token scopes (write:repository, write:user)
- Runner config: host mode, capacity 2, GITEA_NPM_TOKEN injected
- Enables CI on the VM for NETWORK!=corp usage
This commit is contained in:
saravanakumardb1 2026-03-26 23:19:37 -07:00
parent aa139d5021
commit 70fdc6b279

View File

@ -8,7 +8,8 @@
# What gets installed:
# - Docker CE + Docker Compose + BuildKit
# - Node.js 22 LTS + pnpm 10.6.5
# - Gitea (Docker container — npm package registry on :3300)
# - Gitea (Docker container — npm package registry + CI on :3300)
# - act_runner (Gitea CI runner — systemd service, host mode)
# - Ollama (local LLM inference for LocalMemGPT on :11434)
# - All 11 ByteLyst repos (cloned from GitHub)
# - All @bytelyst/* packages (built + published to Gitea)
@ -26,8 +27,8 @@
#
# Phases:
# 1 System dependencies (Docker, Node, pnpm, Ollama)
# 2 Gitea npm registry (container on :3300)
# 3 Clone 11 repositories from GitHub
# 2 Gitea npm registry + CI runner (container on :3300 + act_runner systemd)
# 3 Clone 11 repositories from GitHub + push to Gitea
# 4 Build all @bytelyst/* packages
# 5 Publish packages to Gitea npm registry
# 6 Generate .env.ecosystem config
@ -332,7 +333,7 @@ phase2_gitea() {
token_response=$(curl -sf -X POST "${GITEA_URL}/api/v1/users/${GITEA_ADMIN}/tokens" \
-H "$AUTH_HEADER" \
-H "Content-Type: application/json" \
-d '{"name":"vm-deploy","scopes":["write:package","read:package","write:organization","read:organization"]}')
-d '{"name":"vm-deploy","scopes":["write:package","read:package","write:organization","read:organization","write:repository","read:repository","write:user","read:user"]}')
GITEA_NPM_TOKEN=$(echo "$token_response" | jq -r '.sha1 // .token' 2>/dev/null || echo "")
if [ -z "$GITEA_NPM_TOKEN" ] || [ "$GITEA_NPM_TOKEN" = "null" ]; then
@ -344,7 +345,121 @@ phase2_gitea() {
echo "$GITEA_NPM_TOKEN" > "${INSTALL_DIR}/.gitea_token"
chmod 600 "${INSTALL_DIR}/.gitea_token"
ok "Phase 2 complete. Gitea running at http://localhost:${GITEA_PORT}"
# ── Install act_runner (Gitea CI) ─────────────────────────────────
log "Installing act_runner for Gitea CI..."
local RUNNER_VERSION="0.3.0"
local RUNNER_ARCH
RUNNER_ARCH=$(dpkg --print-architecture) # amd64 or arm64
local RUNNER_BIN="/usr/local/bin/act_runner"
if [ ! -f "$RUNNER_BIN" ]; then
local runner_url="https://gitea.com/gitea/act_runner/releases/download/v${RUNNER_VERSION}/act_runner-${RUNNER_VERSION}-linux-${RUNNER_ARCH}"
curl -sfL "$runner_url" -o "$RUNNER_BIN" || fail "Failed to download act_runner v${RUNNER_VERSION}"
chmod +x "$RUNNER_BIN"
ok "act_runner v${RUNNER_VERSION} installed."
else
ok "act_runner already installed."
fi
# Create runner data directory
local RUNNER_DIR="${INSTALL_DIR}/.act_runner"
mkdir -p "$RUNNER_DIR"
# Register runner (idempotent — skip if already registered)
if [ ! -f "${RUNNER_DIR}/.runner" ]; then
# Get a runner registration token from Gitea API
local reg_token_resp
reg_token_resp=$(curl -sf -X POST "${GITEA_URL}/api/v1/admin/runners/registration-token" \
-H "$AUTH_HEADER" \
-H "Content-Type: application/json" 2>/dev/null || echo "")
local reg_token
reg_token=$(echo "$reg_token_resp" | jq -r '.token' 2>/dev/null || echo "")
if [ -z "$reg_token" ] || [ "$reg_token" = "null" ]; then
warn "Could not get runner registration token (Gitea may not support this API). Trying alternate method..."
# Fallback: use the Gitea admin API (older versions)
reg_token_resp=$(curl -sf "${GITEA_URL}/api/v1/admin/runners/registration-token" \
-H "Authorization: token ${GITEA_NPM_TOKEN}" 2>/dev/null || echo "")
reg_token=$(echo "$reg_token_resp" | jq -r '.token' 2>/dev/null || echo "")
fi
if [ -z "$reg_token" ] || [ "$reg_token" = "null" ]; then
warn "Could not obtain runner registration token. act_runner will need manual registration."
warn "Run: act_runner register --instance http://localhost:${GITEA_PORT} --token <TOKEN>"
else
cd "$RUNNER_DIR"
"$RUNNER_BIN" register \
--instance "http://localhost:${GITEA_PORT}" \
--token "$reg_token" \
--name "bytelyst-vm" \
--labels "ubuntu-latest:host,self-hosted:host" \
--no-interactive 2>/dev/null || true
ok "act_runner registered with Gitea."
fi
else
ok "act_runner already registered."
fi
# Generate runner config
cat > "${RUNNER_DIR}/config.yaml" <<RUNNER_CFG
log:
level: info
runner:
file: ${RUNNER_DIR}/.runner
capacity: 2
envs:
PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOME: /root
NODE_ENV: test
GITEA_NPM_TOKEN: ${GITEA_NPM_TOKEN}
GITEA_NPM_HOST: localhost
timeout: 30m
shutdown_timeout: 10s
insecure: false
fetch_timeout: 5s
fetch_interval: 2s
labels:
- "ubuntu-latest:host"
- "self-hosted:host"
cache:
enabled: true
container:
docker_host: "-"
force_pull: false
require_docker: false
host:
workdir_parent: ${INSTALL_DIR}/.cache/act
RUNNER_CFG
mkdir -p "${INSTALL_DIR}/.cache/act"
# Create systemd service (idempotent)
cat > /etc/systemd/system/act-runner.service <<SYSTEMD_SVC
[Unit]
Description=Gitea Act Runner
After=network.target docker.service
Wants=docker.service
[Service]
Type=simple
WorkingDirectory=${RUNNER_DIR}
ExecStart=${RUNNER_BIN} daemon --config ${RUNNER_DIR}/config.yaml
Restart=on-failure
RestartSec=10
Environment="HOME=/root"
[Install]
WantedBy=multi-user.target
SYSTEMD_SVC
systemctl daemon-reload
systemctl enable act-runner.service 2>/dev/null || true
systemctl restart act-runner.service 2>/dev/null || true
ok "act_runner systemd service started."
ok "Phase 2 complete. Gitea running at http://localhost:${GITEA_PORT}, CI runner active."
}
# ═══════════════════════════════════════════════════════════════════════
@ -378,7 +493,42 @@ phase3_clone() {
# (commit fix(docker) across all 10 product repos + dashboards).
# No runtime sed stripping needed.
ok "Phase 3 complete. All repos in ${INSTALL_DIR}/"
# ── Push repos to VM Gitea (enables CI triggers on push) ──────────
log "Pushing repos to VM Gitea (CI will trigger on push)..."
require_gitea_token
local GITEA_URL="http://localhost:${GITEA_PORT}"
local GITEA_PUSH_URL="http://${GITEA_ADMIN}:${GITEA_PASS}@localhost:${GITEA_PORT}/bytelyst"
for repo in "${REPOS[@]}"; do
local target="${INSTALL_DIR}/${repo}"
[ -d "$target/.git" ] || continue
# Create repo in Gitea org if it doesn't exist (idempotent)
local repo_status
repo_status=$(curl -sf -o /dev/null -w "%{http_code}" \
-H "Authorization: token ${GITEA_NPM_TOKEN}" \
"${GITEA_URL}/api/v1/repos/bytelyst/${repo}" 2>/dev/null || echo "000")
if [ "$repo_status" != "200" ]; then
curl -sf -X POST "${GITEA_URL}/api/v1/orgs/bytelyst/repos" \
-H "Authorization: token ${GITEA_NPM_TOKEN}" \
-H "Content-Type: application/json" \
-d "{\"name\":\"${repo}\",\"default_branch\":\"main\",\"auto_init\":false}" > /dev/null 2>&1 || true
fi
# Add gitea remote and push (idempotent)
cd "$target"
git remote remove gitea 2>/dev/null || true
git remote add gitea "${GITEA_PUSH_URL}/${repo}.git"
if git push gitea main 2>/dev/null; then
log " Pushed: $repo"
else
warn " Push failed (non-fatal): $repo"
fi
done
ok "Phase 3 complete. All repos in ${INSTALL_DIR}/ and pushed to Gitea."
}
# ═══════════════════════════════════════════════════════════════════════
@ -845,8 +995,8 @@ usage() {
echo ""
echo "Phases:"
echo " 1 System dependencies (Docker, Node, pnpm, Ollama)"
echo " 2 Gitea npm registry"
echo " 3 Clone repositories"
echo " 2 Gitea npm registry + CI runner"
echo " 3 Clone repositories + push to Gitea"
echo " 4 Build @bytelyst/* packages"
echo " 5 Publish packages to Gitea"
echo " 6 Generate .env.ecosystem"