ultralytics-actions 0.1.2__tar.gz → 0.1.4__tar.gz
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.
- {ultralytics_actions-0.1.2 → ultralytics_actions-0.1.4}/PKG-INFO +3 -3
- {ultralytics_actions-0.1.2 → ultralytics_actions-0.1.4}/README.md +2 -2
- {ultralytics_actions-0.1.2 → ultralytics_actions-0.1.4}/actions/__init__.py +1 -1
- {ultralytics_actions-0.1.2 → ultralytics_actions-0.1.4}/actions/first_interaction.py +15 -0
- {ultralytics_actions-0.1.2 → ultralytics_actions-0.1.4}/actions/review_pr.py +23 -36
- {ultralytics_actions-0.1.2 → ultralytics_actions-0.1.4}/actions/utils/github_utils.py +19 -5
- {ultralytics_actions-0.1.2 → ultralytics_actions-0.1.4}/actions/utils/openai_utils.py +3 -2
- {ultralytics_actions-0.1.2 → ultralytics_actions-0.1.4}/ultralytics_actions.egg-info/PKG-INFO +3 -3
- {ultralytics_actions-0.1.2 → ultralytics_actions-0.1.4}/LICENSE +0 -0
- {ultralytics_actions-0.1.2 → ultralytics_actions-0.1.4}/actions/dispatch_actions.py +0 -0
- {ultralytics_actions-0.1.2 → ultralytics_actions-0.1.4}/actions/summarize_pr.py +0 -0
- {ultralytics_actions-0.1.2 → ultralytics_actions-0.1.4}/actions/summarize_release.py +0 -0
- {ultralytics_actions-0.1.2 → ultralytics_actions-0.1.4}/actions/update_file_headers.py +0 -0
- {ultralytics_actions-0.1.2 → ultralytics_actions-0.1.4}/actions/update_markdown_code_blocks.py +0 -0
- {ultralytics_actions-0.1.2 → ultralytics_actions-0.1.4}/actions/utils/__init__.py +0 -0
- {ultralytics_actions-0.1.2 → ultralytics_actions-0.1.4}/actions/utils/common_utils.py +0 -0
- {ultralytics_actions-0.1.2 → ultralytics_actions-0.1.4}/actions/utils/version_utils.py +0 -0
- {ultralytics_actions-0.1.2 → ultralytics_actions-0.1.4}/pyproject.toml +0 -0
- {ultralytics_actions-0.1.2 → ultralytics_actions-0.1.4}/setup.cfg +0 -0
- {ultralytics_actions-0.1.2 → ultralytics_actions-0.1.4}/tests/test_cli_commands.py +0 -0
- {ultralytics_actions-0.1.2 → ultralytics_actions-0.1.4}/tests/test_common_utils.py +0 -0
- {ultralytics_actions-0.1.2 → ultralytics_actions-0.1.4}/tests/test_dispatch_actions.py +0 -0
- {ultralytics_actions-0.1.2 → ultralytics_actions-0.1.4}/tests/test_file_headers.py +0 -0
- {ultralytics_actions-0.1.2 → ultralytics_actions-0.1.4}/tests/test_first_interaction.py +0 -0
- {ultralytics_actions-0.1.2 → ultralytics_actions-0.1.4}/tests/test_github_utils.py +0 -0
- {ultralytics_actions-0.1.2 → ultralytics_actions-0.1.4}/tests/test_init.py +0 -0
- {ultralytics_actions-0.1.2 → ultralytics_actions-0.1.4}/tests/test_openai_utils.py +0 -0
- {ultralytics_actions-0.1.2 → ultralytics_actions-0.1.4}/tests/test_summarize_pr.py +0 -0
- {ultralytics_actions-0.1.2 → ultralytics_actions-0.1.4}/tests/test_summarize_release.py +0 -0
- {ultralytics_actions-0.1.2 → ultralytics_actions-0.1.4}/tests/test_update_markdown_codeblocks.py +0 -0
- {ultralytics_actions-0.1.2 → ultralytics_actions-0.1.4}/tests/test_urls.py +0 -0
- {ultralytics_actions-0.1.2 → ultralytics_actions-0.1.4}/ultralytics_actions.egg-info/SOURCES.txt +0 -0
- {ultralytics_actions-0.1.2 → ultralytics_actions-0.1.4}/ultralytics_actions.egg-info/dependency_links.txt +0 -0
- {ultralytics_actions-0.1.2 → ultralytics_actions-0.1.4}/ultralytics_actions.egg-info/entry_points.txt +0 -0
- {ultralytics_actions-0.1.2 → ultralytics_actions-0.1.4}/ultralytics_actions.egg-info/requires.txt +0 -0
- {ultralytics_actions-0.1.2 → ultralytics_actions-0.1.4}/ultralytics_actions.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ultralytics-actions
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
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>
|
|
@@ -64,8 +64,8 @@ Ultralytics Actions automatically applies formats, updates, and enhancements usi
|
|
|
64
64
|
- **Spell Check:** Common misspellings are caught using [codespell](https://github.com/codespell-project/codespell).
|
|
65
65
|
- **Broken Links Check:** Broken links in documentation and Markdown files are identified using [Lychee](https://github.com/lycheeverse/lychee).
|
|
66
66
|
- **PR Summary:** Concise Pull Request summaries are generated using [OpenAI](https://openai.com/) GPT-5, improving clarity and review efficiency.
|
|
67
|
-
- **PR Review:** AI-powered
|
|
68
|
-
- **Auto-labeling:**
|
|
67
|
+
- **PR Review:** AI-powered code reviews identify critical bugs, security issues, and code quality concerns with suggested fixes.
|
|
68
|
+
- **Auto-labeling:** Applies relevant labels to issues and PRs via [OpenAI](https://openai.com/) GPT-5 for intelligent categorization.
|
|
69
69
|
|
|
70
70
|
## 🛠️ How It Works
|
|
71
71
|
|
|
@@ -26,8 +26,8 @@ Ultralytics Actions automatically applies formats, updates, and enhancements usi
|
|
|
26
26
|
- **Spell Check:** Common misspellings are caught using [codespell](https://github.com/codespell-project/codespell).
|
|
27
27
|
- **Broken Links Check:** Broken links in documentation and Markdown files are identified using [Lychee](https://github.com/lycheeverse/lychee).
|
|
28
28
|
- **PR Summary:** Concise Pull Request summaries are generated using [OpenAI](https://openai.com/) GPT-5, improving clarity and review efficiency.
|
|
29
|
-
- **PR Review:** AI-powered
|
|
30
|
-
- **Auto-labeling:**
|
|
29
|
+
- **PR Review:** AI-powered code reviews identify critical bugs, security issues, and code quality concerns with suggested fixes.
|
|
30
|
+
- **Auto-labeling:** Applies relevant labels to issues and PRs via [OpenAI](https://openai.com/) GPT-5 for intelligent categorization.
|
|
31
31
|
|
|
32
32
|
## 🛠️ How It Works
|
|
33
33
|
|
|
@@ -5,12 +5,14 @@ from __future__ import annotations
|
|
|
5
5
|
import os
|
|
6
6
|
import time
|
|
7
7
|
|
|
8
|
+
from . import review_pr
|
|
8
9
|
from .utils import Action, filter_labels, get_completion, get_pr_open_response, remove_html_comments
|
|
9
10
|
|
|
10
11
|
SUMMARY_START = (
|
|
11
12
|
"## 🛠️ PR Summary\n\n<sub>Made with ❤️ by [Ultralytics Actions](https://github.com/ultralytics/actions)<sub>\n\n"
|
|
12
13
|
)
|
|
13
14
|
BLOCK_USER = os.getenv("BLOCK_USER", "false").lower() == "true"
|
|
15
|
+
AUTO_PR_REVIEW = os.getenv("REVIEW", "true").lower() == "true"
|
|
14
16
|
|
|
15
17
|
|
|
16
18
|
def apply_and_check_labels(event, number, node_id, issue_type, username, labels, label_descriptions):
|
|
@@ -185,6 +187,9 @@ def main(*args, **kwargs):
|
|
|
185
187
|
|
|
186
188
|
# Use unified PR open response for new PRs (summary + labels + first comment in 1 API call)
|
|
187
189
|
if issue_type == "pull request" and action == "opened":
|
|
190
|
+
if event.should_skip_pr_author():
|
|
191
|
+
return
|
|
192
|
+
|
|
188
193
|
print("Processing PR open with unified API call...")
|
|
189
194
|
diff = event.get_pr_diff()
|
|
190
195
|
response = get_pr_open_response(event.repository, diff, title, body, label_descriptions)
|
|
@@ -192,6 +197,8 @@ def main(*args, **kwargs):
|
|
|
192
197
|
if summary := response.get("summary"):
|
|
193
198
|
print("Updating PR description with summary...")
|
|
194
199
|
event.update_pr_description(number, SUMMARY_START + summary)
|
|
200
|
+
else:
|
|
201
|
+
summary = body
|
|
195
202
|
|
|
196
203
|
if relevant_labels := response.get("labels", []):
|
|
197
204
|
apply_and_check_labels(event, number, node_id, issue_type, username, relevant_labels, label_descriptions)
|
|
@@ -200,6 +207,14 @@ def main(*args, **kwargs):
|
|
|
200
207
|
print("Adding first interaction comment...")
|
|
201
208
|
time.sleep(1) # sleep to ensure label added first
|
|
202
209
|
event.add_comment(number, node_id, first_comment, issue_type)
|
|
210
|
+
|
|
211
|
+
# Automatic PR review after first interaction
|
|
212
|
+
if AUTO_PR_REVIEW:
|
|
213
|
+
print("Starting automatic PR review...")
|
|
214
|
+
review_number = review_pr.dismiss_previous_reviews(event)
|
|
215
|
+
review_data = review_pr.generate_pr_review(event.repository, diff, title, summary)
|
|
216
|
+
review_pr.post_review_summary(event, review_data, review_number)
|
|
217
|
+
print("PR review completed")
|
|
203
218
|
return
|
|
204
219
|
|
|
205
220
|
# Handle issues and discussions (NOT PRs)
|
|
@@ -79,34 +79,20 @@ def generate_pr_review(repository: str, diff_text: str, pr_title: str, pr_descri
|
|
|
79
79
|
diff_truncated = len(diff_text) > limit
|
|
80
80
|
lines_changed = sum(len(lines) for lines in diff_files.values())
|
|
81
81
|
|
|
82
|
-
comment_guidance = (
|
|
83
|
-
"Provide up to 1-3 comments only if critical issues exist"
|
|
84
|
-
if lines_changed < 50
|
|
85
|
-
else "Provide up to 3-5 comments only if high-impact issues exist"
|
|
86
|
-
if lines_changed < 200
|
|
87
|
-
else "Provide up to 5-10 comments only for the most critical issues"
|
|
88
|
-
)
|
|
89
|
-
|
|
90
82
|
content = (
|
|
91
83
|
"You are an expert code reviewer for Ultralytics. Provide detailed inline comments on specific code changes.\n\n"
|
|
92
|
-
"Focus on:
|
|
93
|
-
"FORMATTING: Use backticks for
|
|
84
|
+
"Focus on: Bugs, security, performance, best practices, edge cases, error handling\n\n"
|
|
85
|
+
"FORMATTING: Use backticks for code: `x=3`, `file.py`, `function()`\n\n"
|
|
94
86
|
"CRITICAL RULES:\n"
|
|
95
|
-
"1. Quality over quantity
|
|
96
|
-
|
|
97
|
-
"3.
|
|
98
|
-
"4.
|
|
99
|
-
"5.
|
|
100
|
-
"6.
|
|
101
|
-
"
|
|
102
|
-
"
|
|
103
|
-
"
|
|
104
|
-
"SUMMARY GUIDELINES:\n"
|
|
105
|
-
"- Keep summary brief, clear, and actionable - avoid overly detailed explanations\n"
|
|
106
|
-
"- Highlight only the most important findings\n"
|
|
107
|
-
"- Do NOT include file names or line numbers in the summary - inline comments already show exact locations\n"
|
|
108
|
-
"- Focus on what needs to be fixed, not where\n\n"
|
|
109
|
-
"CODE SUGGESTIONS:\n"
|
|
87
|
+
"1. Quality over quantity - zero comments is fine for clean code, only flag truly important issues\n"
|
|
88
|
+
"2. Combine issues that are directly related to the same problem\n"
|
|
89
|
+
"3. Use 'start_line' and 'line' to highlight multi-line ranges when issues span multiple lines\n"
|
|
90
|
+
"4. Prioritize: CRITICAL bugs/security > HIGH impact > code quality improvements\n"
|
|
91
|
+
"5. Keep comments concise and friendly - avoid jargon\n"
|
|
92
|
+
"6. Skip routine changes: imports, version updates, standard refactoring\n\n"
|
|
93
|
+
"SUMMARY:\n"
|
|
94
|
+
"- Brief and actionable - what needs fixing, not where (locations shown in inline comments)\n\n"
|
|
95
|
+
"SUGGESTIONS:\n"
|
|
110
96
|
"- ONLY provide 'suggestion' field when you have high certainty the code is problematic AND sufficient context for a confident fix\n"
|
|
111
97
|
"- If uncertain about the correct fix, omit 'suggestion' field and explain the concern in 'message' only\n"
|
|
112
98
|
"- Suggestions must be ready-to-merge code with NO comments, placeholders, or explanations\n"
|
|
@@ -118,10 +104,7 @@ def generate_pr_review(repository: str, diff_text: str, pr_title: str, pr_descri
|
|
|
118
104
|
"Return JSON: "
|
|
119
105
|
'{"comments": [{"file": "exact/path", "line": N, "severity": "HIGH", "message": "...", "suggestion": "..."}], "summary": "..."}\n\n'
|
|
120
106
|
"Rules:\n"
|
|
121
|
-
"- Only
|
|
122
|
-
"- Use exact file paths from diff (no ./ prefix)\n"
|
|
123
|
-
"- Line numbers must match NEW file line numbers from @@ hunks\n"
|
|
124
|
-
"- When '- old' then '+ new', new line keeps SAME line number\n"
|
|
107
|
+
"- Only NEW lines (+ in diff), exact paths (no ./), correct line numbers from @@ hunks\n"
|
|
125
108
|
"- Severity: CRITICAL, HIGH, MEDIUM, LOW, SUGGESTION\n"
|
|
126
109
|
f"- Files changed: {len(file_list)} ({', '.join(file_list[:10])}{'...' if len(file_list) > 10 else ''})\n"
|
|
127
110
|
f"- Lines changed: {lines_changed}\n"
|
|
@@ -142,7 +125,7 @@ def generate_pr_review(repository: str, diff_text: str, pr_title: str, pr_descri
|
|
|
142
125
|
]
|
|
143
126
|
|
|
144
127
|
try:
|
|
145
|
-
response = get_completion(messages, reasoning_effort="medium")
|
|
128
|
+
response = get_completion(messages, reasoning_effort="medium", model="gpt-5-codex")
|
|
146
129
|
print("\n" + "=" * 80 + f"\nFULL AI RESPONSE:\n{response}\n" + "=" * 80 + "\n")
|
|
147
130
|
|
|
148
131
|
json_str = re.search(r"```(?:json)?\s*(\{.*?\})\s*```", response, re.DOTALL)
|
|
@@ -241,12 +224,12 @@ def post_review_summary(event: Action, review_data: dict, review_number: int) ->
|
|
|
241
224
|
body = (
|
|
242
225
|
f"## {review_title}\n\n"
|
|
243
226
|
"<sub>Made with ❤️ by [Ultralytics Actions](https://github.com/ultralytics/actions)</sub>\n\n"
|
|
244
|
-
f"{review_data.get('summary', 'Review completed')}\n\n"
|
|
227
|
+
f"{review_data.get('summary', 'Review completed')[:1000]}\n\n" # Clip summary length
|
|
245
228
|
)
|
|
246
229
|
|
|
247
230
|
if comments:
|
|
248
231
|
shown = min(len(comments), 10)
|
|
249
|
-
body += f"💬 Posted {shown} inline comment{'s' if shown != 1 else ''}
|
|
232
|
+
body += f"💬 Posted {shown} inline comment{'s' if shown != 1 else ''}\n"
|
|
250
233
|
|
|
251
234
|
if review_data.get("diff_truncated"):
|
|
252
235
|
body += "\n⚠️ **Large PR**: Review focused on critical issues. Some details may not be covered.\n"
|
|
@@ -256,14 +239,15 @@ def post_review_summary(event: Action, review_data: dict, review_number: int) ->
|
|
|
256
239
|
|
|
257
240
|
# Build inline comments for the review
|
|
258
241
|
review_comments = []
|
|
259
|
-
for comment in comments[:10]:
|
|
242
|
+
for comment in comments[:10]: # Limit to 10 comments
|
|
260
243
|
if not (file_path := comment.get("file")) or not (line := comment.get("line", 0)):
|
|
261
244
|
continue
|
|
262
245
|
|
|
263
246
|
severity = comment.get("severity", "SUGGESTION")
|
|
264
|
-
comment_body = f"{EMOJI_MAP.get(severity, '💭')} **{severity}**: {comment.get('message', '')}"
|
|
247
|
+
comment_body = f"{EMOJI_MAP.get(severity, '💭')} **{severity}**: {comment.get('message', '')[:1000]}"
|
|
265
248
|
|
|
266
249
|
if suggestion := comment.get("suggestion"):
|
|
250
|
+
suggestion = suggestion[:1000] # Clip suggestion length
|
|
267
251
|
if "```" not in suggestion:
|
|
268
252
|
# Extract original line indentation and apply to suggestion
|
|
269
253
|
if original_line := review_data.get("diff_files", {}).get(file_path, {}).get(line):
|
|
@@ -307,12 +291,15 @@ def main(*args, **kwargs):
|
|
|
307
291
|
print(f"Skipping: PR state is {event.pr.get('state') if event.pr else 'None'}")
|
|
308
292
|
return
|
|
309
293
|
|
|
294
|
+
# Skip self-authored or bot PRs unless manually review_requested
|
|
295
|
+
if event.event_data.get("action") != "review_requested" and event.should_skip_pr_author():
|
|
296
|
+
return
|
|
297
|
+
|
|
310
298
|
print(f"Starting PR review for #{event.pr['number']}")
|
|
311
299
|
review_number = dismiss_previous_reviews(event)
|
|
312
300
|
|
|
313
301
|
diff = event.get_pr_diff()
|
|
314
|
-
|
|
315
|
-
review = generate_pr_review(event.repository, diff, event.pr.get("title", ""), pr_description)
|
|
302
|
+
review = generate_pr_review(event.repository, diff, event.pr.get("title", ""), event.pr.get("body", ""))
|
|
316
303
|
|
|
317
304
|
post_review_summary(event, review, review_number)
|
|
318
305
|
print("PR review completed")
|
|
@@ -188,6 +188,20 @@ class Action:
|
|
|
188
188
|
"""Checks if a user is a member of the organization."""
|
|
189
189
|
return self.get(f"{GITHUB_API_URL}/orgs/{self.repository.split('/')[0]}/members/{username}").status_code == 204
|
|
190
190
|
|
|
191
|
+
def should_skip_pr_author(self) -> bool:
|
|
192
|
+
"""Checks if PR should be skipped based on author (self-authored or bot PRs)."""
|
|
193
|
+
if not self.pr:
|
|
194
|
+
return False
|
|
195
|
+
if pr_author := self.pr.get("user", {}).get("login"):
|
|
196
|
+
if pr_author == self.get_username():
|
|
197
|
+
print(f"Skipping: PR author ({pr_author}) is the same as bot")
|
|
198
|
+
return True
|
|
199
|
+
# Check both user.type and [bot] suffix for robust bot detection
|
|
200
|
+
if self.pr.get("user", {}).get("type") == "Bot" or pr_author.endswith("[bot]"):
|
|
201
|
+
print(f"Skipping: PR author ({pr_author}) is a bot")
|
|
202
|
+
return True
|
|
203
|
+
return False
|
|
204
|
+
|
|
191
205
|
def is_fork_pr(self) -> bool:
|
|
192
206
|
"""Checks if PR is from a fork (different repo than base)."""
|
|
193
207
|
if not self.pr:
|
|
@@ -267,10 +281,10 @@ class Action:
|
|
|
267
281
|
start = "## 🛠️ PR Summary"
|
|
268
282
|
if start in description:
|
|
269
283
|
print("Existing PR Summary found, replacing.")
|
|
270
|
-
updated_description = description.split(start)[0] + new_summary
|
|
284
|
+
updated_description = description.split(start)[0].rstrip() + "\n\n" + new_summary
|
|
271
285
|
else:
|
|
272
286
|
print("PR Summary not found, appending.")
|
|
273
|
-
updated_description = description + "\n\n" + new_summary
|
|
287
|
+
updated_description = (description.rstrip() + "\n\n" + new_summary) if description.strip() else new_summary
|
|
274
288
|
|
|
275
289
|
self.patch(url, json={"body": updated_description})
|
|
276
290
|
self._pr_summary_cache = new_summary
|
|
@@ -386,7 +400,7 @@ Thank you 🙏
|
|
|
386
400
|
try:
|
|
387
401
|
data = response.json()["data"]["repository"]["pullRequest"]
|
|
388
402
|
comments = data["reviews"]["nodes"] + data["comments"]["nodes"]
|
|
389
|
-
|
|
403
|
+
username = self.get_username()
|
|
390
404
|
author = data["author"]["login"] if data["author"]["__typename"] != "Bot" else None
|
|
391
405
|
|
|
392
406
|
contributors = {x["author"]["login"] for x in comments if x["author"]["__typename"] != "Bot"}
|
|
@@ -399,10 +413,10 @@ Thank you 🙏
|
|
|
399
413
|
contributors.add(login)
|
|
400
414
|
|
|
401
415
|
contributors.discard(author)
|
|
402
|
-
contributors.discard(
|
|
416
|
+
contributors.discard(username)
|
|
403
417
|
|
|
404
418
|
pr_credit = ""
|
|
405
|
-
if author and author !=
|
|
419
|
+
if author and author != username:
|
|
406
420
|
pr_credit += f"@{author}"
|
|
407
421
|
if contributors:
|
|
408
422
|
pr_credit += (" with contributions from " if pr_credit else "") + ", ".join(
|
|
@@ -112,6 +112,7 @@ def get_completion(
|
|
|
112
112
|
temperature: float = 1.0,
|
|
113
113
|
reasoning_effort: str = None,
|
|
114
114
|
response_format: dict = None,
|
|
115
|
+
model: str = OPENAI_MODEL,
|
|
115
116
|
) -> str | dict:
|
|
116
117
|
"""Generates a completion using OpenAI's Responses API based on input messages."""
|
|
117
118
|
assert OPENAI_API_KEY, "OpenAI API key is required."
|
|
@@ -122,8 +123,8 @@ def get_completion(
|
|
|
122
123
|
|
|
123
124
|
max_retries = 2
|
|
124
125
|
for attempt in range(max_retries + 2):
|
|
125
|
-
data = {"model":
|
|
126
|
-
if "gpt-5" in
|
|
126
|
+
data = {"model": model, "input": messages, "store": False, "temperature": temperature}
|
|
127
|
+
if "gpt-5" in model:
|
|
127
128
|
data["reasoning"] = {"effort": reasoning_effort or "low"}
|
|
128
129
|
# GPT-5 Responses API handles JSON via prompting, not format parameter
|
|
129
130
|
|
{ultralytics_actions-0.1.2 → ultralytics_actions-0.1.4}/ultralytics_actions.egg-info/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ultralytics-actions
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
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>
|
|
@@ -64,8 +64,8 @@ Ultralytics Actions automatically applies formats, updates, and enhancements usi
|
|
|
64
64
|
- **Spell Check:** Common misspellings are caught using [codespell](https://github.com/codespell-project/codespell).
|
|
65
65
|
- **Broken Links Check:** Broken links in documentation and Markdown files are identified using [Lychee](https://github.com/lycheeverse/lychee).
|
|
66
66
|
- **PR Summary:** Concise Pull Request summaries are generated using [OpenAI](https://openai.com/) GPT-5, improving clarity and review efficiency.
|
|
67
|
-
- **PR Review:** AI-powered
|
|
68
|
-
- **Auto-labeling:**
|
|
67
|
+
- **PR Review:** AI-powered code reviews identify critical bugs, security issues, and code quality concerns with suggested fixes.
|
|
68
|
+
- **Auto-labeling:** Applies relevant labels to issues and PRs via [OpenAI](https://openai.com/) GPT-5 for intelligent categorization.
|
|
69
69
|
|
|
70
70
|
## 🛠️ How It Works
|
|
71
71
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ultralytics_actions-0.1.2 → ultralytics_actions-0.1.4}/actions/update_markdown_code_blocks.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ultralytics_actions-0.1.2 → ultralytics_actions-0.1.4}/tests/test_update_markdown_codeblocks.py
RENAMED
|
File without changes
|
|
File without changes
|
{ultralytics_actions-0.1.2 → ultralytics_actions-0.1.4}/ultralytics_actions.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ultralytics_actions-0.1.2 → ultralytics_actions-0.1.4}/ultralytics_actions.egg-info/requires.txt
RENAMED
|
File without changes
|
{ultralytics_actions-0.1.2 → ultralytics_actions-0.1.4}/ultralytics_actions.egg-info/top_level.txt
RENAMED
|
File without changes
|