-
Notifications
You must be signed in to change notification settings - Fork 9
GH#4142: fix auto-update recovery for dirty tree, diverged branch, and API rate limits #4144
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
07abc8a
de4e88f
1df47ea
b33af98
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -303,6 +303,23 @@ get_local_version() { | |
| ####################################### | ||
| get_remote_version() { | ||
| local version="" | ||
|
|
||
| # Prefer authenticated gh api (higher rate limit: 5000/hr vs 60/hr) | ||
| # This avoids the "remote=unknown" failures seen during overnight polling | ||
| # when unauthenticated API quota is exhausted. | ||
| # See: https://github.com/marcusquinn/aidevops/issues/4142 | ||
| if command -v gh &>/dev/null && gh auth status &>/dev/null; then | ||
| version=$(gh api repos/marcusquinn/aidevops/contents/VERSION \ | ||
| --jq '.content' 2>/dev/null | | ||
| base64 -d 2>/dev/null | | ||
| tr -d '\n') | ||
| if [[ -n "$version" ]]; then | ||
| echo "$version" | ||
| return 0 | ||
| fi | ||
| fi | ||
|
|
||
| # Fallback: unauthenticated curl (60 req/hr limit) | ||
| if command -v jq &>/dev/null; then | ||
| version=$(curl --proto '=https' -fsSL --max-time 10 \ | ||
| "https://api.github.com/repos/marcusquinn/aidevops/contents/VERSION" 2>/dev/null | | ||
|
|
@@ -314,7 +331,8 @@ get_remote_version() { | |
| return 0 | ||
| fi | ||
| fi | ||
| # Fallback to raw (CDN-cached, may be up to 5 min stale) | ||
|
|
||
| # Last resort: raw.githubusercontent.com (CDN-cached, may be up to 5 min stale) | ||
| curl --proto '=https' -fsSL --max-time 10 \ | ||
| "https://raw.githubusercontent.com/marcusquinn/aidevops/main/VERSION" 2>/dev/null | | ||
| tr -d '\n' || echo "unknown" | ||
|
|
@@ -384,6 +402,18 @@ update_state() { | |
| return 0 | ||
| } | ||
|
|
||
| ####################################### | ||
| # Run all periodic freshness checks (skills, OpenClaw, tools, upstream watch). | ||
| # Extracted to avoid duplicating the same 4-call block at every exit point | ||
| # in cmd_check(). Each check has its own internal time gate. | ||
| ####################################### | ||
| run_freshness_checks() { | ||
| check_skill_freshness | ||
| check_openclaw_freshness | ||
| check_tool_freshness | ||
| check_upstream_watch | ||
| } | ||
|
|
||
| ####################################### | ||
| # Check skill freshness and auto-update if stale (24h gate) | ||
| # Called from cmd_check after the main aidevops update logic. | ||
|
|
@@ -1011,10 +1041,7 @@ cmd_check() { | |
| if [[ "$current" == "unknown" || "$remote" == "unknown" ]]; then | ||
| log_warn "Could not determine versions (local=$current, remote=$remote)" | ||
| update_state "check" "$current" "version_unknown" | ||
| check_skill_freshness | ||
| check_openclaw_freshness | ||
| check_tool_freshness | ||
| check_upstream_watch | ||
| run_freshness_checks | ||
| return 0 | ||
| fi | ||
|
|
||
|
|
@@ -1042,10 +1069,7 @@ cmd_check() { | |
| fi | ||
| fi | ||
|
|
||
| check_skill_freshness | ||
| check_openclaw_freshness | ||
| check_tool_freshness | ||
| check_upstream_watch | ||
| run_freshness_checks | ||
| return 0 | ||
| fi | ||
|
|
||
|
|
@@ -1057,32 +1081,62 @@ cmd_check() { | |
| if [[ ! -d "$INSTALL_DIR/.git" ]]; then | ||
| log_error "Install directory is not a git repo: $INSTALL_DIR" | ||
| update_state "update" "$remote" "no_git_repo" | ||
| check_skill_freshness | ||
| check_openclaw_freshness | ||
| check_tool_freshness | ||
| check_upstream_watch | ||
| run_freshness_checks | ||
| return 1 | ||
| fi | ||
|
|
||
| # Clean up any working tree changes left by setup.sh or other processes | ||
| # (e.g., chmod on tracked scripts, scan results written to repo) | ||
| # This ensures git pull --ff-only won't be blocked by dirty files. | ||
| # See: https://github.com/marcusquinn/aidevops/issues/2286 | ||
| if ! git -C "$INSTALL_DIR" diff --quiet 2>/dev/null || ! git -C "$INSTALL_DIR" diff --cached --quiet 2>/dev/null; then | ||
| log_info "Cleaning up stale working tree changes..." | ||
| if ! git -C "$INSTALL_DIR" reset HEAD -- . 2>>"$LOG_FILE"; then | ||
| log_warn "git reset HEAD failed during working tree cleanup" | ||
| fi | ||
| if ! git -C "$INSTALL_DIR" checkout -- . 2>>"$LOG_FILE"; then | ||
| log_warn "git checkout -- . failed during working tree cleanup" | ||
| fi | ||
| fi | ||
|
|
||
| # Ensure we're on the main branch (detached HEAD or stale branch blocks pull) | ||
| # Mirrors recovery logic from aidevops.sh cmd_update() | ||
| # See: https://github.com/marcusquinn/aidevops/issues/4142 | ||
| local current_branch | ||
| current_branch=$(git -C "$INSTALL_DIR" branch --show-current 2>/dev/null || echo "") | ||
| if [[ "$current_branch" != "main" ]]; then | ||
| log_info "Not on main branch ($current_branch), switching..." | ||
| if ! git -C "$INSTALL_DIR" checkout main --quiet 2>>"$LOG_FILE" && | ||
| ! git -C "$INSTALL_DIR" checkout -b main origin/main --quiet 2>>"$LOG_FILE"; then | ||
| log_error "Failed to switch to main branch from '$current_branch' in $INSTALL_DIR" | ||
| update_state "update" "$remote" "branch_switch_failed" | ||
| run_freshness_checks | ||
| return 1 | ||
| fi | ||
| fi | ||
|
|
||
| # Pull latest changes | ||
| if ! git -C "$INSTALL_DIR" fetch origin main --quiet 2>>"$LOG_FILE"; then | ||
| log_error "git fetch failed" | ||
| update_state "update" "$remote" "fetch_failed" | ||
| check_skill_freshness | ||
| check_openclaw_freshness | ||
| check_tool_freshness | ||
| check_upstream_watch | ||
| run_freshness_checks | ||
| return 1 | ||
| fi | ||
|
Comment on lines
+1102
to
1124
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's a logic error in the order of operations here. The While this mirrors the logic in # Pull latest changes
if ! git -C "$INSTALL_DIR" fetch origin main --quiet 2>>"$LOG_FILE"; then
log_error "git fetch failed"
update_state "update" "$remote" "fetch_failed"
run_freshness_checks
return 1
fi
# Ensure we're on the main branch (detached HEAD or stale branch blocks pull)
# Mirrors recovery logic from aidevops.sh cmd_update()
# See: https://github.com/marcusquinn/aidevops/issues/4142
local current_branch
current_branch=$(git -C "$INSTALL_DIR" branch --show-current 2>/dev/null || echo "")
if [[ "$current_branch" != "main" ]]; then
log_info "Not on main branch ($current_branch), switching..."
if ! git -C "$INSTALL_DIR" checkout main --quiet 2>>"$LOG_FILE" &&
! git -C "$INSTALL_DIR" checkout -b main origin/main --quiet 2>>"$LOG_FILE"; then
log_error "Failed to switch to main branch from '$current_branch' in $INSTALL_DIR"
update_state "update" "$remote" "branch_switch_failed"
run_freshness_checks
return 1
fi
fi |
||
|
|
||
| if ! git -C "$INSTALL_DIR" pull --ff-only origin main --quiet 2>>"$LOG_FILE"; then | ||
| log_error "git pull --ff-only failed (local changes?)" | ||
| update_state "update" "$remote" "pull_failed" | ||
| check_skill_freshness | ||
| check_openclaw_freshness | ||
| check_tool_freshness | ||
| check_upstream_watch | ||
| return 1 | ||
| # Fast-forward failed (diverged history or persistent dirty state). | ||
| # Since we just fetched origin/main, reset to it — the repo is managed | ||
| # by aidevops and should always track origin/main exactly. | ||
| # See: https://github.com/marcusquinn/aidevops/issues/2288 | ||
| log_warn "git pull --ff-only failed — falling back to reset" | ||
| if git -C "$INSTALL_DIR" reset --hard origin/main --quiet 2>>"$LOG_FILE"; then | ||
| log_info "Reset to origin/main succeeded" | ||
| else | ||
| log_error "git reset --hard origin/main also failed" | ||
| update_state "update" "$remote" "pull_failed" | ||
| run_freshness_checks | ||
| return 1 | ||
| fi | ||
| fi | ||
|
|
||
| # Run setup.sh non-interactively to deploy agents | ||
|
|
@@ -1105,24 +1159,20 @@ cmd_check() { | |
| else | ||
| log_error "setup.sh failed (exit code: $?)" | ||
| update_state "update" "$remote" "setup_failed" | ||
| check_skill_freshness | ||
| check_openclaw_freshness | ||
| check_tool_freshness | ||
| check_upstream_watch | ||
| run_freshness_checks | ||
| return 1 | ||
| fi | ||
|
|
||
| # Run daily skill freshness check (24h gate) | ||
| check_skill_freshness | ||
|
|
||
| # Run daily OpenClaw update check (24h gate) | ||
| check_openclaw_freshness | ||
|
|
||
| # Run 6-hourly tool freshness check (idle-gated) | ||
| check_tool_freshness | ||
| # Clean up any working tree changes setup.sh may have introduced | ||
| # (e.g., chmod on tracked scripts, scan results written to repo) | ||
| # Prevents dirty tree from blocking the next update cycle. | ||
| # See: https://github.com/marcusquinn/aidevops/issues/2286 | ||
| if ! git -C "$INSTALL_DIR" checkout -- . 2>>"$LOG_FILE"; then | ||
| log_warn "Post-setup working tree cleanup failed — next update cycle may see dirty state" | ||
| fi | ||
|
|
||
| # Run daily upstream watch check (24h gate) | ||
| check_upstream_watch | ||
| # Run periodic freshness checks (skills, OpenClaw, tools, upstream watch) | ||
| run_freshness_checks | ||
|
|
||
| return 0 | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
gh apicommand uses--jq '.content', which relies onjqbeing available. To align with the repository rule of preferring built-in tools likegrepover external dependencies likejqfor simple tasks, consider parsing the JSON output directly usinggreporsedinstead ofgh's--jqflag. This avoids thejqdependency entirely and improves portability.References
grepover external dependencies likejqfor simple tasks, to avoid installation requirements on diverse systems.