Share the target filter, fix cd-status branch, record deploy status

- enabled_targets/names_for: one implementation of 'a host acts only on its
  own targets'; --host s5 and --host s5.fisher.hu now select the same targets
- shell_value: JSON booleans reach shell consumers as true/false
- cd-status: capture before eval, so the unconfigured-host branch is reachable
- cd-deploy writes a .status record; cd-status reads it instead of grepping
  the log's prose
- cd-render-hooks --list-urls replaces two inline JSON readers
This commit is contained in:
fisher
2026-08-23 08:50:45 +00:00
parent b48e112ed7
commit 62c62baf05
8 changed files with 119 additions and 62 deletions
+33 -7
View File
@@ -16,6 +16,7 @@ would accept a deploy request from anyone who can reach the port.
Usage:
cd-render-hooks [--host HOST] [--output PATH] [--redact]
cd-render-hooks --list-urls [--output PATH] [--base-url URL]
"""
from __future__ import annotations
@@ -52,7 +53,8 @@ def _load_cd_target():
_cd_target = _load_cd_target()
load = _cd_target.load
pick_host = _cd_target.pick_host
host_matches = _cd_target.host_matches
names_for = _cd_target.names_for
enabled_targets = _cd_target.enabled_targets
DEFAULT_CONFIG_DIR = Path(
os.environ.get("XDG_CONFIG_HOME", Path.home() / ".config")
@@ -167,6 +169,22 @@ def build_hook(repo: str, branches: list[str], secret: str) -> dict:
}
def list_urls(path: Path, base_url: str) -> int:
"""Print one endpoint URL per hook in an already-rendered hooks file.
Reads the rendered file rather than the manifest so that what is printed is
what the daemon is actually serving. Both the installer and cd-status use
this instead of reaching into the file's schema themselves.
"""
try:
hooks = json.loads(path.read_text())
except FileNotFoundError:
sys.exit(f"cd-render-hooks: no rendered hooks file at {path}")
for hook in hooks:
print(f"{base_url}/hooks/{hook['id']}")
return 0
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
parser.add_argument("--host")
@@ -177,19 +195,27 @@ def main() -> int:
action="store_true",
help="print to stdout with secrets masked, and write nothing",
)
parser.add_argument(
"--list-urls",
action="store_true",
help="print the endpoint URL of each hook in an existing hooks file",
)
parser.add_argument(
"--base-url",
default="",
help="prefix for --list-urls, e.g. http://10.255.255.1:21600",
)
args = parser.parse_args()
if args.list_urls:
return list_urls(args.output, args.base_url.rstrip("/"))
manifest = load()
host = pick_host(manifest, args.host)
names = {host.lower(), host.split(".", 1)[0].lower()}
# repo -> branches, preserving manifest order for a stable diff.
by_repo: dict[str, list[str]] = {}
for target in manifest.get("targets", []):
if not target.get("enabled", True):
continue
if not host_matches(target["host"], names):
continue
for target in enabled_targets(manifest, names_for(host)):
by_repo.setdefault(target["repo"], []).append(target["branch"])
if not by_repo: