ultralytics-actions 0.0.55__py3-none-any.whl → 0.0.57__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.
actions/__init__.py CHANGED
@@ -22,4 +22,4 @@
22
22
  # ├── test_summarize_pr.py
23
23
  # └── ...
24
24
 
25
- __version__ = "0.0.55"
25
+ __version__ = "0.0.57"
actions/summarize_pr.py CHANGED
@@ -44,8 +44,13 @@ def post_merge_message(pr_number, pr_url, repository, summary, pr_credit, header
44
44
  return response.status_code == 201
45
45
 
46
46
 
47
- def generate_issue_comment(pr_url, pr_summary, pr_credit):
48
- """Generates a personalized issue comment using based on the PR context."""
47
+ def generate_issue_comment(pr_url, pr_summary, pr_credit, pr_title=""):
48
+ """Generates personalized issue comment based on PR context."""
49
+ # Extract repo info from PR URL (format: api.github.com/repos/owner/repo/pulls/number)
50
+ repo_parts = pr_url.split("/repos/")[1].split("/pulls/")[0] if "/repos/" in pr_url else ""
51
+ owner_repo = repo_parts.split("/")
52
+ repo_name = owner_repo[-1] if len(owner_repo) > 1 else "package"
53
+
49
54
  messages = [
50
55
  {
51
56
  "role": "system",
@@ -54,13 +59,15 @@ def generate_issue_comment(pr_url, pr_summary, pr_credit):
54
59
  {
55
60
  "role": "user",
56
61
  "content": f"Write a GitHub issue comment announcing a potential fix for this issue is now merged in linked PR {pr_url} by {pr_credit}\n\n"
62
+ f"PR Title: {pr_title}\n\n"
57
63
  f"Context from PR:\n{pr_summary}\n\n"
58
64
  f"Include:\n"
59
65
  f"1. An explanation of key changes from the PR that may resolve this issue\n"
60
66
  f"2. Credit to the PR author and contributors\n"
61
67
  f"3. Options for testing if PR changes have resolved this issue:\n"
62
- f" - pip install git+https://github.com/ultralytics/ultralytics.git@main # test latest changes\n"
63
- f" - or await next official PyPI release\n"
68
+ f" - If the PR mentions a specific version number (like v8.0.0 or 3.1.0), include: pip install -U {repo_name}>=VERSION\n"
69
+ f" - Also suggest: pip install git+https://github.com/{repo_parts}.git@main\n"
70
+ f" - If appropriate, mention they can also wait for the next official PyPI release\n"
64
71
  f"4. Request feedback on whether the PR changes resolve the issue\n"
65
72
  f"5. Thank 🙏 for reporting the issue and welcome any further feedback if the issue persists\n\n",
66
73
  },
@@ -127,6 +134,7 @@ query($owner: String!, $repo: String!, $pr_number: Int!) {
127
134
  pullRequest(number: $pr_number) {
128
135
  closingIssuesReferences(first: 50) { nodes { number } }
129
136
  url
137
+ title
130
138
  body
131
139
  author { login, __typename }
132
140
  reviews(first: 50) { nodes { author { login, __typename } } }
@@ -150,6 +158,7 @@ query($owner: String!, $repo: String!, $pr_number: Int!) {
150
158
  comments = data["reviews"]["nodes"] + data["comments"]["nodes"]
151
159
  token_username = action.get_username() # get GITHUB_TOKEN username
152
160
  author = data["author"]["login"] if data["author"]["__typename"] != "Bot" else None
161
+ pr_title = data.get("title", "")
153
162
 
154
163
  # Get unique contributors from reviews and comments
155
164
  contributors = {x["author"]["login"] for x in comments if x["author"]["__typename"] != "Bot"}
@@ -173,7 +182,9 @@ query($owner: String!, $repo: String!, $pr_number: Int!) {
173
182
  pr_credit += (" with contributions from " if pr_credit else "") + ", ".join(f"@{c}" for c in contributors)
174
183
 
175
184
  # Generate personalized comment
176
- comment = generate_issue_comment(pr_url=data["url"], pr_summary=pr_summary, pr_credit=pr_credit)
185
+ comment = generate_issue_comment(
186
+ pr_url=data["url"], pr_summary=pr_summary, pr_credit=pr_credit, pr_title=pr_title
187
+ )
177
188
 
178
189
  # Update linked issues
179
190
  for issue in data["closingIssuesReferences"]["nodes"]:
@@ -8,10 +8,16 @@ from pathlib import Path
8
8
 
9
9
 
10
10
  def extract_code_blocks(markdown_content):
11
- """Extracts Python code blocks from markdown content using regex pattern matching."""
12
- pattern = r"^( *)```(?:python|py|\{[ ]*\.py[ ]*\.annotate[ ]*\})\n(.*?)\n\1```"
13
- code_block_pattern = re.compile(pattern, re.DOTALL | re.MULTILINE)
14
- return code_block_pattern.findall(markdown_content)
11
+ """Extracts Python and Bash code blocks from markdown content using regex pattern matching."""
12
+ # Python code blocks
13
+ py_pattern = r"^( *)```(?:python|py|\{[ ]*\.py[ ]*\.annotate[ ]*\})\n(.*?)\n\1```"
14
+ py_code_blocks = re.compile(py_pattern, re.DOTALL | re.MULTILINE).findall(markdown_content)
15
+
16
+ # Bash code blocks
17
+ bash_pattern = r"^( *)```(?:bash|sh|shell)\n(.*?)\n\1```"
18
+ bash_code_blocks = re.compile(bash_pattern, re.DOTALL | re.MULTILINE).findall(markdown_content)
19
+
20
+ return {"python": py_code_blocks, "bash": bash_code_blocks}
15
21
 
16
22
 
17
23
  def remove_indentation(code_block, num_spaces):
@@ -89,31 +95,62 @@ def format_code_with_ruff(temp_dir):
89
95
  print(f"ERROR running docformatter ❌ {e}")
90
96
 
91
97
 
92
- def generate_temp_filename(file_path, index):
93
- """Generates a unique temporary filename using a hash of the file path and index."""
94
- unique_string = f"{file_path.parent}_{file_path.stem}_{index}"
95
- unique_hash = hashlib.md5(unique_string.encode()).hexdigest()
96
- return f"temp_{unique_hash}.py"
98
+ def format_bash_with_prettier(temp_dir):
99
+ """Formats bash script files in the specified directory using prettier."""
100
+ try:
101
+ # Run prettier with explicit config path
102
+ result = subprocess.run(
103
+ "npx prettier --write --plugin=$(npm root -g)/prettier-plugin-sh/lib/index.cjs ./**/*.sh",
104
+ shell=True, # must use shell=True to expand internal $(cmd)
105
+ capture_output=True,
106
+ text=True,
107
+ )
108
+ if result.returncode != 0:
109
+ print(f"ERROR running prettier-plugin-sh ❌ {result.stderr}")
110
+ else:
111
+ print("Completed bash formatting ✅")
112
+ except Exception as e:
113
+ print(f"ERROR running prettier-plugin-sh ❌ {e}")
114
+
115
+
116
+ def generate_temp_filename(file_path, index, code_type):
117
+ """Creates unique temp filename with full path info for debugging."""
118
+ stem = file_path.stem
119
+ code_letter = code_type[0] # 'p' for python, 'b' for bash
120
+ path_part = str(file_path.parent).replace("/", "_").replace("\\", "_").replace(" ", "-")
121
+ hash_val = hashlib.md5(f"{file_path}_{index}".encode()).hexdigest()[:6]
122
+ ext = ".py" if code_type == "python" else ".sh"
123
+ filename = f"{stem}_{path_part}_{code_letter}{index}_{hash_val}{ext}"
124
+ return re.sub(r"[^\w\-.]", "_", filename)
97
125
 
98
126
 
99
- def process_markdown_file(file_path, temp_dir, verbose=False):
100
- """Processes a markdown file, extracting Python code blocks for formatting and updating the original file."""
127
+ def process_markdown_file(file_path, temp_dir, process_python=True, process_bash=True, verbose=False):
128
+ """Processes a markdown file, extracting code blocks for formatting and updating the original file."""
101
129
  try:
102
130
  markdown_content = Path(file_path).read_text()
103
- code_blocks = extract_code_blocks(markdown_content)
131
+ code_blocks_by_type = extract_code_blocks(markdown_content)
104
132
  temp_files = []
105
133
 
106
- for i, (num_spaces, code_block) in enumerate(code_blocks):
107
- if verbose:
108
- print(f"Extracting code block {i} from {file_path}")
109
- num_spaces = len(num_spaces)
110
- code_without_indentation = remove_indentation(code_block, num_spaces)
134
+ # Process all code block types based on flags
135
+ code_types = []
136
+ if process_python:
137
+ code_types.append(("python", 0))
138
+ if process_bash:
139
+ code_types.append(("bash", 1000))
140
+
141
+ for code_type, offset in code_types:
142
+ for i, (num_spaces, code_block) in enumerate(code_blocks_by_type[code_type]):
143
+ if verbose:
144
+ print(f"Extracting {code_type} code block {i} from {file_path}")
145
+
146
+ num_spaces = len(num_spaces)
147
+ code_without_indentation = remove_indentation(code_block, num_spaces)
148
+ temp_file_path = temp_dir / generate_temp_filename(file_path, i + offset, code_type)
111
149
 
112
- # Generate a unique temp file path
113
- temp_file_path = temp_dir / generate_temp_filename(file_path, i)
114
- with open(temp_file_path, "w") as temp_file:
115
- temp_file.write(code_without_indentation)
116
- temp_files.append((num_spaces, code_block, temp_file_path))
150
+ with open(temp_file_path, "w") as temp_file:
151
+ temp_file.write(code_without_indentation)
152
+
153
+ temp_files.append((num_spaces, code_block, temp_file_path, code_type))
117
154
 
118
155
  return markdown_content, temp_files
119
156
 
@@ -123,15 +160,18 @@ def process_markdown_file(file_path, temp_dir, verbose=False):
123
160
 
124
161
 
125
162
  def update_markdown_file(file_path, markdown_content, temp_files):
126
- """Updates a markdown file with formatted Python code blocks extracted and processed externally."""
127
- for num_spaces, original_code_block, temp_file_path in temp_files:
163
+ """Updates a markdown file with formatted code blocks."""
164
+ for num_spaces, original_code_block, temp_file_path, code_type in temp_files:
128
165
  try:
129
166
  with open(temp_file_path) as temp_file:
130
167
  formatted_code = temp_file.read().rstrip("\n") # Strip trailing newlines
131
168
  formatted_code_with_indentation = add_indentation(formatted_code, num_spaces)
132
169
 
133
- # Replace both `python` and `py` code blocks
134
- for lang in ["python", "py", "{ .py .annotate }"]:
170
+ # Define the language tags for each code type
171
+ lang_tags = {"python": ["python", "py", "{ .py .annotate }"], "bash": ["bash", "sh", "shell"]}
172
+
173
+ # Replace the code blocks with the formatted version
174
+ for lang in lang_tags[code_type]:
135
175
  markdown_content = markdown_content.replace(
136
176
  f"{' ' * num_spaces}```{lang}\n{original_code_block}\n{' ' * num_spaces}```",
137
177
  f"{' ' * num_spaces}```{lang}\n{formatted_code_with_indentation}\n{' ' * num_spaces}```",
@@ -146,8 +186,8 @@ def update_markdown_file(file_path, markdown_content, temp_files):
146
186
  print(f"Error writing file {file_path}: {e}")
147
187
 
148
188
 
149
- def main(root_dir=Path.cwd(), verbose=False):
150
- """Processes markdown files, extracts and formats Python code blocks, and updates the original files."""
189
+ def main(root_dir=Path.cwd(), process_python=True, process_bash=True, verbose=False):
190
+ """Processes markdown files, extracts and formats code blocks, and updates the original files."""
151
191
  root_path = Path(root_dir)
152
192
  markdown_files = list(root_path.rglob("*.md"))
153
193
  temp_dir = Path("temp_code_blocks")
@@ -158,12 +198,17 @@ def main(root_dir=Path.cwd(), verbose=False):
158
198
  for markdown_file in markdown_files:
159
199
  if verbose:
160
200
  print(f"Processing {markdown_file}")
161
- markdown_content, temp_files = process_markdown_file(markdown_file, temp_dir, verbose)
201
+ markdown_content, temp_files = process_markdown_file(
202
+ markdown_file, temp_dir, process_python, process_bash, verbose
203
+ )
162
204
  if markdown_content and temp_files:
163
205
  all_temp_files.append((markdown_file, markdown_content, temp_files))
164
206
 
165
- # Format all code blocks with ruff
166
- format_code_with_ruff(temp_dir)
207
+ # Format code blocks based on flags
208
+ if process_python:
209
+ format_code_with_ruff(temp_dir) # Format Python files
210
+ if process_bash:
211
+ format_bash_with_prettier(temp_dir) # Format Bash files
167
212
 
168
213
  # Update markdown files with formatted code blocks
169
214
  for markdown_file, markdown_content, temp_files in all_temp_files:
@@ -174,4 +219,4 @@ def main(root_dir=Path.cwd(), verbose=False):
174
219
 
175
220
 
176
221
  if __name__ == "__main__":
177
- main()
222
+ main(process_python=True, process_bash=False)
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: ultralytics-actions
3
- Version: 0.0.55
3
+ Version: 0.0.57
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>
@@ -33,6 +33,7 @@ Requires-Dist: ruff>=0.9.1
33
33
  Requires-Dist: docformatter>=1.7.5
34
34
  Provides-Extra: dev
35
35
  Requires-Dist: pytest; extra == "dev"
36
+ Dynamic: license-file
36
37
 
37
38
  <a href="https://www.ultralytics.com/" target="_blank"><img src="https://raw.githubusercontent.com/ultralytics/assets/main/logo/Ultralytics_Logotype_Original.svg" width="320" alt="Ultralytics logo"></a>
38
39
 
@@ -0,0 +1,15 @@
1
+ actions/__init__.py,sha256=Ahj81FIHSd_RoAqBPeasm8WDsgbMFESfsHki6Qr_IGs,742
2
+ actions/first_interaction.py,sha256=1_WvQHCi5RWaSfyi49ClF2Zk_3CKGjFnZqz6FlxPRAc,17868
3
+ actions/summarize_pr.py,sha256=BKttOq-MGaanVaChLU5B1ewKUA8K6S05Cy3FQtyRmxU,11681
4
+ actions/summarize_release.py,sha256=tov6qsYGC68lfobvkwVyoWZBGtJ598G0m097n4Ydzvo,8472
5
+ actions/update_markdown_code_blocks.py,sha256=YCNJQO48Off5NQwIzdpE9_BLafEDv3-rkEtkREhEItU,8588
6
+ actions/utils/__init__.py,sha256=WStdEAYROVnF0nubEOmrFLrejkRiMXIefA5O1ckfcFs,476
7
+ actions/utils/common_utils.py,sha256=PZkK9Wc3od34J9VSw4ICWHhQQC033o3DCrCy0VIyZE4,6024
8
+ actions/utils/github_utils.py,sha256=-F--JgxtXE0fSPMFEzakz7iZilp-vonzLiyXfg0b17Y,7117
9
+ actions/utils/openai_utils.py,sha256=qQbmrJpOUANxSMf7inDSgPIwgf0JHD1fWZuab-y2W6g,2942
10
+ ultralytics_actions-0.0.57.dist-info/licenses/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
11
+ ultralytics_actions-0.0.57.dist-info/METADATA,sha256=g6TwX1wlWsyosq1JztCpqp_GGZmGzR9L6G5HQTn5fEA,10583
12
+ ultralytics_actions-0.0.57.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
13
+ ultralytics_actions-0.0.57.dist-info/entry_points.txt,sha256=GowvOFplj0C7JmsjbKcbpgLpdf2r921pcaOQkAHWZRA,378
14
+ ultralytics_actions-0.0.57.dist-info/top_level.txt,sha256=5apM5x80QlJcGbACn1v3fkmIuL1-XQCKcItJre7w7Tw,8
15
+ ultralytics_actions-0.0.57.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (76.0.0)
2
+ Generator: setuptools (77.0.3)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,15 +0,0 @@
1
- actions/__init__.py,sha256=DJB5iF9yBtEKiORNXrvFFuRZKrAKH68c_98Wez8VoHs,742
2
- actions/first_interaction.py,sha256=1_WvQHCi5RWaSfyi49ClF2Zk_3CKGjFnZqz6FlxPRAc,17868
3
- actions/summarize_pr.py,sha256=sPKl6gN7HeGb9o9-QxVTnK2WZJW4iUytK6MApthn6HQ,11086
4
- actions/summarize_release.py,sha256=tov6qsYGC68lfobvkwVyoWZBGtJ598G0m097n4Ydzvo,8472
5
- actions/update_markdown_code_blocks.py,sha256=tUChNBIZN-B_unGMG9yQk-dohi7bit02Yl3xc4UtycQ,6610
6
- actions/utils/__init__.py,sha256=WStdEAYROVnF0nubEOmrFLrejkRiMXIefA5O1ckfcFs,476
7
- actions/utils/common_utils.py,sha256=PZkK9Wc3od34J9VSw4ICWHhQQC033o3DCrCy0VIyZE4,6024
8
- actions/utils/github_utils.py,sha256=-F--JgxtXE0fSPMFEzakz7iZilp-vonzLiyXfg0b17Y,7117
9
- actions/utils/openai_utils.py,sha256=qQbmrJpOUANxSMf7inDSgPIwgf0JHD1fWZuab-y2W6g,2942
10
- ultralytics_actions-0.0.55.dist-info/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
11
- ultralytics_actions-0.0.55.dist-info/METADATA,sha256=9NPBdeMdAU7SaSY9VfYQY8KWIDI-6A0RS9vUL8rh82I,10561
12
- ultralytics_actions-0.0.55.dist-info/WHEEL,sha256=52BFRY2Up02UkjOa29eZOS2VxUrpPORXg1pkohGGUS8,91
13
- ultralytics_actions-0.0.55.dist-info/entry_points.txt,sha256=GowvOFplj0C7JmsjbKcbpgLpdf2r921pcaOQkAHWZRA,378
14
- ultralytics_actions-0.0.55.dist-info/top_level.txt,sha256=5apM5x80QlJcGbACn1v3fkmIuL1-XQCKcItJre7w7Tw,8
15
- ultralytics_actions-0.0.55.dist-info/RECORD,,