Compare commits
11
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b3b167ba8d | ||
|
|
bd6c5d445a | ||
|
|
eae02da074 | ||
|
|
4b694d0bef | ||
|
|
67ee2fc28b | ||
|
|
9e88f7c741 | ||
|
|
f0ef647f60 | ||
|
|
49c00e367a | ||
|
|
dcf643cde4 | ||
|
|
def70ab4e2 | ||
|
|
a06784e669 |
+66
-4
@@ -127,6 +127,26 @@ _gitea_sync_vendor_src() {
|
|||||||
echo "$(cd "$_self_dir/.." && pwd)/vendor/ai-stack/gitea-github-sync.sh"
|
echo "$(cd "$_self_dir/.." && pwd)/vendor/ai-stack/gitea-github-sync.sh"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Prompt for a token with retries — pasted tokens over SSH sometimes race the
|
||||||
|
# prompt (the terminal delivers the paste a beat after an already-submitted
|
||||||
|
# empty line, so the token shows up echoed on the *next* line instead of
|
||||||
|
# being read). A single empty answer used to be taken as "no token", silently
|
||||||
|
# — this gives it up to 3 tries before actually giving up, and strips
|
||||||
|
# whitespace in case the paste carried a stray leading/trailing newline.
|
||||||
|
_gitea_prompt_token() {
|
||||||
|
local _question="$1" _varname="$2"
|
||||||
|
local _max=1 _tries=0 _val=""
|
||||||
|
[ "$UNATTENDED" != true ] && _max=3
|
||||||
|
while [[ $_tries -lt $_max ]]; do
|
||||||
|
prompt_text "$_question" "" _val
|
||||||
|
_val="$(printf '%s' "$_val" | tr -d '[:space:]')"
|
||||||
|
[[ -n "$_val" ]] && break
|
||||||
|
_tries=$((_tries + 1))
|
||||||
|
[[ $_tries -lt $_max ]] && log_warning " Nothing came through — if you pasted it, try again (a paste can race the prompt over SSH)."
|
||||||
|
done
|
||||||
|
eval "$_varname='$_val'"
|
||||||
|
}
|
||||||
|
|
||||||
# ── Own systemd timer, not gitea-github-sync.sh's built-in --install-timer ──
|
# ── Own systemd timer, not gitea-github-sync.sh's built-in --install-timer ──
|
||||||
# The vendor script's own timer installer always runs the script bare (no
|
# The vendor script's own timer installer always runs the script bare (no
|
||||||
# --pull-only/--push-only), i.e. always both directions — there's no way to
|
# --pull-only/--push-only), i.e. always both directions — there's no way to
|
||||||
@@ -216,6 +236,34 @@ _gitea_run_sync_direction_step() {
|
|||||||
log_info " cd $DIR && bash gitea-github-sync.sh $FLAG"
|
log_info " cd $DIR && bash gitea-github-sync.sh $FLAG"
|
||||||
[[ -z "$FLAG" ]] && log_info " (no flag needed for both directions)"
|
[[ -z "$FLAG" ]] && log_info " (no flag needed for both directions)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# ── Run it now, off the timer — lets you confirm tokens/config are
|
||||||
|
# actually correct right here instead of waiting for the first
|
||||||
|
# scheduled run (or a manual invocation later) to find out.
|
||||||
|
echo ""
|
||||||
|
echo " Run a sync now?"
|
||||||
|
echo " 1) Dry-run preview only (--list) — shows what would sync, no changes"
|
||||||
|
echo " 2) Run for real now ($DIR_DESC)"
|
||||||
|
echo " 3) Skip — don't run anything now"
|
||||||
|
local _RUN_DEFAULT="1"
|
||||||
|
[ "$UNATTENDED" = true ] && _RUN_DEFAULT="3"
|
||||||
|
local _RUN_NOW=""
|
||||||
|
prompt_text " Choice [$_RUN_DEFAULT]:" "$_RUN_DEFAULT" _RUN_NOW
|
||||||
|
case "$_RUN_NOW" in
|
||||||
|
2)
|
||||||
|
log_info "Running sync now ($DIR_DESC)..."
|
||||||
|
sudo -u "$ACTUAL_USER" env HOME="$ACTUAL_HOME" SYNC_ENV="$DIR/.env" \
|
||||||
|
bash "$DIR/gitea-github-sync.sh" $FLAG \
|
||||||
|
&& log_success "Sync run complete." \
|
||||||
|
|| log_warning "Sync run failed — check the output above, or ~/.config/gitea-github-sync/sync.log"
|
||||||
|
;;
|
||||||
|
3) log_info "Skipped — run it later with the commands above." ;;
|
||||||
|
*)
|
||||||
|
log_info "Dry-run preview (--list)..."
|
||||||
|
sudo -u "$ACTUAL_USER" env HOME="$ACTUAL_HOME" SYNC_ENV="$DIR/.env" \
|
||||||
|
bash "$DIR/gitea-github-sync.sh" --list
|
||||||
|
;;
|
||||||
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
install_gitea() {
|
install_gitea() {
|
||||||
@@ -233,6 +281,7 @@ install_gitea() {
|
|||||||
echo "[DRY-RUN] Would prompt for a GitHub token and copy in gitea-github-sync.sh"
|
echo "[DRY-RUN] Would prompt for a GitHub token and copy in gitea-github-sync.sh"
|
||||||
echo "[DRY-RUN] Would ask sync direction (GitHub->Gitea / Gitea->GitHub / both) and whether"
|
echo "[DRY-RUN] Would ask sync direction (GitHub->Gitea / Gitea->GitHub / both) and whether"
|
||||||
echo "[DRY-RUN] to install a systemd timer for automatic sync, or print manual instructions"
|
echo "[DRY-RUN] to install a systemd timer for automatic sync, or print manual instructions"
|
||||||
|
echo "[DRY-RUN] Would offer to run a sync now (dry-run preview or for real), off-schedule"
|
||||||
echo "[DRY-RUN] Would write $DIR/README.md"
|
echo "[DRY-RUN] Would write $DIR/README.md"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
@@ -337,8 +386,16 @@ EOF
|
|||||||
# what was just entered rather than failing the whole install.
|
# what was just entered rather than failing the whole install.
|
||||||
if docker exec -u git gitea gitea admin user list 2>/dev/null | awk '{print $2}' | grep -qx "$GITEA_ADMIN_USER"; then
|
if docker exec -u git gitea gitea admin user list 2>/dev/null | awk '{print $2}' | grep -qx "$GITEA_ADMIN_USER"; then
|
||||||
_exists=true
|
_exists=true
|
||||||
|
# --must-change-password=false matters here: change-password
|
||||||
|
# defaults to setting that flag TRUE, which then makes Gitea
|
||||||
|
# reject every API call (including this script's own token-based
|
||||||
|
# calls) with 403 "You must change your password" until someone
|
||||||
|
# logs into the web UI and clears it by hand. Confirmed live —
|
||||||
|
# this silently broke the sync script on every retry against an
|
||||||
|
# already-existing account.
|
||||||
docker exec -u git gitea gitea admin user change-password \
|
docker exec -u git gitea gitea admin user change-password \
|
||||||
--username "$GITEA_ADMIN_USER" --password "$GITEA_ADMIN_PASS" &>/dev/null
|
--username "$GITEA_ADMIN_USER" --password "$GITEA_ADMIN_PASS" \
|
||||||
|
--must-change-password=false &>/dev/null
|
||||||
_created=true
|
_created=true
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
@@ -356,15 +413,20 @@ EOF
|
|||||||
log_success "Admin account created: $GITEA_ADMIN_USER"
|
log_success "Admin account created: $GITEA_ADMIN_USER"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Token name includes a timestamp so a retry against an account that
|
||||||
|
# already has a "sync" token from an earlier partial run (see the
|
||||||
|
# already-exists branch above) never collides — Gitea rejects a second
|
||||||
|
# token with a name that's already taken for that user, which used to
|
||||||
|
# silently fall through to the manual-paste prompt below on every retry.
|
||||||
local GITEA_TOKEN=""
|
local GITEA_TOKEN=""
|
||||||
GITEA_TOKEN="$(docker exec -u git gitea gitea admin user generate-access-token \
|
GITEA_TOKEN="$(docker exec -u git gitea gitea admin user generate-access-token \
|
||||||
--username "$GITEA_ADMIN_USER" --token-name sync \
|
--username "$GITEA_ADMIN_USER" --token-name "sync-$(date +%s)" \
|
||||||
--scopes write:repository,write:user --raw 2>/dev/null)"
|
--scopes write:repository,write:user --raw 2>/dev/null)"
|
||||||
if [[ -z "$GITEA_TOKEN" ]]; then
|
if [[ -z "$GITEA_TOKEN" ]]; then
|
||||||
log_warning "Automatic token generation didn't work (older Gitea image?) — generate one"
|
log_warning "Automatic token generation didn't work (older Gitea image?) — generate one"
|
||||||
log_warning "by hand: log into http://localhost:${WEB_PORT} as $GITEA_ADMIN_USER, then"
|
log_warning "by hand: log into http://localhost:${WEB_PORT} as $GITEA_ADMIN_USER, then"
|
||||||
log_warning "Settings -> Applications -> Generate New Token (repo + user write access)."
|
log_warning "Settings -> Applications -> Generate New Token (repo + user write access)."
|
||||||
prompt_text " Paste the Gitea token here:" "" GITEA_TOKEN
|
_gitea_prompt_token " Paste the GITEA token here (not the GitHub one — that's next):" GITEA_TOKEN
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ── GitHub token ─────────────────────────────────────────────────────────
|
# ── GitHub token ─────────────────────────────────────────────────────────
|
||||||
@@ -373,7 +435,7 @@ EOF
|
|||||||
log_info "REST API too, which SSH can't do). Generate one at https://github.com/settings/tokens"
|
log_info "REST API too, which SSH can't do). Generate one at https://github.com/settings/tokens"
|
||||||
log_info "with 'repo' scope if you don't already have one handy."
|
log_info "with 'repo' scope if you don't already have one handy."
|
||||||
local GITHUB_TOKEN=""
|
local GITHUB_TOKEN=""
|
||||||
prompt_text " GitHub token:" "" GITHUB_TOKEN
|
_gitea_prompt_token " GitHub token:" GITHUB_TOKEN
|
||||||
if [[ -z "$GITHUB_TOKEN" ]]; then
|
if [[ -z "$GITHUB_TOKEN" ]]; then
|
||||||
log_warning "No GitHub token entered — Gitea itself is still up, but the sync script won't"
|
log_warning "No GitHub token entered — Gitea itself is still up, but the sync script won't"
|
||||||
log_warning "work until you add one to $DIR/.env and re-run this installer (update mode)."
|
log_warning "work until you add one to $DIR/.env and re-run this installer (update mode)."
|
||||||
|
|||||||
Vendored
+36
-6
@@ -87,6 +87,26 @@ _github_api() {
|
|||||||
|
|
||||||
_log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >> "$LOG_FILE"; }
|
_log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >> "$LOG_FILE"; }
|
||||||
|
|
||||||
|
# On a failed API call, "check your token" is often wrong — it could just as
|
||||||
|
# easily be the remote service down, an account locked behind a
|
||||||
|
# must-change-password wall, or a network/DNS problem. Re-probe with -i so
|
||||||
|
# the actual HTTP status and response body are visible, instead of leaving
|
||||||
|
# the user to run curl by hand to find out which one it actually was.
|
||||||
|
_probe_and_report() {
|
||||||
|
local _what="$1" _url="$2"; shift 2
|
||||||
|
local _tmp _code _body
|
||||||
|
_tmp="$(mktemp)"
|
||||||
|
_code="$(curl -sS -o "$_tmp" -w '%{http_code}' "$@" "$_url" 2>/dev/null)"
|
||||||
|
_body="$(cat "$_tmp" 2>/dev/null)"
|
||||||
|
rm -f "$_tmp"
|
||||||
|
if [[ -z "$_code" || "$_code" == "000" ]]; then
|
||||||
|
warn " $_what: no HTTP response at all — network/DNS problem reaching $_url, not a credentials problem."
|
||||||
|
else
|
||||||
|
warn " $_what responded: HTTP $_code"
|
||||||
|
[[ -n "$_body" ]] && warn " ${_body:0:300}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# ── config management ──────────────────────────────────────────────────────
|
# ── config management ──────────────────────────────────────────────────────
|
||||||
load_config() {
|
load_config() {
|
||||||
mkdir -p "$CONFIG_DIR" "$WORK_DIR"
|
mkdir -p "$CONFIG_DIR" "$WORK_DIR"
|
||||||
@@ -155,12 +175,22 @@ do_init() {
|
|||||||
# Discover usernames
|
# Discover usernames
|
||||||
info "Detecting GitHub user..."
|
info "Detecting GitHub user..."
|
||||||
GITHUB_USER=$(_github_api GET /user | python3 -c "import sys,json; print(json.load(sys.stdin)['login'])" 2>/dev/null) \
|
GITHUB_USER=$(_github_api GET /user | python3 -c "import sys,json; print(json.load(sys.stdin)['login'])" 2>/dev/null) \
|
||||||
|| { err "Failed to reach GitHub API. Check GITHUB_TOKEN."; exit 1; }
|
|| {
|
||||||
|
err "Failed to reach GitHub API. Check GITHUB_TOKEN."
|
||||||
|
_probe_and_report "GitHub" "https://api.github.com/user" \
|
||||||
|
-H "Authorization: Bearer $GITHUB_TOKEN" -H "Accept: application/vnd.github+json"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
ok "GitHub user: $GITHUB_USER"
|
ok "GitHub user: $GITHUB_USER"
|
||||||
|
|
||||||
info "Detecting Gitea user..."
|
info "Detecting Gitea user..."
|
||||||
GITEA_USER=$(_gitea_api GET /user | python3 -c "import sys,json; print(json.load(sys.stdin)['login'])" 2>/dev/null) \
|
GITEA_USER=$(_gitea_api GET /user | python3 -c "import sys,json; print(json.load(sys.stdin)['login'])" 2>/dev/null) \
|
||||||
|| { err "Failed to reach Gitea API. Check GITEA_TOKEN and GITEA_URL ($GITEA_URL)."; exit 1; }
|
|| {
|
||||||
|
err "Failed to reach Gitea API. Check GITEA_TOKEN and GITEA_URL ($GITEA_URL)."
|
||||||
|
_probe_and_report "Gitea" "$GITEA_URL/api/v1/user" \
|
||||||
|
-H "Authorization: token $GITEA_TOKEN"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
ok "Gitea user: $GITEA_USER"
|
ok "Gitea user: $GITEA_USER"
|
||||||
|
|
||||||
# Ask about sync scope
|
# Ask about sync scope
|
||||||
@@ -351,9 +381,9 @@ do_sync() {
|
|||||||
[[ -n "$SINGLE_REPO" && "$name" != "$SINGLE_REPO" ]] && continue
|
[[ -n "$SINGLE_REPO" && "$name" != "$SINGLE_REPO" ]] && continue
|
||||||
is_excluded "$name" && continue
|
is_excluded "$name" && continue
|
||||||
if sync_github_to_gitea "$name" "$url" "$priv"; then
|
if sync_github_to_gitea "$name" "$url" "$priv"; then
|
||||||
((pull_count++))
|
pull_count=$((pull_count + 1))
|
||||||
else
|
else
|
||||||
((fail_count++))
|
fail_count=$((fail_count + 1))
|
||||||
fi
|
fi
|
||||||
done < <(get_github_repos)
|
done < <(get_github_repos)
|
||||||
fi
|
fi
|
||||||
@@ -372,9 +402,9 @@ do_sync() {
|
|||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
if sync_gitea_to_github "$name" "$url" "$priv"; then
|
if sync_gitea_to_github "$name" "$url" "$priv"; then
|
||||||
((push_count++))
|
push_count=$((push_count + 1))
|
||||||
else
|
else
|
||||||
((fail_count++))
|
fail_count=$((fail_count + 1))
|
||||||
fi
|
fi
|
||||||
done < <(get_gitea_repos)
|
done < <(get_gitea_repos)
|
||||||
fi
|
fi
|
||||||
|
|||||||
Reference in New Issue
Block a user