chore: consolidate new foundation and archive v1 (#1495)
This commit is contained in:
+147
@@ -0,0 +1,147 @@
|
||||
#!/bin/bash
|
||||
# issue-view.sh - View issue details, including comments, on GitHub or Gitea
|
||||
# Usage: issue-view.sh -i <issue_number>
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "$SCRIPT_DIR/detect-platform.sh"
|
||||
|
||||
# Parse arguments
|
||||
# Usage-error contract (R4, 2026-08-28): usage errors print to STDERR and exit 2,
|
||||
# distinct from provider, credential, and verification failures (exit 1).
|
||||
usage_error() {
|
||||
echo "Error: $*" >&2
|
||||
echo "Usage: issue-view.sh -i <issue_number> (see --help)" >&2
|
||||
exit 2
|
||||
}
|
||||
|
||||
ISSUE_NUMBER=""
|
||||
|
||||
# get_remote_host and get_gitea_token are provided by detect-platform.sh
|
||||
|
||||
gitea_issue_view_api() {
|
||||
local host repo token url
|
||||
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
|
||||
}
|
||||
|
||||
url="https://${host}/api/v1/repos/${repo}/issues/${ISSUE_NUMBER}"
|
||||
local -a curl_args=(-fsS -H "User-Agent: curl/8" -H "Authorization: token ${token}")
|
||||
if ! command -v python3 >/dev/null 2>&1; then
|
||||
# No renderer: raw JSON is all this path can give. Comments are a
|
||||
# second resource, so fetch them too rather than only the count.
|
||||
curl "${curl_args[@]}" "$url"
|
||||
curl "${curl_args[@]}" "${url}/comments"
|
||||
return
|
||||
fi
|
||||
# Render issue + comments as text (#1357 F2). The old fallback dumped the
|
||||
# issue JSON, which carries only a comment COUNT, so every comment body was
|
||||
# invisible on this path and the wrapper could never show what
|
||||
# `tea issues --comments` shows.
|
||||
{
|
||||
curl "${curl_args[@]}" "$url"
|
||||
echo
|
||||
echo "__MOSAIC_COMMENTS__"
|
||||
curl "${curl_args[@]}" "${url}/comments"
|
||||
} | python3 -c '
|
||||
import json, sys
|
||||
raw = sys.stdin.read()
|
||||
issue_raw, _, comments_raw = raw.partition("__MOSAIC_COMMENTS__")
|
||||
issue = json.loads(issue_raw)
|
||||
comments = json.loads(comments_raw) if comments_raw.strip() else []
|
||||
print("#%s %s" % (issue["number"], issue["title"]))
|
||||
print("State: %s Author: %s Created: %s" % (issue["state"], issue["user"]["login"], issue["created_at"]))
|
||||
labels = ", ".join(l["name"] for l in issue.get("labels") or [])
|
||||
if labels:
|
||||
print("Labels: " + labels)
|
||||
if issue.get("milestone"):
|
||||
print("Milestone: " + issue["milestone"]["title"])
|
||||
print("URL: " + issue["html_url"])
|
||||
print()
|
||||
print(issue.get("body") or "(no body)")
|
||||
if comments:
|
||||
print()
|
||||
print("--- Comments (%d) ---" % len(comments))
|
||||
for c in comments:
|
||||
print()
|
||||
print("[%s at %s]" % (c["user"]["login"], c["created_at"]))
|
||||
print(c.get("body") or "")
|
||||
'
|
||||
}
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
-i|--issue|--number)
|
||||
[[ $# -ge 2 && "$2" != - && "$2" != --* && ! "$2" =~ ^-[[:alnum:]] ]] || usage_error "option $1 requires a value (option-like values are rejected; bare - is reserved)"
|
||||
ISSUE_NUMBER="$2"
|
||||
shift 2
|
||||
;;
|
||||
-h|--help)
|
||||
echo "Usage: issue-view.sh -i <issue_number>"
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo " -n, --number Issue number (required; canonical)"
|
||||
echo " -i, --issue Alias for --number"
|
||||
echo ""
|
||||
echo "Comments are always included (tea --comments / Gitea API /comments)."
|
||||
echo " -h, --help Show this help"
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
usage_error "unknown option: $1"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -z "$ISSUE_NUMBER" ]]; then
|
||||
usage_error "Issue number is required"
|
||||
fi
|
||||
|
||||
detect_platform >/dev/null
|
||||
|
||||
if [[ "$PLATFORM" == "github" ]]; then
|
||||
prov_rc=0
|
||||
gh issue view "$ISSUE_NUMBER" || prov_rc=$?
|
||||
[[ "$prov_rc" -eq 0 ]] || { echo "Error: provider command failed (exit ${prov_rc}; provider failure, not a usage error)" >&2; exit 1; }
|
||||
elif [[ "$PLATFORM" == "gitea" ]]; then
|
||||
if command -v tea >/dev/null 2>&1; then
|
||||
# --comments is what makes tea print the comment bodies (#1357 F3).
|
||||
# Without it tea prompts for them interactively, which in a
|
||||
# non-interactive wrapper means they are silently never shown.
|
||||
tea_err=$(mktemp)
|
||||
if tea issue "$ISSUE_NUMBER" $(get_gitea_repo_args) --comments 2>"$tea_err"; then
|
||||
rm -f "$tea_err"
|
||||
exit 0
|
||||
fi
|
||||
# Name the cause tea actually reported, not a guessed one (#1357 F1/F4).
|
||||
# tea reads the cwd's git config before honouring --repo; a repo with
|
||||
# extensions.worktreeconfig=true makes it exit 1 with a
|
||||
# repositoryformatversion error. That is a git-config condition, not a
|
||||
# credential one. The old path printed the REVOKED OR STALE TOKEN note
|
||||
# here unconditionally, which sent readers to rotate a token that was fine.
|
||||
if grep -q 'repositoryformatversion' "$tea_err"; then
|
||||
echo "Warning: tea cannot read this repo's git config (extensions.worktreeconfig); not a credential problem. Using Gitea API fallback." >&2
|
||||
elif grep -q 'user does not exist' "$tea_err"; then
|
||||
echo "Warning: tea issue view failed, trying Gitea API fallback..." >&2
|
||||
{ declare -F explain_tea_user_does_not_exist >/dev/null && explain_tea_user_does_not_exist; } || true
|
||||
else
|
||||
echo "Warning: tea issue view failed, trying Gitea API fallback..." >&2
|
||||
fi
|
||||
sed 's/^/ tea: /' "$tea_err" >&2
|
||||
rm -f "$tea_err"
|
||||
fi
|
||||
gitea_issue_view_api
|
||||
else
|
||||
echo "Error: Unknown platform"
|
||||
exit 1
|
||||
fi
|
||||
Reference in New Issue
Block a user