#!/usr/bin/env bash
# Check the workflow contract for every repository named by an installed runner.
set -euo pipefail

HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
OVERDECK_REPO_ROOT="${OVERDECK_REPO_ROOT:-$(cd "$HERE/../.." && pwd)}"
RUNNER_HOME="${CI_RUNNER_HOME:-$HOME}"
REPOS_ROOT="${CI_REPOS_ROOT:-$HOME/Projects}"

check_workflow() { # $1=repository $2=workflow $3=enforce|advisory
  local repo="$1" workflow="$2" mode="$3" findings
  findings=$(awk '
    function finish() {
      if (self_hosted && cpu_limit && !sched_idle) print cpu_limit_line
    }
    /^  [A-Za-z0-9_-]+:[[:space:]]*$/ && in_jobs { finish(); self_hosted=0; cpu_limit=0; sched_idle=0 }
    /^jobs:[[:space:]]*$/ { in_jobs=1; next }
    !in_jobs { next }
    /runs-on:.*self-hosted/ || /^[[:space:]]*-[[:space:]]*self-hosted([[:space:]]|$)/ { self_hosted=1 }
    /(^|[[:space:]])(\.\/)?scripts\/cpu-limit\.sh([[:space:]]|$)/ { cpu_limit=1; cpu_limit_line=FNR }
    /BUILD_SCHED_IDLE:[[:space:]]*["'\'' ]*0(["'\'' ]|$)/ { sched_idle=1 }
    END { if (in_jobs) finish() }
  ' "$workflow")
  [ -z "$findings" ] && return 0
  while IFS= read -r line; do
    [ -n "$line" ] || continue
    if [ "$mode" = enforce ]; then
      printf 'FAIL %s:%s self-hosted cpu-limit job is missing BUILD_SCHED_IDLE=0\n' "$workflow" "$line" >&2
      return 1
    fi
    printf 'ADVISORY %s:%s self-hosted cpu-limit job is missing BUILD_SCHED_IDLE=0 (external repo %s)\n' \
      "$workflow" "$line" "$repo" >&2
  done <<<"$findings"
}

check_repo() { # $1=repository path $2=enforce|advisory
  local repo="$1" mode="$2" workflow rc=0
  [ -d "$repo/.github/workflows" ] || return 0
  while IFS= read -r -d '' workflow; do
    check_workflow "$repo" "$workflow" "$mode" || rc=1
  done < <(find "$repo/.github/workflows" -type f \( -name '*.yml' -o -name '*.yaml' \) -print0 | sort -z)
  return "$rc"
}

rc=0
found=0
for runner in "$RUNNER_HOME"/actions-runner-*; do
  [ -d "$runner" ] || continue
  name="${runner##*/actions-runner-}"
  [ -n "$name" ] || continue
  found=1
  if [ "$name" = "$(basename "$OVERDECK_REPO_ROOT")" ]; then
    check_repo "$OVERDECK_REPO_ROOT" enforce || rc=1
  else
    check_repo "$REPOS_ROOT/$name" advisory
  fi
done

[ "$found" -eq 1 ] || echo 'ci-sched-idle: no runner install directories found; nothing to check'
exit "$rc"
