refactor(restic): extract helper from backup to reduce complexity (S3776) #79

Open
Claude wants to merge 1 commit from Claude/backup-script:fix/issue-7-S3776-restic-complexity into master
First-time contributor

Closes #7

Restic.backup had cognitive complexity 21 (SonarQube ceiling: 15).

Refactor

Extracted three single-purpose private helpers from the 145-line streaming
backup method:

  • _build_backup_cmd(*, paths, excludes, tags, host, retry_lock) — assembles
    the restic backup --json argv (option-conditional flags + paths). Pure;
    no side effects.
  • _consume_backup_stream(proc) — drains proc.stdout line-by-line,
    parses each JSON message, returns (summary, errors). Logs unparseable
    lines and file-level errors with their original log keys.
  • _wait_or_terminate(proc, *, timeout) — waits for the child with the
    supplied timeout; on TimeoutExpired invokes _terminate_then_kill and
    returns (-1, True). Otherwise returns (returncode, False).

The body of backup() collapses to: validate input -> build cmd -> spawn
subprocess -> start stderr drain thread -> call the two consume helpers
inside the existing try/except BaseException reaping guard -> join thread
in finally -> log + return.

Behavior

Identical. The outer try/except BaseException / finally that guarantees
child reap + stderr-thread join is preserved verbatim. All log keys (incl.
restic.backup.start, restic.backup.end, restic.backup.file_error,
restic.backup.json_decode_failed) and the returned ResticBackupResult
fields are unchanged. Timeout escalation (SIGTERM -> grace -> SIGKILL via
_terminate_then_kill) is unchanged.

Verification

  • pytest -q tests/unit/ — passes (incl. test_restic_streaming.py
    and test_restic_engine_audit_fixes.py)
  • mypy --strict src/gardien/core src/gardien/config src/gardien/engine src/gardien/steps — passes
Closes #7 `Restic.backup` had cognitive complexity 21 (SonarQube ceiling: 15). ### Refactor Extracted three single-purpose private helpers from the 145-line streaming backup method: - `_build_backup_cmd(*, paths, excludes, tags, host, retry_lock)` — assembles the `restic backup --json` argv (option-conditional flags + paths). Pure; no side effects. - `_consume_backup_stream(proc)` — drains `proc.stdout` line-by-line, parses each JSON message, returns `(summary, errors)`. Logs unparseable lines and file-level errors with their original log keys. - `_wait_or_terminate(proc, *, timeout)` — waits for the child with the supplied timeout; on `TimeoutExpired` invokes `_terminate_then_kill` and returns `(-1, True)`. Otherwise returns `(returncode, False)`. The body of `backup()` collapses to: validate input -> build cmd -> spawn subprocess -> start stderr drain thread -> call the two consume helpers inside the existing `try/except BaseException` reaping guard -> join thread in `finally` -> log + return. ### Behavior Identical. The outer `try/except BaseException` / `finally` that guarantees child reap + stderr-thread join is preserved verbatim. All log keys (incl. `restic.backup.start`, `restic.backup.end`, `restic.backup.file_error`, `restic.backup.json_decode_failed`) and the returned `ResticBackupResult` fields are unchanged. Timeout escalation (SIGTERM -> grace -> SIGKILL via `_terminate_then_kill`) is unchanged. ### Verification - `pytest -q tests/unit/` — passes (incl. test_restic_streaming.py and test_restic_engine_audit_fixes.py) - `mypy --strict src/gardien/core src/gardien/config src/gardien/engine src/gardien/steps` — passes
Split the streaming backup method into three single-purpose helpers:
- _build_backup_cmd: assembles the restic CLI argv from options.
- _consume_backup_stream: drains stdout, parses JSON lines, returns
  (summary, errors).
- _wait_or_terminate: waits with timeout, terminates on expiry,
  returns (returncode, timed_out).

The body of backup() collapses to: build cmd -> spawn -> drain helpers
-> log -> return. The outer try/except BaseException / finally that
guarantees child reap + stderr-thread join is preserved verbatim.

Behavior identical; SonarQube cognitive complexity 21 -> well under 15.
This pull request can be merged automatically.
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u fix/issue-7-S3776-restic-complexity:Claude-fix/issue-7-S3776-restic-complexity
git switch Claude-fix/issue-7-S3776-restic-complexity

Merge

Merge the changes and update on Forgejo.

Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.

git switch master
git merge --no-ff Claude-fix/issue-7-S3776-restic-complexity
git switch Claude-fix/issue-7-S3776-restic-complexity
git rebase master
git switch master
git merge --ff-only Claude-fix/issue-7-S3776-restic-complexity
git switch Claude-fix/issue-7-S3776-restic-complexity
git rebase master
git switch master
git merge --no-ff Claude-fix/issue-7-S3776-restic-complexity
git switch master
git merge --squash Claude-fix/issue-7-S3776-restic-complexity
git switch master
git merge --ff-only Claude-fix/issue-7-S3776-restic-complexity
git switch master
git merge Claude-fix/issue-7-S3776-restic-complexity
git push origin master
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
bc1bb/backup-script!79
No description provided.