ultralytics-actions 0.0.27__tar.gz → 0.0.29__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.
- {ultralytics_actions-0.0.27 → ultralytics_actions-0.0.29}/PKG-INFO +1 -1
- {ultralytics_actions-0.0.27 → ultralytics_actions-0.0.29}/actions/__init__.py +1 -1
- {ultralytics_actions-0.0.27 → ultralytics_actions-0.0.29}/actions/summarize_pr.py +76 -21
- {ultralytics_actions-0.0.27 → ultralytics_actions-0.0.29}/actions/utils/__init__.py +2 -0
- {ultralytics_actions-0.0.27 → ultralytics_actions-0.0.29}/actions/utils/github_utils.py +21 -0
- {ultralytics_actions-0.0.27 → ultralytics_actions-0.0.29}/ultralytics_actions.egg-info/PKG-INFO +1 -1
- {ultralytics_actions-0.0.27 → ultralytics_actions-0.0.29}/LICENSE +0 -0
- {ultralytics_actions-0.0.27 → ultralytics_actions-0.0.29}/README.md +0 -0
- {ultralytics_actions-0.0.27 → ultralytics_actions-0.0.29}/actions/first_interaction.py +0 -0
- {ultralytics_actions-0.0.27 → ultralytics_actions-0.0.29}/actions/summarize_release.py +0 -0
- {ultralytics_actions-0.0.27 → ultralytics_actions-0.0.29}/actions/update_markdown_code_blocks.py +0 -0
- {ultralytics_actions-0.0.27 → ultralytics_actions-0.0.29}/actions/utils/common_utils.py +0 -0
- {ultralytics_actions-0.0.27 → ultralytics_actions-0.0.29}/actions/utils/openai_utils.py +0 -0
- {ultralytics_actions-0.0.27 → ultralytics_actions-0.0.29}/pyproject.toml +0 -0
- {ultralytics_actions-0.0.27 → ultralytics_actions-0.0.29}/setup.cfg +0 -0
- {ultralytics_actions-0.0.27 → ultralytics_actions-0.0.29}/ultralytics_actions.egg-info/SOURCES.txt +0 -0
- {ultralytics_actions-0.0.27 → ultralytics_actions-0.0.29}/ultralytics_actions.egg-info/dependency_links.txt +0 -0
- {ultralytics_actions-0.0.27 → ultralytics_actions-0.0.29}/ultralytics_actions.egg-info/entry_points.txt +0 -0
- {ultralytics_actions-0.0.27 → ultralytics_actions-0.0.29}/ultralytics_actions.egg-info/requires.txt +0 -0
- {ultralytics_actions-0.0.27 → ultralytics_actions-0.0.29}/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.
|
3
|
+
Version: 0.0.29
|
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>
|
@@ -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
|
23
|
-
"""Generates a
|
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
|
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
|
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.
|
34
|
-
f"2.
|
35
|
-
f" - pip install git+https://github.com/ultralytics/ultralytics.git@main #
|
36
|
-
f" - or await next release\n"
|
37
|
-
f"3. Request
|
38
|
-
f"4. Thank 🙏 for reporting the issue and
|
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
|
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
|
-
|
166
|
+
comments = data["reviews"]["nodes"] | data["comments"]["nodes"]
|
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"],
|
174
|
+
comment = generate_issue_comment(pr_url=data["url"], pr_summary=pr_summary)
|
128
175
|
|
129
|
-
|
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
|
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
|
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}"
|
{ultralytics_actions-0.0.27 → ultralytics_actions-0.0.29}/ultralytics_actions.egg-info/PKG-INFO
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: ultralytics-actions
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.29
|
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
|
{ultralytics_actions-0.0.27 → ultralytics_actions-0.0.29}/actions/update_markdown_code_blocks.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{ultralytics_actions-0.0.27 → ultralytics_actions-0.0.29}/ultralytics_actions.egg-info/SOURCES.txt
RENAMED
File without changes
|
File without changes
|
File without changes
|
{ultralytics_actions-0.0.27 → ultralytics_actions-0.0.29}/ultralytics_actions.egg-info/requires.txt
RENAMED
File without changes
|
{ultralytics_actions-0.0.27 → ultralytics_actions-0.0.29}/ultralytics_actions.egg-info/top_level.txt
RENAMED
File without changes
|