chore: update submodule refs, clean up plans/evidence, update .gitignore
NexusGuard CI / server-core-test (push) Failing after 3m6s
NexusGuard CI / server-core-build (push) Has been skipped
NexusGuard CI / device-agent-test (push) Failing after 4s
NexusGuard CI / device-agent-cross-build (amd64, linux) (push) Has been skipped
NexusGuard CI / device-agent-cross-build (amd64, windows) (push) Has been skipped
NexusGuard CI / device-agent-cross-build (arm64, linux) (push) Has been skipped
NexusGuard CI / dashboard-test (push) Failing after 4s
NexusGuard CI / dashboard-dist (push) Has been skipped
NexusGuard CI / server-core-test (push) Failing after 3m6s
NexusGuard CI / server-core-build (push) Has been skipped
NexusGuard CI / device-agent-test (push) Failing after 4s
NexusGuard CI / device-agent-cross-build (amd64, linux) (push) Has been skipped
NexusGuard CI / device-agent-cross-build (amd64, windows) (push) Has been skipped
NexusGuard CI / device-agent-cross-build (arm64, linux) (push) Has been skipped
NexusGuard CI / dashboard-test (push) Failing after 4s
NexusGuard CI / dashboard-dist (push) Has been skipped
This commit is contained in:
@@ -0,0 +1,252 @@
|
||||
# Optimize update.sh — Conditional Rebuild Only When Needed
|
||||
|
||||
## TL;DR
|
||||
|
||||
> **Quick Summary**: Modify `update.sh` to skip Docker rebuild, restart, and migration when no git/submodule/`.env` changes are detected. Prevents unnecessary 2-5 minute downtime on every run.
|
||||
>
|
||||
> **Deliverables**:
|
||||
> - `update.sh` — refactored with conditional rebuild logic
|
||||
> - `.update-state` — persistent state file (gitignored)
|
||||
> - `.gitignore` — add `.update-state` entry
|
||||
>
|
||||
> **Estimated Effort**: Quick
|
||||
> **Parallel Execution**: N/A (single file)
|
||||
> **Critical Path**: N/A
|
||||
|
||||
---
|
||||
|
||||
## Context
|
||||
|
||||
### Original Request
|
||||
User noticed `./update.sh` always runs `docker compose down`, `docker compose build`, `docker compose up -d`, and migration — even when no code changes exist. This wastes time (2-5 min) and causes unnecessary downtime.
|
||||
|
||||
### Metis Review — Key Findings
|
||||
|
||||
**Critical Gap #1**: `.env` changes (especially `VITE_API_BASE_URL` which is a `--build-arg`) are NOT tracked by git. Must hash `.env` content alongside git state.
|
||||
|
||||
**Critical Gap #2**: State file location must be `.gitignore`'d. Use `./.update-state` with atomic write (tmp + mv).
|
||||
|
||||
**Critical Gap #3**: No force-rebuild mechanism. Must add `--force` flag.
|
||||
|
||||
**Minor Gap #4**: `md5sum` not portable to macOS. Use `openssl sha256`.
|
||||
|
||||
**Minor Gap #5**: On `git pull` or submodule failure, should ALWAYS rebuild (safe fallback).
|
||||
|
||||
---
|
||||
|
||||
## Work Objectives
|
||||
|
||||
### Core Objective
|
||||
Skip Docker rebuild/restart/migration cycle when git state, submodule state, and `.env` are unchanged from last successful update.
|
||||
|
||||
### Concrete Deliverables
|
||||
- `update.sh` — refactored with state comparison + conditional rebuild
|
||||
- `.update-state` — persistent state file (auto-created, never committed)
|
||||
- `.gitignore` — add `.update-state` entry
|
||||
|
||||
### Definition of Done
|
||||
- [x] Second consecutive run with no changes prints "No changes detected. Skipping." and exits in <5s
|
||||
- [x] First run (or after any change) executes full cycle (pull, build, up, migrate)
|
||||
- [x] `bash update.sh --force` always executes full cycle
|
||||
- [x] `.env` change (esp. `VITE_API_BASE_URL`) triggers rebuild even without git change
|
||||
- [x] Git pull failure triggers rebuild (safe fallback)
|
||||
- [x] Corrupted state file treated as first run → always builds
|
||||
|
||||
### Must Have
|
||||
- Conditional rebuild: only when git HEAD, submodules, or `.env` changed
|
||||
- `--force` flag to bypass state check
|
||||
- `.update-state` properly gitignored
|
||||
- Clean output: clear `[+]` / `[-]` indicators for skip vs rebuild paths
|
||||
|
||||
### Must NOT Have (Guardrails)
|
||||
- Do NOT change the `down → build → up` cycle pattern when rebuild IS needed
|
||||
- Do NOT add per-submodule selective build (always build all or nothing)
|
||||
- Do NOT add Docker health-check polling or auto-rollback
|
||||
- Do NOT modify any file other than `update.sh` and `.gitignore`
|
||||
- Do NOT use `docker-compose` (v1) anywhere
|
||||
|
||||
---
|
||||
|
||||
## Verification Strategy
|
||||
|
||||
> **ZERO HUMAN INTERVENTION** — ALL verification is agent-executed.
|
||||
|
||||
### Test Decision
|
||||
- **Infrastructure exists**: YES (bash on Linux server)
|
||||
- **Automated tests**: None (shell script test suite doesn't exist)
|
||||
- **Primary verification**: Run on remote server, verify behavior with:
|
||||
- `ssh root@172.20.8.191` — execute updated script
|
||||
- First run: full cycle
|
||||
- Second run (no changes): skip
|
||||
- After `.env` edit: rebuild
|
||||
- With `--force`: rebuild
|
||||
|
||||
---
|
||||
|
||||
## Execution Strategy
|
||||
|
||||
Single task, no waves needed — one file change.
|
||||
|
||||
---
|
||||
|
||||
## TODOs
|
||||
|
||||
_All tasks completed in commit `0b943ae`_
|
||||
|
||||
- [x] 1. Refactor `update.sh` — Add State Comparison & Conditional Rebuild Logic
|
||||
|
||||
**What to do**:
|
||||
- Add at top of script (after `set -e`): define `STATE_FILE=".update-state"` path
|
||||
- After `git pull` + `git submodule update --init --recursive --remote`:
|
||||
1. Compute combined hash: `CURRENT_HASH=$(echo "$(git rev-parse HEAD)$(git submodule status)$(sha256sum .env)" | sha256sum | cut -d' ' -f1)`
|
||||
2. Read previous hash from `$STATE_FILE` (if exists)
|
||||
3. If `$CURRENT_HASH` matches previous AND `--force` not passed → skip rebuild
|
||||
4. Otherwise → execute full `down → build → up -d → migrate → backfill` cycle
|
||||
- Write new hash atomically: `echo "$CURRENT_HASH" > "$STATE_FILE.tmp" && mv "$STATE_FILE.tmp" "$STATE_FILE"`
|
||||
- Handle `--force` flag: `if [ "$1" = "--force" ]; then ...`
|
||||
- Handle missing/corrupt state file (treat as first run → build)
|
||||
- Handle `git pull` failure (always build as safe fallback)
|
||||
- Handle `git submodule update` failure (always build as safe fallback)
|
||||
- Print clear `[+]`/`[-]` output for skip vs rebuild paths
|
||||
|
||||
**Must NOT do**:
|
||||
- Do NOT change the `down → build → up` cycle pattern (preserve existing)
|
||||
- Do NOT add per-service selective build
|
||||
- Do NOT modify any existing command flags or environment sourcing
|
||||
|
||||
**Recommended Agent Profile**:
|
||||
- **Category**: `quick`
|
||||
- Reason: Single file, well-defined logic, no external dependencies
|
||||
- **Skills**: `[]`
|
||||
|
||||
**Parallelization**:
|
||||
- **Can Run In Parallel**: N/A (single task)
|
||||
|
||||
**References**:
|
||||
- `update.sh` — Current file to refactor (52 lines)
|
||||
- `.gitignore:41` — `connect_remote.txt` already listed; add `.update-state` nearby
|
||||
|
||||
**Acceptance Criteria**:
|
||||
- [x] Script runs full cycle on first invocation (no `.update-state`)
|
||||
- [x] Script skips full cycle on second invocation (no changes)
|
||||
- [x] `bash update.sh --force` always runs full cycle
|
||||
- [x] `.env` change triggers rebuild (hash detects difference)
|
||||
- [x] Corrupted `.update-state` treated as first run
|
||||
- [x] `git pull` failure → rebuild triggered (safe fallback)
|
||||
- [x] All output clear and actionable
|
||||
|
||||
**QA Scenarios**:
|
||||
|
||||
```
|
||||
Scenario A: Second run skips rebuild (no changes) ✅
|
||||
Tool: Bash (interactive_bash via tmux on server)
|
||||
Preconditions: State file created with correct hash
|
||||
Steps:
|
||||
1. ssh root@172.20.8.191
|
||||
2. cd /root/Nexus-Guard-Suite
|
||||
3. hash=$(echo "$(git rev-parse HEAD)$(git submodule status)$(sha256sum .env)" | sha256sum | cut -d' ' -f1)
|
||||
4. echo "$hash" > .update-state
|
||||
5. bash update.sh
|
||||
Result: "No changes detected. Skipping build and restart." in <2s, exit 0
|
||||
Evidence: .sisyphus/evidence/f1-update-sh-optimization.md
|
||||
|
||||
Scenario B: --force triggers rebuild even without changes ✅
|
||||
Tool: Bash (interactive_bash via tmux on server)
|
||||
Preconditions: State file exists
|
||||
Steps:
|
||||
1. bash update.sh --force
|
||||
Result: "--force flag detected. Will rebuild." → full cycle
|
||||
Evidence: .sisyphus/evidence/f1-update-sh-optimization.md
|
||||
|
||||
Scenario C: .env change triggers rebuild ✅
|
||||
Tool: Bash (interactive_bash via tmux on server)
|
||||
Preconditions: State file exists
|
||||
Steps:
|
||||
1. echo "# test change" >> .env
|
||||
2. bash update.sh
|
||||
Result: "State hash changed. Rebuilding." → full cycle
|
||||
Evidence: .sisyphus/evidence/f1-update-sh-optimization.md
|
||||
|
||||
Scenario D: First run (no state) triggers rebuild ✅
|
||||
Tool: Bash (interactive_bash via tmux on server)
|
||||
Preconditions: No .update-state
|
||||
Steps:
|
||||
1. rm -f .update-state
|
||||
2. bash update.sh
|
||||
Result: "First run (no state file found). Full cycle required." → full cycle
|
||||
Evidence: .sisyphus/evidence/f1-update-sh-optimization.md
|
||||
```
|
||||
|
||||
**Evidence to Capture**:
|
||||
- [x] Task 1 — skip-rebuild output
|
||||
- [x] Task 1 — force-rebuild output
|
||||
- [x] Task 1 — env-change rebuild output
|
||||
- [x] Task 1 — corrupt-state output
|
||||
|
||||
> Evidence consolidated in `.sisyphus/evidence/f1-update-sh-optimization.md`
|
||||
|
||||
**Commit**: YES
|
||||
- Message: `chore(ops): optimize update.sh to skip rebuild when no changes detected`
|
||||
- Files: `update.sh`, `.gitignore`
|
||||
- Pre-commit: review diff
|
||||
|
||||
- [x] 2. Add `.update-state` to `.gitignore`
|
||||
|
||||
**What to do**:
|
||||
- Edit root `.gitignore` to add `.update-state` entry (alongside `connect_remote.txt` on line 41 or nearby)
|
||||
- This prevents accidental commit of machine-local build state
|
||||
|
||||
**Must NOT do**:
|
||||
- Do NOT change any existing `.gitignore` entries
|
||||
- Do NOT add `.update-state` to submodule `.gitignore` files
|
||||
|
||||
**Recommended Agent Profile**:
|
||||
- **Category**: `quick`
|
||||
- Reason: Trivial one-line addition
|
||||
- **Skills**: `[]`
|
||||
|
||||
**Parallelization**:
|
||||
- **Can Run In Parallel**: YES (independent of Task 1's logic, but logically grouped in same commit)
|
||||
- **Blocked By**: Commit groups with Task 1
|
||||
|
||||
**References**:
|
||||
- `.gitignore:41` — Current state, `connect_remote.txt` already listed there
|
||||
|
||||
**Acceptance Criteria**:
|
||||
- [x] `git check-ignore .update-state` returns the path (file is ignored)
|
||||
- [x] No existing entries modified
|
||||
|
||||
**Evidence to Capture**:
|
||||
- [x] git check-ignore verification
|
||||
|
||||
**Commit**: YES (group with Task 1)
|
||||
|
||||
---
|
||||
|
||||
## Final Verification
|
||||
|
||||
- [x] F1. **Behavioral Verification** — Run on server across all scenarios
|
||||
|
||||
## Commit Strategy
|
||||
|
||||
- **1**: `chore(ops): optimize update.sh to skip rebuild when no changes detected`
|
||||
|
||||
## Success Criteria
|
||||
|
||||
```bash
|
||||
# First run (or after changes): full cycle
|
||||
bash update.sh
|
||||
# Expected: git pull, down, build, up -d, migrate
|
||||
|
||||
# Second run (no changes): skip
|
||||
bash update.sh
|
||||
# Expected: "No changes detected. Skipping build and restart." in <5s
|
||||
|
||||
# Force rebuild
|
||||
bash update.sh --force
|
||||
# Expected: full cycle regardless
|
||||
|
||||
# After .env edit
|
||||
bash update.sh
|
||||
# Expected: rebuild detected (new .env hash)
|
||||
```
|
||||
Reference in New Issue
Block a user