Coverage for src\gibr\cli.py: 0%

70 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2025-10-20 08:09 +0300

1"""CLI for gibr.""" 

2 

3import logging 

4import os 

5 

6import click 

7from git.config import GitConfigParser 

8from tabulate import tabulate 

9 

10from gibr.branch import BranchName 

11from gibr.config import GibrConfig 

12from gibr.git import create_and_push_branch 

13from gibr.logger import configure_logger 

14from gibr.notify import party, success, warning 

15from gibr.trackers.factory import get_tracker 

16 

17 

18class GibrGroup(click.Group): 

19 """Custom Click group.""" 

20 

21 def parse_args(self, ctx, args): 

22 """Parse args to handle 'git' alias routing and default command (create).""" 

23 # If 'git' alias is present, handle it 

24 if args and args[0] == "git": 

25 args.pop(0) 

26 

27 # Move all flags (starting with '--') to the front 

28 flags = [a for a in args if a.startswith("--")] 

29 rest = [a for a in args if not a.startswith("--")] 

30 args[:] = flags + rest 

31 

32 # Treat numeric as 'create' (gibr 123 -> gibr create 123) 

33 for i, arg in enumerate(args): 

34 if not arg.startswith("--"): 

35 if arg.isdigit() and arg not in self.commands: 

36 args.insert(i, "create") 

37 break 

38 

39 return super().parse_args(ctx, args) 

40 

41 

42@click.group(cls=GibrGroup) 

43@click.option("--verbose", is_flag=True, help="Turn on verbose logging") 

44@click.pass_context 

45def cli(ctx, verbose): 

46 """Gibr — streamline your git + issue tracker workflow.""" 

47 # Configure logging and echo verbose mode 

48 configure_logger(verbose) 

49 ctx.ensure_object(dict) 

50 ctx.obj["verbose"] = verbose 

51 logging.debug("Verbose modes enabled.") 

52 

53 # Initialize shared config and tracker once 

54 config = GibrConfig().load() 

55 ctx.obj["config"] = config 

56 ctx.obj["tracker"] = get_tracker(config.config) 

57 

58 

59@cli.command("create") 

60@click.argument("issue_number") 

61@click.pass_context 

62def create(ctx, issue_number): 

63 """Generate a branch based on the issue number provided.""" 

64 config = ctx.obj["config"] 

65 tracker = ctx.obj["tracker"] 

66 issue = tracker.get_issue(issue_number) 

67 branch_name = BranchName(config.config["DEFAULT"]["branch_name_format"]).generate( 

68 issue 

69 ) 

70 click.echo(f"Generating branch name for issue #{issue.id}: {issue.title}") 

71 click.echo(f"Branch name: {branch_name}") 

72 create_and_push_branch(branch_name) 

73 

74 

75@cli.command("issues") 

76@click.pass_context 

77def issues(ctx): 

78 """List open issues from the tracker.""" 

79 tracker = ctx.obj["tracker"] 

80 issues = tracker.list_issues() 

81 if not issues: 

82 warning("No open issues found.") 

83 return 

84 table = [[issue.id, issue.type, issue.title] for issue in issues] 

85 

86 click.echo(tabulate(table, headers=["Issue", "Type", "Title"], tablefmt="github")) 

87 

88 

89@cli.command("alias") 

90@click.pass_context 

91def alias(ctx): 

92 """Add git aliases for gibr commands.""" 

93 commands = [ 

94 name for name, cmd in ctx.parent.command.commands.items() if name != "alias" 

95 ] 

96 

97 try: 

98 config = GitConfigParser(os.path.expanduser("~/.gitconfig"), read_only=False) 

99 for name in commands: 

100 cmd = f"!gibr git {name}" 

101 config.set_value("alias", name, cmd) 

102 success(f"Added git alias: git {name} → {cmd}") 

103 config.write() 

104 party("Git aliases successfully added!") 

105 except Exception as e: 

106 raise click.ClickException(f"Failed to set git aliases: {e}")