Source code for gitconductor.cli

"""Main CLI arguments."""

import os
import pathlib

import rich.console
import rich.markdown
import rich.tree
import rich_click as click

from gitconductor import misc, output, settings, visualise

click.rich_click.TEXT_MARKUP = "markdown"
click.rich_click.MARKDOWN_SYNTAX = "commonmark"


[docs] class CursorRestoringGroup(click.RichGroup): """Click group that restores Rich terminal cursor state after each invocation."""
[docs] def main(self, *args: object, **kwargs: object) -> object: """Run the command and restore the cursor before returning.""" try: return super().main(*args, **kwargs) finally: output.restore_cursor()
@click.group(cls=CursorRestoringGroup, help=misc.readme_header()) @click.option( "--gitlab-key", type=str, default=os.environ.get("GITCONDUCTOR_GITLAB_API_KEY", None), required=False, ) @click.option( "--cfg", type=click.Path(path_type=pathlib.Path), default=os.environ.get("GITCONDUCTOR_CONFIG", pathlib.Path().home() / ".config/gitconductor/gitconductor.toml"), required=False, ) @click.option( "--state", type=click.Path(path_type=pathlib.Path), default=None, required=False, ) @click.pass_context def cli(ctx: click.Context, gitlab_key: str, cfg: pathlib.Path, state: pathlib.Path) -> None: """Manage nested GitLab groups and projects.""" ctx.ensure_object(dict) cfg = settings.Settings(cfg=cfg) ctx.obj["key"] = gitlab_key if gitlab_key else cfg.gitconductor_gitlab_api_key ctx.obj["cfg"] = cfg ctx.obj["state"] = state # Hack to add submodules to the CLI without circular imports. # This is required because the submodules need to import the main CLI group to add their own subcommands, but the main # CLI group also needs to import the submodules to add them as subcommands. from . import cli_git, cli_python # noqa: F401,E402 # ===================================================================================================================== @cli.group() @click.pass_context def viz(ctx: click.Context) -> None: """Visualise the hierarchy recursively in different ways.""" pass @viz.command() @click.pass_context def tree(ctx: click.Context) -> None: """Visualise the hierarchy as a tree.""" group = misc.load_cfg(ctx.obj["state"]) visualise.tree(group) @viz.command() @click.pass_context @click.option("--maxdepth", type=int, default=None, help="Maximum recursion depth to traverse for output.") def table(ctx: click.Context, maxdepth: int | None) -> None: """Visualise the hierarchy as a table.""" group = misc.load_cfg(ctx.obj["state"]) visualise.table(group, maxdepth=maxdepth) @viz.command() @click.pass_context @click.option( "--explicit", is_flag=True, default=False, help="Explicitly show each individual user for each subgroup and project in the full tree. " "Else abbreviate to show only the highest level of access for each group and each user.", ) @click.option( "--matrix", is_flag=True, default=False, help="Show a 2D matrix of each user and each group.", ) @click.option("--maxdepth", type=int, default=None, help="Maximum recursion depth to traverse for output.") def access(ctx: click.Context, explicit: bool, maxdepth: int | None, matrix: bool = False) -> None: """Visualise access recursively.""" group = misc.load_cfg(ctx.obj["state"]) if matrix: visualise.access_matrix(group, maxdepth=maxdepth) else: visualise.access(group, explicit=explicit, maxdepth=maxdepth) # ===================================================================================================================== @cli.command() def help() -> None: """Print setup help.""" console = rich.console.Console() console.print(rich.markdown.Markdown(misc.help_text()))