Files
RedBear-OS/local/scripts/delete-per-component-repos.sh
T
vasilito 54de45d461 docs/scripts: enforce single-repo policy and +rb build-metadata suffix
- Update AGENTS.md single-repo rule to explicitly forbid creating any new
  Gitea repositories and to require deleting per-component repos.
- Change version suffix policy from pre-release -rb to build-metadata +rb
  in AGENTS.md, sync-versions.sh, apply-rb-suffix.sh, verify-fork-versions.sh.
- Update migration instructions to push to existing submodule/<component>
  branches inside RedBear-OS, not create new repos.
- Update BUILD-SYSTEM-IMPROVEMENTS.md and SLEEP-IMPLEMENTATION-PLAN.md to
  reference submodule/* branches instead of defunct per-component repos.
- Fix delete-per-component-repos.sh example to use a real historical repo.
2026-07-05 22:50:33 +03:00

183 lines
6.2 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# Enforce Red Bear OS SINGLE-REPO RULE: delete every repo on
# gitea.redbearos.org/vasilito/ except RedBear-OS and hiperiso.
#
# Token is read at runtime from $REDBEAR_GITEA_TOKEN (or ~/.netrc or
# git credential helper). It is NEVER written to disk, logged, or echoed.
# See local/AGENTS.md § Token Policy.
#
# Usage:
# ./local/scripts/delete-per-component-repos.sh # interactive
# ./local/scripts/delete-per-component-repos.sh --dry-run # list only
# ./local/scripts/delete-per-component-repos.sh --yes # no prompts
# ./local/scripts/delete-per-component-repos.sh --only redbear-os-base
# ./local/scripts/delete-per-component-repos.sh -h # this help
set -euo pipefail
GITEA_HOST="${GITEA_HOST:-https://gitea.redbearos.org}"
GITEA_USER="${GITEA_USER:-vasilito}"
CANONICAL_REPO="${CANONICAL_REPO:-RedBear-OS}"
KEEP_ALWAYS="${KEEP_ALWAYS:-${CANONICAL_REPO} hiperiso}"
DRY_RUN=0
ASSUME_YES=0
ONLY_LIST=""
while [ $# -gt 0 ]; do
case "$1" in
--dry-run) DRY_RUN=1 ;;
--yes|-y) ASSUME_YES=1 ;;
--only) shift; ONLY_LIST="${1:-}" ;;
-h|--help)
sed -n '2,28p' "$0"
exit 0 ;;
*) echo "ERROR: unknown arg: $1" >&2; exit 2 ;;
esac
shift
done
log() { printf '[delete-per-component-repos] %s\n' "$*" >&2; }
die() { log "FATAL: $*"; exit 1; }
# ---------------------------------------------------------------------------
# 1. Locate the token — env var, .netrc, or git credential helper (in order).
# Never echo it, never log it, never write it to disk.
# ---------------------------------------------------------------------------
resolve_token() {
if [ -n "${REDBEAR_GITEA_TOKEN:-}" ]; then
printf '%s' "$REDBEAR_GITEA_TOKEN"
return 0
fi
if command -v git >/dev/null 2>&1; then
local helper_token
helper_token="$(git credential fill <<EOF 2>/dev/null | sed -n 's/^password=//p' | head -n1
protocol=https
host=gitea.redbearos.org
username=${GITEA_USER}
EOF
)"
if [ -n "$helper_token" ]; then
printf '%s' "$helper_token"
return 0
fi
fi
if [ -r "$HOME/.netrc" ]; then
local netrc_token
netrc_token="$(awk -v host="gitea.redbearos.org" -v user="$GITEA_USER" '
$1=="machine" && $2==host { in_block=1; next }
in_block && $1=="login" && $2==user { want=1; next }
in_block && want && $1=="password" { print $2; exit }
in_block && $1=="machine" { in_block=0 }
' "$HOME/.netrc")"
if [ -n "$netrc_token" ]; then
printf '%s' "$netrc_token"
return 0
fi
fi
return 1
}
log "Resolving Gitea token (env → git helper → ~/.netrc) ..."
TOKEN="$(resolve_token || true)"
[ -n "$TOKEN" ] || die "no token found. Set REDBEAR_GITEA_TOKEN or configure ~/.netrc / git credential helper."
# ---------------------------------------------------------------------------
# 2. List every repo visible to the user via the Gitea API.
# ---------------------------------------------------------------------------
api_get() {
curl -fsS -H "Authorization: token $TOKEN" \
-H "Accept: application/json" \
"$GITEA_HOST/api/v1$1"
}
log "Fetching repo list from ${GITEA_HOST}/api/v1/users/${GITEA_USER}/repos ..."
REPOS_JSON="$(api_get "/users/${GITEA_USER}/repos?limit=200")" || die "Gitea API call failed."
REPOS_ALL="$(printf '%s' "$REPOS_JSON" | jq -r '.[].name')"
[ -n "$REPOS_ALL" ] || die "no repos returned — check token permissions."
# ---------------------------------------------------------------------------
# 3. Filter the deletion candidates.
# ---------------------------------------------------------------------------
CANDIDATES=""
while IFS= read -r repo; do
[ -n "$repo" ] || continue
case " $KEEP_ALWAYS " in
*" $repo "*) continue ;; # canonical + user-named keepers
esac
if [ -n "$ONLY_LIST" ]; then
# comma-separated whitelist
case ",$ONLY_LIST," in
*",$repo,"*) ;; # match
*) continue ;;
esac
fi
CANDIDATES="${CANDIDATES}${repo}"$'\n'
done <<< "$REPOS_ALL"
CANDIDATES="$(printf '%s' "$CANDIDATES" | sed '/^$/d')"
if [ -z "$CANDIDATES" ]; then
log "No repos match deletion criteria. Nothing to do."
exit 0
fi
log "Repos flagged for deletion:"
while IFS= read -r r; do
[ -n "$r" ] || continue
log " - $r"
done <<< "$CANDIDATES"
if [ "$DRY_RUN" -eq 1 ]; then
log "Dry run — no deletions performed."
exit 0
fi
# ---------------------------------------------------------------------------
# 4. Confirm with the operator (unless --yes).
# ---------------------------------------------------------------------------
if [ "$ASSUME_YES" -ne 1 ]; then
log ""
log "WARNING: This DELETES repositories from ${GITEA_HOST}."
log "Make sure each repo above has been migrated as a submodule branch"
log "inside ${CANONICAL_REPO} first (see redirect-to-submodules.sh)."
log "The deletion is irreversible."
log ""
read -r -p "Type 'delete' to confirm: " confirm
if [ "$confirm" != "delete" ]; then
log "Aborted."
exit 1
fi
fi
# ---------------------------------------------------------------------------
# 5. Delete each candidate via DELETE /repos/{owner}/{repo}.
# ---------------------------------------------------------------------------
fail_count=0
ok_count=0
while IFS= read -r repo; do
[ -n "$repo" ] || continue
log "Deleting ${GITEA_USER}/${repo} ..."
http_code="$(curl -sS -o /dev/null -w '%{http_code}' \
-X DELETE \
-H "Authorization: token $TOKEN" \
-H "Accept: application/json" \
"${GITEA_HOST}/api/v1/repos/${GITEA_USER}/${repo}")"
case "$http_code" in
2*) log " ✓ deleted ($http_code)"; ok_count=$((ok_count+1)) ;;
403) log " ✗ FORBIDDEN — token lacks delete permission on ${repo}"; fail_count=$((fail_count+1)) ;;
404) log " already gone (404)"; ok_count=$((ok_count+1)) ;;
*) log " ✗ FAILED ($http_code)"; fail_count=$((fail_count+1)) ;;
esac
done <<< "$CANDIDATES"
log ""
log "Summary: ${ok_count} deleted, ${fail_count} failed."
[ "$fail_count" -eq 0 ] || exit 3
exit 0