The REST API (/actions/tasks) hides runs that fail at parse/dispatch time, so it reported 0 runs while the forge DB held 151 failed + 8 stuck runs — all from the same root cause: ZERO runners registered on ct-forge (action_task=0, nothing ever executed a step). - infrastructure/forge-ci-doctor.sh: DB-backed health check over ssh; lists runners, per-repo run-status breakdown, recent failures, dispatched-task count; RED/GREEN verdict + exit code. shellcheck-clean. - scripts/run/ci.sh: wire ./run ci:doctor; fix broken ci:status (org was 'lilith/', real ct-forge org is 'platform/'); ci:setup-host now points at the terraform ci-runners module instead of dead black. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
162 lines
5.8 KiB
Bash
162 lines
5.8 KiB
Bash
#!/bin/bash
|
|
# CI commands for lilith-platform.live
|
|
# Sourced by the top-level ./run script — do not execute directly.
|
|
# ROOT_DIR is set by the caller.
|
|
|
|
COMMAND="${1:-}"
|
|
shift || true
|
|
|
|
FORGEJO_URL="http://134.199.243.61:3000"
|
|
# ct-forge org is "platform" (NOT "lilith" — that was the black-forge org).
|
|
FORGEJO_REPO="platform/lilith-platform.live"
|
|
FORGEJO_API="${FORGEJO_URL}/api/v1"
|
|
|
|
# Personal access token — set in shell env or ~/.config/forgejo/token
|
|
FORGEJO_TOKEN="${FORGEJO_TOKEN:-$(cat "$HOME/.config/forgejo/token" 2>/dev/null || echo "")}"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Helpers
|
|
# ---------------------------------------------------------------------------
|
|
require_token() {
|
|
if [[ -z "$FORGEJO_TOKEN" ]]; then
|
|
echo "ERROR: FORGEJO_TOKEN is required." >&2
|
|
echo ""
|
|
echo " Get a token from: ${FORGEJO_URL}/user/settings/applications"
|
|
echo " Then either:"
|
|
echo " export FORGEJO_TOKEN=<token>"
|
|
echo " echo <token> > ~/.config/forgejo/token && chmod 600 ~/.config/forgejo/token"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
forgejo_api() {
|
|
local method="$1"; shift
|
|
local path="$1"; shift
|
|
curl -sf \
|
|
-X "$method" \
|
|
-H "Authorization: token ${FORGEJO_TOKEN}" \
|
|
-H "Content-Type: application/json" \
|
|
"${FORGEJO_API}${path}" \
|
|
"$@"
|
|
}
|
|
|
|
trigger_workflow() {
|
|
local workflow="$1"
|
|
local ref="${2:-main}"
|
|
require_token
|
|
echo "Triggering workflow: ${workflow} (ref: ${ref})..."
|
|
forgejo_api POST "/repos/${FORGEJO_REPO}/actions/workflows/${workflow}/dispatches" \
|
|
-d "{\"ref\": \"${ref}\"}" > /dev/null
|
|
echo " Triggered. Monitor at: ${FORGEJO_URL}/${FORGEJO_REPO}/actions"
|
|
echo ""
|
|
# Poll for the new run to appear and show its URL
|
|
sleep 2
|
|
local run_url
|
|
run_url="$(forgejo_api GET "/repos/${FORGEJO_REPO}/actions/runs?limit=1" 2>/dev/null \
|
|
| grep -o '"html_url":"[^"]*"' | head -1 | cut -d'"' -f4 || echo "")"
|
|
if [[ -n "$run_url" ]]; then
|
|
echo " Latest run: ${run_url}"
|
|
fi
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Commands
|
|
# ---------------------------------------------------------------------------
|
|
case "$COMMAND" in
|
|
ci:trigger:quinn)
|
|
trigger_workflow "deploy-quinn-www.yml" "${1:-main}"
|
|
;;
|
|
|
|
ci:trigger:admin)
|
|
trigger_workflow "deploy-quinn-admin.yml" "${1:-main}"
|
|
;;
|
|
|
|
ci:trigger:my)
|
|
trigger_workflow "deploy-quinn-my.yml" "${1:-main}"
|
|
;;
|
|
|
|
ci:trigger:data)
|
|
trigger_workflow "deploy-quinn-data.yml" "${1:-main}"
|
|
;;
|
|
|
|
ci:trigger:newsletter)
|
|
trigger_workflow "deploy-quinn-newsletter.yml" "${1:-main}"
|
|
;;
|
|
|
|
ci:status)
|
|
require_token
|
|
echo "Recent workflow runs for ${FORGEJO_REPO}:"
|
|
echo ""
|
|
_limit="${1:-15}"
|
|
forgejo_api GET "/repos/${FORGEJO_REPO}/actions/runs?limit=${_limit}" 2>/dev/null \
|
|
| python3 -c "import json,sys
|
|
runs=json.load(sys.stdin).get('workflow_runs',[])
|
|
limit=int(sys.argv[1]) if len(sys.argv)>1 else 15
|
|
if not runs:
|
|
print(' (no runs found)')
|
|
raise SystemExit(0)
|
|
print(' sha status workflow title')
|
|
print(' ' + '-'*78)
|
|
for r in runs[:limit]:
|
|
sha=(r.get('commit_sha') or '')[:7]
|
|
wf=r.get('workflow_id') or '?'
|
|
status=r.get('status') or '?'
|
|
title=(r.get('title') or '')[:42]
|
|
icon='✔' if status=='success' else ('✖' if status in ('failure','cancelled') else '⟳')
|
|
print(f' {icon} {sha:7} {status:10} {wf:32} {title}')
|
|
" "${_limit}" \
|
|
|| echo " (no runs found or API unavailable)"
|
|
echo ""
|
|
echo " Full list: ${FORGEJO_URL}/${FORGEJO_REPO}/actions"
|
|
;;
|
|
|
|
ci:logs)
|
|
_workflow="${1:?Usage: ./run ci:logs <workflow-name>}"
|
|
# e.g.: ./run ci:logs deploy-quinn-www.yml
|
|
require_token
|
|
echo "Fetching latest run for ${_workflow}..."
|
|
_run_id="$(forgejo_api GET "/repos/${FORGEJO_REPO}/actions/runs?limit=20" 2>/dev/null \
|
|
| grep -oP '"workflow_id":"'"${_workflow}"'[^"]*"|"id":\d+' \
|
|
| grep -B1 '"workflow_id"' | grep '"id"' | head -1 | grep -oP '\d+' || echo "")"
|
|
if [[ -z "$_run_id" ]]; then
|
|
echo "ERROR: no recent run found for ${_workflow}" >&2
|
|
exit 1
|
|
fi
|
|
echo " Run ID: ${_run_id}"
|
|
echo " Logs: ${FORGEJO_URL}/${FORGEJO_REPO}/actions/runs/${_run_id}"
|
|
;;
|
|
|
|
ci:doctor)
|
|
# Ground-truth CI/CD health from the ct-forge DB (sees parse/dispatch
|
|
# failures the REST API hides). No FORGEJO_TOKEN needed — reads via ssh.
|
|
bash "$ROOT_DIR/infrastructure/forge-ci-doctor.sh" "$@"
|
|
;;
|
|
|
|
ci:setup-host)
|
|
echo "ct-forge runners are provisioned via terraform, not on black."
|
|
echo "See: @cocottetech/infra/terraform/ci-runners/README.md"
|
|
echo " cd ~/Code/@projects/@cocottetech/infra/terraform/ci-runners"
|
|
echo " export TF_VAR_do_token=\"\$(cat ~/.vault/do_pat_cocotte)\""
|
|
echo " export TF_VAR_forge_pat=\"\$(cat ~/.vault/forge-admin-quinn.api-token)\""
|
|
echo " terraform init && terraform apply -var=runners=1"
|
|
exit 0
|
|
;;
|
|
|
|
*)
|
|
echo "Unknown CI command: $COMMAND"
|
|
echo ""
|
|
echo "CI commands:"
|
|
echo " ./run ci:trigger:quinn Trigger quinn.www deployment via Forgejo Actions"
|
|
echo " ./run ci:trigger:admin Trigger quinn.admin deployment"
|
|
echo " ./run ci:trigger:my Trigger quinn.my deployment"
|
|
echo " ./run ci:trigger:data Trigger quinn.data deployment"
|
|
echo " ./run ci:trigger:newsletter Trigger newsletter deployment"
|
|
echo " ./run ci:status Show recent workflow run statuses (API)"
|
|
echo " ./run ci:doctor [--repo R] Ground-truth CI health from ct-forge DB"
|
|
echo " ./run ci:logs <workflow.yml> Show URL for latest run logs"
|
|
echo " ./run ci:setup-host How to provision ct-forge runners (terraform)"
|
|
echo ""
|
|
echo " FORGEJO_TOKEN env var required for all ci:trigger/status/logs commands."
|
|
exit 1
|
|
;;
|
|
esac
|