diff --git a/gitops_backup/CHANGELOG.md b/gitops_backup/CHANGELOG.md index 84fabe5..5230e2d 100644 --- a/gitops_backup/CHANGELOG.md +++ b/gitops_backup/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 0.1.1 + +- Fix: keep the addon's own runtime files (`.gitops_backup_status`, + `gitops_backup.log`) out of backups when migrating a repo that already has a + `.gitignore` — they were previously swept into backup PRs and risked a + status-file PR feedback loop. Now excluded via `.git/info/exclude` on every + run, and untracked if a prior run committed them. + ## 0.1.0 - Initial release: PR-gated backup (stash → rebase → drift → branch → PR), diff --git a/gitops_backup/config.json b/gitops_backup/config.json index f44390e..ac2e8fa 100644 --- a/gitops_backup/config.json +++ b/gitops_backup/config.json @@ -1,6 +1,6 @@ { "name": "HA GitOps", - "version": "0.1.0", + "version": "0.1.1", "slug": "gitops_backup", "description": "PR-gated GitHub backup for your Home Assistant config \u2014 nothing force-pushes, every change is reviewable, CI validates before merge", "url": "https://github.com/askb/ha-gitops", diff --git a/gitops_backup/rootfs/app/gitops_backup.sh b/gitops_backup/rootfs/app/gitops_backup.sh index d59d767..2cd4832 100755 --- a/gitops_backup/rootfs/app/gitops_backup.sh +++ b/gitops_backup/rootfs/app/gitops_backup.sh @@ -95,6 +95,37 @@ EOF fi } +ensure_own_excludes() { + # The addon's own runtime files must never be committed — not even when the + # repo already had a .gitignore (seed_gitignore only writes one when none + # exists, so migrating an existing repo would otherwise sweep these into a + # backup PR and risk a status-file PR feedback loop). .git/info/exclude is + # git's local, non-committed ignore — the right home for addon-managed + # metadata. Idempotent: replace our managed block each run. + [ -d .git ] || return 0 + mkdir -p .git/info + local exclude=".git/info/exclude" + if [ -f "$exclude" ]; then +sed -i \ + '/# >>> gitops-backup managed >>>/,/# <<< gitops-backup managed <<> "$exclude" <<'EOF' +# >>> gitops-backup managed >>> +.gitops_backup_status +gitops_backup.log +# <<< gitops-backup managed <<< +EOF + # If a prior buggy run already committed these, stop tracking them (the + # removal flows out through the next backup PR). + local f + for f in .gitops_backup_status gitops_backup.log; do +if git ls-files --error-unmatch "$f" >/dev/null 2>&1; then + git rm -q --cached "$f" +fi + done +} + bootstrap_if_needed() { # Returns 0 if bootstrap ran (caller should stop), 1 if repo already exists if [ -d .git ]; then return 1; fi @@ -151,6 +182,7 @@ main() { fi git remote set-url origin "$REMOTE_URL" seed_gitignore + ensure_own_excludes trap cleanup_branch EXIT # 1–2. Stash local drift, sync upstream (merged PRs flow back here) diff --git a/tests/self_check.sh b/tests/self_check.sh index 90be940..feae558 100755 --- a/tests/self_check.sh +++ b/tests/self_check.sh @@ -62,4 +62,25 @@ git -c safe.bareRepository=all -C "$TMP/origin.git" branch | grep -q "auto-backu status | grep -q "warning:branch_pushed" || { echo "FAIL: drift status = $(status)"; exit 1; } git -C "$TMP/config" branch --show-current | grep -q "^main$" || { echo "FAIL: not back on main"; exit 1; } +# 4. Migration case: repo already had its own .gitignore lacking the addon's +# entries, and was never excluded. The addon's own status file + log must +# still be kept out of the backup (regression test for the seed_gitignore +# skip-when-.gitignore-exists bug). +sleep 1 # ensure a distinct auto-backup/ branch name +rm -f "$TMP/config/.git/info/exclude" # never-excluded repo +printf 'secrets.yaml\n' > "$TMP/config/.gitignore" # user ignore, no addon entries +HOME="$TMP" git -C "$TMP/config" add .gitignore +HOME="$TMP" git -C "$TMP/config" commit -q -m "user gitignore" +echo "success:no_changes:" > "$TMP/config/.gitops_backup_status" +echo "log line" > "$TMP/config/gitops_backup.log" +echo "more drift" >> "$TMP/config/configuration.yaml" +run +newbranch=$(git -c safe.bareRepository=all -C "$TMP/origin.git" branch \ + | grep -o 'auto-backup/[^ ]*' | tail -1) +tree=$(git -c safe.bareRepository=all -C "$TMP/origin.git" ls-tree -r --name-only "$newbranch") +if echo "$tree" | grep -qE '^\.gitops_backup_status$|^gitops_backup\.log$'; then + echo "FAIL: addon runtime files committed to backup branch"; exit 1 +fi +echo "$tree" | grep -q "^configuration.yaml$" || { echo "FAIL: real drift not backed up"; exit 1; } + echo "OK: all self-checks passed"