ai-cr 3.1.0__py3-none-any.whl → 3.1.2__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: ai-cr
3
- Version: 3.1.0
3
+ Version: 3.1.2
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
@@ -1,22 +1,22 @@
1
1
  gito/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  gito/__main__.py,sha256=MSmt_5Xg84uHqzTN38JwgseJK8rsJn_11A8WD99VtEo,61
3
3
  gito/bootstrap.py,sha256=m8g7e4sacTe7SsRKmDms1_L2ESF8TAas1lMaH3hvrl8,3218
4
- gito/cli.py,sha256=BSLbE2Nbe5-HNCcjXJZrFhgTpUhOhbmlO7g-gFSNoBA,6817
4
+ gito/cli.py,sha256=D0XZ7H1Xo6Q7dOL0rC6mJVNQuD7C8MAw1E01jnZXbSw,7072
5
5
  gito/cli_base.py,sha256=h0CvkfOaIYGArqNuKyAuDcJDx-hOB7H7uyfJV3afINg,2390
6
6
  gito/commands/__init__.py,sha256=B2uUQsLMEsHfNT1N3lWYm38WSuQIHFmjiGs2tdBuDBA,55
7
- gito/commands/deploy.py,sha256=PbNcw7Ccau2Bncpi121YDRz9gg9xvkrviytrAEFfpmw,3749
7
+ gito/commands/deploy.py,sha256=JuGLqw3-Mk9cH_BBAkojHBLcAWfOnvBzxW7IQZM8H5U,4913
8
8
  gito/commands/fix.py,sha256=C4imdS776yl7g-KmH9Wu2PqeN4WNJh8NvSeV3pV-63g,5304
9
9
  gito/commands/gh_post_review_comment.py,sha256=xrCauuifrUEufBjx43sw5FMtWP9seHiGYzwAq5SFnvQ,3795
10
- gito/commands/gh_react_to_comment.py,sha256=3R0Ke-Met06epooImI6ZC2TuLQ2Qpv276OWMSelVcNY,6395
10
+ gito/commands/gh_react_to_comment.py,sha256=QAc5cZOu9GfPtbEOWH6dQYhsgFSSWFWzzZ1RPNzHxFA,7090
11
11
  gito/commands/linear_comment.py,sha256=8kCudz0cogWm8LsgLRWN-BybDq13zEqwV456JB3_7xo,1411
12
12
  gito/commands/repl.py,sha256=jJCRO-O7r_fFXZrk9f1_oAcYPOAwPi3cGI3bMoRyer8,549
13
13
  gito/commands/version.py,sha256=u3khraY95jpIoIo-ndBxXYIEvSy_uyCmiHicAXk-V28,188
14
14
  gito/config.toml,sha256=kd2fbztnr2LGaNE2BE81yt1Ed0PTF5xe_8WtTgDxxkw,18417
15
15
  gito/constants.py,sha256=1ElhE4RH0EPEq3xlhwyYRUcgr38X8wXduos0gV9yPy8,819
16
16
  gito/context.py,sha256=OBfcQOREsNx8WHANsplNrnrKYrXz1PyZyne11lSfZjw,446
17
- gito/core.py,sha256=dRPDvfJfQnHV3aequ0L9ayMvUdT1seUKFEis9YSYwDA,14505
17
+ gito/core.py,sha256=YgPuVCZsoSgvskbjHmkB9Bj4cQtnxUfoBjcunSoGRJc,16289
18
18
  gito/env.py,sha256=TVNxqrnLefqfZt5sSg495p8UenSgHaMgTImK1rRMIlY,146
19
- gito/gh_api.py,sha256=FbJ7w6dtuAFUVbZNyNHn8RRDGBvJyQlrIX82m46cTac,2958
19
+ gito/gh_api.py,sha256=2yDikXr9BM2tndYpCo-weJxjoCAlEtuPh-QBinlnHtg,4052
20
20
  gito/issue_trackers.py,sha256=XYspyaIuf0ANQSvDUea5_oOdo9tQvpZZsapI5S9g78U,1551
