ultralytics-actions 0.1.1__py3-none-any.whl → 0.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.

Potentially problematic release.


This version of ultralytics-actions might be problematic. Click here for more details.

actions/__init__.py CHANGED
@@ -23,4 +23,4 @@
23
23
  # ├── test_summarize_pr.py
24
24
  # └── ...
25
25
 
26
- __version__ = "0.1.1"
26
+ __version__ = "0.1.2"
@@ -176,6 +176,9 @@ YOUR {issue_type.upper()} RESPONSE:
176
176
  def main(*args, **kwargs):
177
177
  """Executes auto-labeling and custom response generation for new GitHub issues, PRs, and discussions."""
178
178
  event = Action(*args, **kwargs)
179
+ if event.should_skip_openai():
180
+ return
181
+
179
182
  number, node_id, title, body, username, issue_type, action = get_event_content(event)
180
183
  available_labels = event.get_repo_data("labels")
181
184
  label_descriptions = {label["name"]: label.get("description", "") for label in available_labels}
actions/review_pr.py CHANGED
@@ -90,7 +90,7 @@ def generate_pr_review(repository: str, diff_text: str, pr_title: str, pr_descri
90
90
  content = (
91
91
  "You are an expert code reviewer for Ultralytics. Provide detailed inline comments on specific code changes.\n\n"
92
92
  "Focus on: Code quality, style, best practices, bugs, edge cases, error handling, performance, security, documentation, test coverage\n\n"
93
- "FORMATTING: Use backticks for code, file names, branch names, function names, variable names, packages\n\n"
93
+ "FORMATTING: Use backticks for all summary and suggestion code, files, branches, functions, variables, packages, e.g. `x=3`\n\n"
94
94
  "CRITICAL RULES:\n"
95
95
  "1. Quality over quantity: Zero comments is fine for clean code - only flag truly important issues\n"
96
96
  f"2. {comment_guidance} - these are maximums, not targets\n"
@@ -113,7 +113,7 @@ def generate_pr_review(repository: str, diff_text: str, pr_title: str, pr_descri
113
113
  "- Suggestions replace ONLY the single line at 'line' - for multi-line fixes, describe the change in 'message' instead\n"
114
114
  "- Do NOT provide 'start_line' when including a 'suggestion' - suggestions are always single-line only\n"
115
115
  "- Suggestion content must match the exact indentation of the original line\n"
116
- "- Never include triple backticks (```) in suggestions as they break markdown formatting\n"
116
+ "- Avoid triple backticks (```) in suggestions as they break markdown formatting\n"
117
117
  "- It's better to flag an issue without a suggestion than provide a wrong or uncertain fix\n\n"
118
118
  "Return JSON: "
119
119
  '{"comments": [{"file": "exact/path", "line": N, "severity": "HIGH", "message": "...", "suggestion": "..."}], "summary": "..."}\n\n'
@@ -236,9 +236,7 @@ def post_review_summary(event: Action, review_data: dict, review_number: int) ->
236
236
 
237
237
  review_title = f"{REVIEW_MARKER} {review_number}" if review_number > 1 else REVIEW_MARKER
238
238
  comments = review_data.get("comments", [])
239
- event_type = (
240
- "REQUEST_CHANGES" if any(c.get("severity") not in ["LOW", "SUGGESTION", None] for c in comments) else "APPROVE"
241
- )
239
+ event_type = "COMMENT" if any(c.get("severity") not in ["LOW", "SUGGESTION", None] for c in comments) else "APPROVE"
242
240
 
243
241
  body = (
244
242
  f"## {review_title}\n\n"
@@ -313,7 +311,8 @@ def main(*args, **kwargs):
313
311
  review_number = dismiss_previous_reviews(event)
314
312
 
315
313
  diff = event.get_pr_diff()
316
- review = generate_pr_review(event.repository, diff, event.pr.get("title", ""), event.pr.get("body", ""))
314
+ pr_description = event._pr_summary_cache or event.pr.get("body", "")
315
+ review = generate_pr_review(event.repository, diff, event.pr.get("title", ""), pr_description)
317
316
 
318
317
  post_review_summary(event, review, review_number)
319
318
  print("PR review completed")
actions/summarize_pr.py CHANGED
@@ -96,10 +96,11 @@ def main(*args, **kwargs):
96
96
  """Summarize a pull request and update its description with a summary."""
97
97
  event = Action(*args, **kwargs)
98
98
  action = event.event_data.get("action")
99
-
100
99
  if action == "opened":
101
100
  print("Skipping PR open - handled by first_interaction.py with unified API call")
102
101
  return
102
+ if event.should_skip_openai():
103
+ return
103
104
 
104
105
  print(f"Retrieving diff for PR {event.pr['number']}")
105
106
  diff = event.get_pr_diff()
@@ -19,7 +19,7 @@ def get_release_diff(event, previous_tag: str, latest_tag: str) -> str:
19
19
  """Retrieves the differences between two specified Git tags in a GitHub repository."""
20
20
  url = f"{GITHUB_API_URL}/repos/{event.repository}/compare/{previous_tag}...{latest_tag}"
21
21
  r = event.get(url, headers=event.headers_diff)
22
- return r.text if r.status_code == 200 else f"Failed to get diff: {r.content}"
22
+ return r.text if r.status_code == 200 else f"Failed to get diff: {r.text}"
23
23
 
24
24
 
25
25
  def get_prs_between_tags(event, previous_tag: str, latest_tag: str) -> list:
@@ -42,8 +42,8 @@ def get_prs_between_tags(event, previous_tag: str, latest_tag: str) -> list:
42
42
  pr_numbers.update(pr_matches)
43
43
 
44
44
  prs = []
45
- time.sleep(10) # Allow final PR summary to update on merge
46
45
  for pr_number in sorted(pr_numbers): # earliest to latest
46
+ time.sleep(1) # Rate limit: GitHub search API has strict limits
47
47
  pr_url = f"{GITHUB_API_URL}/repos/{event.repository}/pulls/{pr_number}"
48
48
  pr_response = event.get(pr_url)
49
49
  if pr_response.status_code == 200:
@@ -52,7 +52,7 @@ def get_prs_between_tags(event, previous_tag: str, latest_tag: str) -> list:
52
52
  {
53
53
  "number": pr_data["number"],
54
54
  "title": pr_data["title"],
55
- "body": remove_html_comments(pr_data["body"]),
55
+ "body": remove_html_comments(pr_data.get("body", "")),
56
56
  "author": pr_data["user"]["login"],
57
57
  "html_url": pr_data["html_url"],
58
58
  "merged_at": pr_data["merged_at"],
@@ -140,7 +140,7 @@ def generate_release_summary(
140
140
  },
141
141
  {
142
142
  "role": "user",
143
- "content": f"Summarize the updates made in the '{latest_tag}' tag, focusing on major model or features changes, their purpose, and potential impact. Keep the summary clear and suitable for a broad audience. Add emojis to enliven the summary. Prioritize changes from the current PR (the first in the list), which is usually the most important in the release. Reply directly with a summary along these example guidelines, though feel free to adjust as appropriate:\n\n"
143
+ "content": f"Summarize the updates made in the '{latest_tag}' tag, focusing on major model or features changes, their purpose, and potential impact. Keep the summary clear and suitable for a broad audience. Add emojis to enliven the summary. Prioritize changes from the current PR (the last in the list), which is usually the most important in the release. Reply directly with a summary along these example guidelines, though feel free to adjust as appropriate:\n\n"
144
144
  f"## 🌟 Summary (single-line synopsis)\n"
145
145
  f"## 📊 Key Changes (bullet points highlighting any major changes)\n"
146
146
  f"## 🎯 Purpose & Impact (bullet points explaining any benefits and potential impact to users)\n\n\n"
@@ -114,6 +114,7 @@ class Action:
114
114
  self.verbose = verbose
115
115
  self.eyes_reaction_id = None
116
116
  self._pr_diff_cache = None
117
+ self._pr_summary_cache = None
117
118
  self._username_cache = None
118
119
  self._default_status = {
119
120
  "get": [200],
@@ -187,6 +188,22 @@ class Action:
187
188
  """Checks if a user is a member of the organization."""
188
189
  return self.get(f"{GITHUB_API_URL}/orgs/{self.repository.split('/')[0]}/members/{username}").status_code == 204
189
190
 
191
+ def is_fork_pr(self) -> bool:
192
+ """Checks if PR is from a fork (different repo than base)."""
193
+ if not self.pr:
194
+ return False
195
+ head_repo = self.pr.get("head", {}).get("repo", {}).get("full_name")
196
+ return bool(head_repo) and head_repo != self.repository
197
+
198
+ def should_skip_openai(self) -> bool:
199
+ """Check if OpenAI operations should be skipped."""
200
+ from actions.utils.openai_utils import OPENAI_API_KEY
201
+
202
+ if not OPENAI_API_KEY:
203
+ print("⚠️ Skipping LLM operations (OPENAI_API_KEY not found)")
204
+ return True
205
+ return False
206
+
190
207
  def get_pr_diff(self) -> str:
191
208
  """Retrieves the diff content for a specified pull request with caching."""
192
209
  if self._pr_diff_cache:
@@ -256,6 +273,7 @@ class Action:
256
273
  updated_description = description + "\n\n" + new_summary
257
274
 
258
275
  self.patch(url, json={"body": updated_description})
276
+ self._pr_summary_cache = new_summary
259
277
 
260
278
  def get_label_ids(self, labels: list[str]) -> list[str]:
261
279
  """Retrieves GitHub label IDs for a list of label names using the GraphQL API."""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ultralytics-actions
3
- Version: 0.1.1
3
+ Version: 0.1.2
4
4
  Summary: Ultralytics Actions for GitHub automation and PR management.
5
5
  Author-email: Glenn Jocher <glenn.jocher@ultralytics.com>
6
6
  Maintainer-email: Ultralytics <hello@ultralytics.com>
@@ -0,0 +1,19 @@
1
+ actions/__init__.py,sha256=TJd-NrNbVN3UJfNKfPjHUjsNhC7dbGDea80Ig0A1IVk,772
2
+ actions/dispatch_actions.py,sha256=8jaaVkA_LSlpUQ4tuzmQtf2kw3G09uVRD_LmJyXYKNE,4215
3
+ actions/first_interaction.py,sha256=X0eUAov3HcdNPyNa6tpl3ttbfiBhJZndlyy_LGDmsqU,9244
4
+ actions/review_pr.py,sha256=P9ONfDxIE3w7PcTcgBhatTfxb2L_ghqxQjk6UEUipHs,15485
5
+ actions/summarize_pr.py,sha256=XLYsNTf4J6VPyyecZcuiJaSBDgjDSWFj37v5vb1ATCA,5773
6
+ actions/summarize_release.py,sha256=_067Q5AP-Zdnt_qzhHaCuGCr7T4MXSB5_N-M5GX6qgQ,9081
7
+ actions/update_file_headers.py,sha256=E5fKYLdeW16-BHCcuqxohGpGZqgEh-WX4ZmCQJw2R90,6684
8
+ actions/update_markdown_code_blocks.py,sha256=w3DTRltg2Rmr4-qrNawv_S2vJbheKE0tne1iz79FzXg,8692
9
+ actions/utils/__init__.py,sha256=sKNx6o5jcAraEdGFph0o-YC7dMMY-dg_FprIBa6Jydw,1027
10
+ actions/utils/common_utils.py,sha256=8ZmgaXZU3J2sg-HSaldp3hHYq7bI3akcJHdIXPmcNAo,11908
11
+ actions/utils/github_utils.py,sha256=voWQbn6eeqvhDceVfokHypSydlmmNPsUOuisAqGJ1CQ,18963
12
+ actions/utils/openai_utils.py,sha256=91ohkSlldVZt-icYcK7ZLfgQfnMbf4mTWT3nRnQ1QG4,10486
13
+ actions/utils/version_utils.py,sha256=EIbm3iZVNyNl3dh8aNz_9ITeTC93ZxfyUzIRkO3tSXw,3242
14
+ ultralytics_actions-0.1.2.dist-info/licenses/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
15
+ ultralytics_actions-0.1.2.dist-info/METADATA,sha256=uZQWWi4EX-5Cpu_H8VdWxyzFzG7MmearTFZsVTVQjz4,12389
16
+ ultralytics_actions-0.1.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
17
+ ultralytics_actions-0.1.2.dist-info/entry_points.txt,sha256=n_VbDs3Xj33daaeN_2D72UTEuyeH8hVc6-CPH55ymkY,496
18
+ ultralytics_actions-0.1.2.dist-info/top_level.txt,sha256=5apM5x80QlJcGbACn1v3fkmIuL1-XQCKcItJre7w7Tw,8
19
+ ultralytics_actions-0.1.2.dist-info/RECORD,,
@@ -1,19 +0,0 @@
1
- actions/__init__.py,sha256=Sxxh83BO8x10c7LkJcNoSTK6sE8e4KtnqLV9qZsp_pA,772
2
- actions/dispatch_actions.py,sha256=8jaaVkA_LSlpUQ4tuzmQtf2kw3G09uVRD_LmJyXYKNE,4215
3
- actions/first_interaction.py,sha256=BkiMKppSeZ3VOP9jK0Q7FwqUYivFM4LIjJia9KgqNco,9193
4
- actions/review_pr.py,sha256=O9EfC8qNbfwq1FgFkVVFse1YTUKYyLIbo9d3Hf9luu4,15434
5
- actions/summarize_pr.py,sha256=K7o6RQQxUjsWpP4FgH7Nrgp4Qbvnprk8C01PasX_2vE,5724
6
- actions/summarize_release.py,sha256=bIAqBbjq4eCDBAV3MWb8yq1hSK93MEyazoN29kT1-js,9068
7
- actions/update_file_headers.py,sha256=E5fKYLdeW16-BHCcuqxohGpGZqgEh-WX4ZmCQJw2R90,6684
8
- actions/update_markdown_code_blocks.py,sha256=w3DTRltg2Rmr4-qrNawv_S2vJbheKE0tne1iz79FzXg,8692
9
- actions/utils/__init__.py,sha256=sKNx6o5jcAraEdGFph0o-YC7dMMY-dg_FprIBa6Jydw,1027
10
- actions/utils/common_utils.py,sha256=8ZmgaXZU3J2sg-HSaldp3hHYq7bI3akcJHdIXPmcNAo,11908
11
- actions/utils/github_utils.py,sha256=WpvVQIWScIB_mZxWSZ_zGun-oW90bI15eKqVCDLusJs,18264
12
- actions/utils/openai_utils.py,sha256=91ohkSlldVZt-icYcK7ZLfgQfnMbf4mTWT3nRnQ1QG4,10486
13
- actions/utils/version_utils.py,sha256=EIbm3iZVNyNl3dh8aNz_9ITeTC93ZxfyUzIRkO3tSXw,3242
14
- ultralytics_actions-0.1.1.dist-info/licenses/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
15
- ultralytics_actions-0.1.1.dist-info/METADATA,sha256=iDfUTlwy7koo7KAtTHwkrvYMSRRqJHzr67RJEBI4nus,12389
16
- ultralytics_actions-0.1.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
17
- ultralytics_actions-0.1.1.dist-info/entry_points.txt,sha256=n_VbDs3Xj33daaeN_2D72UTEuyeH8hVc6-CPH55ymkY,496
18
- ultralytics_actions-0.1.1.dist-info/top_level.txt,sha256=5apM5x80QlJcGbACn1v3fkmIuL1-XQCKcItJre7w7Tw,8
19
- ultralytics_actions-0.1.1.dist-info/RECORD,,