ultralytics-actions 0.0.27__tar.gz → 0.0.30__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.
Files changed (20) hide show
  1. {ultralytics_actions-0.0.27 → ultralytics_actions-0.0.30}/PKG-INFO +1 -1
  2. {ultralytics_actions-0.0.27 → ultralytics_actions-0.0.30}/actions/__init__.py +1 -1
  3. {ultralytics_actions-0.0.27 → ultralytics_actions-0.0.30}/actions/summarize_pr.py +76 -21
  4. {ultralytics_actions-0.0.27 → ultralytics_actions-0.0.30}/actions/utils/__init__.py +2 -0
  5. {ultralytics_actions-0.0.27 → ultralytics_actions-0.0.30}/actions/utils/github_utils.py +21 -0
  6. {ultralytics_actions-0.0.27 → ultralytics_actions-0.0.30}/ultralytics_actions.egg-info/PKG-INFO +1 -1
  7. {ultralytics_actions-0.0.27 → ultralytics_actions-0.0.30}/LICENSE +0 -0
  8. {ultralytics_actions-0.0.27 → ultralytics_actions-0.0.30}/README.md +0 -0
  9. {ultralytics_actions-0.0.27 → ultralytics_actions-0.0.30}/actions/first_interaction.py +0 -0
  10. {ultralytics_actions-0.0.27 → ultralytics_actions-0.0.30}/actions/summarize_release.py +0 -0
  11. {ultralytics_actions-0.0.27 → ultralytics_actions-0.0.30}/actions/update_markdown_code_blocks.py +0 -0
  12. {ultralytics_actions-0.0.27 → ultralytics_actions-0.0.30}/actions/utils/common_utils.py +0 -0
  13. {ultralytics_actions-0.0.27 → ultralytics_actions-0.0.30}/actions/utils/openai_utils.py +0 -0
  14. {ultralytics_actions-0.0.27 → ultralytics_actions-0.0.30}/pyproject.toml +0 -0
  15. {ultralytics_actions-0.0.27 → ultralytics_actions-0.0.30}/setup.cfg +0 -0
  16. {ultralytics_actions-0.0.27 → ultralytics_actions-0.0.30}/ultralytics_actions.egg-info/SOURCES.txt +0 -0
  17. {ultralytics_actions-0.0.27 → ultralytics_actions-0.0.30}/ultralytics_actions.egg-info/dependency_links.txt +0 -0
  18. {ultralytics_actions-0.0.27 → ultralytics_actions-0.0.30}/ultralytics_actions.egg-info/entry_points.txt +0 -0
  19. {ultralytics_actions-0.0.27 → ultralytics_actions-0.0.30}/ultralytics_actions.egg-info/requires.txt +0 -0
  20. {ultralytics_actions-0.0.27 → ultralytics_actions-0.0.30}/ultralytics_actions.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ultralytics-actions
3
- Version: 0.0.27
3
+ Version: 0.0.30
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>
@@ -22,4 +22,4 @@
22
22
  # ├── test_summarize_pr.py
23
23
  # └── ...
24
24
 
25
- __version__ = "0.0.27"
25
+ __version__ = "0.0.30"
@@ -10,6 +10,7 @@ from .utils import (
10
10
  GITHUB_REPOSITORY,
11
11
  PR,
12
12
  get_completion,
13
+ get_github_username,
13
14
  get_pr_diff,
14
15
  )
15
16
 
@@ -19,23 +20,57 @@ SUMMARY_START = (
19
20
  )
20
21
 
21
22
 
22
- def generate_issue_comment(pr_url, pr_body):
23
- """Generates a personalized issue comment using AI based on the PR context."""
23
+ def generate_merge_message(pr_author, contributors, pr_summary=None):
24
+ """Generates a thank-you message for merged PR contributors."""
25
+ contributors_str = ", ".join(f"@{c}" for c in contributors if c != pr_author)
26
+ mention_str = f"@{pr_author}"
27
+ if contributors_str:
28
+ mention_str += f" and {contributors_str}"
29
+
30
+ messages = [
31
+ {
32
+ "role": "system",
33
+ "content": "You are an Ultralytics AI assistant. Generate meaningful, inspiring messages to GitHub users.",
34
+ },
35
+ {
36
+ "role": "user",
37
+ "content": f"Write a friendly thank you for a merged PR by these GitHub contributors: {mention_str}. "
38
+ f"Context from PR:\n{pr_summary}\n\n"
39
+ f"Start with the exciting message that this PR is now merged, and weave in an inspiring quote "
40
+ f"from a famous figure in science, philosophy or stoicism. "
41
+ f"Keep the message concise yet relevant to the specific contributions in this PR. "
42
+ f"We want the contributors to feel their effort is appreciated and will make a difference in the world.",
43
+ },
44
+ ]
45
+ return get_completion(messages)
46
+
47
+
48
+ def post_merge_message(pr_number, pr_author, contributors, summary):
49
+ """Posts thank you message on PR after merge."""
50
+ message = generate_merge_message(pr_author, contributors, summary)
51
+ comment_url = f"{GITHUB_API_URL}/repos/{GITHUB_REPOSITORY}/issues/{pr_number}/comments"
52
+ response = requests.post(comment_url, json={"body": message}, headers=GITHUB_HEADERS)
53
+ return response.status_code == 201
54
+
55
+
56
+ def generate_issue_comment(pr_url, pr_summary):
57
+ """Generates a personalized issue comment using based on the PR context."""
24
58
  messages = [
25
59
  {
26
60
  "role": "system",
27
- "content": "You are the Ultralytics AI assistant. Generate friendly GitHub issue comments. No @ mentions or direct addressing.",
61
+ "content": "You are an Ultralytics AI assistant. Generate friendly GitHub issue comments. No @ mentions or direct addressing.",
28
62
  },
29
63
  {
30
64
  "role": "user",
31
- "content": f"Write a comment for a fixed GitHub issue using this merged PR context:\n\n{pr_body}\n\n"
65
+ "content": f"Write a GitHub issue comment announcing a potential fix has been merged in linked PR {pr_url}\n\n"
66
+ f"Context from PR:\n{pr_summary}\n\n"
32
67
  f"Include:\n"
33
- f"1. Reference to fix PR: {pr_url}\n"
34
- f"2. Key changes in the PR and instructions to test the fix with:\n"
35
- f" - pip install git+https://github.com/ultralytics/ultralytics.git@main # immediate testing\n"
36
- f" - or await next release\n"
37
- f"3. Request verification that PR fix works\n"
38
- f"4. Thank 🙏 for reporting the issue and encourage reporting any new issues in the future\n\n",
68
+ f"1. An explanation of key changes from the PR that may resolve this issue\n"
69
+ f"2. Options for testing if PR changes have resolved this issue:\n"
70
+ f" - pip install git+https://github.com/ultralytics/ultralytics.git@main # test latest changes\n"
71
+ f" - or await next official PyPI release\n"
72
+ f"3. Request feedback on whether the PR changes resolve the issue\n"
73
+ f"4. Thank 🙏 for reporting the issue and welcome any further feedback if the issue persists\n\n",
39
74
  },
40
75
  ]
41
76
  return get_completion(messages)
@@ -93,8 +128,8 @@ def update_pr_description(repo_name, pr_number, new_summary, max_retries=2):
93
128
  return update_response.status_code
94
129
 
95
130
 
96
- def label_fixed_issues(pr_number):
97
- """Labels issues closed by this PR when merged and notifies users about the fix with AI-generated comments."""
131
+ def label_fixed_issues(pr_number, pr_summary):
132
+ """Labels issues closed by this PR when merged, notifies users, and returns PR contributors."""
98
133
  query = """
99
134
  query($owner: String!, $repo: String!, $pr_number: Int!) {
100
135
  repository(owner: $owner, name: $repo) {
@@ -106,6 +141,13 @@ query($owner: String!, $repo: String!, $pr_number: Int!) {
106
141
  }
107
142
  url
108
143
  body
144
+ author { login, __typename }
145
+ reviews(first: 50) {
146
+ nodes { author { login, __typename } }
147
+ }
148
+ comments(first: 50) {
149
+ nodes { author { login, __typename } }
150
+ }
109
151
  }
110
152
  }
111
153
  }
@@ -117,22 +159,28 @@ query($owner: String!, $repo: String!, $pr_number: Int!) {
117
159
  response = requests.post(graphql_url, json={"query": query, "variables": variables}, headers=GITHUB_HEADERS)
118
160
  if response.status_code != 200:
119
161
  print(f"Failed to fetch linked issues. Status code: {response.status_code}")
120
- return
162
+ return [], None
121
163
 
122
164
  try:
123
165
  data = response.json()["data"]["repository"]["pullRequest"]
124
- issues = data["closingIssuesReferences"]["nodes"]
166
+ comments = data["reviews"]["nodes"] + data["comments"]["nodes"] # merge lists
167
+ author = data["author"]["login"]
168
+
169
+ # Get unique contributors from reviews and comments
170
+ contributors = {x["author"]["login"] for x in comments if x["author"]["__typename"] != "Bot"}
171
+ contributors.discard(author) # Remove author from contributors list
125
172
 
126
173
  # Generate personalized comment
127
- comment = generate_issue_comment(pr_url=data["url"], pr_body=data["body"])
174
+ comment = generate_issue_comment(pr_url=data["url"], pr_summary=pr_summary)
128
175
 
129
- for issue in issues:
176
+ # Update linked issues
177
+ for issue in data["closingIssuesReferences"]["nodes"]:
130
178
  issue_number = issue["number"]
131
179
  # Add fixed label
132
180
  label_url = f"{GITHUB_API_URL}/repos/{GITHUB_REPOSITORY}/issues/{issue_number}/labels"
133
181
  label_response = requests.post(label_url, json={"labels": ["fixed"]}, headers=GITHUB_HEADERS)
134
182
 
135
- # Add AI-generated comment
183
+ # Add comment
136
184
  comment_url = f"{GITHUB_API_URL}/repos/{GITHUB_REPOSITORY}/issues/{issue_number}/comments"
137
185
  comment_response = requests.post(comment_url, json={"body": comment}, headers=GITHUB_HEADERS)
138
186
 
@@ -143,9 +191,11 @@ query($owner: String!, $repo: String!, $pr_number: Int!) {
143
191
  f"Failed to update issue #{issue_number}. Label status: {label_response.status_code}, "
144
192
  f"Comment status: {comment_response.status_code}"
145
193
  )
194
+
195
+ return contributors, author
146
196
  except KeyError as e:
147
197
  print(f"Error parsing GraphQL response: {e}")
148
- return
198
+ return [], None
149
199
 
150
200
 
151
201
  def remove_todos_on_merge(pr_number):
@@ -157,7 +207,7 @@ def remove_todos_on_merge(pr_number):
157
207
 
158
208
 
159
209
  def main():
160
- """Summarize a pull request and update its description with an AI-generated summary."""
210
+ """Summarize a pull request and update its description with a summary."""
161
211
  pr_number = PR["number"]
162
212
 
163
213
  print(f"Retrieving diff for PR {pr_number}")
@@ -175,12 +225,17 @@ def main():
175
225
  else:
176
226
  print(f"Failed to update PR description. Status code: {status_code}")
177
227
 
178
- # Update linked issues
228
+ # Update linked issues and post thank you message if merged
179
229
  if PR.get("merged"):
180
230
  print("PR is merged, labeling fixed issues...")
181
- label_fixed_issues(pr_number)
231
+ contributors, author = label_fixed_issues(pr_number, summary)
182
232
  print("Removing TODO label from PR...")
183
233
  remove_todos_on_merge(pr_number)
234
+ username = get_github_username() # get GITHUB_TOKEN username
235
+ if author and author != username:
236
+ print("Posting PR author thank you message...")
237
+ contributors.discard(username)
238
+ post_merge_message(pr_number, author, contributors, summary)
184
239
 
185
240
 
186
241
  if __name__ == "__main__":
@@ -14,6 +14,7 @@ from .github_utils import (
14
14
  PR,
15
15
  check_pypi_version,
16
16
  get_github_data,
17
+ get_github_username,
17
18
  get_pr_diff,
18
19
  graphql_request,
19
20
  ultralytics_actions_info,
@@ -38,6 +39,7 @@ __all__ = (
38
39
  "OPENAI_API_KEY",
39
40
  "OPENAI_MODEL",
40
41
  "get_completion",
42
+ "get_github_username",
41
43
  "check_pypi_version",
42
44
  "ultralytics_actions_info",
43
45
  )
@@ -24,6 +24,27 @@ PR = EVENT_DATA.get("pull_request", {})
24
24
  DISCUSSION = EVENT_DATA.get("discussion", {})
25
25
 
26
26
 
27
+ def get_github_username():
28
+ """Gets username associated with the GitHub token in GITHUB_HEADERS."""
29
+ query = """
30
+ query {
31
+ viewer {
32
+ login
33
+ }
34
+ }
35
+ """
36
+ response = requests.post("https://api.github.com/graphql", json={"query": query}, headers=GITHUB_HEADERS)
37
+ if response.status_code != 200:
38
+ print(f"Failed to fetch authenticated user. Status code: {response.status_code}")
39
+ return None
40
+
41
+ try:
42
+ return response.json()["data"]["viewer"]["login"]
43
+ except KeyError as e:
44
+ print(f"Error parsing authenticated user response: {e}")
45
+ return None
46
+
47
+
27
48
  def get_pr_diff(pr_number: int) -> str:
28
49
  """Retrieves the diff content for a specified pull request in a GitHub repository."""
29
50
  url = f"{GITHUB_API_URL}/repos/{GITHUB_REPOSITORY}/pulls/{pr_number}"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ultralytics-actions
3
- Version: 0.0.27
3
+ Version: 0.0.30
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>