#!/usr/bin/env sh set -eu # Check OpenAPI contract levels for multi-module layout. # - For PRs targeting main: require provider contract level >= L2. # - Always require info.x-contract-level exists and is L0-L3. # # Expected locations: # - spec//openapi.provider.yaml # - spec//openapi.deps.yaml (optional) require_provider_l2="${REQUIRE_PROVIDER_L2:-0}" die() { echo "ERROR: $*" >&2 exit 1 } level_rank() { case "$1" in L0) echo 0;; L1) echo 1;; L2) echo 2;; L3) echo 3;; *) echo -1;; esac } extract_level() { # Extracts the first occurrence of info.x-contract-level: L? # Accepts patterns like: # x-contract-level: L2 # x-contract-level: "L2" # under info: file="$1" awk ' BEGIN{in_info=0; level=""} { # detect "info:" at any indentation if ($0 ~ /^[[:space:]]*info:[[:space:]]*$/) { in_info=1; info_indent=match($0,/[^ ]/)-1; next } if (in_info==1) { # if indentation decreases or new top-level key begins, leave info block cur_indent=match($0,/[^ ]/)-1; if (cur_indent <= info_indent && $0 ~ /^[^[:space:]]/ ) { in_info=0 } } if (in_info==1 && level=="" && $0 ~ /^[[:space:]]*x-contract-level:[[:space:]]*/) { line=$0 sub(/^[[:space:]]*x-contract-level:[[:space:]]*/,"",line) gsub(/"|\047/,"",line) # strip comments sub(/[[:space:]]*#.*/,"",line) gsub(/[[:space:]]+/,"",line) level=line } } END{print level} ' "$file" } check_file_level() { file="$1" kind="$2" # provider|deps [ -f "$file" ] || die "Missing OpenAPI file: $file" level="$(extract_level "$file" | tr -d '\r')" [ -n "$level" ] || die "$file: missing info.x-contract-level (expected under info: x-contract-level: L0|L1|L2|L3)" rank="$(level_rank "$level")" [ "$rank" -ge 0 ] || die "$file: invalid x-contract-level '$level' (expected L0|L1|L2|L3)" if [ "$kind" = "provider" ] && [ "$require_provider_l2" = "1" ]; then if [ "$rank" -lt 2 ]; then die "$file: provider contract-level must be >= L2 for merge-to-main (current: $level)" fi fi echo "OK: $file level=$level" } # Find all provider openapi files under spec/* provider_files="$(find spec -mindepth 2 -maxdepth 2 -type f -name 'openapi.provider.yaml' 2>/dev/null || true)" [ -n "$provider_files" ] || die "No provider OpenAPI found. Expected at least one spec//openapi.provider.yaml" # Provider files always must have a valid level; for main merges, require >= L2 for f in $provider_files; do check_file_level "$f" provider done # Deps files are optional, but if present must have valid level for d in $(find spec -mindepth 2 -maxdepth 2 -type f -name 'openapi.deps.yaml' 2>/dev/null || true); do check_file_level "$d" deps done echo "All OpenAPI contract level checks passed."