diff --git a/.gitea/workflows/cicd.yaml b/.gitea/workflows/cicd.yaml index 0f15fe7..d65abbc 100644 --- a/.gitea/workflows/cicd.yaml +++ b/.gitea/workflows/cicd.yaml @@ -804,6 +804,113 @@ jobs: exit 0 + source-lanes-postmortem: + name: Source Lanes Failure Postmortem + # Capture follow-up diagnostics when any source lane dies during platform + # setup before step logging is available. + runs-on: ubuntu-act-8gb + needs: [backend-tests, precommit-tests, frontend-tests, xdoctest] + if: always() && (needs['backend-tests'].result == 'failure' || needs['precommit-tests'].result == 'failure' || needs['frontend-tests'].result == 'failure' || needs.xdoctest.result == 'failure') + timeout-minutes: 10 + steps: + - name: Identify runner + run: | + echo "=== Runner Identity ===" + echo "runner_name=${RUNNER_NAME:-}" + echo "runner_name_hint=${GITEA_RUNNER_NAME:-${ACT_RUNNER_NAME:-${RUNNER_NAME:-unknown}}}" + echo "runner_hostname_env=${HOSTNAME:-unknown}" + echo "runner_uname_n=$(uname -n 2>/dev/null || echo unknown)" + echo "runner_etc_hostname=$(cat /etc/hostname 2>/dev/null || echo unknown)" + echo "runner_os=${RUNNER_OS:-unknown}" + echo "runner_arch=${RUNNER_ARCH:-unknown}" + echo "timestamp_utc=$(date -u +%Y-%m-%dT%H:%M:%SZ)" + + - name: Collect source lane postmortem context + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + set +e + + echo "=== Postmortem Context ===" + echo "workflow=${GITHUB_WORKFLOW:-unknown}" + echo "run_id=${GITHUB_RUN_ID:-unknown}" + echo "run_number=${GITHUB_RUN_NUMBER:-unknown}" + echo "run_attempt=${GITHUB_RUN_ATTEMPT:-unknown}" + echo "repository=${GITHUB_REPOSITORY:-unknown}" + echo "server_url=${GITHUB_SERVER_URL:-unknown}" + echo "backend_tests_result=${{ needs['backend-tests'].result }}" + echo "precommit_tests_result=${{ needs['precommit-tests'].result }}" + echo "frontend_tests_result=${{ needs['frontend-tests'].result }}" + echo "xdoctest_result=${{ needs.xdoctest.result }}" + + echo "=== Local Runner Telemetry (postmortem job host) ===" + uname -a || true + cat /etc/os-release 2>/dev/null || true + df -h || true + free -h || true + if command -v docker >/dev/null 2>&1; then + docker version || true + docker info || true + fi + + echo "=== Registry Reachability Probe ===" + timeout 10 curl -fsSIL "https://${GITEA_REGISTRY}/v2/" || true + + if [ -z "${GITHUB_TOKEN:-}" ]; then + echo "No GITHUB_TOKEN available for API diagnostics" + exit 0 + fi + + API_BASE="${GITHUB_API_URL:-${GITHUB_SERVER_URL}/api/v1}" + JOBS_URL="${API_BASE}/repos/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}/jobs?limit=200" + + echo "=== Actions API Job Summary ===" + echo "jobs_url=${JOBS_URL}" + if ! curl -fsSL -H "Authorization: token ${GITHUB_TOKEN}" -H "Accept: application/json" "${JOBS_URL}" -o /tmp/actions-jobs.json; then + echo "Could not fetch job metadata from Actions API" + exit 0 + fi + + if command -v python3 >/dev/null 2>&1; then + python3 -c "$(printf '%s\n' \ + 'import json' \ + 'from pathlib import Path' \ + '' \ + 'path = Path("/tmp/actions-jobs.json")' \ + 'payload = json.loads(path.read_text())' \ + 'jobs = payload.get("jobs") or payload.get("data") or []' \ + '' \ + 'print("job_count=", len(jobs))' \ + '' \ + 'def _g(job, *keys):' \ + ' for key in keys:' \ + ' if key in job and job[key] not in (None, ""):' \ + ' return job[key]' \ + ' return "unknown"' \ + '' \ + 'targets = {' \ + ' "Backend Tests",' \ + ' "Pre-commit Checks",' \ + ' "Frontend Tests",' \ + ' "Backend Doctests",' \ + '}' \ + '' \ + 'for job in jobs:' \ + ' name = str(_g(job, "name", "job_name"))' \ + ' if name in targets:' \ + ' status = _g(job, "status")' \ + ' conclusion = _g(job, "conclusion", "result")' \ + ' runner = _g(job, "runner_name", "runner")' \ + ' started = _g(job, "started_at", "start_time")' \ + ' completed = _g(job, "completed_at", "end_time")' \ + ' print(f"job={name} status={status} conclusion={conclusion} runner={runner} started={started} completed={completed}")')" + else + echo "python3 unavailable; emitting raw jobs payload head" + sed -n '1,120p' /tmp/actions-jobs.json || true + fi + + exit 0 + integration-tests: name: Runtime Black-Box Integration Tests # Pin integration tests to high-memory worker to reduce setup-stage runner churn.