21
21
  gito/pipeline.py,sha256=H6eiyDHUg_p3jxNVhSnyB7EVVNbMIZkA35WMymgPnh0,2610
22
22
  gito/pipeline_steps/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -24,14 +24,16 @@ gito/pipeline_steps/jira.py,sha256=NjFgpGFAkT5PSXi6jQ9Yr8CY9M8sa3_rMb7RFhdpoNg,1
24
24
  gito/pipeline_steps/linear.py,sha256=6UDc8nGKGpwHruPq8VItE2QBWshWxaTapoMhu_qjN_g,2445
25
25
  gito/project_config.py,sha256=jOPVMgN01_krELlNXzZlrZOKmXZP-RLDS7iOgVSUyic,3182
26
26
  gito/report_struct.py,sha256=96gDYnw0MXhOZrrGaNOTyWstqpjjS7_cuWufd0XJzR4,4320
27
- gito/tpl/github_workflows/components/env-vars.j2,sha256=ouZY4vpKUkAAM5qUxA3BKAh9BpJMfwsrn8qqahhrh7U,356
27
+ gito/tpl/github_workflows/components/env-vars.j2,sha256=ypmf938h5PA38mXTZnP1eI4Un3AIhhmnl6wXg2X4kqI,406
28
28
  gito/tpl/github_workflows/components/installs.j2,sha256=j5wl0yVEIrXZDpAgzqBwmhXQA9End3xFspPxr2ZzHR0,693
29
- gito/tpl/github_workflows/gito-code-review.yml.j2,sha256=PcxXMTblWX2ANK-8bkxFPI3H-xby5Do_yaufhxGzw0Y,1159
30
- gito/tpl/github_workflows/gito-react-to-comments.yml.j2,sha256=zVNkJRgje75AejXAePZugruDu3pOuDaPcujrDfth8K4,2165
31
- gito/tpl/release_notes.j2,sha256=20QtQwdZYcFEjmfYxTysenY-njTPl2nmHpv9077WFdg,849
29
+ gito/tpl/github_workflows/gito-code-review.yml.j2,sha256=rciiX_HzygwVFTp0nUxzsLYQTRcJlR-wnft7-6gM_6Q,963
30
+ gito/tpl/github_workflows/gito-react-to-comments.yml.j2,sha256=EpBXgFwF7jMU-Zty0usx6q2lj31Ocd_OMoTPYRg7kr0,2129
31
+ gito/tpl/questions/changes_summary.j2,sha256=N80OQoo9UKii0CWLuck5bOwbijul5RefvCqHJljenmE,2213
32
+ gito/tpl/questions/release_notes.j2,sha256=20QtQwdZYcFEjmfYxTysenY-njTPl2nmHpv9077WFdg,849
33
+ gito/tpl/questions/testing_guide.j2,sha256=AVnl7MoFrRxrH2A83PgV-l7VxqPE6XNRh7VksjE50as,832
32
34
  gito/utils.py,sha256=OSBn7IeWKjoLJoGOcdgQcJHBA69UiHUChtaYMInUeko,6852
33
- ai_cr-3.1.0.dist-info/LICENSE,sha256=VbdF_GbbDK24JvdTfnsxa2M6jmhsxmRSFeHCx-lICGE,1075
34
- ai_cr-3.1.0.dist-info/METADATA,sha256=yGLpvMwx55qR2mIzKvrIqMPqaG48JUAI48e54weEBhQ,7989
35
- ai_cr-3.1.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
36
- ai_cr-3.1.0.dist-info/entry_points.txt,sha256=Ua1DxkhJJ8TZuLgnH-IlWCkrre_0S0dq_GtYRaYupWk,38
37
- ai_cr-3.1.0.dist-info/RECORD,,
35
+ ai_cr-3.1.2.dist-info/LICENSE,sha256=VbdF_GbbDK24JvdTfnsxa2M6jmhsxmRSFeHCx-lICGE,1075
36
+ ai_cr-3.1.2.dist-info/METADATA,sha256=HHiTm0njhVeKyLE-nryAPsNLcXIhXqANJGcscvJ8soM,7989
37
+ ai_cr-3.1.2.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
38
+ ai_cr-3.1.2.dist-info/entry_points.txt,sha256=Ua1DxkhJJ8TZuLgnH-IlWCkrre_0S0dq_GtYRaYupWk,38
39
+ ai_cr-3.1.2.dist-info/RECORD,,
gito/cli.py CHANGED
@@ -92,6 +92,7 @@ def cmd_review(
92
92
  out: str = arg_out()
93
93
  ):
