framework tools/git: issue-list, milestone-create, lane-brief R1/R4 conversions (P1 complete)

- issue-list + milestone-create: usage() default exit 2, value guards,
  missing-title via usage_error.
- lane-brief: getopts replaced with a while/case parser carrying R2
  long-flag aliases (--repo --milestone --label/--labels --login
  --limit) beside the short forms; login-resolution failure reclassified
  from exit 2 to exit 1 (credential class, not an invocation defect).
- Three suites enrolled (population 88); lane-brief pr-linkage suite
  still ALL PASS; green in both trees; mirrored to the brain tree.

With this, every agent-facing wrapper in tools/git carries the R1/R4
usage-error contract (22/22 non-guard wrappers; guards keep their own
contracts).
This commit is contained in:
2026-08-28 18:10:27 -05:00
parent bb23cb6feb
commit c8b4af59c3
7 changed files with 418 additions and 16 deletions
@@ -28,18 +28,25 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/detect-platform.sh"
REPO="" MILESTONE="" LABEL="" LOGIN="" LIMIT=100
while getopts "r:m:l:L:n:h" opt; do
case "$opt" in
r) REPO="$OPTARG" ;;
m) MILESTONE="$OPTARG" ;;
l) LABEL="$OPTARG" ;;
L) LOGIN="$OPTARG" ;;
n) LIMIT="$OPTARG" ;;
h) grep '^#' "$0" | sed 's/^# \?//'; exit 0 ;;
*) echo "see -h" >&2; exit 2 ;;
# R2 (2026-08-28): long-flag aliases with the same usage-error contract the
# wrapper family shares (rc 2, stderr). getopts could not take long flags.
usage_error() {
echo "Error: $*" >&2
echo "Usage: lane-brief.sh -r <owner/repo> [-m milestone] [-l label] [-L login] [-n limit]" >&2
exit 2
}
while [[ $# -gt 0 ]]; do
case "$1" in
-r|--repo) [[ $# -ge 2 ]] || usage_error "option $1 requires a value"; REPO="$2"; shift 2 ;;
-m|--milestone) [[ $# -ge 2 ]] || usage_error "option $1 requires a value"; MILESTONE="$2"; shift 2 ;;
-l|--label|--labels) [[ $# -ge 2 ]] || usage_error "option $1 requires a value"; LABEL="$2"; shift 2 ;;
-L|--login) [[ $# -ge 2 ]] || usage_error "option $1 requires a value"; LOGIN="$2"; shift 2 ;;
-n|--limit) [[ $# -ge 2 ]] || usage_error "option $1 requires a value"; LIMIT="$2"; shift 2 ;;
-h|--help) grep '^#' "$0" | sed 's/^# \?//'; exit 0 ;;
*) usage_error "unknown option: $1" ;;
esac
done
[[ -n "$REPO" ]] || { echo "FATAL: -r <owner/repo> required" >&2; exit 2; }
[[ -n "$REPO" ]] || usage_error "-r/--repo <owner/repo> required"
# Resolve login: explicit -L, then $GITEA_LOGIN, then owner inference, then the
# shared default-login resolver. Owner inference comes before the shared fallback
@@ -72,7 +79,7 @@ if [[ -z "$LOGIN" ]]; then
fi
fi
fi
[[ -n "$LOGIN" ]] || { echo "FATAL: could not resolve a Gitea login for $REPO (pass -L or set GITEA_LOGIN)" >&2; exit 2; }
[[ -n "$LOGIN" ]] || { echo "FATAL: could not resolve a Gitea login for $REPO (pass -L or set GITEA_LOGIN)" >&2; exit 1; }
command -v tea >/dev/null || { echo "FATAL: tea not found" >&2; exit 1; }
command -v jq >/dev/null || { echo "FATAL: jq not found" >&2; exit 1; }