Coverage for src / gh_secrets_and_vars_async / init_cmd.py: 97%
69 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-16 17:56 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-16 17:56 +0000
1"""Lightweight repo bootstrap: ensure .env, apply repo settings, push secrets.
3For full repository standardization (rulesets, pipeline, pre-commit, renovate,
4release, dotfiles) use ``/ai-standardize-repo`` from augint-shell. ai-gh init
5is intentionally minimal.
6"""
8import asyncio
9from pathlib import Path
11import click
12from rich import print
13from rich.panel import Panel
14from rich.table import Table
16from .common import configure_logging, get_github_repo, load_env_config
17from .config import set_repo_settings
18from .push import perform_update
21def ensure_env_file(filename: str = ".env") -> str:
22 """Ensure .env exists with required GH_* values. Prompts interactively if missing.
24 Returns the filename used.
25 """
26 env_path = Path(filename)
27 existing_lines: list[str] = []
28 existing_keys: set[str] = set()
30 if env_path.exists():
31 existing_lines = env_path.read_text().splitlines()
32 for line in existing_lines:
33 stripped = line.strip()
34 if stripped and not stripped.startswith("#") and "=" in stripped:
35 key = stripped.split("=", 1)[0].strip()
36 existing_keys.add(key)
38 required = {
39 "GH_ACCOUNT": ("GitHub account/org name", None),
40 "GH_REPO": ("Repository name", Path.cwd().name),
41 "GH_TOKEN": ("GitHub token (PAT)", None),
42 }
44 new_entries: list[str] = []
45 for key, (prompt_text, default) in required.items():
46 if key not in existing_keys:
47 hide = key == "GH_TOKEN"
48 value = click.prompt(prompt_text, default=default, hide_input=hide)
49 new_entries.append(f"{key}={value}")
51 if new_entries:
52 with env_path.open("a") as f:
53 if existing_lines and existing_lines[-1].strip():
54 f.write("\n")
55 f.write("\n".join(new_entries) + "\n")
56 print(f"[green]Updated {filename} with {len(new_entries)} new value(s).[/green]")
58 return filename
61@click.command("init")
62@click.option("--no-config", is_flag=True, help="Skip repo settings step.")
63@click.option("--no-push", is_flag=True, help="Skip secrets/variables push step.")
64@click.option("--verbose", "-v", is_flag=True, help="Print detailed output.")
65@click.option(
66 "--dry-run", "-d", is_flag=True, help="Show what would be done without making changes."
67)
68def init_command(no_config: bool, no_push: bool, verbose: bool, dry_run: bool) -> None:
69 """Bootstrap a GitHub repository: settings + secrets.
71 For full standardization (rulesets, pipeline, pre-commit, renovate, etc.)
72 use /ai-standardize-repo from augint-shell.
73 """
74 configure_logging(verbose)
76 filename = ensure_env_file()
77 gh_repo, gh_account, gh_token = load_env_config(filename)
79 if not gh_repo or not gh_account:
80 raise click.ClickException("GH_REPO and GH_ACCOUNT are required.")
81 if not gh_token:
82 raise click.ClickException("GH_TOKEN is required.")
84 try:
85 repo = get_github_repo(gh_account, gh_repo)
86 except Exception as e:
87 raise click.ClickException(f"Cannot connect to {gh_account}/{gh_repo}: {e}") from e
89 print(f"\n[bold]Initializing {gh_account}/{gh_repo}[/bold]\n")
91 summary = Table(show_header=False, box=None, padding=(0, 2))
92 summary.add_column("Setting", style="bold")
93 summary.add_column("Result")
94 summary.add_row("Repository", f"{gh_account}/{gh_repo}")
96 # Repo settings
97 if not no_config:
98 set_repo_settings(repo, dry_run=dry_run)
99 summary.add_row("Merge strategy", "merge commits only")
100 summary.add_row("Delete branch on merge", "True")
101 else:
102 summary.add_row("Repo settings", "skipped")
104 # Secrets push
105 if not no_push:
106 push_results: dict = asyncio.run(perform_update(filename, verbose, dry_run))
107 total = len(push_results.get("SECRETS", [])) + len(push_results.get("VARIABLES", []))
108 summary.add_row("Secrets/Vars", f"{total} synced")
109 else:
110 summary.add_row("Secrets/Vars", "skipped")
112 print()
113 print(Panel(summary, title="[bold green]Setup Complete[/bold green]", expand=False))
114 print(
115 "[dim]For rulesets, pipeline, pre-commit, renovate, release, and dotfiles, "
116 "run /ai-standardize-repo in augint-shell.[/dim]"
117 )