ai-cr 3.2.2__py3-none-any.whl → 3.3.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. {ai_cr-3.2.2.dist-info → ai_cr-3.3.0.dist-info}/LICENSE +21 -21
  2. {ai_cr-3.2.2.dist-info → ai_cr-3.3.0.dist-info}/METADATA +1 -1
  3. ai_cr-3.3.0.dist-info/RECORD +41 -0
  4. {ai_cr-3.2.2.dist-info → ai_cr-3.3.0.dist-info}/WHEEL +1 -1
  5. gito/__main__.py +4 -4
  6. gito/bootstrap.py +90 -90
  7. gito/cli.py +255 -244
  8. gito/cli_base.py +104 -94
  9. gito/commands/__init__.py +1 -1
  10. gito/commands/deploy.py +138 -138
  11. gito/commands/fix.py +160 -160
  12. gito/commands/gh_post_review_comment.py +111 -111
  13. gito/commands/gh_react_to_comment.py +217 -217
  14. gito/commands/linear_comment.py +53 -53
  15. gito/commands/repl.py +30 -30
  16. gito/commands/version.py +8 -8
  17. gito/config.toml +450 -448
  18. gito/constants.py +15 -14
  19. gito/context.py +19 -19
  20. gito/core.py +520 -508
  21. gito/env.py +8 -7
  22. gito/gh_api.py +116 -116
  23. gito/issue_trackers.py +50 -50
  24. gito/pipeline.py +83 -83
  25. gito/pipeline_steps/jira.py +62 -62
  26. gito/pipeline_steps/linear.py +85 -85
  27. gito/project_config.py +85 -85
  28. gito/report_struct.py +136 -136
  29. gito/tpl/answer.j2 +25 -25
  30. gito/tpl/github_workflows/components/env-vars.j2 +11 -11
  31. gito/tpl/github_workflows/components/installs.j2 +23 -23
  32. gito/tpl/github_workflows/gito-code-review.yml.j2 +32 -32
  33. gito/tpl/github_workflows/gito-react-to-comments.yml.j2 +70 -70
  34. gito/tpl/partial/aux_files.j2 +8 -8
  35. gito/tpl/questions/changes_summary.j2 +55 -55
  36. gito/tpl/questions/release_notes.j2 +26 -26
  37. gito/tpl/questions/test_cases.j2 +37 -37
  38. gito/utils.py +267 -267
  39. ai_cr-3.2.2.dist-info/RECORD +0 -41
  40. {ai_cr-3.2.2.dist-info → ai_cr-3.3.0.dist-info}/entry_points.txt +0 -0
