#!/usr/bin/env bash # Run the checks declared in the manifest, record each result in DealSage, and # stop the pipeline if a required check failed. Advisory checks never block. # # Every result is posted to record-app-check with the commit and branch, so # DealSage can show checks per commit before a version exists and attach them # to the version once it is allocated. A DealSage outage is a warning here, not # a failure: the build should not be blocked by the dashboard being down. set -euo pipefail . "$(dirname "$0")/lib.sh" step_start checks require_env APP_ID CHECKS_JSON DEALSAGE_FUNCTIONS_URL PUBLISH_TOKEN SUPABASE_ANON_KEY git_context CHECKS_DIR="$(cd "$(dirname "$0")/../checks" && pwd)" post_check() { # id name status required duration_ms summary logfile started finished local payload payload="$(jq -n \ --arg appId "$APP_ID" --arg sha "$COMMIT_SHA" --arg branch "$BRANCH" \ --arg id "$1" --arg name "$2" --arg status "$3" --argjson required "$4" \ --argjson duration "$5" --arg summary "$6" --rawfile log "$7" \ --arg started "$8" --arg finished "$9" \ '{appId:$appId, commitSha:$sha, branch:$branch, checkId:$id, name:$name, status:$status, required:$required, durationMs:$duration, summary:$summary, logTail:($log | split("\n") | .[-80:] | join("\n")), reportedBy:"ci", startedAt:$started, finishedAt:$finished}')" ds_post record-app-check "$payload" >/dev/null || warn "could not record check $1 in DealSage" } results='[]' required_failed=() advisory_failed=() count="$(jq 'length' <<<"$CHECKS_JSON")" if [ "$count" = 0 ]; then log "No checks declared in .dealsage/app.json" persist_env CHECKS_RESULT_JSON '[]' step_done checks skipped "No checks declared in .dealsage/app.json" exit 0 fi while IFS= read -r check; do id="$(jq -r .id <<<"$check")"; name="$(jq -r .name <<<"$check")" run="$(jq -r '.run // empty' <<<"$check")"; uses="$(jq -r '.uses // empty' <<<"$check")" required="$(jq -r .required <<<"$check")"; timeout_min="$(jq -r .timeoutMinutes <<<"$check")" logf="$(mktemp)"; started="$(iso_now)"; t0="$(now_ms)" echo "::group::check: $name ($id)" if [ -n "$uses" ]; then printf '$ platform check %s\n' "$uses" | tee "$logf" set +e; timeout "${timeout_min}m" bash "$CHECKS_DIR/$uses.sh" 2>&1 | tee -a "$logf"; rc=${PIPESTATUS[0]}; set -e else printf '$ %s\n' "$run" | tee "$logf" set +e; timeout "${timeout_min}m" bash -o pipefail -c "$run" 2>&1 | tee -a "$logf"; rc=${PIPESTATUS[0]}; set -e fi echo "::endgroup::" dur=$(( $(now_ms) - t0 )) case "$rc" in 0) status=passed; summary="passed in $(( dur / 1000 ))s" ;; 124) status=error; summary="timed out after ${timeout_min} minutes" ;; *) status=failed; summary="exit code $rc" ;; esac printf '%s: %s (%s)\n' "$name" "$status" "$summary" post_check "$id" "$name" "$status" "$required" "$dur" "$summary" "$logf" "$started" "$(iso_now)" results="$(jq -c --arg id "$id" --arg status "$status" --argjson d "$dur" --argjson req "$required" \ '. + [{id:$id, status:$status, durationMs:$d, required:$req}]' <<<"$results")" if [ "$status" != passed ]; then if [ "$required" = true ]; then required_failed+=("$name"); else advisory_failed+=("$name"); fi fi rm -f "$logf" done < <(jq -c '.[]' <<<"$CHECKS_JSON") persist_env CHECKS_RESULT_JSON "$results" summary "### Checks" summary "$(jq -r '.[] | "- \(.id): **\(.status)** (\(.durationMs)ms\(if .required then "" else ", advisory" end))"' <<<"$results")" if [ "${#required_failed[@]}" -gt 0 ]; then fail_build checks_failed "Required check(s) failed: ${required_failed[*]}. The build was not published." fi log "All required checks passed" passed="$(jq '[.[] | select(.status == "passed")] | length' <<<"$results")" note="$passed of $count passed" if [ "${#advisory_failed[@]}" -gt 0 ]; then note="$note ($(printf '%s, ' "${advisory_failed[@]}" | sed 's/, $//') failed, not required)" fi step_done checks passed "$note"