Files
tgit/infra/uploads-template/.tgit/changed_services.py
ElebobaandClaude Opus 5.5 d4dba9748d feat(infra): шаблон репозитория загрузок tgit-uploads — CI/CD, служебные скрипты, демо-сервис
- .sourcecraft/ci.yaml: push в main → check (compile · ruff мягкий · bandit · pytest по сервисам) → deploy
- .tgit/changed_services.py: изменённые services/<name>/ (без родителя — все сервисы)
- .tgit/run_tests.py: pytest каждого сервиса со своими requirements.txt
- deploy пока заглушка со списком сервисов — tgit-runner в #13
- services/hello: демо-сервис с тестом; tgit.yaml — формат настроек сервиса

Refs #7

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 23:59:41 +03:00

49 lines
1.4 KiB
Python

"""Print services (`services/<name>/`) changed by the pushed commit, one per line.
Falls back to every service when the parent commit is unavailable (first commit or shallow clone),
so a deploy never silently skips a service.
"""
import re
import subprocess
import sys
from pathlib import Path
NAME = re.compile(r"^[a-z][a-z0-9-]{1,30}$")
def git(*args: str) -> str:
return subprocess.run(["git", *args], check=True, capture_output=True, text=True).stdout
def all_services() -> list[str]:
root = Path("services")
return sorted(p.name for p in root.iterdir() if p.is_dir() and NAME.match(p.name)) if root.is_dir() else []
def changed_paths() -> list[str] | None:
try:
git("rev-parse", "--verify", "HEAD~1")
except subprocess.CalledProcessError:
try:
git("fetch", "--deepen=1", "-q")
git("rev-parse", "--verify", "HEAD~1")
except subprocess.CalledProcessError:
return None
return git("diff", "--name-only", "HEAD~1", "HEAD").splitlines()
def main() -> None:
paths = changed_paths()
if paths is None:
print("no parent commit — deploying all services", file=sys.stderr)
services = all_services()
else:
existing = set(all_services())
services = sorted({p.split("/")[1] for p in paths if p.startswith("services/") and p.count("/") >= 2} & existing)
print("\n".join(services))
if __name__ == "__main__":
main()