#!/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 ] # # 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"