framework tools/git: R3 --body-file across all nine body/comment carriers
ci/woodpecker/pr/ci Pipeline is running
ci/woodpecker/pr/ci Pipeline is running
--body-file <path> and --body-file - (stdin) load the body/comment from a file, killing the fragile shell-quoting class for long Markdown (Jason remediation R3). Contract: mutually exclusive with --body (rc 2), unreadable file rc 2 naming the path, resolution runs AFTER parsing and BEFORE the required-value checks. Full arm set on the issue-comment suite (file, stdin, exclusive, missing); all nine carrier suites and the readback suite green. Mirrored to brain.
This commit is contained in:
@@ -12,6 +12,7 @@ source "$SCRIPT_DIR/detect-platform.sh"
|
|||||||
# Parse arguments
|
# Parse arguments
|
||||||
ISSUE_NUMBER=""
|
ISSUE_NUMBER=""
|
||||||
COMMENT=""
|
COMMENT=""
|
||||||
|
BODY_FILE=""
|
||||||
|
|
||||||
# Usage-error contract (R4, 2026-08-28): usage errors print to STDERR and exit 2,
|
# Usage-error contract (R4, 2026-08-28): usage errors print to STDERR and exit 2,
|
||||||
# distinct from provider, credential, and verification failures (exit 1), so a
|
# distinct from provider, credential, and verification failures (exit 1), so a
|
||||||
@@ -36,6 +37,12 @@ while [[ $# -gt 0 ]]; do
|
|||||||
COMMENT="$2"
|
COMMENT="$2"
|
||||||
shift 2
|
shift 2
|
||||||
;;
|
;;
|
||||||
|
--body-file)
|
||||||
|
# R3: body from file (or '-' = stdin); mutually exclusive with --body.
|
||||||
|
[[ $# -ge 2 && "$2" != --* ]] || usage_error "option $1 requires a path (or - for stdin)"
|
||||||
|
BODY_FILE="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
-h|--help)
|
-h|--help)
|
||||||
echo "Usage: issue-close.sh -i <issue_number> [-b <comment>]"
|
echo "Usage: issue-close.sh -i <issue_number> [-b <comment>]"
|
||||||
echo ""
|
echo ""
|
||||||
@@ -54,6 +61,19 @@ while [[ $# -gt 0 ]]; do
|
|||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# R3 (2026-08-29): resolve --body-file into COMMENT (file or stdin '-');
|
||||||
|
# exclusive with an explicit --body/--comment value.
|
||||||
|
if [[ -n "$BODY_FILE" ]]; then
|
||||||
|
[[ -z "$COMMENT" ]] || usage_error "--body-file and --body are mutually exclusive"
|
||||||
|
if [[ "$BODY_FILE" == "-" ]]; then
|
||||||
|
COMMENT=$(cat) || usage_error "could not read body from stdin"
|
||||||
|
else
|
||||||
|
[[ -r "$BODY_FILE" ]] || usage_error "body file not readable: $BODY_FILE"
|
||||||
|
COMMENT=$(cat "$BODY_FILE") || usage_error "could not read body file: $BODY_FILE"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
if [[ -z "$ISSUE_NUMBER" ]]; then
|
if [[ -z "$ISSUE_NUMBER" ]]; then
|
||||||
usage_error "issue number is required (-i/--issue)"
|
usage_error "issue number is required (-i/--issue)"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ source "$SCRIPT_DIR/detect-platform.sh"
|
|||||||
# Parse arguments
|
# Parse arguments
|
||||||
ISSUE_NUMBER=""
|
ISSUE_NUMBER=""
|
||||||
COMMENT=""
|
COMMENT=""
|
||||||
|
BODY_FILE=""
|
||||||
LOGIN_OVERRIDE=""
|
LOGIN_OVERRIDE=""
|
||||||
|
|
||||||
# Usage-error contract (R4, 2026-08-28): usage errors print to STDERR and exit 2,
|
# Usage-error contract (R4, 2026-08-28): usage errors print to STDERR and exit 2,
|
||||||
@@ -58,6 +59,12 @@ while [[ $# -gt 0 ]]; do
|
|||||||
COMMENT="$2"
|
COMMENT="$2"
|
||||||
shift 2
|
shift 2
|
||||||
;;
|
;;
|
||||||
|
--body-file)
|
||||||
|
# R3: body from file (or '-' = stdin); mutually exclusive with --body.
|
||||||
|
[[ $# -ge 2 && "$2" != --* ]] || usage_error "option $1 requires a path (or - for stdin)"
|
||||||
|
BODY_FILE="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
-l|--login)
|
-l|--login)
|
||||||
[[ $# -ge 2 && "$2" != - && "$2" != --* && ! "$2" =~ ^-[[:alnum:]] ]] || usage_error "option $1 requires a value (option-like values are rejected; bare - is reserved)"
|
[[ $# -ge 2 && "$2" != - && "$2" != --* && ! "$2" =~ ^-[[:alnum:]] ]] || usage_error "option $1 requires a value (option-like values are rejected; bare - is reserved)"
|
||||||
LOGIN_OVERRIDE="$2"
|
LOGIN_OVERRIDE="$2"
|
||||||
@@ -82,6 +89,19 @@ while [[ $# -gt 0 ]]; do
|
|||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# R3 (2026-08-29): resolve --body-file into COMMENT (file or stdin '-');
|
||||||
|
# exclusive with an explicit --body/--comment value.
|
||||||
|
if [[ -n "$BODY_FILE" ]]; then
|
||||||
|
[[ -z "$COMMENT" ]] || usage_error "--body-file and --body are mutually exclusive"
|
||||||
|
if [[ "$BODY_FILE" == "-" ]]; then
|
||||||
|
COMMENT=$(cat) || usage_error "could not read body from stdin"
|
||||||
|
else
|
||||||
|
[[ -r "$BODY_FILE" ]] || usage_error "body file not readable: $BODY_FILE"
|
||||||
|
COMMENT=$(cat "$BODY_FILE") || usage_error "could not read body file: $BODY_FILE"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
if [[ -z "$ISSUE_NUMBER" ]]; then
|
if [[ -z "$ISSUE_NUMBER" ]]; then
|
||||||
usage_error "issue number is required (-i/--issue)"
|
usage_error "issue number is required (-i/--issue)"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ source "$SCRIPT_DIR/detect-platform.sh"
|
|||||||
# Default values
|
# Default values
|
||||||
TITLE=""
|
TITLE=""
|
||||||
BODY=""
|
BODY=""
|
||||||
|
BODY_FILE=""
|
||||||
LABELS=""
|
LABELS=""
|
||||||
MILESTONE=""
|
MILESTONE=""
|
||||||
INTERACTIVE=false
|
INTERACTIVE=false
|
||||||
@@ -100,6 +101,12 @@ while [[ $# -gt 0 ]]; do
|
|||||||
BODY="$2"
|
BODY="$2"
|
||||||
shift 2
|
shift 2
|
||||||
;;
|
;;
|
||||||
|
--body-file)
|
||||||
|
# R3: body from file (or '-' = stdin); mutually exclusive with --body.
|
||||||
|
[[ $# -ge 2 && "$2" != --* ]] || usage_error "option $1 requires a path (or - for stdin)"
|
||||||
|
BODY_FILE="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
-l|--labels)
|
-l|--labels)
|
||||||
[[ $# -ge 2 && "$2" != - && "$2" != --* && ! "$2" =~ ^-[[:alnum:]] ]] || usage_error "option $1 requires a value (option-like values are rejected; bare - is reserved)"
|
[[ $# -ge 2 && "$2" != - && "$2" != --* && ! "$2" =~ ^-[[:alnum:]] ]] || usage_error "option $1 requires a value (option-like values are rejected; bare - is reserved)"
|
||||||
LABELS="$2"
|
LABELS="$2"
|
||||||
@@ -124,6 +131,19 @@ while [[ $# -gt 0 ]]; do
|
|||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# R3 (2026-08-29): resolve --body-file into BODY (file or stdin '-');
|
||||||
|
# exclusive with an explicit --body/--comment value.
|
||||||
|
if [[ -n "$BODY_FILE" ]]; then
|
||||||
|
[[ -z "$BODY" ]] || usage_error "--body-file and --body are mutually exclusive"
|
||||||
|
if [[ "$BODY_FILE" == "-" ]]; then
|
||||||
|
BODY=$(cat) || usage_error "could not read body from stdin"
|
||||||
|
else
|
||||||
|
[[ -r "$BODY_FILE" ]] || usage_error "body file not readable: $BODY_FILE"
|
||||||
|
BODY=$(cat "$BODY_FILE") || usage_error "could not read body file: $BODY_FILE"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
if [[ "$INTERACTIVE" == true ]]; then
|
if [[ "$INTERACTIVE" == true ]]; then
|
||||||
[[ -n "$TITLE" ]] || read -r -p "Issue title: " TITLE
|
[[ -n "$TITLE" ]] || read -r -p "Issue title: " TITLE
|
||||||
[[ -n "$BODY" ]] || read -r -p "Issue body (optional): " BODY || true
|
[[ -n "$BODY" ]] || read -r -p "Issue body (optional): " BODY || true
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ source "$SCRIPT_DIR/detect-platform.sh"
|
|||||||
ISSUE_NUMBER=""
|
ISSUE_NUMBER=""
|
||||||
TITLE=""
|
TITLE=""
|
||||||
BODY=""
|
BODY=""
|
||||||
|
BODY_FILE=""
|
||||||
LABELS=""
|
LABELS=""
|
||||||
MILESTONE=""
|
MILESTONE=""
|
||||||
|
|
||||||
@@ -40,6 +41,12 @@ while [[ $# -gt 0 ]]; do
|
|||||||
BODY="$2"
|
BODY="$2"
|
||||||
shift 2
|
shift 2
|
||||||
;;
|
;;
|
||||||
|
--body-file)
|
||||||
|
# R3: body from file (or '-' = stdin); mutually exclusive with --body.
|
||||||
|
[[ $# -ge 2 && "$2" != --* ]] || usage_error "option $1 requires a path (or - for stdin)"
|
||||||
|
BODY_FILE="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
-l|--labels)
|
-l|--labels)
|
||||||
[[ $# -ge 2 && "$2" != - && "$2" != --* && ! "$2" =~ ^-[[:alnum:]] ]] || usage_error "option $1 requires a value (option-like values are rejected; bare - is reserved)"
|
[[ $# -ge 2 && "$2" != - && "$2" != --* && ! "$2" =~ ^-[[:alnum:]] ]] || usage_error "option $1 requires a value (option-like values are rejected; bare - is reserved)"
|
||||||
LABELS="$2"
|
LABELS="$2"
|
||||||
@@ -70,6 +77,19 @@ while [[ $# -gt 0 ]]; do
|
|||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# R3 (2026-08-29): resolve --body-file into BODY (file or stdin '-');
|
||||||
|
# exclusive with an explicit --body/--comment value.
|
||||||
|
if [[ -n "$BODY_FILE" ]]; then
|
||||||
|
[[ -z "$BODY" ]] || usage_error "--body-file and --body are mutually exclusive"
|
||||||
|
if [[ "$BODY_FILE" == "-" ]]; then
|
||||||
|
BODY=$(cat) || usage_error "could not read body from stdin"
|
||||||
|
else
|
||||||
|
[[ -r "$BODY_FILE" ]] || usage_error "body file not readable: $BODY_FILE"
|
||||||
|
BODY=$(cat "$BODY_FILE") || usage_error "could not read body file: $BODY_FILE"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
if [[ -z "$ISSUE_NUMBER" ]]; then
|
if [[ -z "$ISSUE_NUMBER" ]]; then
|
||||||
usage_error "issue number is required (-i/--issue)"
|
usage_error "issue number is required (-i/--issue)"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ source "$SCRIPT_DIR/detect-platform.sh"
|
|||||||
# Parse arguments
|
# Parse arguments
|
||||||
ISSUE_NUMBER=""
|
ISSUE_NUMBER=""
|
||||||
COMMENT=""
|
COMMENT=""
|
||||||
|
BODY_FILE=""
|
||||||
|
|
||||||
# Usage-error contract (R4, 2026-08-28): usage errors print to STDERR and exit 2,
|
# Usage-error contract (R4, 2026-08-28): usage errors print to STDERR and exit 2,
|
||||||
# distinct from provider, credential, and verification failures (exit 1), so a
|
# distinct from provider, credential, and verification failures (exit 1), so a
|
||||||
@@ -35,6 +36,12 @@ while [[ $# -gt 0 ]]; do
|
|||||||
COMMENT="$2"
|
COMMENT="$2"
|
||||||
shift 2
|
shift 2
|
||||||
;;
|
;;
|
||||||
|
--body-file)
|
||||||
|
# R3: body from file (or '-' = stdin); mutually exclusive with --body.
|
||||||
|
[[ $# -ge 2 && "$2" != --* ]] || usage_error "option $1 requires a path (or - for stdin)"
|
||||||
|
BODY_FILE="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
-h|--help)
|
-h|--help)
|
||||||
echo "Usage: issue-reopen.sh -i <issue_number> [-b <comment>]"
|
echo "Usage: issue-reopen.sh -i <issue_number> [-b <comment>]"
|
||||||
echo ""
|
echo ""
|
||||||
@@ -53,6 +60,19 @@ while [[ $# -gt 0 ]]; do
|
|||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# R3 (2026-08-29): resolve --body-file into COMMENT (file or stdin '-');
|
||||||
|
# exclusive with an explicit --body/--comment value.
|
||||||
|
if [[ -n "$BODY_FILE" ]]; then
|
||||||
|
[[ -z "$COMMENT" ]] || usage_error "--body-file and --body are mutually exclusive"
|
||||||
|
if [[ "$BODY_FILE" == "-" ]]; then
|
||||||
|
COMMENT=$(cat) || usage_error "could not read body from stdin"
|
||||||
|
else
|
||||||
|
[[ -r "$BODY_FILE" ]] || usage_error "body file not readable: $BODY_FILE"
|
||||||
|
COMMENT=$(cat "$BODY_FILE") || usage_error "could not read body file: $BODY_FILE"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
if [[ -z "$ISSUE_NUMBER" ]]; then
|
if [[ -z "$ISSUE_NUMBER" ]]; then
|
||||||
usage_error "issue number is required (-i/--issue)"
|
usage_error "issue number is required (-i/--issue)"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ source "$SCRIPT_DIR/detect-platform.sh"
|
|||||||
# Parse arguments
|
# Parse arguments
|
||||||
PR_NUMBER=""
|
PR_NUMBER=""
|
||||||
COMMENT=""
|
COMMENT=""
|
||||||
|
BODY_FILE=""
|
||||||
|
|
||||||
# Usage-error contract (R4, 2026-08-28): usage errors print to STDERR and exit 2,
|
# Usage-error contract (R4, 2026-08-28): usage errors print to STDERR and exit 2,
|
||||||
# distinct from provider, credential, and verification failures (exit 1), so a
|
# distinct from provider, credential, and verification failures (exit 1), so a
|
||||||
@@ -35,6 +36,12 @@ while [[ $# -gt 0 ]]; do
|
|||||||
COMMENT="$2"
|
COMMENT="$2"
|
||||||
shift 2
|
shift 2
|
||||||
;;
|
;;
|
||||||
|
--body-file)
|
||||||
|
# R3: body from file (or '-' = stdin); mutually exclusive with --body.
|
||||||
|
[[ $# -ge 2 && "$2" != --* ]] || usage_error "option $1 requires a path (or - for stdin)"
|
||||||
|
BODY_FILE="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
-h|--help)
|
-h|--help)
|
||||||
echo "Usage: pr-close.sh -n <pr_number> [-b <comment>]"
|
echo "Usage: pr-close.sh -n <pr_number> [-b <comment>]"
|
||||||
echo ""
|
echo ""
|
||||||
@@ -53,6 +60,19 @@ while [[ $# -gt 0 ]]; do
|
|||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# R3 (2026-08-29): resolve --body-file into COMMENT (file or stdin '-');
|
||||||
|
# exclusive with an explicit --body/--comment value.
|
||||||
|
if [[ -n "$BODY_FILE" ]]; then
|
||||||
|
[[ -z "$COMMENT" ]] || usage_error "--body-file and --body are mutually exclusive"
|
||||||
|
if [[ "$BODY_FILE" == "-" ]]; then
|
||||||
|
COMMENT=$(cat) || usage_error "could not read body from stdin"
|
||||||
|
else
|
||||||
|
[[ -r "$BODY_FILE" ]] || usage_error "body file not readable: $BODY_FILE"
|
||||||
|
COMMENT=$(cat "$BODY_FILE") || usage_error "could not read body file: $BODY_FILE"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
if [[ -z "$PR_NUMBER" ]]; then
|
if [[ -z "$PR_NUMBER" ]]; then
|
||||||
usage_error "PR number is required (-n/--number)"
|
usage_error "PR number is required (-n/--number)"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ source "$SCRIPT_DIR/detect-platform.sh"
|
|||||||
# Default values
|
# Default values
|
||||||
TITLE=""
|
TITLE=""
|
||||||
BODY=""
|
BODY=""
|
||||||
|
BODY_FILE=""
|
||||||
BASE_BRANCH=""
|
BASE_BRANCH=""
|
||||||
HEAD_BRANCH=""
|
HEAD_BRANCH=""
|
||||||
LABELS=""
|
LABELS=""
|
||||||
@@ -158,6 +159,12 @@ while [[ $# -gt 0 ]]; do
|
|||||||
BODY="$2"
|
BODY="$2"
|
||||||
shift 2
|
shift 2
|
||||||
;;
|
;;
|
||||||
|
--body-file)
|
||||||
|
# R3: body from file (or '-' = stdin); mutually exclusive with --body.
|
||||||
|
[[ $# -ge 2 && "$2" != --* ]] || usage_error "option $1 requires a path (or - for stdin)"
|
||||||
|
BODY_FILE="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
-B|--base)
|
-B|--base)
|
||||||
[[ $# -ge 2 && "$2" != - && "$2" != --* && ! "$2" =~ ^-[[:alnum:]] ]] || usage_error "option $1 requires a value (option-like values are rejected; bare - is reserved)"
|
[[ $# -ge 2 && "$2" != - && "$2" != --* && ! "$2" =~ ^-[[:alnum:]] ]] || usage_error "option $1 requires a value (option-like values are rejected; bare - is reserved)"
|
||||||
BASE_BRANCH="$2"
|
BASE_BRANCH="$2"
|
||||||
@@ -197,6 +204,19 @@ while [[ $# -gt 0 ]]; do
|
|||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# R3 (2026-08-29): resolve --body-file into BODY (file or stdin '-');
|
||||||
|
# exclusive with an explicit --body/--comment value.
|
||||||
|
if [[ -n "$BODY_FILE" ]]; then
|
||||||
|
[[ -z "$BODY" ]] || usage_error "--body-file and --body are mutually exclusive"
|
||||||
|
if [[ "$BODY_FILE" == "-" ]]; then
|
||||||
|
BODY=$(cat) || usage_error "could not read body from stdin"
|
||||||
|
else
|
||||||
|
[[ -r "$BODY_FILE" ]] || usage_error "body file not readable: $BODY_FILE"
|
||||||
|
BODY=$(cat "$BODY_FILE") || usage_error "could not read body file: $BODY_FILE"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
# If no title but issue provided, generate title
|
# If no title but issue provided, generate title
|
||||||
if [[ -z "$TITLE" ]] && [[ -n "$ISSUE" ]]; then
|
if [[ -z "$TITLE" ]] && [[ -n "$ISSUE" ]]; then
|
||||||
TITLE="Fixes #$ISSUE"
|
TITLE="Fixes #$ISSUE"
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ source "$SCRIPT_DIR/detect-platform.sh"
|
|||||||
PR_NUMBER=""
|
PR_NUMBER=""
|
||||||
TITLE=""
|
TITLE=""
|
||||||
BODY=""
|
BODY=""
|
||||||
|
BODY_FILE=""
|
||||||
BASE_BRANCH=""
|
BASE_BRANCH=""
|
||||||
DRAFT_MODE=""
|
DRAFT_MODE=""
|
||||||
LOGIN_OVERRIDE=""
|
LOGIN_OVERRIDE=""
|
||||||
@@ -65,6 +66,7 @@ while [[ $# -gt 0 ]]; do
|
|||||||
-n|--number) [[ $# -ge 2 && "$2" != - && "$2" != --* && ! "$2" =~ ^-[[:alnum:]] ]] || usage_error "option $1 requires a value (option-like values are rejected; bare - is reserved)"; PR_NUMBER="${2:-}"; shift 2 ;;
|
-n|--number) [[ $# -ge 2 && "$2" != - && "$2" != --* && ! "$2" =~ ^-[[:alnum:]] ]] || usage_error "option $1 requires a value (option-like values are rejected; bare - is reserved)"; PR_NUMBER="${2:-}"; shift 2 ;;
|
||||||
-t|--title) [[ $# -ge 2 && "$2" != - && "$2" != --* && ! "$2" =~ ^-[[:alnum:]] ]] || usage_error "option $1 requires a value (option-like values are rejected; bare - is reserved)"; TITLE="${2:-}"; shift 2 ;;
|
-t|--title) [[ $# -ge 2 && "$2" != - && "$2" != --* && ! "$2" =~ ^-[[:alnum:]] ]] || usage_error "option $1 requires a value (option-like values are rejected; bare - is reserved)"; TITLE="${2:-}"; shift 2 ;;
|
||||||
-b|--body) [[ $# -ge 2 && "$2" != - && "$2" != --* && ! "$2" =~ ^-[[:alnum:]] ]] || usage_error "option $1 requires a value (option-like values are rejected; bare - is reserved)"; BODY="${2:-}"; shift 2 ;;
|
-b|--body) [[ $# -ge 2 && "$2" != - && "$2" != --* && ! "$2" =~ ^-[[:alnum:]] ]] || usage_error "option $1 requires a value (option-like values are rejected; bare - is reserved)"; BODY="${2:-}"; shift 2 ;;
|
||||||
|
--body-file) [[ $# -ge 2 && "$2" != --* ]] || usage_error "option $1 requires a path (or - for stdin)"; BODY_FILE="$2"; shift 2 ;;
|
||||||
-B|--base) [[ $# -ge 2 && "$2" != - && "$2" != --* && ! "$2" =~ ^-[[:alnum:]] ]] || usage_error "option $1 requires a value (option-like values are rejected; bare - is reserved)"; BASE_BRANCH="${2:-}"; shift 2 ;;
|
-B|--base) [[ $# -ge 2 && "$2" != - && "$2" != --* && ! "$2" =~ ^-[[:alnum:]] ]] || usage_error "option $1 requires a value (option-like values are rejected; bare - is reserved)"; BASE_BRANCH="${2:-}"; shift 2 ;;
|
||||||
--draft)
|
--draft)
|
||||||
[[ "$DRAFT_MODE" != "ready" ]] || { echo "Error: --draft and --ready are mutually exclusive" >&2; exit 2; }
|
[[ "$DRAFT_MODE" != "ready" ]] || { echo "Error: --draft and --ready are mutually exclusive" >&2; exit 2; }
|
||||||
@@ -80,6 +82,19 @@ while [[ $# -gt 0 ]]; do
|
|||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# R3 (2026-08-29): resolve --body-file into BODY (file or stdin '-');
|
||||||
|
# exclusive with an explicit --body value.
|
||||||
|
if [[ -n "$BODY_FILE" ]]; then
|
||||||
|
[[ -z "$BODY" ]] || usage_error "--body-file and --body are mutually exclusive"
|
||||||
|
if [[ "$BODY_FILE" == "-" ]]; then
|
||||||
|
BODY=$(cat) || usage_error "could not read body from stdin"
|
||||||
|
else
|
||||||
|
[[ -r "$BODY_FILE" ]] || usage_error "body file not readable: $BODY_FILE"
|
||||||
|
BODY=$(cat "$BODY_FILE") || usage_error "could not read body file: $BODY_FILE"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
[[ -n "$PR_NUMBER" ]] || { echo "Error: Pull request number is required (-n)" >&2; exit 2; }
|
[[ -n "$PR_NUMBER" ]] || { echo "Error: Pull request number is required (-n)" >&2; exit 2; }
|
||||||
[[ "$PR_NUMBER" =~ ^[1-9][0-9]*$ ]] || { echo "Error: Pull request number must be a positive integer" >&2; exit 2; }
|
[[ "$PR_NUMBER" =~ ^[1-9][0-9]*$ ]] || { echo "Error: Pull request number must be a positive integer" >&2; exit 2; }
|
||||||
if [[ -z "$TITLE" && -z "$BODY" && -z "$BASE_BRANCH" && -z "$DRAFT_MODE" ]]; then
|
if [[ -z "$TITLE" && -z "$BODY" && -z "$BASE_BRANCH" && -z "$DRAFT_MODE" ]]; then
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ source "$SCRIPT_DIR/detect-platform.sh"
|
|||||||
PR_NUMBER=""
|
PR_NUMBER=""
|
||||||
ACTION=""
|
ACTION=""
|
||||||
COMMENT=""
|
COMMENT=""
|
||||||
|
BODY_FILE=""
|
||||||
LOGIN_OVERRIDE=""
|
LOGIN_OVERRIDE=""
|
||||||
REPO_OVERRIDE=""
|
REPO_OVERRIDE=""
|
||||||
HOST_OVERRIDE=""
|
HOST_OVERRIDE=""
|
||||||
@@ -71,6 +72,12 @@ while [[ $# -gt 0 ]]; do
|
|||||||
COMMENT="$2"
|
COMMENT="$2"
|
||||||
shift 2
|
shift 2
|
||||||
;;
|
;;
|
||||||
|
--body-file)
|
||||||
|
# R3: body from file (or '-' = stdin); mutually exclusive with --body.
|
||||||
|
[[ $# -ge 2 && "$2" != --* ]] || usage_error "option $1 requires a path (or - for stdin)"
|
||||||
|
BODY_FILE="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
-l|--login)
|
-l|--login)
|
||||||
[[ $# -ge 2 && "$2" != - && "$2" != --* && ! "$2" =~ ^-[[:alnum:]] ]] || usage_error "option $1 requires a value (option-like values are rejected; bare - is reserved)"
|
[[ $# -ge 2 && "$2" != - && "$2" != --* && ! "$2" =~ ^-[[:alnum:]] ]] || usage_error "option $1 requires a value (option-like values are rejected; bare - is reserved)"
|
||||||
LOGIN_OVERRIDE="$2"
|
LOGIN_OVERRIDE="$2"
|
||||||
@@ -108,6 +115,19 @@ while [[ $# -gt 0 ]]; do
|
|||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# R3 (2026-08-29): resolve --body-file into COMMENT (file or stdin '-');
|
||||||
|
# exclusive with an explicit --body/--comment value.
|
||||||
|
if [[ -n "$BODY_FILE" ]]; then
|
||||||
|
[[ -z "$COMMENT" ]] || usage_error "--body-file and --body are mutually exclusive"
|
||||||
|
if [[ "$BODY_FILE" == "-" ]]; then
|
||||||
|
COMMENT=$(cat) || usage_error "could not read body from stdin"
|
||||||
|
else
|
||||||
|
[[ -r "$BODY_FILE" ]] || usage_error "body file not readable: $BODY_FILE"
|
||||||
|
COMMENT=$(cat "$BODY_FILE") || usage_error "could not read body file: $BODY_FILE"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
if [[ -z "$PR_NUMBER" ]]; then
|
if [[ -z "$PR_NUMBER" ]]; then
|
||||||
usage_error "PR number is required (-n/--number)"
|
usage_error "PR number is required (-n/--number)"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -161,6 +161,30 @@ rc=0
|
|||||||
grep -q "GitHub comment write failed" "$ERR_FILE" || fail "GitHub path: normalized error missing from stderr"
|
grep -q "GitHub comment write failed" "$ERR_FILE" || fail "GitHub path: normalized error missing from stderr"
|
||||||
grep -q "^gh issue comment" "$PROBE_LOG" || fail "GitHub path: gh write was not invoked"
|
grep -q "^gh issue comment" "$PROBE_LOG" || fail "GitHub path: gh write was not invoked"
|
||||||
|
|
||||||
|
# R3 body-file arms (2026-08-29): --body-file <path> and '-' (stdin).
|
||||||
|
BF_FILE="$WORK_DIR/body.md"
|
||||||
|
printf 'line one\nline two\n' > "$BF_FILE"
|
||||||
|
|
||||||
|
# File loads the body: parse acceptance then credential-class failure
|
||||||
|
# (sandboxed runner: rc nonzero and NOT 2).
|
||||||
|
rc=0
|
||||||
|
run_wrapper_sandboxed -i 5 --body-file "$BF_FILE" >"$OUT_FILE" 2>"$ERR_FILE" || rc=$?
|
||||||
|
[[ "$rc" -ne 0 ]] || fail "body-file arm unexpectedly succeeded in the sandbox"
|
||||||
|
[[ "$rc" -ne 2 ]] || fail "body-file arm misclassified credential failure as a usage error"
|
||||||
|
|
||||||
|
# Stdin form loads the body the same way.
|
||||||
|
rc=0
|
||||||
|
printf 'from stdin' | run_wrapper_sandboxed -i 5 --body-file - >"$OUT_FILE" 2>"$ERR_FILE" || rc=$?
|
||||||
|
[[ "$rc" -ne 0 && "$rc" -ne 2 ]] || fail "body-file stdin arm rc=$rc (want nonzero, not 2)"
|
||||||
|
|
||||||
|
# Mutually exclusive with --body: rc 2.
|
||||||
|
expect_rc 2 "body-file + body exclusive" -i 5 --body-file "$BF_FILE" -b explicit
|
||||||
|
expect_stderr "mutually exclusive" "exclusivity message on stderr"
|
||||||
|
|
||||||
|
# Missing file: rc 2 naming the path.
|
||||||
|
expect_rc 2 "missing body file" -i 5 --body-file "$WORK_DIR/nope.md"
|
||||||
|
expect_stderr "not readable" "missing-file message on stderr"
|
||||||
|
|
||||||
# 7. No provider contact from any usage-error arm (arm 6b's deliberate gh
|
# 7. No provider contact from any usage-error arm (arm 6b's deliberate gh
|
||||||
# invocation is the only permitted entry in the probe log).
|
# invocation is the only permitted entry in the probe log).
|
||||||
if grep -v '^gh issue comment' "$PROBE_LOG" | grep -q .; then
|
if grep -v '^gh issue comment' "$PROBE_LOG" | grep -q .; then
|
||||||
|
|||||||
Reference in New Issue
Block a user