ai-robot-channel/scripts/check-openapi-level.sh

99 lines
2.8 KiB
Bash

#!/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/<module>/openapi.provider.yaml
# - spec/<module>/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/<module>/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."