94
94
  _what, _against = args_to_target(refs, what, against)
95
+ pr = pr or os.getenv("PR_NUMBER_FROM_WORKFLOW_DISPATCH")
95
96
  with get_repo_context(url, _what) as (repo, out_folder):
96
97
  asyncio.run(review(
97
98
  repo=repo,
@@ -100,6 +101,7 @@ def cmd_review(
100
101
  filters=filters,
101
102
  use_merge_base=merge_base,
102
103
  out_folder=out or out_folder,
104
+ pr=pr,
103
105
  ))
104
106
  if post_comment:
105
107
  try:
@@ -134,8 +136,13 @@ def cmd_answer(
134
136
  default=None,
135
137
  show_default=False
136
138
  ),
139
+ pr: int = typer.Option(
140
+ default=None,
141
+ help="GitHub Pull Request number"
142
+ ),
137
143
  ):
138
144
  _what, _against = args_to_target(refs, what, against)
145
+ pr = pr or os.getenv("PR_NUMBER_FROM_WORKFLOW_DISPATCH")
139
146
  if str(question).startswith("tpl:"):
140
147
  prompt_file = str(question)[4:]
141
148
  question = ""
@@ -149,6 +156,7 @@ def cmd_answer(
149
156
  use_merge_base=merge_base,
150
157
  prompt_file=prompt_file,
151
158
  use_pipeline=use_pipeline,
159
+ pr=pr,
152
160
  )
153
161
  if post_to == 'linear':
154
162
  logging.info("Posting answer to Linear...")
gito/commands/deploy.py CHANGED
@@ -1,16 +1,31 @@
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
15
  @app.command(name="deploy", help="Deploy Gito workflows to GitHub Actions")
12
16
  @app.command(name="init", hidden=True)
13
- def deploy(api_type: ApiType = None, commit: bool = None, rewrite: bool = False):
17
+ def deploy(
18
+ api_type: ApiType = None,
19
+ commit: bool = None,
20
+ rewrite: bool = False,
21
+ to_branch: str = typer.Option(
22
+ default="gito_deploy",
23
+ help="Branch name for new PR containing with Gito workflows commit"
24
+ ),
25
+ token: str = typer.Option(
26
+ "", help="GitHub token (or set GITHUB_TOKEN env var)"
27
+ ),
28
+ ):
14
29
  repo = Repo(".")
15
30
  workflow_files = dict(
16
31
  code_review=Path(".github/workflows/gito-code-review.yml"),
@@ -77,16 +92,35 @@ def deploy(api_type: ApiType = None, commit: bool = None, rewrite: bool = False)
77
92
  "Do you want to commit and push created GitHub workflows to a new branch?"
78
93
  ):
79
94
  repo.git.add([str(file) for file in workflow_files.values()])
