hive-forge: --body-file + piped stdin for pr-create / issue-create / issue-edit (closes #382)

This commit is contained in:
damocles 2026-05-24 14:16:04 +02:00 committed by Mara
parent ba669d2d6c
commit d79b8a0a38

View file

@ -71,6 +71,34 @@ pkgs.writeShellApplication {
fi
}
# Pick a body string from --body, --body-file (with `-` meaning
# stdin), or piped stdin. Exactly one source — passing both
# `--body` and `--body-file` errors out so the caller is
# forced to pick. Shared between pr-create / issue-create /
# issue-edit so the body-input surface stays consistent across
# body-accepting verbs (#382). Falling all the way through
# (no flag, no piped stdin) yields empty; callers that
# require a body check after this returns.
resolve_body() {
local _body="$1"
local _file="$2"
if [ -n "$_body" ] && [ -n "$_file" ]; then
echo "hive-forge: --body and --body-file are mutually exclusive" >&2
exit 1
fi
if [ -n "$_file" ]; then
if [ "$_file" = "-" ]; then
cat
else
cat "$_file"
fi
elif [ -n "$_body" ]; then
printf '%s' "$_body"
elif [ ! -t 0 ]; then
cat
fi
}
cmd_view() {
# view <number> [repo]
# Dump title + body + all comments for an issue or PR.
@ -322,23 +350,29 @@ pkgs.writeShellApplication {
}
cmd_pr_create() {
# pr-create --title <title> --head <branch> [--base <base>] [--body <body>] [--draft] [repo]
# pr-create --title <title> --head <branch> [--base <base>]
# [--body <body> | --body-file <path>] [--draft] [repo]
# Create a pull request. Prints the PR URL on success.
local _title="" _head="" _base="main" _body="" _draft="false" _repo="$HIVE_FORGE_REPO"
# Body sources (priority): --body, --body-file <path> (use `-`
# for stdin), piped stdin (when neither flag is set). Closes
# #382.
local _title="" _head="" _base="main" _body="" _body_file="" _draft="false" _repo="$HIVE_FORGE_REPO"
while [ $# -gt 0 ]; do
case "$1" in
--title) _title="$2"; shift 2 ;;
--head) _head="$2"; shift 2 ;;
--base) _base="$2"; shift 2 ;;
--body) _body="$2"; shift 2 ;;
--draft) _draft="true"; shift ;;
*) _repo="$1"; shift ;;
--title) _title="$2"; shift 2 ;;
--head) _head="$2"; shift 2 ;;
--base) _base="$2"; shift 2 ;;
--body) _body="$2"; shift 2 ;;
--body-file) _body_file="$2"; shift 2 ;;
--draft) _draft="true"; shift ;;
*) _repo="$1"; shift ;;
esac
done
if [ -z "$_title" ] || [ -z "$_head" ]; then
echo "usage: hive-forge pr-create --title <title> --head <branch> [--base <base>] [--body <body>] [--draft] [repo]" >&2
echo "usage: hive-forge pr-create --title <title> --head <branch> [--base <base>] [--body <body> | --body-file <path>] [--draft] [repo]" >&2
exit 1
fi
_body=$(resolve_body "$_body" "$_body_file")
local _payload
_payload=$(jq -n \
--arg title "$_title" \
@ -352,21 +386,27 @@ pkgs.writeShellApplication {
}
cmd_issue_create() {
# issue-create --title <title> [--body <body>] [--assignee <user>] [repo]
# issue-create --title <title> [--body <body> | --body-file <path>]
# [--assignee <user>] [repo]
# Create an issue. Prints the issue URL on success.
local _title="" _body="" _assignee="" _repo="$HIVE_FORGE_REPO"
# Body sources (priority): --body, --body-file <path> (use `-`
# for stdin), piped stdin (when neither flag is set). Closes
# #382.
local _title="" _body="" _body_file="" _assignee="" _repo="$HIVE_FORGE_REPO"
while [ $# -gt 0 ]; do
case "$1" in
--title) _title="$2"; shift 2 ;;
--body) _body="$2"; shift 2 ;;
--assignee) _assignee="$2"; shift 2 ;;
*) _repo="$1"; shift ;;
--title) _title="$2"; shift 2 ;;
--body) _body="$2"; shift 2 ;;
--body-file) _body_file="$2"; shift 2 ;;
--assignee) _assignee="$2"; shift 2 ;;
*) _repo="$1"; shift ;;
esac
done
if [ -z "$_title" ]; then
echo "usage: hive-forge issue-create --title <title> [--body <body>] [--assignee <user>] [repo]" >&2
echo "usage: hive-forge issue-create --title <title> [--body <body> | --body-file <path>] [--assignee <user>] [repo]" >&2
exit 1
fi
_body=$(resolve_body "$_body" "$_body_file")
local _payload
if [ -n "$_assignee" ]; then
_payload=$(jq -n --arg t "$_title" --arg b "$_body" --arg a "$_assignee" \
@ -379,20 +419,28 @@ pkgs.writeShellApplication {
}
cmd_issue_edit() {
# issue-edit <number> [--title <title>] [--body <body>] [--state open|closed] [--milestone <id>] [repo]
# Edit an issue's title, body, state, or milestone. Only provided fields are changed.
if [ $# -lt 1 ]; then echo "usage: hive-forge issue-edit <number> [--title <title>] [--body <body>] [--state open|closed] [--milestone <id>] [repo]" >&2; exit 1; fi
# issue-edit <number> [--title <title>] [--body <body> | --body-file <path>]
# [--state open|closed] [--milestone <id>] [repo]
# Edit an issue's title, body, state, or milestone. Only
# provided fields are changed. Body sources for #382 parity:
# --body, --body-file <path> (use `-` for stdin), or piped
# stdin (only when neither --body nor --body-file is set; the
# partial-update contract still treats unset → "leave body
# alone", so piping nothing is a no-op rather than a clobber).
if [ $# -lt 1 ]; then echo "usage: hive-forge issue-edit <number> [--title <title>] [--body <body> | --body-file <path>] [--state open|closed] [--milestone <id>] [repo]" >&2; exit 1; fi
local _n="$1"; shift
local _title="" _body="" _state="" _milestone="" _repo="$HIVE_FORGE_REPO"
local _title="" _body="" _body_file="" _state="" _milestone="" _repo="$HIVE_FORGE_REPO"
while [ $# -gt 0 ]; do
case "$1" in
--title) _title="$2"; shift 2 ;;
--body) _body="$2"; shift 2 ;;
--body-file) _body_file="$2"; shift 2 ;;
--state) _state="$2"; shift 2 ;;
--milestone) _milestone="$2"; shift 2 ;;
*) _repo="$1"; shift ;;
esac
done
_body=$(resolve_body "$_body" "$_body_file")
local _payload
_payload=$(jq -n \
--arg title "$_title" \