Files
git.sethpc.xyz-connector/bin/gitea
T
Mortdecai 9be145bd4b feat: add gitea bash CLI with silly personality
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 17:45:36 -04:00

165 lines
5.7 KiB
Bash
Executable File

#!/usr/bin/env bash
# gitea — your friendly neighborhood Gitea CLI
# It creates repos. It pushes code. It occasionally judges your commit messages.
# Usage: gitea <command> [options]
set -euo pipefail
cmd_help() {
cat <<'EOF'
gitea — your friendly neighborhood Gitea CLI
Usage: gitea <command> [options]
Commands:
create <name> [--private] [--description "..."] Bring a new repo into this world
remote <name> Wire up git origin with token auth
push Yeet current branch to origin
delete <name> Send a repo into the void (confirms first)
list Show your repos (sorted by last updated)
Examples:
gitea create my-project --private --description "Top secret stuff"
gitea remote my-project
gitea push
Config files (~/.config/gitea/):
token Your API token (required)
username Your Gitea username (required)
host Gitea host override (default: git.sethpc.xyz)
First time? Run /gitea-setup in Claude Code to get started.
EOF
}
# Short-circuit help/unknown before loading config
case "${1:-help}" in
help|--help|-h) cmd_help; exit 0 ;;
create|remote|push|delete|list|ls) ;;
*) echo "Unknown command: $1 (try 'gitea help' — I promise it's helpful)" >&2; exit 1 ;;
esac
# --- Config ---
GITEA_HOST="git.sethpc.xyz"
if [[ -f "$HOME/.config/gitea/host" ]]; then
GITEA_HOST="$(< "$HOME/.config/gitea/host")"
GITEA_HOST="${GITEA_HOST%%[[:space:]]}"
fi
GITEA_USER=""
if [[ -f "$HOME/.config/gitea/username" ]]; then
GITEA_USER="$(< "$HOME/.config/gitea/username")"
GITEA_USER="${GITEA_USER%%[[:space:]]}"
fi
[[ -z "$GITEA_USER" ]] && { echo "ERROR: No username found. Run /gitea-setup or put your username in ~/.config/gitea/username" >&2; exit 1; }
GITEA_TOKEN="${GITEA_TOKEN:-}"
if [[ -z "$GITEA_TOKEN" && -f "$HOME/.config/gitea/token" ]]; then
GITEA_TOKEN="$(< "$HOME/.config/gitea/token")"
GITEA_TOKEN="${GITEA_TOKEN%%[[:space:]]}"
fi
[[ -z "$GITEA_TOKEN" ]] && { echo "ERROR: No token found. Run /gitea-setup or put your token in ~/.config/gitea/token" >&2; exit 1; }
API_BASE="https://${GITEA_HOST}/api/v1"
# --- Helpers ---
api() {
local method="$1" endpoint="$2"
shift 2
curl -sf -X "$method" "${API_BASE}${endpoint}" \
-H "Content-Type: application/json" \
-H "Authorization: token ${GITEA_TOKEN}" \
"$@"
}
# --- Commands ---
cmd_create() {
local name="" private=false description=""
while [[ $# -gt 0 ]]; do
case "$1" in
--private|-p) private=true; shift ;;
--public) private=false; shift ;;
--description|-d) description="$2"; shift 2 ;;
-*) echo "Unknown option: $1 (I don't know what that means and I'm too proud to guess)" >&2; exit 1 ;;
*) name="$1"; shift ;;
esac
done
[[ -z "$name" ]] && { echo "Usage: gitea create <name> [--private] [--description \"...\"]"; echo " (You forgot the name. The repo needs a name. We all need names.)" >&2; exit 1; }
local payload
payload=$(jq -n \
--arg name "$name" \
--argjson private "$private" \
--arg desc "$description" \
'{name: $name, private: $private, description: $desc, auto_init: false}')
local resp
resp=$(api POST "/user/repos" -d "$payload") || { echo "FAIL: Gitea said no. Check your token and network." >&2; exit 1; }
local html_url
html_url=$(echo "$resp" | jq -r '.html_url')
echo "Created: ${html_url}"
echo "Clone: https://${GITEA_HOST}/${GITEA_USER}/${name}.git"
echo ""
echo "Next up: 'gitea remote ${name}' to wire up your origin. You know the drill."
}
cmd_remote() {
local name="${1:-}"
[[ -z "$name" ]] && { echo "Usage: gitea remote <repo-name>"; echo " (Which repo? I can't read minds. Yet.)" >&2; exit 1; }
local url="https://${GITEA_HOST}/${GITEA_USER}/${name}.git"
git config credential.helper 'store'
local cred_file="${HOME}/.git-credentials"
local cred_entry="https://${GITEA_USER}:${GITEA_TOKEN}@${GITEA_HOST}"
if ! grep -qF "${GITEA_HOST}" "$cred_file" 2>/dev/null; then
echo "$cred_entry" >> "$cred_file"
chmod 600 "$cred_file"
fi
if git remote get-url origin &>/dev/null; then
git remote set-url origin "$url"
echo "Updated origin -> ${url}"
else
git remote add origin "$url"
echo "Added origin -> ${url}"
fi
echo "You're locked and loaded. 'gitea push' when ready."
}
cmd_push() {
local branch
branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null) || { echo "This isn't a git repo. I checked." >&2; exit 1; }
echo "Pushing ${branch} to origin... hold onto your bits."
git push -u origin "$branch"
}
cmd_delete() {
local name="${1:-}"
[[ -z "$name" ]] && { echo "Usage: gitea delete <repo-name>"; echo " (Delete what? Be specific. Destruction requires precision.)" >&2; exit 1; }
read -rp "Delete ${GITEA_USER}/${name}? This is permanent. No take-backs. [y/N] " confirm
[[ "$confirm" =~ ^[Yy]$ ]] || { echo "Crisis averted. Repo lives another day."; exit 0; }
if api DELETE "/repos/${GITEA_USER}/${name}"; then
echo "Deleted: ${GITEA_USER}/${name}. It's gone. Pour one out."
else
echo "FAIL: Could not delete ${GITEA_USER}/${name}. Maybe it's already gone? Maybe it's fighting back?" >&2; exit 1
fi
}
cmd_list() {
local resp
resp=$(api GET "/user/repos?limit=50&sort=updated") || { echo "FAIL: Couldn't fetch repos. Is Gitea awake?" >&2; exit 1; }
echo "$resp" | jq -r '.[] | "\(.name)\t\(if .private then "private" else "public" end)\t\(.description // "")"' | column -t -s$'\t'
}
case "${1:-help}" in
create) shift; cmd_create "$@" ;;
remote) shift; cmd_remote "$@" ;;
push) shift; cmd_push "$@" ;;
delete) shift; cmd_delete "$@" ;;
list|ls) shift; cmd_list "$@" ;;
esac