framework tools/git: strict value guards + provider-failure normalization family-wide (codex blockers on PR #1464)
ci/woodpecker/pr/ci Pipeline is pending

- Value guards now reject option-like values: --anything always, and
  single-dash flag shapes (-h, -i). Previously -b --help consumed
  --help as the body and performed the write (codex example:
  issue-close -i --help proceeding to 'Closed GitHub issue #--help').
  Multi-char dash-leading text (-start of a list) stays a legal value.
- Every remaining direct provider exec (gh/tea/CMD arrays across
  issue-create/edit/assign/list/view, milestone-*, pr-create/edit,
  pr-close, issue-close/reopen) wrapped with rc capture and normalized
  to exit 1 with a stderr message — provider exit 2 no longer collides
  with the reserved usage-error status.
- All 16 usage-contract suites gained option-like and short-flag arms
  (16/16 green). Existing suites re-verified; test-pr-edit and
  test-issue-create-interactive-auth fail identically with these
  changes stashed (environment-coupled, not regressions; documented).
This commit is contained in:
2026-08-28 18:26:10 -05:00
parent ca91586222
commit d326e6572a
32 changed files with 264 additions and 90 deletions
@@ -50,32 +50,32 @@ usage_error() {
while [[ $# -gt 0 ]]; do
case $1 in
-s|--state)
[[ $# -ge 2 ]] || usage_error "option $1 requires a value"
[[ $# -ge 2 && "$2" != --* && ! "$2" =~ ^-[a-zA-Z]$ ]] || usage_error "option $1 requires a value (option-like values are rejected)"
STATE="$2"
shift 2
;;
-l|--label)
[[ $# -ge 2 ]] || usage_error "option $1 requires a value"
[[ $# -ge 2 && "$2" != --* && ! "$2" =~ ^-[a-zA-Z]$ ]] || usage_error "option $1 requires a value (option-like values are rejected)"
LABEL="$2"
shift 2
;;
-m|--milestone)
[[ $# -ge 2 ]] || usage_error "option $1 requires a value"
[[ $# -ge 2 && "$2" != --* && ! "$2" =~ ^-[a-zA-Z]$ ]] || usage_error "option $1 requires a value (option-like values are rejected)"
MILESTONE="$2"
shift 2
;;
-a|--assignee)
[[ $# -ge 2 ]] || usage_error "option $1 requires a value"
[[ $# -ge 2 && "$2" != --* && ! "$2" =~ ^-[a-zA-Z]$ ]] || usage_error "option $1 requires a value (option-like values are rejected)"
ASSIGNEE="$2"
shift 2
;;
-n|--limit)
[[ $# -ge 2 ]] || usage_error "option $1 requires a value"
[[ $# -ge 2 && "$2" != --* && ! "$2" =~ ^-[a-zA-Z]$ ]] || usage_error "option $1 requires a value (option-like values are rejected)"
LIMIT="$2"
shift 2
;;
-r|--repo)
[[ $# -ge 2 ]] || usage_error "option $1 requires a value"
[[ $# -ge 2 && "$2" != --* && ! "$2" =~ ^-[a-zA-Z]$ ]] || usage_error "option $1 requires a value (option-like values are rejected)"
REPO_OVERRIDE="$2"
shift 2
;;
@@ -108,7 +108,9 @@ case "$PLATFORM" in
[[ -n "$LABEL" ]] && CMD+=(--label "$LABEL")
[[ -n "$MILESTONE" ]] && CMD+=(--milestone "$MILESTONE")
[[ -n "$ASSIGNEE" ]] && CMD+=(--assignee "$ASSIGNEE")
"${CMD[@]}"
prov_rc=0
"${CMD[@]}" || prov_rc=$?
[[ "$prov_rc" -eq 0 ]] || { echo "Error: provider command failed (exit ${prov_rc}; provider failure, not a usage error)" >&2; exit 1; }
;;
gitea)
if [[ -n "$REPO_OVERRIDE" ]]; then
@@ -127,7 +129,9 @@ case "$PLATFORM" in
[[ -n "$MILESTONE" ]] && CMD+=(--milestones "$MILESTONE")
# Note: tea may not support assignee filter directly in all versions.
[[ -n "$ASSIGNEE" ]] && echo "Note: Assignee filtering may require manual review for Gitea" >&2
"${CMD[@]}"
prov_rc=0
"${CMD[@]}" || prov_rc=$?
[[ "$prov_rc" -eq 0 ]] || { echo "Error: provider command failed (exit ${prov_rc}; provider failure, not a usage error)" >&2; exit 1; }
;;
*)
echo "Error: Could not detect git platform" >&2