Files
docs/infrastructure/test-contour/k3s-test-reference/_generate.py
T
2026-06-03 18:37:53 +03:00

366 lines
19 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""Generate k3s-test file reference markdown from repo tree."""
from __future__ import annotations
import os
import re
from pathlib import Path
ROOT = Path(__file__).resolve().parents[4] # k3s-test/
OUT = Path(__file__).resolve().parent
SKIP_PARTS = {
"node_modules", ".git", "vendor", "dist", ".vitepress/cache",
".vitepress/dist", ".terraform", ".tmp-chart", ".phpunit",
}
SKIP_NAMES = {".DS_Store"}
def should_skip(rel: str) -> bool:
parts = Path(rel).parts
if any(p in SKIP_PARTS for p in parts):
return True
if Path(rel).name in SKIP_NAMES:
return True
if "public/build" in rel:
return True
return False
def describe(rel: str) -> str:
name = Path(rel).name
p = rel.lower()
# Extension-based defaults
ext = Path(rel).suffix.lower()
ext_map = {
".sh": "Shell-скрипт",
".py": "Python-скрипт",
".yaml": "YAML-конфиг / Helm / K8s",
".yml": "YAML-конфиг / docker-compose",
".md": "Документация Markdown",
".json": "JSON-данные / конфиг",
".sql": "SQL (schema или seed)",
".php": "PHP (Symfony)",
".twig": "Twig-шаблон",
".js": "JavaScript",
".jsx": "React-компонент",
".scss": "SCSS-стили",
".css": "CSS-стили",
".svg": "SVG-иконка / изображение",
".png": "PNG-изображение",
".jpg": "JPEG-изображение",
".ico": "Favicon",
".pdf": "PDF-документ",
".pem": "TLS/JWT ключ",
".tf": "Terraform",
".hcl": "Terraform lock",
".tfvars": "Terraform переменные",
".tpl": "Helm template partial",
".tgz": "Vendored Helm subchart",
".lock": "Lockfile (Helm/composer/yarn)",
".html": "HTML",
".mts": "TypeScript (VitePress config)",
".ts": "TypeScript",
".mjs": "ES module (Node)",
".env": "Переменные окружения",
".xml": "XML-конфиг",
".zip": "Архив",
".tar": "Docker image tarball",
".woff": "Web-font",
".ttf": "TrueType font",
".eot": "Embedded OpenType font",
}
# Known files
known = {
"readme.md": "Главный README k3s-test",
"plan-sentry-redmine.md": "План Redmine (Sentry удалён из контура)",
"presentation-practical-guide.md": "Практическое руководство / демо для команды",
".gitignore": "Git ignore rules",
"dockerfile": "Docker multistage build",
"compose.yaml": "Docker Compose (Symfony)",
"compose.override.yaml": "Локальные overrides Compose",
"docker-compose.yml": "Docker Compose (моки / cabinet dev)",
"package.json": "NPM/Yarn зависимости и scripts",
"composer.json": "PHP Composer зависимости",
"composer.lock": "Composer lockfile",
"yarn.lock": "Yarn lockfile",
"webpack.config.js": "Webpack Encore конфиг",
"vite.config.js": "Vite bundler конфиг",
"nginx.conf": "nginx конфиг контейнера",
"index.php": "HTTP front controller Symfony",
"index.html": "HTML entry (Vite/React)",
"console": "Symfony CLI entry",
"phpunit": "PHPUnit runner wrapper",
"build.yml": "Gitea Actions CI pipeline",
"config.mts": "VitePress: nav, sidebar, mermaid",
"manifest.json": "Метаданные скриншотов",
"env.js": "Runtime API URL (adminpanel)",
"entrypoint.sh": "Container entrypoint (env injection)",
"all.yaml": "Combined Helm template (Deployment/Service/Ingress)",
"values.yaml": "Базовые Helm values",
"values-test.yaml": "Overrides для test-контура",
"values-stage.yaml": "Overrides для stage-контура",
"chart.yaml": "Helm chart metadata",
"app-of-apps.yaml": "ArgoCD root Application (sova-root)",
"platform-tools.yaml": "ArgoCD: monitoring, Gitea Actions, Redmine",
"test-contour.yaml": "ArgoCD: приложения test-контура",
"sova-projects.yaml": "ArgoCD GitOps: AppProject definitions",
"sova-project.yaml": "ArgoCD AppProject RBAC и namespaces",
"db-init-jobs.yaml": "K8s Jobs: schema → seed SQL",
"release-tag.sh": "Создать git tag → Gitea CI → GitOps",
"bootstrap-multipass.sh": "Полный bootstrap VM + k3s + platform",
"deploy-test-stack.sh": "Деплой приложений test-контура",
"prepare-db-init.sh": "Генерация schema/seed SQL из monorepo",
"sync-from-monorepo.sh": "Синхронизация кода из родительского monorepo",
"use-kubeconfig.sh": "export KUBECONFIG=~/.kube/sova-test-config",
"print-urls.sh": "URL всех сервисов и пароли platform",
"smoke-test.sh": "Smoke-проверки HTTP + kubectl",
"testsdk.js": "Stub WrSDK/SmartCaptcha для *.sova.local",
"slideshow_controller.js": "Stimulus: lazy import owl.carousel",
"services_stub.yaml": "Stub-клиенты SMS/Calltouch/Captcha для test",
"services.php": "PHP DI bindings по APP_ENV",
}
if name.lower() in known:
return known[name.lower()]
script_desc = {
"scripts/bootstrap-argocd.sh": "ArgoCD AppProject + Applications (sova-root, data-test, test-contour)",
"scripts/bootstrap-gitea-ci-secrets.sh": "Gitea Actions secrets: registry, deploy SSH key",
"scripts/bootstrap-gitea-runner.sh": "Установка Gitea Actions runner в k3s",
"scripts/bootstrap-gitea.sh": "Bootstrap Gitea: org sova, repos, admin user",
"scripts/bootstrap-redmine.sh": "REST API: проект sova-platform + задача #27",
"scripts/bootstrap-vm.sh": "Generic VM bootstrap helper",
"scripts/build-images.sh": "Сборка Docker-образов всех приложений (local-test/test tag)",
"scripts/configure-k3s-registry.sh": "k3s registries.yaml → pull из git.sova.local",
"scripts/deploy-monitoring-logs.sh": "Helm: Loki + Promtail (логи в Grafana)",
"scripts/deploy-platform-ingress.sh": "Ingress rules: Gitea, ArgoCD, Grafana, Redmine, docs",
"scripts/deploy-platform.sh": "Platform stack: ingress, ArgoCD, Gitea, Prometheus/Grafana",
"scripts/deploy-redmine.sh": "Helm Redmine + ingress + ArgoCD app redmine-test",
"scripts/deploy-sentry-redmine.sh": "Alias → deploy-redmine.sh (Sentry удалён)",
"scripts/import-images-to-vm.sh": "docker load .images/*.tar в Multipass VM",
"scripts/install-k3s-multipass.sh": "Установка k3s внутри Multipass VM",
"scripts/k3d-bootstrap.sh": "k3d cluster + ingress + apps (Mac без Multipass)",
"scripts/migrate-monorepo-branch.sh": "Demo: миграция ветки monorepo для issue #27",
"scripts/prepare-db-init.py": "Split SQL на schema/seed (helper для prepare-db-init.sh)",
"scripts/print-test-users.sh": "Тестовые логины/пароли приложений",
"scripts/release-test-tag.sh": "Wrapper → release-tag.sh (backward compat)",
"scripts/resize-multipass-vm.sh": "Увеличить CPU/RAM Multipass VM",
"scripts/setup-git-flow-branches.sh": "Создать prod/test/stage в Gitea repos",
"scripts/setup-gitea-branch-protection.sh": "Branch protection: PR-only на env-ветки",
"scripts/setup-gitea-redmine-integration.sh": "Инструкции Gitea ↔ Redmine (manual UI)",
"scripts/capture-platform-screenshots/capture.mjs": "Playwright: снять UI platform screenshots",
"scripts/capture-platform-screenshots/harness-check.mjs": "Проверка prerequisites screenshot harness",
"scripts/capture-platform-screenshots/reg-e2e.mjs": "E2E: сценарий регистрации cabinet",
"scripts/capture-platform-screenshots/run.sh": "Entry point: полный pipeline скриншотов",
}
if rel in script_desc:
return script_desc[rel]
if "wiremock/mappings" in p or "charts/mocks/mappings" in p:
stub = name.replace(".json", "").replace("-", " ")
return f"WireMock stub: {stub}"
if "/migrations/version" in p:
return "Doctrine migration"
if "/entity/" in p:
return f"Doctrine entity: {name.replace('.php', '')}"
if "/repository/" in p:
return f"Doctrine repository: {name.replace('.php', '')}"
if "/controller/" in p and ext == ".php":
return f"Symfony controller: {name.replace('.php', '')}"
if "/command/" in p and ext == ".php":
return f"Console command: {name.replace('.php', '')}"
if "/service/" in p and ext == ".php":
return f"Service: {name.replace('.php', '')}"
if "/dto/" in p or "/dto\\" in p:
return f"DTO: {name.replace('.php', '')}"
if "/form/" in p and ext == ".php":
return f"Form type: {name.replace('.php', '')}"
if "/messagehandler/" in p:
return f"Messenger handler: {name.replace('.php', '')}"
if "/message/" in p and ext == ".php":
return f"Messenger message: {name.replace('.php', '')}"
if "/controllers/" in p and name.endswith("_controller.js"):
return f"Stimulus controller: {name.replace('_controller.js', '')}"
if "/pages/" in p and ext == ".jsx":
return f"React page: {name.replace('.jsx', '')}"
if "/api/api" in p and ext == ".js":
return f"RTK Query API slice: {name.replace('.js', '')}"
if "/components/" in p and ext == ".jsx":
return f"React component: {name.replace('.jsx', '')}"
if "/hooks/" in p and ext == ".jsx":
return f"React hook: {name.replace('.jsx', '')}"
if "/templates/" in p and ext == ".twig":
return f"Twig template: {rel.split('templates/')[-1]}"
if "/config/packages/" in p:
return f"Symfony bundle config: {name}"
if "/assets/sass/" in p:
return f"SCSS entry: {name}"
if "/screenshots/" in p and ext == ".png":
return f"Скриншот UI: {name}"
if "/forms-screenshots/" in p and ext == ".png":
return f"Скриншот формы cabinet: {name}"
if "/backend-scenarios/" in p:
return f"Сценарий backend: {name.replace('.md', '')}"
if "/apps/" in p and ext == ".md":
return f"Документация приложения: {name.replace('.md', '')}"
if "/infrastructure/" in p and ext == ".md":
return f"Инфра-документация: {name.replace('.md', '')}"
if "platform-credentials.env" in p:
return "Сгенерированные креды platform (не в git)"
if ".images/" in p and ext == ".tar":
return f"Saved Docker image для import-images-to-vm.sh"
if "ci-ssh/" in p:
return "SSH-ключ Gitea Actions → sova-deploy GitOps"
if ext in ext_map:
return ext_map[ext]
return "Файл проекта"
def collect(prefix: str) -> list[tuple[str, str]]:
base = ROOT / prefix if prefix else ROOT
files: list[tuple[str, str]] = []
for path in sorted(base.rglob("*")):
if not path.is_file():
continue
rel = path.relative_to(ROOT).as_posix()
if should_skip(rel):
continue
if prefix and not rel.startswith(prefix.rstrip("/")):
continue
files.append((rel, describe(rel)))
return files
def md_table(rows: list[tuple[str, str]], path_col: str = "Путь") -> str:
if not rows:
return "_Нет файлов._\n"
lines = [f"| {path_col} | Назначение |", "|------|------------|"]
for rel, desc in rows:
lines.append(f"| `{rel}` | {desc} |")
return "\n".join(lines) + "\n"
def group_by_dir(files: list[tuple[str, str]]) -> dict[str, list[tuple[str, str]]]:
groups: dict[str, list[tuple[str, str]]] = {}
for rel, desc in files:
parent = str(Path(rel).parent)
groups.setdefault(parent if parent != "." else "(root)", []).append((rel, desc))
return dict(sorted(groups.items()))
def write_page(filename: str, title: str, intro: str, files: list[tuple[str, str]], grouped: bool = True) -> None:
body = [f"# {title}\n", intro, f"\n**Файлов:** {len(files)}\n"]
if grouped:
for dirname, rows in group_by_dir(files).items():
body.append(f"\n## `{dirname}/`\n\n")
body.append(md_table(rows, "Файл"))
else:
body.append("\n")
body.append(md_table(files))
(OUT / filename).write_text("\n".join(body), encoding="utf-8")
SECTIONS = [
("scripts.md", "scripts/", "Скрипты k3s-test", "Все shell/Python/Node скрипты bootstrap, deploy, CI и утилит. Запускать из каталога `k3s-test/`."),
("sova-deploy.md", "sova-deploy/", "sova-deploy: Helm и ArgoCD", "GitOps-репозиторий: Helm charts приложений, data layer, ArgoCD Applications и platform values."),
("sova-platform.md", "sova-platform/", "sova-platform: Terraform", "Terraform для Multipass VM и установки k3s на single-node."),
("sova-mocks.md", "sova-mocks/", "sova-mocks: WireMock и Mailpit", "Моки внешних API (MIS, Calltouch, Captcha) и SMTP для test-контура."),
("sova-redmine.md", "sova-redmine/", "sova-redmine: custom image", "Опциональный custom Docker-образ Redmine с plugin github_hook."),
("docs-pointers.md", "docs/", "docs/: указатели", "Короткие markdown-файлы со ссылками на VitePress."),
("sova-backend.md", "sova-backend/", "sova-backend: Symfony API", "Backend API для adminpanel и интеграций. Копия из monorepo + test-специфичные правки."),
("sova-adminpanel.md", "sova-adminpanel/", "sova-adminpanel: React admin", "React + Vite admin panel для CRUD контента и специалистов."),
("sova-cabinet.md", "sova-cabinet/", "sova-cabinet: Symfony ЛК", "Личный кабинет пациента: регистрация, запись, оплата."),
("sova-docs-repo.md", "sova-docs/", "sova-docs: сайт документации", "VitePress-сайт (монорепо docs + test-contour). Собирается в Docker и деплоится как docs-test."),
]
ROOT_FILES = [
"README.md", "plan-sentry-redmine.md", "presentation-practical-guide.md", ".gitignore",
]
def main() -> None:
for filename, prefix, title, intro in SECTIONS:
files = collect(prefix)
write_page(filename, title, intro, files)
# Root + generated + images
root_rows: list[tuple[str, str]] = []
for name in ROOT_FILES:
p = ROOT / name
if p.exists():
root_rows.append((name, describe(name)))
for prefix in [".generated/", ".images/"]:
root_rows.extend(collect(prefix))
write_page(
"root-and-artifacts.md",
"Корень k3s-test и артеfacts",
"Файлы в корне `k3s-test/`, сгенерированные креды и tar-образы для offline import.\n\n"
"> **Не документируем:** `.tmp-chart/` (legacy Sentry chart, 456 upstream-файлов), "
"`vendor/`, `node_modules/`, `public/build/` (сборка Webpack), `.terraform/providers/`.",
root_rows,
grouped=False,
)
# Index
total = sum(len(collect(p)) for _, p, _, _ in SECTIONS) + len(root_rows)
index = [
"# Справочник файлов k3s-test\n",
"Полный перечень файлов песочницы `k3s-test/` с кратким назначением каждого.",
"Для понимания **как пользоваться** контуром начните с [обзора test-контура](../) и [статьи «что сделано»](../test-contour-article).",
"Этот справочник отвечает на вопрос **«что лежит в каком файле»**.\n",
f"**Документировано файлов:** ~{total} (без vendor/node_modules/dist/.tmp-chart).\n",
"## Дерево каталогов\n",
"```",
"k3s-test/",
"├── README.md, plan-sentry-redmine.md, presentation-practical-guide.md",
"├── .generated/ # platform-credentials.env, CI SSH keys",
"├── .images/ # *.tar для import-images-to-vm.sh",
"├── docs/ # указатели на VitePress",
"├── scripts/ # bootstrap, deploy, CI, smoke",
"├── sova-adminpanel/ # React admin + Gitea CI",
"├── sova-backend/ # Symfony API + Gitea CI",
"├── sova-cabinet/ # Symfony ЛК + Gitea CI",
"├── sova-deploy/ # Helm + ArgoCD GitOps",
"├── sova-docs/ # VitePress documentation site",
"├── sova-mocks/ # WireMock + Mailpit",
"├── sova-platform/ # Terraform k3s bootstrap",
"└── sova-redmine/ # custom Redmine image (optional)",
"```\n",
"## Разделы справочника\n",
"| Раздел | Файлов | Описание |",
"|--------|--------|----------|",
]
for filename, prefix, title, _ in SECTIONS:
n = len(collect(prefix))
link = filename.replace(".md", "")
index.append(f"| [{title}](./{link}) | {n} | `{prefix}` |")
index.append(f"| [Корень и артеfacts](./root-and-artifacts) | {len(root_rows)} | README, `.generated/`, `.images/` |")
index.extend([
"\n## Типовые сценарии (какие скрипты вызывать)\n",
"| Сценарий | Команды |",
"|----------|---------|",
"| **Первый запуск (Multipass)** | `bootstrap-multipass.sh` → `build-images.sh` → `import-images-to-vm.sh` → `deploy-platform.sh` → `deploy-test-stack.sh` |",
"| **Первый запуск (k3d на Mac)** | `sync-from-monorepo.sh` → `build-images.sh` → `k3d-bootstrap.sh` |",
"| **Старт/стоп VM** | `multipass start sova-test` / `multipass stop sova-test` → `source scripts/use-kubeconfig.sh` |",
"| **Релиз приложения** | `scripts/release-tag.sh {backend\\|adminpanel\\|cabinet\\|docs} {tag} test` |",
"| **Обновить БД test** | `prepare-db-init.sh` → удалить job db-init → redeploy data-test |",
"| **Redmine** | `deploy-redmine.sh --bootstrap` |",
"| **Скриншоты для доков** | `capture-platform-screenshots/run.sh` |",
"\n## Связанная документация\n",
"- [Git-flow](../git-flow) — ветки prod/test/stage",
"- [Система тегов](../tags) — `{component}-v{semver}-{env}`",
"- [ArgoCD приложения](../argocd-apps) — sova-root, data-test",
"- [Gitea CI](./guides/gitea-ci) — pipeline и registry",
"- [Redmine](./guides/redmine) — issue tracker",
])
(OUT / "index.md").write_text("\n".join(index), encoding="utf-8")
print(f"Generated {len(SECTIONS)+2} pages, ~{total} files")
if __name__ == "__main__":
main()