ultralytics-actions 0.1.5__tar.gz → 0.1.7__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.5 → ultralytics_actions-0.1.7}/PKG-INFO +1 -1
- {ultralytics_actions-0.1.5 → ultralytics_actions-0.1.7}/actions/__init__.py +1 -1
- {ultralytics_actions-0.1.5 → ultralytics_actions-0.1.7}/actions/review_pr.py +85 -30
- {ultralytics_actions-0.1.5 → ultralytics_actions-0.1.7}/actions/utils/github_utils.py +8 -7
- {ultralytics_actions-0.1.5 → ultralytics_actions-0.1.7}/actions/utils/openai_utils.py +2 -0
- {ultralytics_actions-0.1.5 → ultralytics_actions-0.1.7}/tests/test_github_utils.py +2 -0
- {ultralytics_actions-0.1.5 → ultralytics_actions-0.1.7}/tests/test_openai_utils.py +2 -0
- {ultralytics_actions-0.1.5 → ultralytics_actions-0.1.7}/ultralytics_actions.egg-info/PKG-INFO +1 -1
- {ultralytics_actions-0.1.5 → ultralytics_actions-0.1.7}/LICENSE +0 -0
- {ultralytics_actions-0.1.5 → ultralytics_actions-0.1.7}/README.md +0 -0
- {ultralytics_actions-0.1.5 → ultralytics_actions-0.1.7}/actions/dispatch_actions.py +0 -0
- {ultralytics_actions-0.1.5 → ultralytics_actions-0.1.7}/actions/first_interaction.py +0 -0
- {ultralytics_actions-0.1.5 → ultralytics_actions-0.1.7}/actions/summarize_pr.py +0 -0
- {ultralytics_actions-0.1.5 → ultralytics_actions-0.1.7}/actions/summarize_release.py +0 -0
- {ultralytics_actions-0.1.5 → ultralytics_actions-0.1.7}/actions/update_file_headers.py +0 -0
- {ultralytics_actions-0.1.5 → ultralytics_actions-0.1.7}/actions/update_markdown_code_blocks.py +0 -0
- {ultralytics_actions-0.1.5 → ultralytics_actions-0.1.7}/actions/utils/__init__.py +0 -0
- {ultralytics_actions-0.1.5 → ultralytics_actions-0.1.7}/actions/utils/common_utils.py +0 -0
- {ultralytics_actions-0.1.5 → ultralytics_actions-0.1.7}/actions/utils/version_utils.py +0 -0
- {ultralytics_actions-0.1.5 → ultralytics_actions-0.1.7}/pyproject.toml +0 -0
- {ultralytics_actions-0.1.5 → ultralytics_actions-0.1.7}/setup.cfg +0 -0
- {ultralytics_actions-0.1.5 → ultralytics_actions-0.1.7}/tests/test_cli_commands.py +0 -0
- {ultralytics_actions-0.1.5 → ultralytics_actions-0.1.7}/tests/test_common_utils.py +0 -0
- {ultralytics_actions-0.1.5 → ultralytics_actions-0.1.7}/tests/test_dispatch_actions.py +0 -0
- {ultralytics_actions-0.1.5 → ultralytics_actions-0.1.7}/tests/test_file_headers.py +0 -0
- {ultralytics_actions-0.1.5 → ultralytics_actions-0.1.7}/tests/test_first_interaction.py +0 -0
- {ultralytics_actions-0.1.5 → ultralytics_actions-0.1.7}/tests/test_init.py +0 -0
- {ultralytics_actions-0.1.5 → ultralytics_actions-0.1.7}/tests/test_summarize_pr.py +0 -0
- {ultralytics_actions-0.1.5 → ultralytics_actions-0.1.7}/tests/test_summarize_release.py +0 -0
- {ultralytics_actions-0.1.5 → ultralytics_actions-0.1.7}/tests/test_update_markdown_codeblocks.py +0 -0
- {ultralytics_actions-0.1.5 → ultralytics_actions-0.1.7}/tests/test_urls.py +0 -0
- {ultralytics_actions-0.1.5 → ultralytics_actions-0.1.7}/ultralytics_actions.egg-info/SOURCES.txt +0 -0
- {ultralytics_actions-0.1.5 → ultralytics_actions-0.1.7}/ultralytics_actions.egg-info/dependency_links.txt +0 -0
- {ultralytics_actions-0.1.5 → ultralytics_actions-0.1.7}/ultralytics_actions.egg-info/entry_points.txt +0 -0
- {ultralytics_actions-0.1.5 → ultralytics_actions-0.1.7}/ultralytics_actions.egg-info/requires.txt +0 -0
- {ultralytics_actions-0.1.5 → ultralytics_actions-0.1.7}/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.7
|
|
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>
|
|
@@ -8,6 +8,7 @@ import re
|
|
|
8
8
|
from .utils import GITHUB_API_URL, MAX_PROMPT_CHARS, Action, get_completion, remove_html_comments
|
|
9
9
|
|
|
10
10
|
REVIEW_MARKER = "🔍 PR Review"
|
|
11
|
+
ERROR_MARKER = "⚠️ Review generation encountered an error"
|
|
11
12
|
EMOJI_MAP = {"CRITICAL": "❗", "HIGH": "⚠️", "MEDIUM": "💡", "LOW": "📝", "SUGGESTION": "💭"}
|
|
12
13
|
SKIP_PATTERNS = [
|
|
13
14
|
r"\.lock$", # Lock files
|
|
@@ -30,25 +31,31 @@ SKIP_PATTERNS = [
|
|
|
30
31
|
|
|
31
32
|
|
|
32
33
|
def parse_diff_files(diff_text: str) -> dict:
|
|
33
|
-
"""Parse diff to extract file paths, valid line numbers, and line content for comments."""
|
|
34
|
-
files, current_file,
|
|
34
|
+
"""Parse diff to extract file paths, valid line numbers, and line content for comments (both sides)."""
|
|
35
|
+
files, current_file, new_line, old_line = {}, None, 0, 0
|
|
35
36
|
|
|
36
37
|
for line in diff_text.split("\n"):
|
|
37
38
|
if line.startswith("diff --git"):
|
|
38
39
|
match = re.search(r" b/(.+)$", line)
|
|
39
40
|
current_file = match.group(1) if match else None
|
|
40
|
-
|
|
41
|
+
new_line, old_line = 0, 0
|
|
41
42
|
if current_file:
|
|
42
|
-
files[current_file] = {}
|
|
43
|
+
files[current_file] = {"RIGHT": {}, "LEFT": {}}
|
|
43
44
|
elif line.startswith("@@") and current_file:
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
# Extract both old and new line numbers
|
|
46
|
+
match = re.search(r"@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)?", line)
|
|
47
|
+
if match:
|
|
48
|
+
old_line, new_line = int(match.group(1)), int(match.group(2))
|
|
49
|
+
elif current_file and (new_line > 0 or old_line > 0):
|
|
47
50
|
if line.startswith("+") and not line.startswith("+++"):
|
|
48
|
-
files[current_file][
|
|
49
|
-
|
|
50
|
-
elif not line.startswith("
|
|
51
|
-
|
|
51
|
+
files[current_file]["RIGHT"][new_line] = line[1:] # Added line (right/new side)
|
|
52
|
+
new_line += 1
|
|
53
|
+
elif line.startswith("-") and not line.startswith("---"):
|
|
54
|
+
files[current_file]["LEFT"][old_line] = line[1:] # Removed line (left/old side)
|
|
55
|
+
old_line += 1
|
|
56
|
+
elif not line.startswith("\\"): # Context line (ignore "No newline" markers)
|
|
57
|
+
new_line += 1
|
|
58
|
+
old_line += 1
|
|
52
59
|
|
|
53
60
|
return files
|
|
54
61
|
|
|
@@ -64,8 +71,8 @@ def generate_pr_review(repository: str, diff_text: str, pr_title: str, pr_descri
|
|
|
64
71
|
|
|
65
72
|
# Filter out generated/vendored files
|
|
66
73
|
filtered_files = {
|
|
67
|
-
path:
|
|
68
|
-
for path,
|
|
74
|
+
path: sides
|
|
75
|
+
for path, sides in diff_files.items()
|
|
69
76
|
if not any(re.search(pattern, path) for pattern in SKIP_PATTERNS)
|
|
70
77
|
}
|
|
71
78
|
skipped_count = len(diff_files) - len(filtered_files)
|
|
@@ -76,7 +83,7 @@ def generate_pr_review(repository: str, diff_text: str, pr_title: str, pr_descri
|
|
|
76
83
|
|
|
77
84
|
file_list = list(diff_files.keys())
|
|
78
85
|
diff_truncated = len(diff_text) > MAX_PROMPT_CHARS
|
|
79
|
-
lines_changed = sum(len(
|
|
86
|
+
lines_changed = sum(len(sides["RIGHT"]) + len(sides["LEFT"]) for sides in diff_files.values())
|
|
80
87
|
|
|
81
88
|
content = (
|
|
82
89
|
"You are an expert code reviewer for Ultralytics. Provide detailed inline comments on specific code changes.\n\n"
|
|
@@ -100,10 +107,18 @@ def generate_pr_review(repository: str, diff_text: str, pr_title: str, pr_descri
|
|
|
100
107
|
"- Suggestion content must match the exact indentation of the original line\n"
|
|
101
108
|
"- Avoid triple backticks (```) in suggestions as they break markdown formatting\n"
|
|
102
109
|
"- It's better to flag an issue without a suggestion than provide a wrong or uncertain fix\n\n"
|
|
110
|
+
"LINE NUMBERS:\n"
|
|
111
|
+
"- You MUST extract line numbers directly from the @@ hunk headers in the diff below\n"
|
|
112
|
+
"- RIGHT (added +): Find @@ lines, use numbers after +N (e.g., @@ -10,5 +20,7 @@ means RIGHT starts at line 20)\n"
|
|
113
|
+
"- LEFT (removed -): Find @@ lines, use numbers after -N (e.g., @@ -10,5 +20,7 @@ means LEFT starts at line 10)\n"
|
|
114
|
+
"- Count forward from hunk start: + lines increment RIGHT, - lines increment LEFT, context lines increment both\n"
|
|
115
|
+
"- CRITICAL: Using line numbers not in the diff will cause your comment to be rejected\n"
|
|
116
|
+
"- Suggestions only work on RIGHT (added) lines, never on LEFT (removed) lines\n\n"
|
|
103
117
|
"Return JSON: "
|
|
104
|
-
'{"comments": [{"file": "exact/path", "line": N, "
|
|
118
|
+
'{"comments": [{"file": "exact/path", "line": N, "side": "RIGHT", "severity": "HIGH", "message": "..."}], "summary": "..."}\n\n'
|
|
105
119
|
"Rules:\n"
|
|
106
|
-
"-
|
|
120
|
+
"- Verify line numbers from @@ hunks: +N for RIGHT (added), -N for LEFT (removed)\n"
|
|
121
|
+
"- Exact paths (no ./), 'side' field defaults to RIGHT if omitted\n"
|
|
107
122
|
"- Severity: CRITICAL, HIGH, MEDIUM, LOW, SUGGESTION\n"
|
|
108
123
|
f"- Files changed: {len(file_list)} ({', '.join(file_list[:10])}{'...' if len(file_list) > 10 else ''})\n"
|
|
109
124
|
f"- Lines changed: {lines_changed}\n"
|
|
@@ -125,11 +140,10 @@ def generate_pr_review(repository: str, diff_text: str, pr_title: str, pr_descri
|
|
|
125
140
|
|
|
126
141
|
try:
|
|
127
142
|
response = get_completion(messages, reasoning_effort="medium", model="gpt-5-codex")
|
|
128
|
-
print("\n" + "=" * 80 + f"\nFULL AI RESPONSE:\n{response}\n" + "=" * 80 + "\n")
|
|
129
143
|
|
|
130
144
|
json_str = re.search(r"```(?:json)?\s*(\{.*?\})\s*```", response, re.DOTALL)
|
|
131
145
|
review_data = json.loads(json_str.group(1) if json_str else response)
|
|
132
|
-
|
|
146
|
+
print(json.dumps(review_data, indent=2))
|
|
133
147
|
print(f"AI generated {len(review_data.get('comments', []))} comments")
|
|
134
148
|
|
|
135
149
|
# Validate, filter, and deduplicate comments
|
|
@@ -137,11 +151,27 @@ def generate_pr_review(repository: str, diff_text: str, pr_title: str, pr_descri
|
|
|
137
151
|
for c in review_data.get("comments", []):
|
|
138
152
|
file_path, line_num = c.get("file"), c.get("line", 0)
|
|
139
153
|
start_line = c.get("start_line")
|
|
154
|
+
side = (c.get("side") or "RIGHT").upper() # Default to RIGHT (added lines)
|
|
140
155
|
|
|
141
|
-
# Validate line numbers are in diff
|
|
142
|
-
if file_path not in diff_files
|
|
143
|
-
print(f"Filtered out {file_path}:{line_num} (
|
|
156
|
+
# Validate line numbers are in diff (check appropriate side)
|
|
157
|
+
if file_path not in diff_files:
|
|
158
|
+
print(f"Filtered out {file_path}:{line_num} (file not in diff)")
|
|
144
159
|
continue
|
|
160
|
+
if line_num not in diff_files[file_path].get(side, {}):
|
|
161
|
+
# Try other side if not found
|
|
162
|
+
other_side = "LEFT" if side == "RIGHT" else "RIGHT"
|
|
163
|
+
if line_num in diff_files[file_path].get(other_side, {}):
|
|
164
|
+
print(f"Switching {file_path}:{line_num} from {side} to {other_side}")
|
|
165
|
+
c["side"] = other_side
|
|
166
|
+
side = other_side
|
|
167
|
+
# GitHub rejects suggestions on removed lines
|
|
168
|
+
if side == "LEFT" and c.get("suggestion"):
|
|
169
|
+
print(f"Dropping suggestion for {file_path}:{line_num} - LEFT side doesn't support suggestions")
|
|
170
|
+
c.pop("suggestion", None)
|
|
171
|
+
else:
|
|
172
|
+
available = {s: list(diff_files[file_path][s].keys())[:10] for s in ["RIGHT", "LEFT"]}
|
|
173
|
+
print(f"Filtered out {file_path}:{line_num} (available: {available})")
|
|
174
|
+
continue
|
|
145
175
|
|
|
146
176
|
# Validate start_line if provided - drop start_line for suggestions (single-line only)
|
|
147
177
|
if start_line:
|
|
@@ -151,12 +181,12 @@ def generate_pr_review(repository: str, diff_text: str, pr_title: str, pr_descri
|
|
|
151
181
|
elif start_line >= line_num:
|
|
152
182
|
print(f"Invalid start_line {start_line} >= line {line_num} for {file_path}, dropping start_line")
|
|
153
183
|
c.pop("start_line", None)
|
|
154
|
-
elif start_line not in diff_files[file_path]:
|
|
184
|
+
elif start_line not in diff_files[file_path].get(side, {}):
|
|
155
185
|
print(f"start_line {start_line} not in diff for {file_path}, dropping start_line")
|
|
156
186
|
c.pop("start_line", None)
|
|
157
187
|
|
|
158
|
-
# Deduplicate by line number
|
|
159
|
-
key = f"{file_path}:{line_num}"
|
|
188
|
+
# Deduplicate by line number and side
|
|
189
|
+
key = f"{file_path}:{side}:{line_num}"
|
|
160
190
|
if key not in unique_comments:
|
|
161
191
|
unique_comments[key] = c
|
|
162
192
|
else:
|
|
@@ -179,7 +209,7 @@ def generate_pr_review(repository: str, diff_text: str, pr_title: str, pr_descri
|
|
|
179
209
|
error_details = traceback.format_exc()
|
|
180
210
|
print(f"Review generation failed: {e}\n{error_details}")
|
|
181
211
|
summary = (
|
|
182
|
-
f"
|
|
212
|
+
f"{ERROR_MARKER}: `{type(e).__name__}`\n\n"
|
|
183
213
|
f"<details><summary>Debug Info</summary>\n\n```\n{error_details}\n```\n</details>"
|
|
184
214
|
)
|
|
185
215
|
return {"comments": [], "summary": summary}
|
|
@@ -219,7 +249,29 @@ def post_review_summary(event: Action, review_data: dict, review_number: int) ->
|
|
|
219
249
|
|
|
220
250
|
review_title = f"{REVIEW_MARKER} {review_number}" if review_number > 1 else REVIEW_MARKER
|
|
221
251
|
comments = review_data.get("comments", [])
|
|
222
|
-
|
|
252
|
+
summary = review_data.get("summary") or ""
|
|
253
|
+
|
|
254
|
+
# Don't approve if error occurred or if there are critical/high severity issues
|
|
255
|
+
has_error = not summary or ERROR_MARKER in summary
|
|
256
|
+
has_issues = any(c.get("severity") not in ["LOW", "SUGGESTION", None] for c in comments)
|
|
257
|
+
requests_changes = any(
|
|
258
|
+
phrase in summary.lower()
|
|
259
|
+
for phrase in [
|
|
260
|
+
"please",
|
|
261
|
+
"should",
|
|
262
|
+
"must",
|
|
263
|
+
"raise",
|
|
264
|
+
"needs",
|
|
265
|
+
"before merging",
|
|
266
|
+
"fix",
|
|
267
|
+
"error",
|
|
268
|
+
"issue",
|
|
269
|
+
"problem",
|
|
270
|
+
"warning",
|
|
271
|
+
"concern",
|
|
272
|
+
]
|
|
273
|
+
)
|
|
274
|
+
event_type = "COMMENT" if (has_error or has_issues or requests_changes) else "APPROVE"
|
|
223
275
|
|
|
224
276
|
body = (
|
|
225
277
|
f"## {review_title}\n\n"
|
|
@@ -246,22 +298,25 @@ def post_review_summary(event: Action, review_data: dict, review_number: int) ->
|
|
|
246
298
|
severity = comment.get("severity") or "SUGGESTION"
|
|
247
299
|
comment_body = f"{EMOJI_MAP.get(severity, '💭')} **{severity}**: {(comment.get('message') or '')[:1000]}"
|
|
248
300
|
|
|
301
|
+
# Get side (LEFT for removed lines, RIGHT for added lines)
|
|
302
|
+
side = comment.get("side", "RIGHT")
|
|
303
|
+
|
|
249
304
|
if suggestion := comment.get("suggestion"):
|
|
250
305
|
suggestion = suggestion[:1000] # Clip suggestion length
|
|
251
306
|
if "```" not in suggestion:
|
|
252
307
|
# Extract original line indentation and apply to suggestion
|
|
253
|
-
if original_line := review_data.get("diff_files", {}).get(file_path, {}).get(line):
|
|
308
|
+
if original_line := review_data.get("diff_files", {}).get(file_path, {}).get(side, {}).get(line):
|
|
254
309
|
indent = len(original_line) - len(original_line.lstrip())
|
|
255
310
|
suggestion = " " * indent + suggestion.strip()
|
|
256
311
|
comment_body += f"\n\n**Suggested change:**\n```suggestion\n{suggestion}\n```"
|
|
257
312
|
|
|
258
313
|
# Build comment with optional start_line for multi-line context
|
|
259
|
-
review_comment = {"path": file_path, "line": line, "body": comment_body, "side":
|
|
314
|
+
review_comment = {"path": file_path, "line": line, "body": comment_body, "side": side}
|
|
260
315
|
if start_line := comment.get("start_line"):
|
|
261
316
|
if start_line < line:
|
|
262
317
|
review_comment["start_line"] = start_line
|
|
263
|
-
review_comment["start_side"] =
|
|
264
|
-
print(f"Multi-line comment: {file_path}:{start_line}-{line}")
|
|
318
|
+
review_comment["start_side"] = side
|
|
319
|
+
print(f"Multi-line comment: {file_path}:{start_line}-{line} ({side})")
|
|
265
320
|
|
|
266
321
|
review_comments.append(review_comment)
|
|
267
322
|
|
|
@@ -125,21 +125,22 @@ class Action:
|
|
|
125
125
|
|
|
126
126
|
def _request(self, method: str, url: str, headers=None, expected_status=None, hard=False, **kwargs):
|
|
127
127
|
"""Unified request handler with error checking."""
|
|
128
|
-
|
|
128
|
+
r = getattr(requests, method)(url, headers=headers or self.headers, **kwargs)
|
|
129
129
|
expected = expected_status or self._default_status[method]
|
|
130
|
-
success =
|
|
130
|
+
success = r.status_code in expected
|
|
131
131
|
|
|
132
132
|
if self.verbose:
|
|
133
|
-
|
|
133
|
+
elapsed = r.elapsed.total_seconds()
|
|
134
|
+
print(f"{'✓' if success else '✗'} {method.upper()} {url} → {r.status_code} ({elapsed:.1f}s)")
|
|
134
135
|
if not success:
|
|
135
136
|
try:
|
|
136
|
-
print(f" ❌ Error: {
|
|
137
|
+
print(f" ❌ Error: {r.json().get('message', 'Unknown error')}")
|
|
137
138
|
except Exception:
|
|
138
|
-
print(f" ❌ Error: {
|
|
139
|
+
print(f" ❌ Error: {r.text[:200]}")
|
|
139
140
|
|
|
140
141
|
if not success and hard:
|
|
141
|
-
|
|
142
|
-
return
|
|
142
|
+
r.raise_for_status()
|
|
143
|
+
return r
|
|
143
144
|
|
|
144
145
|
def get(self, url, **kwargs):
|
|
145
146
|
"""Performs GET request with error handling."""
|
|
@@ -125,6 +125,8 @@ def get_completion(
|
|
|
125
125
|
|
|
126
126
|
try:
|
|
127
127
|
r = requests.post(url, json=data, headers=headers, timeout=600)
|
|
128
|
+
success = r.status_code == 200
|
|
129
|
+
print(f"{'✓' if success else '✗'} POST {url} → {r.status_code} ({r.elapsed.total_seconds():.1f}s)")
|
|
128
130
|
r.raise_for_status()
|
|
129
131
|
|
|
130
132
|
# Parse response
|
|
@@ -15,6 +15,7 @@ def test_check_pypi_version():
|
|
|
15
15
|
with patch("requests.get") as mock_get:
|
|
16
16
|
mock_response = MagicMock()
|
|
17
17
|
mock_response.status_code = 200
|
|
18
|
+
mock_response.elapsed.total_seconds.return_value = 0.5
|
|
18
19
|
mock_response.json.return_value = {"info": {"version": "0.9.0"}}
|
|
19
20
|
mock_get.return_value = mock_response
|
|
20
21
|
|
|
@@ -43,6 +44,7 @@ def test_action_request_methods():
|
|
|
43
44
|
with patch("requests.get") as mock_get:
|
|
44
45
|
mock_response = MagicMock()
|
|
45
46
|
mock_response.status_code = 200
|
|
47
|
+
mock_response.elapsed.total_seconds.return_value = 0.3
|
|
46
48
|
mock_get.return_value = mock_response
|
|
47
49
|
|
|
48
50
|
action = Action(token="test-token")
|
|
@@ -28,6 +28,7 @@ def test_get_completion(mock_post):
|
|
|
28
28
|
# Setup mock response with Responses API structure
|
|
29
29
|
mock_response = MagicMock()
|
|
30
30
|
mock_response.status_code = 200
|
|
31
|
+
mock_response.elapsed.total_seconds.return_value = 1.5
|
|
31
32
|
mock_response.json.return_value = {
|
|
32
33
|
"output": [
|
|
33
34
|
{
|
|
@@ -57,6 +58,7 @@ def test_get_completion_with_link_check(mock_check_links, mock_post):
|
|
|
57
58
|
# Setup mocks with Responses API structure
|
|
58
59
|
mock_response = MagicMock()
|
|
59
60
|
mock_response.status_code = 200
|
|
61
|
+
mock_response.elapsed.total_seconds.return_value = 2.0
|
|
60
62
|
mock_response.json.return_value = {
|
|
61
63
|
"output": [
|
|
62
64
|
{
|
{ultralytics_actions-0.1.5 → ultralytics_actions-0.1.7}/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.7
|
|
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>
|
|
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.5 → ultralytics_actions-0.1.7}/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
|
{ultralytics_actions-0.1.5 → ultralytics_actions-0.1.7}/tests/test_update_markdown_codeblocks.py
RENAMED
|
File without changes
|
|
File without changes
|
{ultralytics_actions-0.1.5 → ultralytics_actions-0.1.7}/ultralytics_actions.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ultralytics_actions-0.1.5 → ultralytics_actions-0.1.7}/ultralytics_actions.egg-info/requires.txt
RENAMED
|
File without changes
|
{ultralytics_actions-0.1.5 → ultralytics_actions-0.1.7}/ultralytics_actions.egg-info/top_level.txt
RENAMED
|
File without changes
|