gito/cli_base.py CHANGED
@@ -1,94 +1,104 @@
1
- import contextlib
2
- import logging
3
- import tempfile
4
-
5
- import microcore as mc
6
- import typer
7
- from git import Repo
8
- from gito.utils import parse_refs_pair
9
-
10
-
11
- def args_to_target(refs, what, against) -> tuple[str | None, str | None]:
12
- _what, _against = parse_refs_pair(refs)
13
- if _what:
14
- if what:
15
- raise typer.BadParameter(
16
- "You cannot specify both 'refs' <WHAT>..<AGAINST> and '--what'. Use one of them."
17
- )
18
- else:
19
- _what = what
20
- if _against:
21
- if against:
22
- raise typer.BadParameter(
23
- "You cannot specify both 'refs' <WHAT>..<AGAINST> and '--against'. Use one of them."
24
- )
25
- else:
26
- _against = against
27
- return _what, _against
28
-
29
-
30
- def arg_refs() -> typer.Argument:
31
- return typer.Argument(
32
- default=None,
33
- help=(
34
- "Git refs to review, [what]..[against] (e.g., 'HEAD..HEAD~1'). "
35
- "If omitted, the current index (including added but not committed files) "
36
- "will be compared to the repository’s main branch."
37
- ),
38
- )
39
-
40
-
41
- def arg_what() -> typer.Option:
42
- return typer.Option(None, "--what", "-w", help="Git ref to review")
43
-
44
-
45
- def arg_filters() -> typer.Option:
46
- return typer.Option(
47
- "", "--filter", "-f", "--filters",
48
- help="""
49
- filter reviewed files by glob / fnmatch pattern(s),
50
- e.g. 'src/**/*.py', may be comma-separated
51
- """,
52
- )
53
-
54
-
55
- def arg_out() -> typer.Option:
56
- return typer.Option(
57
- None,
58
- "--out", "-o", "--output",
59
- help="Output folder for the code review report"
60
- )
61
-
62
-
63
- def arg_against() -> typer.Option:
64
- return typer.Option(
65
- None,
66
- "--against", "-vs", "--vs",
67
- help="Git ref to compare against"
68
- )
69
-
70
-
71
- app = typer.Typer(pretty_exceptions_show_locals=False)
72
-
73
-
74
- @contextlib.contextmanager
75
- def get_repo_context(url: str, branch: str):
76
- """Context manager for handling both local and remote repositories."""
77
- if url:
78
- with tempfile.TemporaryDirectory() as temp_dir:
79
- logging.info(
80
- f"get_repo_context: "
81
- f"Cloning [{mc.ui.green(url)}] to {mc.utils.file_link(temp_dir)} ..."
82
- )
83
- repo = Repo.clone_from(url, branch=branch, to_path=temp_dir)
84
- try:
85
- yield repo, temp_dir
86
- finally:
87
- repo.close()
88
- else:
89
- logging.info("get_repo_context: Using local repo...")
90
- repo = Repo(".")
91
- try:
92
- yield repo, "."
93
- finally:
94
- repo.close()
1
+ import contextlib
2
+ import logging
3
+ import tempfile
4
+
5
+ import microcore as mc
6
+ import typer
7
+ from git import Repo
8
+ from gito.constants import REFS_VALUE_ALL
9
+
10
+ from .utils import parse_refs_pair
11
+ from .env import Env
12
+
13
+
14
+ def args_to_target(refs, what, against) -> tuple[str | None, str | None]:
15
+ if refs == REFS_VALUE_ALL:
16
+ return REFS_VALUE_ALL, None
17
+ _what, _against = parse_refs_pair(refs)
18
+ if _what:
19
+ if what:
20
+ raise typer.BadParameter(
21
+ "You cannot specify both 'refs' <WHAT>..<AGAINST> and '--what'. Use one of them."
22
+ )
23
+ else:
24
+ _what = what
25
+ if _against:
26
+ if against:
27
+ raise typer.BadParameter(
28
+ "You cannot specify both 'refs' <WHAT>..<AGAINST> and '--against'. Use one of them."
29
+ )
30
+ else:
31
+ _against = against
32
+ return _what, _against
33
+
34
+
35
+ def arg_refs() -> typer.Argument:
36
+ return typer.Argument(
37
+ default=None,
38
+ help=(
39
+ "Git refs to review, [what]..[against] (e.g., 'HEAD..HEAD~1'). "
40
+ "If omitted, the current index (including added but not committed files) "
41
+ "will be compared to the repository’s main branch."
42
+ ),
43
+ )
44
+
45
+
46
+ def arg_what() -> typer.Option:
47
+ return typer.Option(None, "--what", "-w", help="Git ref to review")
48
+
49
+
50
+ def arg_filters() -> typer.Option:
51
+ return typer.Option(
52
+ "", "--filter", "-f", "--filters",
53
+ help="""
54
+ filter reviewed files by glob / fnmatch pattern(s),
55
+ e.g. 'src/**/*.py', may be comma-separated
56
+ """,
57
+ )
58
+
59
+
60
+ def arg_out() -> typer.Option:
61
+ return typer.Option(
62
+ None,
63
+ "--out", "-o", "--output",
64
+ help="Output folder for the code review report"
65
+ )
66
+
67
+
68
+ def arg_against() -> typer.Option:
69
+ return typer.Option(
70
+ None,
71
+ "--against", "-vs", "--vs",
72
+ help="Git ref to compare against"
73
+ )
74
+
75
+
76
+ app = typer.Typer(pretty_exceptions_show_locals=False)
77
+
78
+
79
+ @contextlib.contextmanager
80
+ def get_repo_context(url: str, branch: str):
81
+ if branch == REFS_VALUE_ALL:
82
+ branch = None
83
+ """Context manager for handling both local and remote repositories."""
84
+ if url:
85
+ with tempfile.TemporaryDirectory() as temp_dir:
86
+ logging.info(
87
+ f"get_repo_context: "
88
+ f"Cloning [{mc.ui.green(url)}] to {mc.utils.file_link(temp_dir)} ..."
89
+ )
90
+ repo = Repo.clone_from(url, branch=branch, to_path=temp_dir)
91
+ prev_folder = Env.working_folder
92
+ Env.working_folder = temp_dir
93
+ try:
94
+ yield repo, temp_dir
95
+ finally:
96
+ repo.close()
97
+ Env.working_folder = prev_folder
98
+ else:
99
+ logging.info("get_repo_context: Using local repo...")
100
+ repo = Repo(".")
101
+ try:
102
+ yield repo, "."
103
+ finally:
104
+ repo.close()
gito/commands/__init__.py CHANGED
@@ -1 +1 @@
1
- # Command modules register themselves with the CLI app
1
+ # Command modules register themselves with the CLI app
gito/commands/deploy.py CHANGED
@@ -1,138 +1,138 @@
1
- import logging
2
- from pathlib import Path
3
-
4
- import microcore as mc
5
- from microcore import ApiType, ui, utils
6
- from git import Repo, GitCommandError
7
- import typer
8
-
9
- from ..core import get_base_branch
10
- from ..utils import version, extract_gh_owner_repo
11
- from ..cli_base import app
12
- from ..gh_api import gh_api
13
-
14
-
15
- @app.command(
16
- name="deploy",
17
- help="\bCreate and configure Gito GitHub Actions for current repository.\naliases: init"
18
- )
19
- @app.command(name="init", hidden=True)
20
- def deploy(
21
- api_type: ApiType = None,
22
- commit: bool = None,
23
- rewrite: bool = False,
24
- to_branch: str = typer.Option(
25
- default="gito_deploy",
26
- help="Branch name for new PR containing with Gito workflows commit"
27
- ),
28
- token: str = typer.Option(
29
- "", help="GitHub token (or set GITHUB_TOKEN env var)"
30
- ),
31
- ):
32
- repo = Repo(".")
33
- workflow_files = dict(
34
- code_review=Path(".github/workflows/gito-code-review.yml"),
35
- react_to_comments=Path(".github/workflows/gito-react-to-comments.yml")
36
- )
37
- for file in workflow_files.values():
38
- if file.exists():
39
- message = f"Gito workflow already exists at {utils.file_link(file)}."
40
- if rewrite:
41
- ui.warning(message)
42
- else:
43
- message += "\nUse --rewrite to overwrite it."
44
- ui.error(message)
45
- return False
46
-
47
- api_types = [ApiType.ANTHROPIC, ApiType.OPEN_AI, ApiType.GOOGLE_AI_STUDIO]
48
- default_models = {
49
- ApiType.ANTHROPIC: "claude-sonnet-4-20250514",
50
- ApiType.OPEN_AI: "gpt-4.1",
51
- ApiType.GOOGLE_AI_STUDIO: "gemini-2.5-pro",
52
- }
53
- secret_names = {
54
- ApiType.ANTHROPIC: "ANTHROPIC_API_KEY",
55
- ApiType.OPEN_AI: "OPENAI_API_KEY",
56
- ApiType.GOOGLE_AI_STUDIO: "GOOGLE_AI_API_KEY",
57
- }
58
- if not api_type:
59
- api_type = mc.ui.ask_choose(
60
- "Choose your LLM API type",
61
- api_types,
62
- )
63
- elif api_type not in api_types:
64
- mc.ui.error(f"Unsupported API type: {api_type}")
65
- return False
66
- major, minor, *_ = version().split(".")
67
- template_vars = dict(
68
- model=default_models[api_type],
69
- api_type=api_type,
70
- secret_name=secret_names[api_type],
71
- major=major,
72
- minor=minor,
73
- ApiType=ApiType,
74
- remove_indent=True,
75
- )
76
- gito_code_review_yml = mc.tpl(
77
- "github_workflows/gito-code-review.yml.j2",
78
- **template_vars
79
- )
80
- gito_react_to_comments_yml = mc.tpl(
81
- "github_workflows/gito-react-to-comments.yml.j2",
82
- **template_vars
83
- )
84
-
85
- workflow_files["code_review"].parent.mkdir(parents=True, exist_ok=True)
86
- workflow_files["code_review"].write_text(gito_code_review_yml)
87
- workflow_files["react_to_comments"].write_text(gito_react_to_comments_yml)
88
- print(
89
- mc.ui.green("Gito workflows have been created.\n")
90
- + f" - {mc.utils.file_link(workflow_files['code_review'])}\n"
91
- + f" - {mc.utils.file_link(workflow_files['react_to_comments'])}\n"
92
- )
93
- owner, repo_name = extract_gh_owner_repo(repo)
94
- if commit is True or commit is None and mc.ui.ask_yn(
95
- "Do you want to commit and push created GitHub workflows to a new branch?"
96
- ):
97
- repo.git.add([str(file) for file in workflow_files.values()])
98
- if not repo.active_branch.name.startswith(to_branch):
99
- repo.git.checkout("-b", to_branch)
100
- try:
101
- repo.git.commit("-m", "Deploy Gito workflows")
102
- except GitCommandError as e:
103
- if "nothing added" in str(e):
104
- ui.warning("Failed to commit changes: nothing was added")
105
- else:
106
- ui.error(f"Failed to commit changes: {e}")
107
- return False
108
-
109
- repo.git.push("origin", to_branch)
110
- print(f"Changes pushed to {to_branch} branch.")
111
- try:
112
- api = gh_api(repo=repo)
113
- base = get_base_branch(repo).split('/')[-1]
114
- logging.info(f"Creating PR {ui.green(to_branch)} -> {ui.yellow(base)}...")
115
- res = api.pulls.create(
116
- head=to_branch,
117
- base=base,
118
- title="Deploy Gito workflows",
119
- )
120
- print(f"Pull request #{res.number} created successfully:\n{res.html_url}")
121
- except Exception as e:
122
- mc.ui.error(f"Failed to create pull request automatically: {e}")
123
- print(
124
- f"Please create a PR from '{to_branch}' to your main branch and merge it:\n"
125
- f"https://github.com/{owner}/{repo_name}/compare/{to_branch}?expand=1"
126
- )
127
- else:
128
- print(
129
- "Now you can commit and push created GitHub workflows to your main repository branch.\n"
130
- )
131
-
132
- print(
133
- "(!IMPORTANT):\n"
134
- f"Add {mc.ui.cyan(secret_names[api_type])} with actual API_KEY "
135
- "to your repository secrets here:\n"
136
- f"https://github.com/{owner}/{repo_name}/settings/secrets/actions"
137
- )
138
- return True
1
+ import logging
2
+ from pathlib import Path
3
+
4
+ import microcore as mc
5
+ from microcore import ApiType, ui, utils
6
+ from git import Repo, GitCommandError
7
+ import typer
8
+
9
+ from ..core import get_base_branch
10
+ from ..utils import version, extract_gh_owner_repo
11
+ from ..cli_base import app
12
+ from ..gh_api import gh_api
13
+
14
+
15
+ @app.command(
16
+ name="deploy",
17
+ help="\bCreate and configure Gito GitHub Actions for current repository.\naliases: init"
18
+ )
19
+ @app.command(name="init", hidden=True)
20
+ def deploy(
21
+ api_type: ApiType = None,
22
+ commit: bool = None,
23
+ rewrite: bool = False,
24
+ to_branch: str = typer.Option(
25
+ default="gito_deploy",
26
+ help="Branch name for new PR containing with Gito workflows commit"
27
+ ),
28
+ token: str = typer.Option(
29
+ "", help="GitHub token (or set GITHUB_TOKEN env var)"
30
+ ),
31
+ ):
32
+ repo = Repo(".")
33
+ workflow_files = dict(
34
+ code_review=Path(".github/workflows/gito-code-review.yml"),
35
+ react_to_comments=Path(".github/workflows/gito-react-to-comments.yml")
36
+ )
37
+ for file in workflow_files.values():
38
+ if file.exists():
39
+ message = f"Gito workflow already exists at {utils.file_link(file)}."
40
+ if rewrite:
41
+ ui.warning(message)
42
+ else:
43
+ message += "\nUse --rewrite to overwrite it."
44
+ ui.error(message)
45
+ return False
46
+
47
+ api_types = [ApiType.ANTHROPIC, ApiType.OPEN_AI, ApiType.GOOGLE_AI_STUDIO]
48
+ default_models = {
49
+ ApiType.ANTHROPIC: "claude-sonnet-4-20250514",
50
+ ApiType.OPEN_AI: "gpt-4.1",
51
+ ApiType.GOOGLE_AI_STUDIO: "gemini-2.5-pro",
52
+ }
53
+ secret_names = {
54
+ ApiType.ANTHROPIC: "ANTHROPIC_API_KEY",
55
+ ApiType.OPEN_AI: "OPENAI_API_KEY",
56
+ ApiType.GOOGLE_AI_STUDIO: "GOOGLE_AI_API_KEY",
57
+ }
58
+ if not api_type:
59
+ api_type = mc.ui.ask_choose(
60
+ "Choose your LLM API type",
61
+ api_types,
62
+ )
63
+ elif api_type not in api_types:
64
+ mc.ui.error(f"Unsupported API type: {api_type}")
65
+ return False
66
+ major, minor, *_ = version().split(".")
67
+ template_vars = dict(
68
+ model=default_models[api_type],
69
+ api_type=api_type,
70
+ secret_name=secret_names[api_type],
71
+ major=major,
72
+ minor=minor,
73
+ ApiType=ApiType,
74
+ remove_indent=True,
75
+ )
76
+ gito_code_review_yml = mc.tpl(
77
+ "github_workflows/gito-code-review.yml.j2",
78
+ **template_vars
79
+ )
80
+ gito_react_to_comments_yml = mc.tpl(
81
+ "github_workflows/gito-react-to-comments.yml.j2",
82
+ **template_vars
83
+ )
84
+
85
+ workflow_files["code_review"].parent.mkdir(parents=True, exist_ok=True)
86
+ workflow_files["code_review"].write_text(gito_code_review_yml)
87
+ workflow_files["react_to_comments"].write_text(gito_react_to_comments_yml)
88
+ print(
89
+ mc.ui.green("Gito workflows have been created.\n")
90
+ + f" - {mc.utils.file_link(workflow_files['code_review'])}\n"
91
+ + f" - {mc.utils.file_link(workflow_files['react_to_comments'])}\n"
92
+ )
93
+ owner, repo_name = extract_gh_owner_repo(repo)
94
+ if commit is True or commit is None and mc.ui.ask_yn(
95
+ "Do you want to commit and push created GitHub workflows to a new branch?"
96
+ ):
97
+ repo.git.add([str(file) for file in workflow_files.values()])
98
+ if not repo.active_branch.name.startswith(to_branch):
99
+ repo.git.checkout("-b", to_branch)
100
+ try:
101
+ repo.git.commit("-m", "Deploy Gito workflows")
102
+ except GitCommandError as e:
103
+ if "nothing added" in str(e):
104
+ ui.warning("Failed to commit changes: nothing was added")
105
+ else:
106
+ ui.error(f"Failed to commit changes: {e}")
107
+ return False
108
+
109
+ repo.git.push("origin", to_branch)
110
+ print(f"Changes pushed to {to_branch} branch.")
111
+ try:
112
+ api = gh_api(repo=repo)
113
+ base = get_base_branch(repo).split('/')[-1]
114
+ logging.info(f"Creating PR {ui.green(to_branch)} -> {ui.yellow(base)}...")
115
+ res = api.pulls.create(
116
+ head=to_branch,
117
+ base=base,
118
+ title="Deploy Gito workflows",
119
+ )
120
+ print(f"Pull request #{res.number} created successfully:\n{res.html_url}")
121
+ except Exception as e:
122
+ mc.ui.error(f"Failed to create pull request automatically: {e}")
123
+ print(
124
+ f"Please create a PR from '{to_branch}' to your main branch and merge it:\n"
125
+ f"https://github.com/{owner}/{repo_name}/compare/{to_branch}?expand=1"
126
+ )
127
+ else:
128
+ print(
129
+ "Now you can commit and push created GitHub workflows to your main repository branch.\n"
130
+ )
131
+
132
+ print(
133
+ "(!IMPORTANT):\n"
134
+ f"Add {mc.ui.cyan(secret_names[api_type])} with actual API_KEY "
135
+ "to your repository secrets here:\n"
136
+ f"https://github.com/{owner}/{repo_name}/settings/secrets/actions"
137
+ )
138
+ return True