From cb6187b0145e12ac3bdfc2a3f29c905855c7f933 Mon Sep 17 00:00:00 2001 From: Anton Afanasyeu Date: Thu, 11 Jun 2026 09:42:19 +0200 Subject: [PATCH] sync --- .../backend/scripts/gitea/README.md | 19 ++ .../backend/scripts/gitea/gitea_org_lib.sh | 37 ++- .../scripts/gitea/gitea_polish_project.sh | 215 ++++++++++++++++++ 3 files changed, 262 insertions(+), 9 deletions(-) create mode 100755 examples/crash_reporter/backend/scripts/gitea/gitea_polish_project.sh diff --git a/examples/crash_reporter/backend/scripts/gitea/README.md b/examples/crash_reporter/backend/scripts/gitea/README.md index ad72210..c0d662e 100644 --- a/examples/crash_reporter/backend/scripts/gitea/README.md +++ b/examples/crash_reporter/backend/scripts/gitea/README.md @@ -331,6 +331,25 @@ GITEA_SUBMODULES_CONF=/root/my-submodules.list sudo ./gitea_mirror_submodules.sh sudo -u gitea gitea -c /var/lib/gitea/custom/conf/app.ini admin repo-sync-mirrors ``` +## Polish (finish line — safe BE run) + +```bash +cd /var/www/.../androidcast_project/android_cast +sudo ./examples/crash_reporter/backend/scripts/gitea/gitea_polish_project.sh . +``` + +Idempotent: **foxx** → AndroidCast **Owners**, transfer `admin/*` repos, **sync mirrors now**, create missing **libvpx/opus/speex**, default branch **`next`**. + +If `gitea_diagnose_mirror_sync.sh` shows `mirror=false` for `android_cast`: + +```bash +GITEA_RECREATE_MAIN_MIRROR=yes sudo ./gitea_polish_project.sh . +``` + +**foxx UI:** browse **`…/git/AndroidCast`** (org), not only profile “Your repositories”. + +**Email/2FA (deferred):** `REGISTER_EMAIL_CONFIRM = false` until SMTP; passwords via `gitea_user_admin.sh`. + ## Verify ```bash diff --git a/examples/crash_reporter/backend/scripts/gitea/gitea_org_lib.sh b/examples/crash_reporter/backend/scripts/gitea/gitea_org_lib.sh index c6e0d73..6855a9c 100644 --- a/examples/crash_reporter/backend/scripts/gitea/gitea_org_lib.sh +++ b/examples/crash_reporter/backend/scripts/gitea/gitea_org_lib.sh @@ -102,17 +102,34 @@ gitea_org_owners_team_id() { command -v curl >/dev/null 2>&1 || return 1 _token="$(gitea_api_token)" || return 1 _api="$(gitea_api_base)" - _id="$(curl -sS "$_api/orgs/$_org/teams" \ - -H "Authorization: token $_token" \ - | awk -F'"' ' - /"id":/ { id = $4 } - /"name": "Owners"/ { print id; exit } - /"name":"Owners"/ { print id; exit } + _json="$(curl -sS "$_api/orgs/$_org/teams" -H "Authorization: token $_token")" + _id="$(printf '%s' "$_json" | awk ' + /"name":"Owners"/ || /"name": "Owners"/ { + for (i = 1; i <= NF; i++) if ($i ~ /^"id":/) { gsub(/[^0-9]/, "", $(i+1)); print $(i+1); exit } + } + ')" + if [ -z "$_id" ]; then + _id="$(printf '%s' "$_json" | tr ',' '\n' | awk ' + /"name":"Owners"/ { found=1 } + found && /"id":/ { gsub(/[^0-9]/, "", $0); print; exit } ')" + fi [ -n "$_id" ] || return 1 printf '%s' "$_id" } +gitea_org_team_has_member() { + _org="$1" + _user="$2" + _team_id="$(gitea_org_owners_team_id "$_org")" || return 1 + command -v curl >/dev/null 2>&1 || return 1 + _token="$(gitea_api_token)" || return 1 + _api="$(gitea_api_base)" + curl -sS "$_api/teams/$_team_id/members" \ + -H "Authorization: token $_token" \ + | grep -q "\"login\":\"$_user\"" +} + gitea_team_add_member_api() { _team_id="$1" _user="$2" @@ -139,10 +156,12 @@ gitea_org_add_owners() { [ -n "$_u" ] || continue gitea_user_create_if_missing "$_u" || true if gitea_user_exists "$_u"; then - if gitea_team_add_member_api "$_team_id" "$_u"; then - gitea_org_log "Owners team: $_u" + if gitea_org_team_has_member "$_org" "$_u"; then + gitea_org_log "Owners team: $_u (already member)" + elif gitea_team_add_member_api "$_team_id" "$_u"; then + gitea_org_log "Owners team: $_u (added)" else - gitea_org_warn "could not add $_u to Owners (may already be member)" + gitea_org_warn "could not add $_u to Owners — add in UI: Org $_org -> Teams -> Owners" fi fi done diff --git a/examples/crash_reporter/backend/scripts/gitea/gitea_polish_project.sh b/examples/crash_reporter/backend/scripts/gitea/gitea_polish_project.sh new file mode 100755 index 0000000..c3f0ce6 --- /dev/null +++ b/examples/crash_reporter/backend/scripts/gitea/gitea_polish_project.sh @@ -0,0 +1,215 @@ +#!/bin/ash +# +# Safe idempotent Gitea polish: org access (foxx), repo inventory, mirror sync, +# submodule mirrors, default branch next. Does NOT delete repos unless +# GITEA_RECREATE_MAIN_MIRROR=yes (android_cast pull-mirror repair). +# +# Usage (BE as root): +# sudo ./gitea_polish_project.sh +# sudo ./gitea_polish_project.sh /var/www/.../androidcast_project/android_cast +# +set -eu + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +# shellcheck source=gitea_ini.sh +. "$SCRIPT_DIR/gitea_ini.sh" +# shellcheck source=gitea_mirror_lib.sh +. "$SCRIPT_DIR/gitea_mirror_lib.sh" +# shellcheck source=gitea_org_lib.sh +. "$SCRIPT_DIR/gitea_org_lib.sh" +# shellcheck source=gitea_submodule_lib.sh +. "$SCRIPT_DIR/gitea_submodule_lib.sh" + +GITEA_ORG="${GITEA_ORG:-AndroidCast}" +GITEA_OWNER="${GITEA_OWNER:-$GITEA_ORG}" +GITEA_REPO="${GITEA_REPO:-android_cast}" +GITEA_MIRROR_URL="${GITEA_MIRROR_URL:-git://10.7.0.10/android_cast}" +GITEA_DEFAULT_BRANCH="${GITEA_DEFAULT_BRANCH:-next}" +GITEA_SUBMODULES_CONF="${GITEA_SUBMODULES_CONF:-$SCRIPT_DIR/submodules.defaults.conf}" +GITEA_RECREATE_MAIN_MIRROR="${GITEA_RECREATE_MAIN_MIRROR:-}" + +log() { printf '[gitea-polish] %s\n' "$*"; } +warn() { printf '[gitea-polish] WARN: %s\n' "$*" >&2; } + +json_bool() { + printf '%s' "$1" | tr -d '\n' | grep -o "\"$2\":[^,}]*" | head -1 | sed 's/.*://;s/ //g' +} + +repo_mirror_status() { + _owner="$1" + _repo="$2" + gitea_repo_exists_api "$_owner" "$_repo" || return 1 + _meta="$(gitea_repo_get_api "$_owner" "$_repo")" + _mirror="$(json_bool "$_meta" "mirror")" + _updated="$(printf '%s' "$_meta" | tr -d '\n' | grep -o '"updated_at":"[^"]*"' | head -1 | sed 's/.*:"//;s/"$//')" + log " $_owner/$_repo mirror=$_mirror updated=$_updated" + [ "$_mirror" = "true" ] +} + +list_owner_repos() { + _owner="$1" + log "repos under $_owner:" + _names="$(gitea_list_repos_api "$_owner" 2>/dev/null)" || _names="" + if [ -z "$(echo "$_names" | tr -d ' ')" ]; then + warn " (none)" + return 1 + fi + echo "$_names" | while read -r _r; do + [ -n "$_r" ] && log " - $_owner/$_r" + done + return 0 +} + +gitea_org_team_members() { + _org="$1" + _team_id="$(gitea_org_owners_team_id "$_org")" || return 1 + command -v curl >/dev/null 2>&1 || return 1 + _token="$(gitea_api_token)" || return 1 + _api="$(gitea_api_base)" + curl -sS "$_api/teams/$_team_id/members" \ + -H "Authorization: token $_token" \ + | awk -F'"' '/"login":/ { print $4 }' +} + +verify_org_access() { + log "org $GITEA_ORG Owners team members:" + gitea_org_team_members "$GITEA_ORG" | while read -r _u; do + [ -n "$_u" ] && log " - $_u" + done + for _u in $GITEA_ORG_OWNERS; do + if gitea_org_team_members "$GITEA_ORG" | grep -Fx "$_u" >/dev/null 2>&1; then + log "ok: $_u is org Owner" + else + warn "missing: $_u NOT in Owners — re-run gitea_migrate_org_setup.sh" + fi + done +} + +sync_all_mirrors() { + log "trigger mirror sync (all repos)..." + if gitea_cli "admin" "repo-sync-mirrors"; then + log "repo-sync-mirrors OK" + return 0 + fi + warn "repo-sync-mirrors CLI failed — trying per-repo API" + for _owner in "$GITEA_ORG" admin; do + gitea_list_repos_api "$_owner" 2>/dev/null | while read -r _r; do + [ -n "$_r" ] || continue + gitea_sync_mirror_api "$_owner" "$_r" && log " synced $_owner/$_r" \ + || warn " sync failed $_owner/$_r" + done + done +} + +mirror_submodules_if_missing() { + _checkout="${1:-}" + _repo_dir="" + _gitmodules="" + if [ -n "$_checkout" ] && [ -d "$_checkout" ]; then + _repo_dir="$(cd "$_checkout" && pwd)" + _gitmodules="$_repo_dir/.gitmodules" + fi + + _need=0 + for _sub in libvpx opus speex; do + gitea_repo_exists_api "$GITEA_ORG" "$_sub" && continue + _need=1 + break + done + [ "$_need" -eq 1 ] || { + log "submodule mirrors present under $GITEA_ORG" + return 0 + } + + log "creating missing submodule mirrors under $GITEA_ORG..." + _list="$(mktemp /tmp/gitea-polish-sub-XXXXXX)" + gitea_submodule_collect_entries "$_repo_dir" HEAD "$_gitmodules" "$GITEA_SUBMODULES_CONF" > "$_list" + while IFS= read -r _line; do + [ -n "$_line" ] || continue + _name="${_line%%|*}" + _rest="${_line#*|}" + _url="${_rest%%|*}" + log " mirror $_name <- $_url" + gitea_mirror_pull_repo "$_url" "$_name" "$GITEA_ORG" "24h" "/tmp/gitea-polish-$$" \ + && gitea_sync_mirror_api "$GITEA_ORG" "$_name" || warn " failed $_name" + gitea_rm_path "/tmp/gitea-polish-$$/${_name}.mirror.git" + done < "$_list" + gitea_rm_path "$_list" +} + +recreate_main_pull_mirror_if_asked() { + if [ "$GITEA_RECREATE_MAIN_MIRROR" != "yes" ]; then + return 0 + fi + warn "GITEA_RECREATE_MAIN_MIRROR=yes — delete $GITEA_ORG/$GITEA_REPO and re-attach" + command -v curl >/dev/null 2>&1 || return 1 + _token="$(gitea_api_token)" || return 1 + _api="$(gitea_api_base)" + curl -sS -o /dev/null -X DELETE "$_api/repos/$GITEA_ORG/$GITEA_REPO" \ + -H "Authorization: token $_token" || true + GITEA_OWNER="$GITEA_ORG" "$SCRIPT_DIR/gitea_attach_remote.sh" "$GITEA_MIRROR_URL" +} + +# --- main --- + +_checkout="${1:-}" +if [ -d "./.git" ] || [ -f "./.git" ]; then + _checkout="${_checkout:-$(pwd)}" +fi + +gitea_load_config || exit 1 +gitea_ensure_cli_access || exit 1 + +log "=== Gitea polish (safe) ===" +log "ini=$GITEA_APP_INI org=$GITEA_ORG" + +# 1) Org + foxx Owners +gitea_org_ensure_androidcast "$GITEA_ORG" || warn "org setup incomplete" +verify_org_access + +# 2) Inventory +list_owner_repos "$GITEA_ORG" || true +list_owner_repos admin || true + +# 3) Main mirror health +log "main repo mirror status:" +_main_ok=0 +if repo_mirror_status "$GITEA_ORG" "$GITEA_REPO"; then + _main_ok=1 +elif repo_mirror_status "admin" "$GITEA_REPO"; then + warn "android_cast still under admin — transfer to org:" + warn " sudo ./gitea_migrate_org_setup.sh" + _main_ok=1 +else + warn "no pull mirror for $GITEA_REPO — auto-sync disabled" + warn "fix (destructive): GITEA_RECREATE_MAIN_MIRROR=yes sudo ./gitea_polish_project.sh" + warn " or delete $GITEA_ORG/$GITEA_REPO in UI then: sudo ./gitea_attach_remote.sh $GITEA_MIRROR_URL" +fi + +recreate_main_pull_mirror_if_asked + +# 4) Manual sync now +sync_all_mirrors + +# 5) Submodules +mirror_submodules_if_missing "$_checkout" + +# 6) Default branch +if command -v "$SCRIPT_DIR/gitea_set_default_branch.sh" >/dev/null 2>&1; then + GITEA_OWNER="$GITEA_ORG" GITEA_DEFAULT_BRANCH="$GITEA_DEFAULT_BRANCH" \ + sh "$SCRIPT_DIR/gitea_set_default_branch.sh" || warn "default branch set failed (sync first)" +fi + +# 7) Summary +log "=== done ===" +cat <