114 lines
4.1 KiB
Python
114 lines
4.1 KiB
Python
#!/usr/bin/env python3
|
|
"""Install Gitea issue workflow files into one or more repositories."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import pathlib
|
|
import sys
|
|
|
|
from gitea_common import GiteaError, repo_root
|
|
|
|
|
|
SOURCE_ROOT = pathlib.Path(__file__).resolve().parents[2]
|
|
WORKFLOW_FILES = (
|
|
".gitea/PULL_REQUEST_TEMPLATE.md",
|
|
".gitea/ISSUE_TEMPLATE/bug_report.md",
|
|
".gitea/ISSUE_TEMPLATE/config.yaml",
|
|
".gitea/ISSUE_TEMPLATE/docs_workflow.md",
|
|
".gitea/ISSUE_TEMPLATE/feature_request.md",
|
|
".gitea/ISSUE_TEMPLATE/task.md",
|
|
".gitea/ISSUE_TEMPLATE/tech_debt.md",
|
|
)
|
|
MODULE_LABEL_BY_REPO = {
|
|
"govoplan-core": "module/core",
|
|
"govoplan-access": "module/access",
|
|
"govoplan-admin": "module/admin",
|
|
"govoplan-tenancy": "module/tenancy",
|
|
"govoplan-policy": "module/policy",
|
|
"govoplan-audit": "module/audit",
|
|
"govoplan-mail": "module/mail",
|
|
"govoplan-files": "module/files",
|
|
"govoplan-campaign": "module/campaign",
|
|
"addideas-govoplan-website": "area/marketing",
|
|
}
|
|
|
|
|
|
def main() -> int:
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument("targets", nargs="*", type=pathlib.Path, help="target repository roots or child paths")
|
|
parser.add_argument("--module-label", help="module label to write into issue templates; only valid for one target")
|
|
parser.add_argument("--include-labels-file", action="store_true", help="also copy docs/gitea-labels.json")
|
|
parser.add_argument("--apply", action="store_true", help="write files instead of previewing changes")
|
|
args = parser.parse_args()
|
|
|
|
try:
|
|
target_roots = [repo_root(path) for path in (args.targets or [pathlib.Path.cwd()])]
|
|
unique_roots = list(dict.fromkeys(target_roots))
|
|
if args.module_label and len(unique_roots) != 1:
|
|
raise GiteaError("--module-label can only be used with a single target")
|
|
|
|
rel_paths = list(WORKFLOW_FILES)
|
|
if args.include_labels_file:
|
|
rel_paths.append("docs/gitea-labels.json")
|
|
|
|
for target_root in unique_roots:
|
|
module_label = args.module_label or infer_module_label(target_root)
|
|
install_files(target_root, rel_paths, module_label, apply=args.apply)
|
|
|
|
if not args.apply:
|
|
print("Dry run only. Re-run with --apply to write files.")
|
|
return 0
|
|
except GiteaError as exc:
|
|
print(f"error: {exc}", file=sys.stderr)
|
|
return 1
|
|
|
|
|
|
def infer_module_label(target_root: pathlib.Path) -> str:
|
|
repo_name = target_root.name
|
|
try:
|
|
repo_name = target_root.resolve().name
|
|
except OSError:
|
|
pass
|
|
label = MODULE_LABEL_BY_REPO.get(repo_name)
|
|
if label:
|
|
return label
|
|
if repo_name.startswith("govoplan-"):
|
|
suffix = repo_name.removeprefix("govoplan-")
|
|
if suffix:
|
|
return f"module/{suffix}"
|
|
raise GiteaError(f"cannot infer repository label for {target_root}. Use --module-label module/<name> or area/<name>.")
|
|
|
|
|
|
def install_files(target_root: pathlib.Path, rel_paths: list[str], module_label: str, *, apply: bool) -> None:
|
|
print(f"Target: {target_root} ({module_label})")
|
|
for rel_path in rel_paths:
|
|
source = SOURCE_ROOT / rel_path
|
|
target = target_root / rel_path
|
|
if not source.exists():
|
|
raise GiteaError(f"missing workflow source file: {source}")
|
|
|
|
content = source.read_text(encoding="utf-8")
|
|
content = transform_content(rel_path, content, module_label)
|
|
|
|
existing = target.read_text(encoding="utf-8") if target.exists() else None
|
|
if existing == content:
|
|
print(f"unchanged {rel_path}")
|
|
continue
|
|
|
|
action = "create" if existing is None else "update"
|
|
print(f"{action if apply else 'would ' + action} {rel_path}")
|
|
if apply:
|
|
target.parent.mkdir(parents=True, exist_ok=True)
|
|
target.write_text(content, encoding="utf-8")
|
|
|
|
|
|
def transform_content(rel_path: str, content: str, module_label: str) -> str:
|
|
if rel_path.startswith(".gitea/ISSUE_TEMPLATE/") and rel_path.endswith(".md"):
|
|
return content.replace(" - module/core", f" - {module_label}")
|
|
return content
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|