Files
stack/packages/mosaic/framework/tools/git/issue-create.sh
T
Hermes AgentandClaude Opus 5 5394e284bd
ci/woodpecker/pr/ci Pipeline was successful
feat(tools/git): explain tea's misleading user does not exist error
`user does not exist [uid: 0, name: ]` from tea reads as a missing account.
It almost always means a revoked or stale token: `tea login` keeps its own
copy of the token, so rotating the credential store does not update it. The
error points at the account; the cause is the cached credential.

Adds explain_tea_user_does_not_exist() to detect-platform.sh and invokes it
from the three tea-failure fallback paths, each guarded by `declare -F` so
the call site is independent of load order and a no-op if the helper is absent.

Purely additive: stderr only, no control flow, no gate or credential changes.

Verified both directions: the helper emits when sourced, and the guarded call
is a silent no-op (exit 1, no output) when it is not.

Refs #1082

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Amf1Neca162odgcbCWMk1y
2026-08-06 15:39:33 -05:00

168 lines
4.9 KiB
Bash
Executable File

#!/bin/bash
# issue-create.sh - Create issues on Gitea or GitHub
# Usage: issue-create.sh -t "Title" [-b "Body"] [-l "label1,label2"] [-m "milestone"]
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/detect-platform.sh"
# Default values
TITLE=""
BODY=""
LABELS=""
MILESTONE=""
INTERACTIVE=false
# get_remote_host and get_gitea_token are provided by detect-platform.sh
gitea_issue_create_api() {
local host repo token url payload
host=$(get_remote_host) || {
echo "Error: could not determine remote host for API fallback" >&2
return 1
}
repo=$(get_repo_info) || {
echo "Error: could not determine repo owner/name for API fallback" >&2
return 1
}
token=$(get_gitea_token "$host") || {
echo "Error: Gitea token not found for API fallback (set GITEA_TOKEN or configure ~/.git-credentials)" >&2
return 1
}
if [[ -n "$LABELS" || -n "$MILESTONE" ]]; then
echo "Warning: API fallback currently applies title/body only; labels/milestone require authenticated tea setup." >&2
fi
payload=$(TITLE="$TITLE" BODY="$BODY" python3 - <<'PY'
import json
import os
payload = {"title": os.environ["TITLE"]}
body = os.environ.get("BODY", "")
if body:
payload["body"] = body
print(json.dumps(payload))
PY
)
url="https://${host}/api/v1/repos/${repo}/issues"
curl -fsS -X POST \
-H "User-Agent: curl/8" \
-H "Authorization: token ${token}" \
-H "Content-Type: application/json" \
-d "$payload" \
"$url"
}
usage() {
cat <<EOF
Usage: $(basename "$0") [OPTIONS]
Create an issue on the current repository (Gitea or GitHub).
Options:
-t, --title TITLE Issue title (required)
-b, --body BODY Issue body/description
-l, --labels LABELS Comma-separated labels (e.g., "bug,feature")
-m, --milestone NAME Milestone name to assign
-i, --interactive Prompt for missing issue fields
-h, --help Show this help message
Examples:
$(basename "$0") -t "Fix login bug" -l "bug,priority-high"
$(basename "$0") -t "Add dark mode" -b "Implement theme switching" -m "0.2.0"
$(basename "$0") -i
EOF
exit "${1:-1}"
}
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
-t|--title)
TITLE="$2"
shift 2
;;
-b|--body)
BODY="$2"
shift 2
;;
-l|--labels)
LABELS="$2"
shift 2
;;
-m|--milestone)
MILESTONE="$2"
shift 2
;;
-i|--interactive)
INTERACTIVE=true
shift
;;
-h|--help)
usage 0
;;
*)
echo "Unknown option: $1" >&2
usage
;;
esac
done
if [[ "$INTERACTIVE" == true ]]; then
[[ -n "$TITLE" ]] || read -r -p "Issue title: " TITLE
[[ -n "$BODY" ]] || read -r -p "Issue body (optional): " BODY || true
[[ -n "$LABELS" ]] || read -r -p "Labels, comma-separated (optional): " LABELS || true
[[ -n "$MILESTONE" ]] || read -r -p "Milestone (optional): " MILESTONE || true
fi
if [[ -z "$TITLE" ]]; then
echo "Error: Title is required (-t)" >&2
usage
fi
PLATFORM=$(detect_platform)
case "$PLATFORM" in
github)
CMD=(gh issue create --title "$TITLE")
[[ -n "$BODY" ]] && CMD+=(--body "$BODY")
[[ -n "$LABELS" ]] && CMD+=(--label "$LABELS")
[[ -n "$MILESTONE" ]] && CMD+=(--milestone "$MILESTONE")
"${CMD[@]}"
;;
gitea)
if command -v tea >/dev/null 2>&1; then
REPO_SLUG=$(get_repo_slug)
GITEA_LOGIN_NAME=$(get_gitea_login) || {
echo "Warning: could not resolve Gitea login for tea; trying Gitea API fallback..." >&2
gitea_issue_create_api
exit $?
}
if ! get_gitea_authenticated_user "$GITEA_LOGIN_NAME" >/dev/null; then
echo "Warning: Tea authenticated-user validation failed (possible stale user/login); trying Gitea API fallback..." >&2
gitea_issue_create_api
exit $?
fi
REPO_ARGS=(--repo "$REPO_SLUG" --login "$GITEA_LOGIN_NAME")
CMD=(tea issue create "${REPO_ARGS[@]}" --title "$TITLE")
[[ -n "$BODY" ]] && CMD+=(--description "$BODY")
[[ -n "$LABELS" ]] && CMD+=(--labels "$LABELS")
# tea accepts milestone by name directly (verified 2026-02-05)
[[ -n "$MILESTONE" ]] && CMD+=(--milestone "$MILESTONE")
if "${CMD[@]}"; then
exit 0
fi
echo "Warning: tea issue create failed, trying Gitea API fallback..." >&2
declare -F explain_tea_user_does_not_exist >/dev/null && explain_tea_user_does_not_exist
fi
gitea_issue_create_api
;;
*)
echo "Error: Could not detect git platform" >&2
exit 1
;;
esac