#!/usr/bin/env bash # Q-Blog Tracker Scripts v4 — 2025-08-17 00:53Z set -euo pipefail # Env: GITEA_BASE_URL, GITEA_TOKEN, OWNER, REPO need () { for v in GITEA_BASE_URL GITEA_TOKEN OWNER REPO; do if [[ -z "${!v:-}" ]]; then echo "ERROR: Missing $v" >&2; exit 1; fi done } api () { local method="$1"; shift local path="$1"; shift local data="${1:-}" local code body tmp; tmp="$(mktemp)" if [[ -n "$data" && "$data" != "-" ]]; then code="$(curl -sS -o "$tmp" -w "%{http_code}" -X "$method" -H "Content-Type: application/json" -H "Authorization: token $GITEA_TOKEN" "$GITEA_BASE_URL/api/v1$path" --data @"$data")" elif [[ "$data" == "-" ]]; then code="$(curl -sS -o "$tmp" -w "%{http_code}" -X "$method" -H "Content-Type: application/json" -H "Authorization: token $GITEA_TOKEN" "$GITEA_BASE_URL/api/v1$path" --data @-)" else code="$(curl -sS -o "$tmp" -w "%{http_code}" -X "$method" -H "Content-Type: application/json" -H "Authorization: token $GITEA_TOKEN" "$GITEA_BASE_URL/api/v1$path")" fi body="$(cat "$tmp")"; rm -f "$tmp"; echo "$code" "$body" } get_json () { local method="$1" path="$2" read -r code body < <(api "$method" "$path") if [[ "$code" != "200" ]]; then echo "ERROR $code: $body" >&2; exit 1; fi echo "$body" } ensure_auth_repo () { echo "==> Checking token and repo" local user repoFull user="$(get_json GET "/user" | jq -r '.login // .username')" echo "Authenticated as: $user" repoFull="$(get_json GET "/repos/$OWNER/$REPO" | jq -r '.full_name')" echo "Repo OK: $repoFull" } create_labels () { echo "==> Creating labels (idempotent by name)" local file=".gitea/labels.json"; [[ -f "$file" ]] || { echo "WARN: $file missing"; return 0; } local existing; existing="$(get_json GET "/repos/$OWNER/$REPO/labels" | jq -r '.[].name')" local n; n="$(jq '.labels | length' "$file")" for i in $(seq 0 $((n-1))); do local name color color_clean payload code body name="$(jq -r ".labels[$i].name" "$file")" if echo "$existing" | grep -Fxq "$name"; then echo "Label exists: $name (skip)" continue fi color="$(jq -r ".labels[$i].color" "$file")" color_clean="${color###}" payload="$(jq -n --arg name "$name" --arg color "$color_clean" '{name:$name, color:$color}')" read -r code body < <(echo "$payload" | api POST "/repos/$OWNER/$REPO/labels" -) if [[ "$code" == "201" || "$code" == "200" ]]; then echo "Label created: $name"; else echo "WARN: $name → $code ($body)"; fi done } ensure_phase0_milestone () { # returns id only local title="Patch 0 — Orientation & Quality Bar" local ms_payload="milestone_patch0.json" local list ms_id code body list="$(get_json GET "/repos/$OWNER/$REPO/milestones")" ms_id="$(echo "$list" | jq -r --arg t "$title" '.[] | select(.title==$t) | .id' | head -n1)" if [[ -z "$ms_id" || "$ms_id" == "null" ]]; then [[ -f "$ms_payload" ]] || { echo "ERROR: $ms_payload missing" >&2; exit 1; } read -r code body < <(api POST "/repos/$OWNER/$REPO/milestones" "$ms_payload") [[ "$code" == "201" || "$code" == "200" ]] || { echo "ERROR: create milestone $code: $body" >&2; exit 1; } ms_id="$(echo "$body" | jq -r '.id')" fi echo "$ms_id" } create_issues () { local ms_id="$1" echo "==> Creating issues (milestone ID: $ms_id)" local file="issues/issues_patch0_phase1-3.json"; [[ -f "$file" ]] || { echo "ERROR: $file missing" >&2; exit 1; } local n; n="$(jq '.issues | length' "$file")" for i in $(seq 0 $((n-1))); do local title body payload code resp title="$(jq -r ".issues[$i].title" "$file")" body="$(jq -r ".issues[$i].body" "$file")" payload="$(jq -n --arg title "$title" --arg body "$body" --argjson milestone "$ms_id" '{title:$title, body:$body, milestone:$milestone}')" read -r code resp < <(echo "$payload" | api POST "/repos/$OWNER/$REPO/issues" -) if [[ "$code" == "201" || "$code" == "200" ]]; then echo "Created: $title"; else echo "WARN: $title → $code ($resp)"; fi done } need ensure_auth_repo create_labels ms_id="$(ensure_phase0_milestone)" create_issues "$ms_id" echo "==> Done."