style(1b): auto-format + lint-clean the whole codebase (RL1)

Mechanical, semantics-preserving cleanup so the codebase passes the new lint stage:
- ruff format: all 32 Python files (wraps long signatures, normalizes quotes/blank lines).
- nixpkgs-fmt: modules/drone-runner.nix.
- shfmt (-i 2 -ci): scripts/*.sh.

Lint fixes (reviewed, behavior-preserving — no test weakened):
- ruff SIM105: try/except-pass -> contextlib.suppress (abra.py app_config rm; lifecycle.py janitor).
- ruff SIM115: open().read() -> with open() (run_recipe_ci.py redaction-values + gitea-token).
- statix: merge repeated sops `secrets.*` keys into one `secrets = { ... }` (comments kept);
  empty fn pattern `{ ... }:` -> `_:` (packages.nix).
- deadnix: drop unused lambda args (flake `self`; configuration.nix `lib`; overlay `final` -> `_`).

Verified on cc-ci: `scripts/lint.sh` -> lint: PASS; nixosConfigurations.cc-ci evaluates;
all Python byte-compiles. The deployed bridge/dashboard/runner source changes hash (reformat),
so cc-ci will be rebuilt to the new closure in W2 before the cold D1-D10 re-verification.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-27 20:52:05 +01:00
parent a0ea2f0aa9
commit 2cede01ed7
35 changed files with 431 additions and 185 deletions

View File

@ -6,11 +6,11 @@ Bakes in the known abra gotchas (re-verify per installed abra version, currently
- `abra app ls -S -m` returns nested {server: {apps: [...]}} — parse the inner structure.
- run non-interactively with `-n` (`--no-input`) everywhere.
"""
from __future__ import annotations
import json
import subprocess
from typing import Optional
ABRA = "abra"
@ -19,13 +19,17 @@ class AbraError(RuntimeError):
pass
def _run_pty(args: list[str], timeout: int = 900, check: bool = True) -> subprocess.CompletedProcess:
def _run_pty(
args: list[str], timeout: int = 900, check: bool = True
) -> subprocess.CompletedProcess:
"""Run abra under a pseudo-TTY (via util-linux `script`). Needed for commands that exec into
a container interactively (backup create / restore: 'the input device is not a TTY')."""
cmd = "abra " + " ".join(args)
proc = subprocess.run(
["script", "-qec", cmd, "/dev/null"],
capture_output=True, text=True, timeout=timeout,
capture_output=True,
text=True,
timeout=timeout,
)
if check and proc.returncode != 0:
raise AbraError(f"[pty] {cmd} failed ({proc.returncode}):\n{proc.stdout}\n{proc.stderr}")
@ -40,12 +44,19 @@ def _run(args: list[str], timeout: int = 300, check: bool = True) -> subprocess.
timeout=timeout,
)
if check and proc.returncode != 0:
raise AbraError(f"abra {' '.join(args)} failed ({proc.returncode}):\n{proc.stdout}\n{proc.stderr}")
raise AbraError(
f"abra {' '.join(args)} failed ({proc.returncode}):\n{proc.stdout}\n{proc.stderr}"
)
return proc
def app_new(recipe: str, domain: str, server: str = "default", version: Optional[str] = None,
secrets: bool = False) -> None:
def app_new(
recipe: str,
domain: str,
server: str = "default",
version: str | None = None,
secrets: bool = False,
) -> None:
args = ["app", "new", recipe]
args += ["-s", server, "-D", domain, "-o", "-n"]
if version:
@ -64,6 +75,7 @@ def env_set(domain: str, key: str, value: str) -> None:
"""Set a key in the app's .env (abra has no setter; edit the file directly)."""
import os
import re
path = os.path.expanduser(f"~/.abra/servers/default/{domain}.env")
with open(path) as fh:
lines = fh.read().splitlines()
@ -86,8 +98,11 @@ def secret_generate(domain: str, timeout: int = 300) -> None:
# captured by _run and never logged. -C -o keep the recipe at the PR checkout (without -o it
# re-resolves to a version tag, dropping the PR's files incl. tests/). check=False: recipes with
# no secrets are a no-op.
_run(["app", "secret", "generate", domain, "--all", "-m", "-C", "-o", "-n"],
timeout=timeout, check=False)
_run(
["app", "secret", "generate", domain, "--all", "-m", "-C", "-o", "-n"],
timeout=timeout,
check=False,
)
def deploy(domain: str, chaos: bool = True, timeout: int = 900) -> None:
@ -97,7 +112,7 @@ def deploy(domain: str, chaos: bool = True, timeout: int = 900) -> None:
_run(args, timeout=timeout)
def upgrade(domain: str, version: Optional[str] = None, timeout: int = 900) -> None:
def upgrade(domain: str, version: str | None = None, timeout: int = 900) -> None:
args = ["app", "upgrade", domain]
if version:
args.append(version)
@ -127,9 +142,11 @@ def recipe_versions(recipe: str) -> list[str]:
"""Published versions of a recipe, oldest→newest (from the recipe git tags)."""
import os
import subprocess
path = os.path.expanduser(f"~/.abra/recipes/{recipe}")
proc = subprocess.run(["git", "-C", path, "tag", "--sort=creatordate"],
capture_output=True, text=True)
proc = subprocess.run(
["git", "-C", path, "tag", "--sort=creatordate"], capture_output=True, text=True
)
return [t for t in proc.stdout.split("\n") if t.strip()]
@ -149,12 +166,12 @@ def secret_remove_all(domain: str, timeout: int = 300) -> None:
def app_config_remove(domain: str, server: str = "default") -> None:
"""Delete the app's .env config so a re-run can recreate it (teardown completeness)."""
import contextlib
import os
path = os.path.expanduser(f"~/.abra/servers/{server}/{domain}.env")
try:
with contextlib.suppress(FileNotFoundError):
os.remove(path)
except FileNotFoundError:
pass
def app_ls(server: str = "default") -> list[dict]: