#!/usr/bin/env bash # recipe-upgrade :: trigger cc-ci on a recipe PR via `!testme` and read the verdict FROM the PR. # ------------------------------------------------------------------------- # Runs on the ORCHESTRATOR (just hits the Gitea API with /srv/cc-ci/.testenv creds). Posting # `!testme` as a PR comment is the REAL CI path — the bridge runs the harness on cc-ci and the # run + its results are posted back to the PR, so the operator can see them in the PR itself. # # testme-on-pr.sh # env: POST=1 post a fresh `!testme` first (default). POST=0 = poll an in-flight run only, # WITHOUT re-triggering (use on follow-up calls so you don't launch duplicate runs). # MAX_WAIT=480 INTERVAL=30 poll window per call, in seconds. 480s stays under the 10-min # tool cap — if it prints VERDICT=PENDING, just run again with POST=0 to keep polling. # # Prints: VERDICT=GREEN|RED|PENDING and BUILD= set -o errexit -o nounset -o pipefail RECIPE="${1:?usage: testme-on-pr.sh }" PRIDX="${2:?usage: testme-on-pr.sh }" TESTENV="${TESTENV:-/srv/cc-ci/.testenv}" set -a; . "$TESTENV"; set +a : "${GITEA_USERNAME:?}"; : "${GITEA_PASSWORD:?}"; : "${GITEA_URL:?}" NS="${GITEA_NAMESPACE:-recipe-maintainers}" API="https://${GITEA_URL}/api/v1"; AUTH=(-u "${GITEA_USERNAME}:${GITEA_PASSWORD}") POST="${POST:-1}"; MAX_WAIT="${MAX_WAIT:-480}"; INTERVAL="${INTERVAL:-30}" status_fields() { curl -s "${AUTH[@]}" "${API}/repos/${NS}/${RECIPE}/commits/${SHA}/status" 2>/dev/null \ | python3 -c "import json,sys try: d=json.load(sys.stdin) except Exception: d={} sts=d.get('statuses') or [] ctx=[s for s in sts if s.get('context')=='cc-ci/testme'] cur=ctx[0] if ctx else {} state=cur.get('state') or d.get('state','') or 'none' url=cur.get('target_url','') or ((sts[0].get('target_url','') if sts else '')) updated=cur.get('updated_at','') or cur.get('created_at','') or '' print(state, url or '', updated or '')" 2>/dev/null || echo "none " } SHA="$(curl -s "${AUTH[@]}" "${API}/repos/${NS}/${RECIPE}/pulls/${PRIDX}" \ | python3 -c "import json,sys;print(json.load(sys.stdin)['head']['sha'])" 2>/dev/null || true)" [ -n "$SHA" ] || { echo "ERROR: could not resolve ${NS}/${RECIPE} PR #${PRIDX} head sha"; exit 1; } baseline_state="" baseline_url="" baseline_updated="" if [ "$POST" = "1" ]; then read -r baseline_state baseline_url baseline_updated < <(status_fields) fi if [ "$POST" = "1" ]; then curl -s -o /dev/null "${AUTH[@]}" -H "Content-Type: application/json" -X POST \ "${API}/repos/${NS}/${RECIPE}/issues/${PRIDX}/comments" -d '{"body":"!testme"}' echo "→ posted !testme on ${NS}/${RECIPE}#${PRIDX} (head ${SHA:0:8}) — results will appear in the PR" sleep 5 fi # Poll the Drone-reported combined commit status on the PR head (terminal = success/failure/error). deadline=$(( $(date +%s) + MAX_WAIT )) url="" while [ "$(date +%s)" -lt "$deadline" ]; do read -r state url updated < <(status_fields) if [ "$POST" = "1" ] && [ "$state" = "$baseline_state" ] \ && [ "$url" = "$baseline_url" ] && [ "$updated" = "$baseline_updated" ]; then sleep "$INTERVAL" continue fi case "$state" in success) echo "VERDICT=GREEN"; echo "BUILD=${url}"; exit 0;; failure|error) echo "VERDICT=RED"; echo "BUILD=${url}"; exit 2;; esac sleep "$INTERVAL" done echo "VERDICT=PENDING"; echo "BUILD=${url:-?}" echo "(run still in flight — re-run with POST=0 to keep polling without re-triggering)" exit 3