80
- branch_name = "gito_deploy"
81
- if not repo.active_branch.name.startswith(branch_name):
82
- repo.git.checkout("-b", branch_name)
83
- repo.git.commit("-m", "Deploy Gito workflows")
84
- repo.git.push("origin", branch_name)
85
- print(f"Changes pushed to {branch_name} branch.")
86
- print(
87
- f"Please create a PR from {branch_name} to your main branch and merge it:\n"
88
- f"https://github.com/{owner}/{repo_name}/compare/gito_deploy?expand=1"
89
- )
95
+ if not repo.active_branch.name.startswith(to_branch):
96
+ repo.git.checkout("-b", to_branch)
97
+ try:
98
+ repo.git.commit("-m", "Deploy Gito workflows")
99
+ except GitCommandError as e:
100
+ if "nothing added" in str(e):
101
+ ui.warning("Failed to commit changes: nothing was added")
102
+ else:
103
+ ui.error(f"Failed to commit changes: {e}")
104
+ return False
105
+
106
+ repo.git.push("origin", to_branch)
107
+ print(f"Changes pushed to {to_branch} branch.")
108
+ try:
109
+ api = gh_api(repo=repo)
110
+ base = get_base_branch(repo).split('/')[-1]
111
+ logging.info(f"Creating PR {ui.green(to_branch)} -> {ui.yellow(base)}...")
112
+ res = api.pulls.create(
113
+ head=to_branch,
114
+ base=base,
115
+ title="Deploy Gito workflows",
116
+ )
117
+ print(f"Pull request #{res.number} created successfully:\n{res.html_url}")
118
+ except Exception as e:
119
+ mc.ui.error(f"Failed to create pull request automatically: {e}")
120
+ print(
121
+ f"Please create a PR from '{to_branch}' to your main branch and merge it:\n"
122
+ f"https://github.com/{owner}/{repo_name}/compare/{to_branch}?expand=1"
123
+ )
90
124
  else:
91
125
  print(
92
126
  "Now you can commit and push created GitHub workflows to your main repository branch.\n"
@@ -25,6 +25,30 @@ from ..utils import extract_gh_owner_repo
25
25
  from .fix import fix
26
26
 
27
27
 
28
+ def cleanup_comment_addressed_to_gito(text):
29
+ if not text:
30
+ return text
31
+ patterns = [
32
+ r'^\s*gito\b',
33
+ r'^\s*ai\b',
34
+ r'^\s*bot\b',
35
+ r'^\s*@gito\b',
36
+ r'^\s*@ai\b',
37
+ r'^\s*@bot\b'
38
+ ]
39
+ result = text
40
+ # Remove each pattern from the beginning
41
+ for pattern in patterns:
42
+ result = re.sub(pattern, '', result, flags=re.IGNORECASE)
43
+
44
+ # Remove leading comma and spaces that may be left after prefix removal
45
+ result = re.sub(r'^\s*,\s*', '', result)
46
+
47
+ # Clean up extra whitespace
48
+ result = re.sub(r'\s+', ' ', result).strip()
49
+ return result
50
+
51
+
28
52
  @app.command(hidden=True)
29
53
  def react_to_comment(
30
54
  comment_id: int = typer.Argument(),
@@ -99,7 +123,8 @@ def react_to_comment(
99
123
  )
100
124
  else:
101
125
  if cfg.answer_github_comments:
102
- response = answer(comment.body, repo=repo)
126
+ question = cleanup_comment_addressed_to_gito(comment.body)
127
+ response = answer(question, repo=repo, pr=pr)
103
128
  post_gh_comment(
104
129
  gh_repository=f"{owner}/{repo_name}",
105
130
  pr_or_issue_number=pr,
gito/core.py CHANGED
@@ -1,11 +1,12 @@
1
+ import os
1
2
  import fnmatch
2
3
  import logging
3
- from os import PathLike
4
4
  from typing import Iterable
5
5
  from pathlib import Path
6
6
  from functools import partial
7
7
 
8
8
  import microcore as mc
9
+ from gito.gh_api import gh_api
9
10
  from microcore import ui
10
11
  from git import Repo, Commit
11
12
  from git.exc import GitCommandError
@@ -66,16 +67,57 @@ def commit_in_branch(repo: Repo, commit: Commit, target_branch: str) -> bool:
66
67
  return False
67
68
 
68
69
 
70
+ def get_base_branch(repo: Repo, pr: int | str = None):
71
+ if os.getenv('GITHUB_ACTIONS'):
72
+
73
+ # triggered from PR
74
+ if base_ref := os.getenv('GITHUB_BASE_REF'):
75
+ logging.info(f"Using GITHUB_BASE_REF:{base_ref} as base branch")
76
+ return f'origin/{base_ref}'
77
+ logging.info("GITHUB_BASE_REF is not available...")
78
+ if pr:
79
+ api = gh_api(repo=repo)
80
+ pr_obj = api.pulls.get(pr)
81
+ logging.info(
82
+ f"Using 'origin/{pr_obj.base.ref}' as base branch "
83
+ f"(received via GH API for PR#{pr})"
84
+ )
85
+ return f'origin/{pr_obj.base.ref}'
86
+
87
+ try:
88
+ logging.info(
89
+ "Trying to resolve base branch from repo.remotes.origin.refs.HEAD.reference.name..."
90
+ )
91
+ # 'origin/main', 'origin/master', etc
92
+ # Stopped working in github actions since 07/2025
93
+ return repo.remotes.origin.refs.HEAD.reference.name
94
+ except AttributeError:
95
+ try:
96
+ logging.info(
97
+ "Checking if repo has 'main' or 'master' branchs to use as --against branch..."
98
+ )
99
+ remote_refs = repo.remotes.origin.refs
100
+ for branch_name in ['main', 'master']:
101
+ if hasattr(remote_refs, branch_name):
102
+ return f'origin/{branch_name}'
103
+ except Exception:
104
+ pass
105
+
106
+ logging.error("Could not determine default branch from remote refs.")
107
+ raise ValueError("No default branch found in the repository.")
108
+
109
+
69
110
  def get_diff(
70
111
  repo: Repo = None,
71
112
  what: str = None,
72
113
  against: str = None,
73
114
  use_merge_base: bool = True,
115
+ pr: str | int = None
74
116
  ) -> PatchSet | list[PatchedFile]:
75
117
  repo = repo or Repo(".")
76
118
  if not against:
77
119
  # 'origin/main', 'origin/master', etc
78
- against = repo.remotes.origin.refs.HEAD.reference.name
120
+ against = get_base_branch(repo, pr=pr)
79
121
  if review_subject_is_index(what):
80
122
  what = None # working copy
81
123
  if use_merge_base:
@@ -175,7 +217,7 @@ def get_diff(
175
217
  )
176
218
  if file_path == DEV_NULL:
177
219
  continue
178
- if is_binary_file(repo, file_path.lstrip("b/")):
220
+ if is_binary_file(repo, file_path.removeprefix("b/")):
179
221
  logging.info(f"Skipping binary file: {patched_file.path}")
180
222
  continue
181
223
  non_binary_diff.append(patched_file)
@@ -251,11 +293,12 @@ def _prepare(
251
293
  against: str = None,
252
294
  filters: str | list[str] = "",
253
295
  use_merge_base: bool = True,
296
+ pr: str | int = None,
254
297
  ):
255
298
  repo = repo or Repo(".")
256
299
  cfg = ProjectConfig.load_for_repo(repo)
257
300
  diff = get_diff(
258
- repo=repo, what=what, against=against, use_merge_base=use_merge_base
301
+ repo=repo, what=what, against=against, use_merge_base=use_merge_base, pr=pr,
259
302
  )
260
303
  diff = filter_diff(diff, filters)
261
304
  if not diff:
@@ -318,11 +361,17 @@ async def review(
318
361
  against: str = None,
319
362
  filters: str | list[str] = "",
320
363
  use_merge_base: bool = True,
321
- out_folder: str | PathLike | None = None,
364
+ out_folder: str | os.PathLike | None = None,
365
+ pr: str | int = None
322
366
  ):
323
367
  try:
324
368
  repo, cfg, diff, lines = _prepare(
325
- repo=repo, what=what, against=against, filters=filters, use_merge_base=use_merge_base
369
+ repo=repo,
370
+ what=what,
371
+ against=against,
372
+ filters=filters,
373
+ use_merge_base=use_merge_base,
374
+ pr=pr,
326
375
  )
327
376
  except NoChangesInContextError:
328
377
  logging.error("No changes to review")
@@ -378,10 +427,16 @@ def answer(
378
427
  use_merge_base: bool = True,
379
428
  use_pipeline: bool = True,
380
429
  prompt_file: str = None,
430
+ pr: str | int = None,
381
431
  ) -> str | None:
382
432
  try:
383
433
  repo, config, diff, lines = _prepare(
384
- repo=repo, what=what, against=against, filters=filters, use_merge_base=use_merge_base
434
+ repo=repo,
435
+ what=what,
436
+ against=against,
437
+ filters=filters,
438
+ use_merge_base=use_merge_base,
439
+ pr=pr
385
440
  )
386
441
  except NoChangesInContextError:
387
442
  logging.error("No changes to review")
gito/gh_api.py CHANGED
@@ -2,7 +2,38 @@ import os
2
2
  import logging
3
3
 
4
4
  import requests
5
+ import git
5
6
  from fastcore.basics import AttrDict # objects returned by ghapi
7
+ from ghapi.core import GhApi
8
+
9
+ from .project_config import ProjectConfig
10
+ from .utils import extract_gh_owner_repo
11
+
12
+
13
+ def gh_api(
14
+ repo: git.Repo = None, # used to resolve owner/repo
15
+ config: ProjectConfig | None = None, # used to resolve owner/repo
16
+ token: str | None = None
17
+ ) -> GhApi:
18
+ if repo:
19
+ # resolve owner/repo from repo.remotes.origin.url
20
+ owner, repo_name = extract_gh_owner_repo(repo)
21
+ else:
22
+ if not config:
23
+ config = ProjectConfig.load()
24
+ # resolve owner/repo from github env vars (github actions)
25
+ gh_env = config.prompt_vars.get("github_env", {})
26
+ gh_repo = gh_env.get("github_repo")
27
+ if not gh_repo:
28
+ raise ValueError("GitHub repository not specified and not found in project config.")
29
+ parts = gh_repo.split('/')
30
+ if len(parts) != 2:
31
+ raise ValueError(f"Invalid GitHub repository format: {gh_repo}. Expected 'owner/repo'.")
32
+ owner, repo_name = parts
33
+
34
+ token = resolve_gh_token(token)
35
+ api = GhApi(owner, repo_name, token=token)
36
+ return api
6
37
 
7
38
 
8
39
  def resolve_gh_token(token_or_none: str | None = None) -> str | None:
@@ -7,4 +7,5 @@
7
7
  JIRA_URL: ${{ secrets.JIRA_URL }}
8
8
  JIRA_USER: ${{ secrets.JIRA_USER }}
9
9
  LINEAR_API_KEY: ${{ secrets.LINEAR_API_KEY }}
10
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
10
11
  {%- endraw %}
@@ -22,8 +22,8 @@ jobs:
22
22
  {%- include("github_workflows/components/env-vars.j2") %}
23
23
  PR_NUMBER_FROM_WORKFLOW_DISPATCH: {% raw %}${{ github.event.inputs.pr_number }}{% endraw %}
24
24
  run: |{% raw %}
25
- gito --verbose review ${{ github.event_name == 'pull_request' && github.event.pull_request.base.ref && format(' --against="origin/{0}"', github.event.pull_request.base.ref) || '' }}
26
- gito github-comment --token ${{ secrets.GITHUB_TOKEN }}{% endraw %}
25
+ gito --verbose review
26
+ gito github-comment{% endraw %}
27
27
 
28
28
  - uses: actions/upload-artifact@v4
29
29
  with:
@@ -67,4 +67,4 @@ jobs:
67
67
  # Otherwise, use LLM_API_TYPE: none
68
68
  {%- include("github_workflows/components/env-vars.j2") %}
69
69
  run: |
70
- {% raw %}gito react-to-comment ${{ github.event.comment.id }} --token ${{ secrets.GITHUB_TOKEN }}{%- endraw %}
70
+ {% raw %}gito react-to-comment ${{ github.event.comment.id }}{%- endraw %}
@@ -0,0 +1,55 @@
1
+ {{ self_id }}
2
+ ----TASK----
3
+
4
+ ## Subtask 1:
5
+ Write a codebase changes summary clearly describing and explaining it for the engineering managers.
6
+ - It is intended to be posted into bug tracker for estimating work done in the pull request.
7
+ - Summary should be in a form of compact changelist where each change is described by one sentence.
8
+ - Caption should be: ## PR Summary: <3-10 words>
9
+ - Each change summary BP list item should start from effort estimation icon:
10
+ - - ◆◇◇ (up to 2 hours)
11
+ - - ◆◆◇ (half day)
12
+ - - ◆◆◆ (1-2 days and more)
13
+
14
+ Also include this estimation legend below as "Pure Codebase Work Estimation Legend".
15
+
16
+
17
+ ## Subtask 1 (Issue alignment sentence)
18
+ Include one sentence about how the code changes address the requirements of the associated issue listed below.
19
+ - Use ✅ or ⚠️ to indicate whether the implementation fully satisfies the issue requirements.
20
+ - Put this sentence immediately below the PR Summary title
21
+ Examples:
22
+
23
+ If the implementation fully delivers the requested functionality:
24
+ ```
25
+ ✅ Implementation Satisfies [<ISSUE_KEY>](<ISSUE_URL>).
26
+ ```
27
+ If there are concerns about how thoroughly the code covers the requirements and technical description from the associated issue:
28
+ ```
29
+ ⚠️ <Describe specific gap or concern>.
30
+ ⚠️ <Describe additional limitation or missing feature>.
31
+ ```
32
+
33
+ ## Subtask 3:
34
+ Write release notes for public documentation.
35
+ - Caption should be: ## Release Notes Proposal
36
+ Summarize the following changes, focusing on what is new, improved, or fixed for the end user.
37
+ Do not include internal or technical details.
38
+ Structure release notes using clear sections: Added, Changed, Fixed.
39
+ Avoid internal technical jargon or developer-specific details.
40
+
41
+ ----RELATED CODEBASE CHANGES----
42
+ {% for part in diff %}{{ part }}\n{% endfor %}
43
+
44
+ ----FULL FILE CONTENT AFTER APPLYING CHANGES----
45
+ {% for file, file_lines in all_file_lines.items() %}
46
+ --FILE: {{ file }}--
47
+ {{ file_lines }}
48
+ {% endfor %}
49
+
50
+ {%- if pipeline_out.associated_issue and pipeline_out.associated_issue.title %}
51
+ ----ASSOCIATED ISSUE----
52
+ # {{ pipeline_out.associated_issue.title }}
53
+ {{ pipeline_out.associated_issue.description }}
54
+ URL: {{ pipeline_out.associated_issue.url }}
55
+ {%- endif -%}{{ '\n' }}
@@ -0,0 +1,23 @@
1
+ {{ self_id }}
2
+ ----TASK----
3
+ Create a concise comment for QA specialists that explains how to test the code-base changes.
4
+ Include:
5
+ - User journeys that could be disrupted by failures
6
+ - Relevant security scenarios and edge cases
7
+ - Potential risk areas introduced by the changes, with suggestions for focused testing to mitigate them
8
+
9
+ ----RELATED CODEBASE CHANGES----
10
+ {% for part in diff %}{{ part }}\n{% endfor %}
11
+
12
+ ----FULL FILE CONTENT AFTER APPLYING CHANGES----
13
+ {% for file, file_lines in all_file_lines.items() %}
14
+ --FILE: {{ file }}--
15
+ {{ file_lines }}
16
+ {% endfor %}
17
+
18
+ {%- if pipeline_out.associated_issue and pipeline_out.associated_issue.title %}
19
+ ----ASSOCIATED ISSUE----
20
+ # {{ pipeline_out.associated_issue.title }}
21
+ {{ pipeline_out.associated_issue.description }}
22
+ URL: {{ pipeline_out.associated_issue.url }}
23
+ {%- endif -%}{{ '\n' }}
File without changes
File without changes