#!/usr/bin/env bash # The pipeline's last step, run however the steps before it ended (if: # always()). Settles the step list with how the run ended and sends it one # last time: # * a step still running never finished, so it failed; # * a step that never started was skipped; # * when nothing closed the build record (a step died without fail_build: # Set up Node.js, a crash), close it as failed, naming the step, so the hub # does not show the run as running until it goes stale. # Never fails: the run's result is already decided. set -uo pipefail . "$(dirname "$0")/lib.sh" settle() { local f before stopped reason f="$(steps_file)" [ -s "$f" ] && command -v jq >/dev/null || return 0 before="$(cat "$f")" # Why the run stopped, from the step that stopped it: one still running # (never finished), else the first that failed, else the first that never # started (it died before it could say so). stopped="$(jq -r ' (map(select(.status == "running"))[0] | select(.) | .name + " did not finish.") // (map(select(.status == "failed"))[0] | select(.) | .name + (if .summary then ": " + .summary else " failed." end)) // (map(select(.status == "pending"))[0] | select(.) | "The run stopped before " + .name + ".") // empty' "$f")" _steps_edit 'map(if .status == "running" then .status = "failed" elif .status == "pending" then .status = "skipped" else . end)' || return 0 # A step that was running when the run stopped gets its finish time too. _steps_edit --arg at "$(iso_now)" --argjson ms "$(now_ms)" \ 'map(if .status == "failed" and .startedMs and (.finishedAt | not) then .finishedAt = $at | .durationMs = ($ms - .startedMs) else . end)' || return 0 if [ -n "${BUILD_ID:-}" ] && [ ! -e "$f.finished" ]; then reason="${stopped:-The run stopped before it finished.}" report_build_finish failed "$reason" fi [ "$(cat "$f")" = "$before" ] || steps_post } ( settle ) || true exit 0