137 lines
3.8 KiB
Bash
137 lines
3.8 KiB
Bash
|
|
#!/usr/bin/env bash
|
||
|
|
# Open a pull request against the Mimic Gitea repository using the credentials
|
||
|
|
# already stored in ~/.git-credentials (the same token used for `git push`).
|
||
|
|
#
|
||
|
|
# Usage:
|
||
|
|
# scripts/open-pr.sh --title "feat: sprint N — short summary" \
|
||
|
|
# --body path/to/body.md \
|
||
|
|
# [--base main] \
|
||
|
|
# [--head <current branch by default>]
|
||
|
|
#
|
||
|
|
# Or via the Makefile wrapper:
|
||
|
|
# make open-pr TITLE="feat: sprint 4 — UI polish" BODY=tasks/pr-body-sprint-4.md
|
||
|
|
#
|
||
|
|
# Output: prints the PR URL on success, exits non-zero on failure.
|
||
|
|
|
||
|
|
set -euo pipefail
|
||
|
|
|
||
|
|
# --- Arg parsing ------------------------------------------------------------
|
||
|
|
|
||
|
|
TITLE=""
|
||
|
|
BODY_FILE=""
|
||
|
|
BASE="main"
|
||
|
|
HEAD=""
|
||
|
|
|
||
|
|
while [[ $# -gt 0 ]]; do
|
||
|
|
case "$1" in
|
||
|
|
--title)
|
||
|
|
TITLE="${2:-}"
|
||
|
|
shift 2
|
||
|
|
;;
|
||
|
|
--body)
|
||
|
|
BODY_FILE="${2:-}"
|
||
|
|
shift 2
|
||
|
|
;;
|
||
|
|
--base)
|
||
|
|
BASE="${2:-}"
|
||
|
|
shift 2
|
||
|
|
;;
|
||
|
|
--head)
|
||
|
|
HEAD="${2:-}"
|
||
|
|
shift 2
|
||
|
|
;;
|
||
|
|
--sprint)
|
||
|
|
# purely informational; ignored — the title is what carries semantics
|
||
|
|
shift 2
|
||
|
|
;;
|
||
|
|
-h|--help)
|
||
|
|
sed -n '2,15p' "$0"
|
||
|
|
exit 0
|
||
|
|
;;
|
||
|
|
*)
|
||
|
|
echo "Unknown arg: $1" >&2
|
||
|
|
exit 2
|
||
|
|
;;
|
||
|
|
esac
|
||
|
|
done
|
||
|
|
|
||
|
|
[[ -n "$TITLE" ]] || { echo "--title is required" >&2; exit 2; }
|
||
|
|
[[ -n "$BODY_FILE" ]] || { echo "--body is required" >&2; exit 2; }
|
||
|
|
[[ -f "$BODY_FILE" ]] || { echo "body file not found: $BODY_FILE" >&2; exit 2; }
|
||
|
|
|
||
|
|
# --- Credentials ------------------------------------------------------------
|
||
|
|
|
||
|
|
CRED_FILE="${HOME}/.git-credentials"
|
||
|
|
[[ -f "$CRED_FILE" ]] || { echo "no ~/.git-credentials — git push must have run at least once" >&2; exit 3; }
|
||
|
|
|
||
|
|
# Detect Gitea host from origin remote
|
||
|
|
ORIGIN_URL=$(git remote get-url origin)
|
||
|
|
# Strip protocol, .git suffix → host/owner/repo
|
||
|
|
case "$ORIGIN_URL" in
|
||
|
|
https://*)
|
||
|
|
REST="${ORIGIN_URL#https://}"
|
||
|
|
;;
|
||
|
|
*)
|
||
|
|
echo "origin is not https (got: $ORIGIN_URL) — this script supports HTTPS Gitea only" >&2
|
||
|
|
exit 3
|
||
|
|
;;
|
||
|
|
esac
|
||
|
|
REST="${REST%.git}"
|
||
|
|
HOST="${REST%%/*}"
|
||
|
|
PATHPART="${REST#*/}" # owner/repo
|
||
|
|
OWNER="${PATHPART%%/*}"
|
||
|
|
REPO="${PATHPART#*/}"
|
||
|
|
REPO="${REPO%%/*}" # belt + braces in case of trailing slash
|
||
|
|
|
||
|
|
# Match the credential line for this host
|
||
|
|
CRED_LINE=$(grep -E "^https://[^@]+@${HOST}\$" "$CRED_FILE" || true)
|
||
|
|
[[ -n "$CRED_LINE" ]] || { echo "no credential for host ${HOST} in ${CRED_FILE}" >&2; exit 3; }
|
||
|
|
|
||
|
|
USER_PART=$(echo "$CRED_LINE" | sed -E 's|^https://([^:]+):.*|\1|')
|
||
|
|
TOKEN=$(echo "$CRED_LINE" | sed -E 's|^https://[^:]+:([^@]+)@.*$|\1|')
|
||
|
|
|
||
|
|
[[ -n "$USER_PART" && -n "$TOKEN" ]] || { echo "could not parse user/token from credential" >&2; exit 3; }
|
||
|
|
|
||
|
|
# --- Branch -----------------------------------------------------------------
|
||
|
|
|
||
|
|
if [[ -z "$HEAD" ]]; then
|
||
|
|
HEAD=$(git rev-parse --abbrev-ref HEAD)
|
||
|
|
fi
|
||
|
|
[[ "$HEAD" != "HEAD" ]] || { echo "detached HEAD — pass --head explicitly" >&2; exit 3; }
|
||
|
|
|
||
|
|
# --- Compose payload --------------------------------------------------------
|
||
|
|
|
||
|
|
API_URL="https://${HOST}/api/v1/repos/${OWNER}/${REPO}/pulls"
|
||
|
|
|
||
|
|
PAYLOAD=$(jq -n \
|
||
|
|
--arg title "$TITLE" \
|
||
|
|
--rawfile body "$BODY_FILE" \
|
||
|
|
--arg head "$HEAD" \
|
||
|
|
--arg base "$BASE" \
|
||
|
|
'{title:$title, body:$body, head:$head, base:$base}')
|
||
|
|
|
||
|
|
# --- POST -------------------------------------------------------------------
|
||
|
|
|
||
|
|
RESPONSE_FILE=$(mktemp)
|
||
|
|
HTTP_CODE=$(curl -sS -u "${USER_PART}:${TOKEN}" \
|
||
|
|
-H "Content-Type: application/json" \
|
||
|
|
-X POST \
|
||
|
|
-d "$PAYLOAD" \
|
||
|
|
-o "$RESPONSE_FILE" \
|
||
|
|
-w "%{http_code}" \
|
||
|
|
"$API_URL")
|
||
|
|
|
||
|
|
if [[ "$HTTP_CODE" != "201" ]]; then
|
||
|
|
echo "PR creation failed (HTTP $HTTP_CODE):" >&2
|
||
|
|
jq -r '.message // empty' "$RESPONSE_FILE" >&2 2>/dev/null || cat "$RESPONSE_FILE" >&2
|
||
|
|
rm -f "$RESPONSE_FILE"
|
||
|
|
exit 4
|
||
|
|
fi
|
||
|
|
|
||
|
|
PR_URL=$(jq -r '.html_url' "$RESPONSE_FILE")
|
||
|
|
PR_NUMBER=$(jq -r '.number' "$RESPONSE_FILE")
|
||
|
|
rm -f "$RESPONSE_FILE"
|
||
|
|
|
||
|
|
echo "Opened PR #${PR_NUMBER}"
|
||
|
|
echo "$PR_URL"
|