ai-cr 3.1.1__py3-none-any.whl → 3.2.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.
- {ai_cr-3.1.1.dist-info → ai_cr-3.2.0.dist-info}/METADATA +24 -4
- {ai_cr-3.1.1.dist-info → ai_cr-3.2.0.dist-info}/RECORD +20 -18
- gito/bootstrap.py +1 -1
- gito/cli.py +34 -8
- gito/cli_base.py +5 -1
- gito/commands/deploy.py +50 -13
- gito/commands/fix.py +4 -1
- gito/commands/linear_comment.py +1 -1
- gito/commands/repl.py +3 -1
- gito/commands/version.py +1 -1
- gito/config.toml +2 -26
- gito/core.py +48 -14
- gito/project_config.py +1 -0
- gito/tpl/{questions/testing_guide.j2 → answer.j2} +9 -6
- gito/tpl/partial/aux_files.j2 +8 -0
- gito/tpl/questions/release_notes.j2 +2 -0
- gito/tpl/questions/test_cases.j2 +37 -0
- {ai_cr-3.1.1.dist-info → ai_cr-3.2.0.dist-info}/LICENSE +0 -0
- {ai_cr-3.1.1.dist-info → ai_cr-3.2.0.dist-info}/WHEEL +0 -0
- {ai_cr-3.1.1.dist-info → ai_cr-3.2.0.dist-info}/entry_points.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: ai-cr
|
3
|
-
Version: 3.
|
3
|
+
Version: 3.2.0
|
4
4
|
Summary: AI code review tool that works with any language model provider. It detects issues in GitHub pull requests or local changes—instantly, reliably, and without vendor lock-in.
|
5
5
|
License: MIT
|
6
6
|
Keywords: static code analysis,code review,code quality,ai,coding,assistant,llm,github,automation,devops,developer tools,github actions,workflows,git
|
@@ -16,7 +16,7 @@ Classifier: Programming Language :: Python :: 3.12
|
|
16
16
|
Classifier: Programming Language :: Python :: 3.13
|
17
17
|
Classifier: Topic :: Software Development
|
18
18
|
Requires-Dist: GitPython (>=3.1.44,<4.0.0)
|
19
|
-
Requires-Dist: ai-microcore (==4.
|
19
|
+
Requires-Dist: ai-microcore (==4.3.0)
|
20
20
|
Requires-Dist: anthropic (>=0.57.1,<0.58.0)
|
21
21
|
Requires-Dist: ghapi (>=1.0.6,<1.1.0)
|
22
22
|
Requires-Dist: google-generativeai (>=0.8.5,<0.9.0)
|
@@ -37,10 +37,22 @@ Description-Content-Type: text/markdown
|
|
37
37
|
</p>
|
38
38
|
|
39
39
|
**Gito** is an open-source **AI code reviewer** that works with any language model provider.
|
40
|
-
It detects issues in GitHub pull requests or local changes—instantly, reliably, and without vendor lock-in.
|
40
|
+
It detects issues in GitHub pull requests or local codebase changes—instantly, reliably, and without vendor lock-in.
|
41
41
|
|
42
42
|
Get consistent, thorough code reviews in seconds—no waiting for human availability.
|
43
43
|
|
44
|
+
## 📋 Table of Contents
|
45
|
+
- [Why Gito?](#-why-gito)
|
46
|
+
- [Perfect For](#-perfect-for)
|
47
|
+
- [Quickstart](#-quickstart)
|
48
|
+
- [1. Review Pull Requests via GitHub Actions](#1-review-pull-requests-via-github-actions)
|
49
|
+
- [2. Running Code Analysis Locally](#2-running-code-analysis-locally)
|
50
|
+
- [Configuration](#-configuration)
|
51
|
+
- [Documentation](#-documentation)
|
52
|
+
- [Development Setup](#-development-setup)
|
53
|
+
- [Contributing](#-contributing)
|
54
|
+
- [License](#-license)
|
55
|
+
|
44
56
|
## ✨ Why Gito?
|
45
57
|
|
46
58
|
- [⚡] **Lightning Fast:** Get detailed code reviews in seconds, not days — powered by parallelized LLM processing
|
@@ -106,7 +118,7 @@ jobs:
|
|
106
118
|
code-review-report.json
|
107
119
|
```
|
108
120
|
|
109
|
-
> ⚠️ Make sure to add `LLM_API_KEY` to your repository
|
121
|
+
> ⚠️ Make sure to add `LLM_API_KEY` to your repository's GitHub secrets.
|
110
122
|
|
111
123
|
💪 Done!
|
112
124
|
PRs to your repository will now receive AI code reviews automatically. ✨
|
@@ -180,6 +192,14 @@ See default configuration [here](https://github.com/Nayjest/Gito/blob/main/gito/
|
|
180
192
|
|
181
193
|
More details can be found in [📖 Configuration Cookbook](https://github.com/Nayjest/Gito/blob/main/documentation/config_cookbook.md)
|
182
194
|
|
195
|
+
## 📚 Documentation
|
196
|
+
|
197
|
+
- [Command Line Reference](https://github.com/Nayjest/Gito/blob/main/documentation/command_line_reference.md)
|
198
|
+
- [Configuration Cookbook](https://github.com/Nayjest/Gito/blob/main/documentation/config_cookbook.md)
|
199
|
+
- [GitHub Setup Guide](https://github.com/Nayjest/Gito/blob/main/documentation/github_setup.md)
|
200
|
+
- [Troubleshooting](https://github.com/Nayjest/Gito/blob/main/documentation/troubleshooting.md)
|
201
|
+
|
202
|
+
|
183
203
|
## 💻 Development Setup
|
184
204
|
|
185
205
|
Install dependencies:
|
@@ -1,20 +1,20 @@
|
|
1
1
|
gito/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
2
|
gito/__main__.py,sha256=MSmt_5Xg84uHqzTN38JwgseJK8rsJn_11A8WD99VtEo,61
|
3
|
-
gito/bootstrap.py,sha256=
|
4
|
-
gito/cli.py,sha256=
|
5
|
-
gito/cli_base.py,sha256=
|
3
|
+
gito/bootstrap.py,sha256=hJfRKTmCLKxMgzqWvTYhSF5zFKnS4t2N98BS5E7Ggew,3217
|
4
|
+
gito/cli.py,sha256=h4Bn7BUa4Nxr1yQWcO5s6T-mBRHBJpW60rfpNvOCx5Y,8203
|
5
|
+
gito/cli_base.py,sha256=nJGxE_zcGr51KZ4EXTFLrHwj88JIz3OQyQXL5m22FJY,2573
|
6
6
|
gito/commands/__init__.py,sha256=B2uUQsLMEsHfNT1N3lWYm38WSuQIHFmjiGs2tdBuDBA,55
|
7
|
-
gito/commands/deploy.py,sha256=
|
8
|
-
gito/commands/fix.py,sha256=
|
7
|
+
gito/commands/deploy.py,sha256=ybmlBvuDsOXKBhNvYI9xp6ph7LaH0d39stxVUORhEjo,4965
|
8
|
+
gito/commands/fix.py,sha256=kROlQSlW1dDDBvl0tr21vBTuH8APcKjL05xeCOOH_Mc,5375
|
9
9
|
gito/commands/gh_post_review_comment.py,sha256=xrCauuifrUEufBjx43sw5FMtWP9seHiGYzwAq5SFnvQ,3795
|
10
10
|
gito/commands/gh_react_to_comment.py,sha256=QAc5cZOu9GfPtbEOWH6dQYhsgFSSWFWzzZ1RPNzHxFA,7090
|
11
|
-
gito/commands/linear_comment.py,sha256=
|
12
|
-
gito/commands/repl.py,sha256=
|
13
|
-
gito/commands/version.py,sha256=
|
14
|
-
gito/config.toml,sha256=
|
11
|
+
gito/commands/linear_comment.py,sha256=c67A_v263rYorO43pyvSKqnV4WEVQZM8WEovDDu411M,1484
|
12
|
+
gito/commands/repl.py,sha256=s3GxYw3m7wMi7lMDiVovvVU9xW6keL9nej7OX1lkGUE,631
|
13
|
+
gito/commands/version.py,sha256=OdAuKtjGV9Ok2_igAs-EqdJijXCKU1dcLcA5KEz1ydg,178
|
14
|
+
gito/config.toml,sha256=51TeM_m0_v89u3X1lmafA-D5TqjiXWc-j1W_12VBppg,17777
|
15
15
|
gito/constants.py,sha256=1ElhE4RH0EPEq3xlhwyYRUcgr38X8wXduos0gV9yPy8,819
|
16
16
|
gito/context.py,sha256=OBfcQOREsNx8WHANsplNrnrKYrXz1PyZyne11lSfZjw,446
|
17
|
-
gito/core.py,sha256=
|
17
|
+
gito/core.py,sha256=H4DcVFt46BdqXfy1AxYFJMFlKgzLiXzBPqY4oaO6NeM,17379
|
18
18
|
gito/env.py,sha256=TVNxqrnLefqfZt5sSg495p8UenSgHaMgTImK1rRMIlY,146
|
19
19
|
gito/gh_api.py,sha256=2yDikXr9BM2tndYpCo-weJxjoCAlEtuPh-QBinlnHtg,4052
|
20
20
|
gito/issue_trackers.py,sha256=XYspyaIuf0ANQSvDUea5_oOdo9tQvpZZsapI5S9g78U,1551
|
@@ -22,18 +22,20 @@ gito/pipeline.py,sha256=H6eiyDHUg_p3jxNVhSnyB7EVVNbMIZkA35WMymgPnh0,2610
|
|
22
22
|
gito/pipeline_steps/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
23
23
|
gito/pipeline_steps/jira.py,sha256=NjFgpGFAkT5PSXi6jQ9Yr8CY9M8sa3_rMb7RFhdpoNg,1862
|
24
24
|
gito/pipeline_steps/linear.py,sha256=6UDc8nGKGpwHruPq8VItE2QBWshWxaTapoMhu_qjN_g,2445
|
25
|
-
gito/project_config.py,sha256=
|
25
|
+
gito/project_config.py,sha256=ZdHy4aNzjlVAgTUjmznrGcdd2NHMMvGX8VeSmAnzZ34,3237
|
26
26
|
gito/report_struct.py,sha256=96gDYnw0MXhOZrrGaNOTyWstqpjjS7_cuWufd0XJzR4,4320
|
27
|
+
gito/tpl/answer.j2,sha256=JrBOv-a8xBqTccRJeWly2U1Y5jehc_mOBt5nSbRJldI,700
|
27
28
|
gito/tpl/github_workflows/components/env-vars.j2,sha256=ypmf938h5PA38mXTZnP1eI4Un3AIhhmnl6wXg2X4kqI,406
|
28
29
|
gito/tpl/github_workflows/components/installs.j2,sha256=j5wl0yVEIrXZDpAgzqBwmhXQA9End3xFspPxr2ZzHR0,693
|
29
30
|
gito/tpl/github_workflows/gito-code-review.yml.j2,sha256=rciiX_HzygwVFTp0nUxzsLYQTRcJlR-wnft7-6gM_6Q,963
|
30
31
|
gito/tpl/github_workflows/gito-react-to-comments.yml.j2,sha256=EpBXgFwF7jMU-Zty0usx6q2lj31Ocd_OMoTPYRg7kr0,2129
|
32
|
+
gito/tpl/partial/aux_files.j2,sha256=lJhqnCsHBbEEocpyyOmQX27jzuLvEIuEVXY0RGqxWnY,191
|
31
33
|
gito/tpl/questions/changes_summary.j2,sha256=N80OQoo9UKii0CWLuck5bOwbijul5RefvCqHJljenmE,2213
|
32
|
-
gito/tpl/questions/release_notes.j2,sha256=
|
33
|
-
gito/tpl/questions/
|
34
|
+
gito/tpl/questions/release_notes.j2,sha256=OXi6o7T1bum88_2Pt4FiLHmKUe86A1t9Be_3s4mrnmU,889
|
35
|
+
gito/tpl/questions/test_cases.j2,sha256=bB7ESjy02mwWml4zyq87DqkFDj-I0-BYpfJVgzE77cc,1410
|
34
36
|
gito/utils.py,sha256=OSBn7IeWKjoLJoGOcdgQcJHBA69UiHUChtaYMInUeko,6852
|
35
|
-
ai_cr-3.
|
36
|
-
ai_cr-3.
|
37
|
-
ai_cr-3.
|
38
|
-
ai_cr-3.
|
39
|
-
ai_cr-3.
|
37
|
+
ai_cr-3.2.0.dist-info/LICENSE,sha256=VbdF_GbbDK24JvdTfnsxa2M6jmhsxmRSFeHCx-lICGE,1075
|
38
|
+
ai_cr-3.2.0.dist-info/METADATA,sha256=jpHSdAUyaroAZRxlDG6rX2QfohgnCgrbCvFHslRguPA,8874
|
39
|
+
ai_cr-3.2.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
40
|
+
ai_cr-3.2.0.dist-info/entry_points.txt,sha256=Ua1DxkhJJ8TZuLgnH-IlWCkrre_0S0dq_GtYRaYupWk,38
|
41
|
+
ai_cr-3.2.0.dist-info/RECORD,,
|
gito/bootstrap.py
CHANGED
gito/cli.py
CHANGED
@@ -47,14 +47,31 @@ def main():
|
|
47
47
|
app()
|
48
48
|
|
49
49
|
|
50
|
-
@app.callback(
|
50
|
+
@app.callback(
|
51
|
+
invoke_without_command=True,
|
52
|
+
help="\bGito is an open-source AI code reviewer that works with any language model provider."
|
53
|
+
"\nIt detects issues in GitHub pull requests or local codebase changes"
|
54
|
+
"—instantly, reliably, and without vendor lock-in."
|
55
|
+
)
|
51
56
|
def cli(
|
52
57
|
ctx: typer.Context,
|
53
|
-
verbose: bool = typer.Option(default=None),
|
54
58
|
verbosity: int = typer.Option(
|
55
59
|
None,
|
56
60
|
'--verbosity', '-v',
|
57
|
-
|
61
|
+
show_default=False,
|
62
|
+
help="\b"
|
63
|
+
"Set verbosity level. Supported values: 0-3. Default: 1."
|
64
|
+
"\n [ 0 ]: no additional output, "
|
65
|
+
"\n [ 1 ]: normal mode, shows warnings, shortened LLM requests and logging.INFO"
|
66
|
+
"\n [ 2 ]: verbose mode, show full LLM requests"
|
67
|
+
"\n [ 3 ]: very verbose mode, also debug information"
|
68
|
+
),
|
69
|
+
verbose: bool = typer.Option(
|
70
|
+
default=None,
|
71
|
+
help="\b"
|
72
|
+
"--verbose is equivalent to -v2, "
|
73
|
+
"\n--no-verbose is equivalent to -v0. "
|
74
|
+
"\n(!) Can't be used together with -v or --verbosity."
|
58
75
|
),
|
59
76
|
):
|
60
77
|
if verbose is not None and verbosity is not None:
|
@@ -71,7 +88,7 @@ def cli(
|
|
71
88
|
|
72
89
|
|
73
90
|
@app_no_subcommand.command(name="review", help="Perform code review")
|
74
|
-
@app.command(name="review", help="Perform code review")
|
91
|
+
@app.command(name="review", help="Perform a code review of the target codebase changes.")
|
75
92
|
@app.command(name="run", hidden=True)
|
76
93
|
def cmd_review(
|
77
94
|
refs: str = arg_refs(),
|
@@ -120,7 +137,7 @@ def cmd_review(
|
|
120
137
|
)
|
121
138
|
|
122
139
|
|
123
|
-
@app.command(name="ask", help="Answer questions about codebase changes")
|
140
|
+
@app.command(name="ask", help="Answer questions about the target codebase changes.")
|
124
141
|
@app.command(name="answer", hidden=True)
|
125
142
|
@app.command(name="talk", hidden=True)
|
126
143
|
def cmd_answer(
|
@@ -140,6 +157,10 @@ def cmd_answer(
|
|
140
157
|
default=None,
|
141
158
|
help="GitHub Pull Request number"
|
142
159
|
),
|
160
|
+
aux_files: list[str] = typer.Option(
|
161
|
+
default=None,
|
162
|
+
help="Auxiliary files that might be helpful"
|
163
|
+
)
|
143
164
|
):
|
144
165
|
_what, _against = args_to_target(refs, what, against)
|
145
166
|
pr = pr or os.getenv("PR_NUMBER_FROM_WORKFLOW_DISPATCH")
|
@@ -157,6 +178,7 @@ def cmd_answer(
|
|
157
178
|
prompt_file=prompt_file,
|
158
179
|
use_pipeline=use_pipeline,
|
159
180
|
pr=pr,
|
181
|
+
aux_files=aux_files,
|
160
182
|
)
|
161
183
|
if post_to == 'linear':
|
162
184
|
logging.info("Posting answer to Linear...")
|
@@ -164,12 +186,12 @@ def cmd_answer(
|
|
164
186
|
return out
|
165
187
|
|
166
188
|
|
167
|
-
@app.command(help="Configure LLM for local usage interactively")
|
189
|
+
@app.command(help="Configure LLM for local usage interactively.")
|
168
190
|
def setup():
|
169
191
|
mc.interactive_setup(HOME_ENV_PATH)
|
170
192
|
|
171
193
|
|
172
|
-
@app.command(name="render")
|
194
|
+
@app.command(name="render", help="Render and display code review report.")
|
173
195
|
@app.command(name="report", hidden=True)
|
174
196
|
def render(
|
175
197
|
format: str = typer.Argument(default=Report.Format.CLI),
|
@@ -183,7 +205,11 @@ def render(
|
|
183
205
|
Report.load(file_name=source).to_cli(report_format=format)
|
184
206
|
|
185
207
|
|
186
|
-
@app.command(
|
208
|
+
@app.command(
|
209
|
+
help="\bList files in the changeset. "
|
210
|
+
"\nMight be useful to check what will be reviewed if run `gito review` "
|
211
|
+
"with current CLI arguments and options."
|
212
|
+
)
|
187
213
|
def files(
|
188
214
|
refs: str = arg_refs(),
|
189
215
|
what: str = arg_what(),
|
gito/cli_base.py
CHANGED
@@ -30,7 +30,11 @@ def args_to_target(refs, what, against) -> tuple[str | None, str | None]:
|
|
30
30
|
def arg_refs() -> typer.Argument:
|
31
31
|
return typer.Argument(
|
32
32
|
default=None,
|
33
|
-
help=
|
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
|
+
),
|
34
38
|
)
|
35
39
|
|
36
40
|
|
gito/commands/deploy.py
CHANGED
@@ -1,16 +1,34 @@
|
|
1
|
+
import logging
|
1
2
|
from pathlib import Path
|
2
3
|
|
3
4
|
import microcore as mc
|
4
5
|
from microcore import ApiType, ui, utils
|
5
|
-
from git import Repo
|
6
|
+
from git import Repo, GitCommandError
|
7
|
+
import typer
|
6
8
|
|
9
|
+
from ..core import get_base_branch
|
7
10
|
from ..utils import version, extract_gh_owner_repo
|
8
11
|
from ..cli_base import app
|
12
|
+
from ..gh_api import gh_api
|
9
13
|
|
10
14
|
|
11
|
-
@app.command(
|
15
|
+
@app.command(
|
16
|
+
name="deploy",
|
17
|
+
help="\bCreate and configure Gito GitHub Actions for current repository.\naliases: init"
|
18
|
+
)
|
12
19
|
@app.command(name="init", hidden=True)
|
13
|
-
def deploy(
|
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
|
+
):
|
14
32
|
repo = Repo(".")
|
15
33
|
workflow_files = dict(
|
16
34
|
code_review=Path(".github/workflows/gito-code-review.yml"),
|
@@ -77,16 +95,35 @@ def deploy(api_type: ApiType = None, commit: bool = None, rewrite: bool = False)
|
|
77
95
|
"Do you want to commit and push created GitHub workflows to a new branch?"
|
78
96
|
):
|
79
97
|
repo.git.add([str(file) for file in workflow_files.values()])
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
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
|
+
)
|
90
127
|
else:
|
91
128
|
print(
|
92
129
|
"Now you can commit and push created GitHub workflows to your main repository branch.\n"
|
gito/commands/fix.py
CHANGED
@@ -15,7 +15,10 @@ from ..constants import JSON_REPORT_FILE_NAME
|
|
15
15
|
from ..report_struct import Report, Issue
|
16
16
|
|
17
17
|
|
18
|
-
@app.command(
|
18
|
+
@app.command(
|
19
|
+
help="Fix an issue from the code review report "
|
20
|
+
"(latest code review results will be used by default)"
|
21
|
+
)
|
19
22
|
def fix(
|
20
23
|
issue_number: int = typer.Argument(..., help="Issue number to fix"),
|
21
24
|
report_path: Optional[str] = typer.Option(
|
gito/commands/linear_comment.py
CHANGED
@@ -29,7 +29,7 @@ def post_linear_comment(issue_key, text, api_key):
|
|
29
29
|
return response.json()
|
30
30
|
|
31
31
|
|
32
|
-
@app.command()
|
32
|
+
@app.command(help="Post a comment with specified text to the associated Linear issue.")
|
33
33
|
def linear_comment(
|
34
34
|
text: str = typer.Argument(None),
|
35
35
|
refs: str = arg_refs(),
|
gito/commands/repl.py
CHANGED
gito/commands/version.py
CHANGED
gito/config.toml
CHANGED
@@ -242,32 +242,8 @@ If there are concerns about how thoroughly the code covers the requirements and
|
|
242
242
|
{{ summary_requirements -}}
|
243
243
|
"""
|
244
244
|
answer_github_comments = true
|
245
|
-
answer_prompt = ""
|
246
|
-
|
247
|
-
----TASK----
|
248
|
-
Answer the following user question:
|
249
|
-
--USER QUESTION--
|
250
|
-
{{ question }}
|
251
|
-
----
|
252
|
-
----RELATED CODEBASE CHANGES----
|
253
|
-
{% for part in diff %}{{ part }}\n{% endfor %}
|
254
|
-
|
255
|
-
----FULL FILE CONTENT AFTER APPLYING CHANGES----
|
256
|
-
{% for file, file_lines in all_file_lines.items() %}
|
257
|
-
--FILE: {{ file }}--
|
258
|
-
{{ file_lines }}
|
259
|
-
{% endfor %}
|
260
|
-
|
261
|
-
{%- if pipeline_out.associated_issue and pipeline_out.associated_issue.title %}
|
262
|
-
----ASSOCIATED ISSUE----
|
263
|
-
# {{ pipeline_out.associated_issue.title }}
|
264
|
-
{{ pipeline_out.associated_issue.description }}
|
265
|
-
URL: {{ pipeline_out.associated_issue.url }}
|
266
|
-
{%- endif -%}{{ '\n' }}
|
267
|
-
|
268
|
-
----ANSWERING INSTRUCTIONS----
|
269
|
-
{{ answering_instructions }}
|
270
|
-
"""
|
245
|
+
answer_prompt = "tpl:answer.j2"
|
246
|
+
aux_files = []
|
271
247
|
[pipeline_steps.jira]
|
272
248
|
call="gito.pipeline_steps.jira.fetch_associated_issue"
|
273
249
|
envs=["local","gh-action"]
|
gito/core.py
CHANGED
@@ -190,7 +190,7 @@ def get_diff(
|
|
190
190
|
else:
|
191
191
|
logging.error(f"Can't find other merge parent for {merge_sha}")
|
192
192
|
else:
|
193
|
-
logging.
|
193
|
+
logging.warning(
|
194
194
|
f"No merge‐commit found for {current_ref!r}→{against!r}; "
|
195
195
|
"falling back to merge‐base diff"
|
196
196
|
)
|
@@ -243,18 +243,20 @@ def filter_diff(
|
|
243
243
|
return files
|
244
244
|
|
245
245
|
|
246
|
-
def
|
246
|
+
def read_file(repo: Repo, file: str, use_local_files: bool = False) -> str:
|
247
247
|
if use_local_files:
|
248
248
|
file_path = Path(repo.working_tree_dir) / file
|
249
249
|
try:
|
250
|
-
|
250
|
+
return file_path.read_text(encoding='utf-8')
|
251
251
|
except (FileNotFoundError, UnicodeDecodeError) as e:
|
252
252
|
logging.warning(f"Could not read file {file} from working directory: {e}")
|
253
|
-
text = repo.tree()[file].data_stream.read().decode('utf-8')
|
254
|
-
else:
|
255
|
-
# Read from HEAD (committed version)
|
256
|
-
text = repo.tree()[file].data_stream.read().decode('utf-8')
|
257
253
|
|
254
|
+
# Read from HEAD (committed version)
|
255
|
+
return repo.tree()[file].data_stream.read().decode('utf-8')
|
256
|
+
|
257
|
+
|
258
|
+
def file_lines(repo: Repo, file: str, max_tokens: int = None, use_local_files: bool = False) -> str:
|
259
|
+
text = read_file(repo=repo, file=file, use_local_files=use_local_files)
|
258
260
|
lines = [f"{i + 1}: {line}\n" for i, line in enumerate(text.splitlines())]
|
259
261
|
if max_tokens:
|
260
262
|
lines, removed_qty = mc.tokenizing.fit_to_token_size(lines, max_tokens)
|
@@ -265,6 +267,22 @@ def file_lines(repo: Repo, file: str, max_tokens: int = None, use_local_files: b
|
|
265
267
|
return "".join(lines)
|
266
268
|
|
267
269
|
|
270
|
+
def read_files(repo: Repo, files: list[str], max_tokens: int = None) -> dict:
|
271
|
+
out = dict()
|
272
|
+
total_tokens = 0
|
273
|
+
for file in files:
|
274
|
+
content = read_file(repo=repo, file=file, use_local_files=True)
|
275
|
+
total_tokens += mc.tokenizing.num_tokens_from_string(file)
|
276
|
+
total_tokens += mc.tokenizing.num_tokens_from_string(content)
|
277
|
+
if max_tokens and total_tokens > max_tokens:
|
278
|
+
logging.warning(
|
279
|
+
f"Skipping file {file} due to exceeding max_tokens limit ({max_tokens})"
|
280
|
+
)
|
281
|
+
continue
|
282
|
+
out[file] = content
|
283
|
+
return out
|
284
|
+
|
285
|
+
|
268
286
|
def make_cr_summary(ctx: Context, **kwargs) -> str:
|
269
287
|
return (
|
270
288
|
mc.prompt(
|
@@ -428,6 +446,7 @@ def answer(
|
|
428
446
|
use_pipeline: bool = True,
|
429
447
|
prompt_file: str = None,
|
430
448
|
pr: str | int = None,
|
449
|
+
aux_files: list[str] = None,
|
431
450
|
) -> str | None:
|
432
451
|
try:
|
433
452
|
repo, config, diff, lines = _prepare(
|
@@ -454,18 +473,33 @@ def answer(
|
|
454
473
|
steps=config.pipeline_steps
|
455
474
|
)
|
456
475
|
pipe.run()
|
476
|
+
|
477
|
+
if aux_files or config.aux_files:
|
478
|
+
aux_files_dict = read_files(
|
479
|
+
repo,
|
480
|
+
(aux_files or list()) + config.aux_files,
|
481
|
+
config.max_code_tokens // 2
|
482
|
+
)
|
483
|
+
else:
|
484
|
+
aux_files_dict = dict()
|
485
|
+
|
486
|
+
if not prompt_file and config.answer_prompt.startswith("tpl:"):
|
487
|
+
prompt_file = str(config.answer_prompt)[4:]
|
488
|
+
|
457
489
|
if prompt_file:
|
458
490
|
prompt_func = partial(mc.tpl, prompt_file)
|
459
491
|
else:
|
460
492
|
prompt_func = partial(mc.prompt, config.answer_prompt)
|
493
|
+
prompt = prompt_func(
|
494
|
+
question=question,
|
495
|
+
diff=diff,
|
496
|
+
all_file_lines=lines,
|
497
|
+
pipeline_out=ctx.pipeline_out,
|
498
|
+
aux_files=aux_files_dict,
|
499
|
+
**config.prompt_vars,
|
500
|
+
)
|
461
501
|
response = mc.llm(
|
462
|
-
|
463
|
-
question=question,
|
464
|
-
diff=diff,
|
465
|
-
all_file_lines=lines,
|
466
|
-
pipeline_out=ctx.pipeline_out,
|
467
|
-
**config.prompt_vars,
|
468
|
-
),
|
502
|
+
prompt,
|
469
503
|
callback=make_streaming_function() if Env.verbosity == 0 else None,
|
470
504
|
)
|
471
505
|
return response
|
gito/project_config.py
CHANGED
@@ -32,6 +32,7 @@ class ProjectConfig:
|
|
32
32
|
Defines the keyword or mention tag that triggers bot actions
|
33
33
|
when referenced in code review comments.
|
34
34
|
"""
|
35
|
+
aux_files: list[str] = field(default_factory=list)
|
35
36
|
pipeline_steps: dict[str, dict | PipelineStep] = field(default_factory=dict)
|
36
37
|
collapse_previous_code_review_comments: bool = field(default=True)
|
37
38
|
"""
|
@@ -1,11 +1,9 @@
|
|
1
1
|
{{ self_id }}
|
2
2
|
----TASK----
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
- Potential risk areas introduced by the changes, with suggestions for focused testing to mitigate them
|
8
|
-
|
3
|
+
Answer the following user question:
|
4
|
+
--USER QUESTION--
|
5
|
+
{{ question }}
|
6
|
+
----
|
9
7
|
----RELATED CODEBASE CHANGES----
|
10
8
|
{% for part in diff %}{{ part }}\n{% endfor %}
|
11
9
|
|
@@ -15,9 +13,14 @@ Include:
|
|
15
13
|
{{ file_lines }}
|
16
14
|
{% endfor %}
|
17
15
|
|
16
|
+
{% include "partial/aux_files.j2" %}
|
17
|
+
|
18
18
|
{%- if pipeline_out.associated_issue and pipeline_out.associated_issue.title %}
|
19
19
|
----ASSOCIATED ISSUE----
|
20
20
|
# {{ pipeline_out.associated_issue.title }}
|
21
21
|
{{ pipeline_out.associated_issue.description }}
|
22
22
|
URL: {{ pipeline_out.associated_issue.url }}
|
23
23
|
{%- endif -%}{{ '\n' }}
|
24
|
+
|
25
|
+
----ANSWERING INSTRUCTIONS----
|
26
|
+
{{ answering_instructions }}
|
@@ -16,6 +16,8 @@ Avoid internal technical jargon or developer-specific details.
|
|
16
16
|
{{ file_lines }}
|
17
17
|
{% endfor %}
|
18
18
|
|
19
|
+
{%- include "partial/aux_files.j2" -%}
|
20
|
+
|
19
21
|
{%- if pipeline_out.associated_issue and pipeline_out.associated_issue.title %}
|
20
22
|
----ASSOCIATED ISSUE----
|
21
23
|
# {{ pipeline_out.associated_issue.title }}
|
@@ -0,0 +1,37 @@
|
|
1
|
+
{{ self_id }}
|
2
|
+
----TASK----
|
3
|
+
Create a concise list of manual QA test cases for the newly introduced codebase changes.
|
4
|
+
The purpose of this document is to identify user journeys that could be disrupted by failures,
|
5
|
+
cover security scenarios and edge cases, highlight potential risk areas introduced by the changes,
|
6
|
+
and suggest focused testing to mitigate them.
|
7
|
+
|
8
|
+
- Split the test cases into two categories:
|
9
|
+
- Critical
|
10
|
+
- Extended Coverage
|
11
|
+
|
12
|
+
- Structure test cases using Markdown headers or bullet-point lists.
|
13
|
+
|
14
|
+
- If the context includes the necessary details, describe the steps as thoroughly as possible—like for a junior QA
|
15
|
+
seeing this project for the first time.
|
16
|
+
If there are no details on how to perform a specific action, keep it abstract.
|
17
|
+
It is extremely important not to invent information.
|
18
|
+
|
19
|
+
- Number test cases sequentially (C-01, C-02, E-01, E-02, etc.).
|
20
|
+
|
21
|
+
----RELATED CODEBASE CHANGES----
|
22
|
+
{% for part in diff %}{{ part }}\n{% endfor %}
|
23
|
+
|
24
|
+
----FULL FILE CONTENT AFTER APPLYING CHANGES----
|
25
|
+
{% for file, file_lines in all_file_lines.items() %}
|
26
|
+
--FILE: {{ file }}--
|
27
|
+
{{ file_lines }}
|
28
|
+
{% endfor %}
|
29
|
+
|
30
|
+
{%- include "partial/aux_files.j2" -%}
|
31
|
+
|
32
|
+
{%- if pipeline_out.associated_issue and pipeline_out.associated_issue.title %}
|
33
|
+
----ASSOCIATED ISSUE----
|
34
|
+
# {{ pipeline_out.associated_issue.title }}
|
35
|
+
{{ pipeline_out.associated_issue.description }}
|
36
|
+
URL: {{ pipeline_out.associated_issue.url }}
|
37
|
+
{%- endif -%}{{ '\n' }}
|
File without changes
|
File without changes
|
File without changes
|