ultralytics-actions 0.0.25__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.
- {ultralytics_actions-0.0.25 → ultralytics_actions-0.0.30}/PKG-INFO +1 -1
- {ultralytics_actions-0.0.25 → ultralytics_actions-0.0.30}/actions/__init__.py +1 -1
- {ultralytics_actions-0.0.25 → ultralytics_actions-0.0.30}/actions/first_interaction.py +2 -2
- ultralytics_actions-0.0.30/actions/summarize_pr.py +242 -0
- {ultralytics_actions-0.0.25 → ultralytics_actions-0.0.30}/actions/utils/__init__.py +2 -0
- {ultralytics_actions-0.0.25 → ultralytics_actions-0.0.30}/actions/utils/github_utils.py +21 -0
- {ultralytics_actions-0.0.25 → ultralytics_actions-0.0.30}/ultralytics_actions.egg-info/PKG-INFO +1 -1
- ultralytics_actions-0.0.25/actions/summarize_pr.py +0 -140
- {ultralytics_actions-0.0.25 → ultralytics_actions-0.0.30}/LICENSE +0 -0
- {ultralytics_actions-0.0.25 → ultralytics_actions-0.0.30}/README.md +0 -0
- {ultralytics_actions-0.0.25 → ultralytics_actions-0.0.30}/actions/summarize_release.py +0 -0
- {ultralytics_actions-0.0.25 → ultralytics_actions-0.0.30}/actions/update_markdown_code_blocks.py +0 -0
- {ultralytics_actions-0.0.25 → ultralytics_actions-0.0.30}/actions/utils/common_utils.py +0 -0
- {ultralytics_actions-0.0.25 → ultralytics_actions-0.0.30}/actions/utils/openai_utils.py +0 -0
- {ultralytics_actions-0.0.25 → ultralytics_actions-0.0.30}/pyproject.toml +0 -0
- {ultralytics_actions-0.0.25 → ultralytics_actions-0.0.30}/setup.cfg +0 -0
- {ultralytics_actions-0.0.25 → ultralytics_actions-0.0.30}/ultralytics_actions.egg-info/SOURCES.txt +0 -0
- {ultralytics_actions-0.0.25 → ultralytics_actions-0.0.30}/ultralytics_actions.egg-info/dependency_links.txt +0 -0
- {ultralytics_actions-0.0.25 → ultralytics_actions-0.0.30}/ultralytics_actions.egg-info/entry_points.txt +0 -0
- {ultralytics_actions-0.0.25 → ultralytics_actions-0.0.30}/ultralytics_actions.egg-info/requires.txt +0 -0
- {ultralytics_actions-0.0.25 → 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.
|
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>
|
@@ -335,7 +335,7 @@ INSTRUCTIONS:
|
|
335
335
|
- Adapt the example {issue_type} response below as appropriate, keeping all badges, links and references provided
|
336
336
|
- For bug reports, specifically request a minimum reproducible example (MRE) if not provided
|
337
337
|
- INCLUDE ALL LINKS AND INSTRUCTIONS IN THE EXAMPLE BELOW, customized as appropriate
|
338
|
-
-
|
338
|
+
- Mention to the user that this is an automated response and that an Ultralytics engineer will also assist soon
|
339
339
|
- Do not add a sign-off or valediction like "best regards" at the end of your response
|
340
340
|
- Do not add spaces between bullet points or numbered lists
|
341
341
|
- Only link to files or URLs in the example below, do not add external links
|
@@ -359,7 +359,7 @@ YOUR {issue_type.upper()} RESPONSE:
|
|
359
359
|
messages = [
|
360
360
|
{
|
361
361
|
"role": "system",
|
362
|
-
"content": f"You are a helpful assistant responding to GitHub {issue_type}s for
|
362
|
+
"content": f"You are a helpful assistant responding to GitHub {issue_type}s for {org_name}.",
|
363
363
|
},
|
364
364
|
{"role": "user", "content": prompt},
|
365
365
|
]
|
@@ -0,0 +1,242 @@
|
|
1
|
+
# Ultralytics Actions 🚀, AGPL-3.0 license https://ultralytics.com/license
|
2
|
+
|
3
|
+
import time
|
4
|
+
|
5
|
+
import requests
|
6
|
+
|
7
|
+
from .utils import (
|
8
|
+
GITHUB_API_URL,
|
9
|
+
GITHUB_HEADERS,
|
10
|
+
GITHUB_REPOSITORY,
|
11
|
+
PR,
|
12
|
+
get_completion,
|
13
|
+
get_github_username,
|
14
|
+
get_pr_diff,
|
15
|
+
)
|
16
|
+
|
17
|
+
# Constants
|
18
|
+
SUMMARY_START = (
|
19
|
+
"## 🛠️ PR Summary\n\n<sub>Made with ❤️ by [Ultralytics Actions](https://github.com/ultralytics/actions)<sub>\n\n"
|
20
|
+
)
|
21
|
+
|
22
|
+
|
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."""
|
58
|
+
messages = [
|
59
|
+
{
|
60
|
+
"role": "system",
|
61
|
+
"content": "You are an Ultralytics AI assistant. Generate friendly GitHub issue comments. No @ mentions or direct addressing.",
|
62
|
+
},
|
63
|
+
{
|
64
|
+
"role": "user",
|
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"
|
67
|
+
f"Include:\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",
|
74
|
+
},
|
75
|
+
]
|
76
|
+
return get_completion(messages)
|
77
|
+
|
78
|
+
|
79
|
+
def generate_pr_summary(repo_name, diff_text):
|
80
|
+
"""Generates a concise, professional summary of a PR using OpenAI's API for Ultralytics repositories."""
|
81
|
+
if not diff_text:
|
82
|
+
diff_text = "**ERROR: DIFF IS EMPTY, THERE ARE ZERO CODE CHANGES IN THIS PR."
|
83
|
+
ratio = 3.3 # about 3.3 characters per token
|
84
|
+
limit = round(128000 * ratio * 0.5) # use up to 50% of the 128k context window for prompt
|
85
|
+
messages = [
|
86
|
+
{
|
87
|
+
"role": "system",
|
88
|
+
"content": "You are an Ultralytics AI assistant skilled in software development and technical communication. Your task is to summarize GitHub PRs from Ultralytics in a way that is accurate, concise, and understandable to both expert developers and non-expert users. Focus on highlighting the key changes and their impact in simple, concise terms.",
|
89
|
+
},
|
90
|
+
{
|
91
|
+
"role": "user",
|
92
|
+
"content": f"Summarize this '{repo_name}' PR, focusing on major changes, their purpose, and potential impact. Keep the summary clear and concise, suitable for a broad audience. Add emojis to enliven the summary. Reply directly with a summary along these example guidelines, though feel free to adjust as appropriate:\n\n"
|
93
|
+
f"### 🌟 Summary (single-line synopsis)\n"
|
94
|
+
f"### 📊 Key Changes (bullet points highlighting any major changes)\n"
|
95
|
+
f"### 🎯 Purpose & Impact (bullet points explaining any benefits and potential impact to users)\n"
|
96
|
+
f"\n\nHere's the PR diff:\n\n{diff_text[:limit]}",
|
97
|
+
},
|
98
|
+
]
|
99
|
+
reply = get_completion(messages)
|
100
|
+
if len(diff_text) > limit:
|
101
|
+
reply = "**WARNING ⚠️** this PR is very large, summary may not cover all changes.\n\n" + reply
|
102
|
+
return SUMMARY_START + reply
|
103
|
+
|
104
|
+
|
105
|
+
def update_pr_description(repo_name, pr_number, new_summary, max_retries=2):
|
106
|
+
"""Updates PR description with new summary, retrying if description is None."""
|
107
|
+
pr_url = f"{GITHUB_API_URL}/repos/{repo_name}/pulls/{pr_number}"
|
108
|
+
description = ""
|
109
|
+
for i in range(max_retries + 1):
|
110
|
+
description = requests.get(pr_url, headers=GITHUB_HEADERS).json().get("body") or ""
|
111
|
+
if description:
|
112
|
+
break
|
113
|
+
if i < max_retries:
|
114
|
+
print("No current PR description found, retrying...")
|
115
|
+
time.sleep(1)
|
116
|
+
|
117
|
+
# Check if existing summary is present and update accordingly
|
118
|
+
start = "## 🛠️ PR Summary"
|
119
|
+
if start in description:
|
120
|
+
print("Existing PR Summary found, replacing.")
|
121
|
+
updated_description = description.split(start)[0] + new_summary
|
122
|
+
else:
|
123
|
+
print("PR Summary not found, appending.")
|
124
|
+
updated_description = description + "\n\n" + new_summary
|
125
|
+
|
126
|
+
# Update the PR description
|
127
|
+
update_response = requests.patch(pr_url, json={"body": updated_description}, headers=GITHUB_HEADERS)
|
128
|
+
return update_response.status_code
|
129
|
+
|
130
|
+
|
131
|
+
def label_fixed_issues(pr_number, pr_summary):
|
132
|
+
"""Labels issues closed by this PR when merged, notifies users, and returns PR contributors."""
|
133
|
+
query = """
|
134
|
+
query($owner: String!, $repo: String!, $pr_number: Int!) {
|
135
|
+
repository(owner: $owner, name: $repo) {
|
136
|
+
pullRequest(number: $pr_number) {
|
137
|
+
closingIssuesReferences(first: 50) {
|
138
|
+
nodes {
|
139
|
+
number
|
140
|
+
}
|
141
|
+
}
|
142
|
+
url
|
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
|
+
}
|
151
|
+
}
|
152
|
+
}
|
153
|
+
}
|
154
|
+
"""
|
155
|
+
|
156
|
+
owner, repo = GITHUB_REPOSITORY.split("/")
|
157
|
+
variables = {"owner": owner, "repo": repo, "pr_number": pr_number}
|
158
|
+
graphql_url = "https://api.github.com/graphql"
|
159
|
+
response = requests.post(graphql_url, json={"query": query, "variables": variables}, headers=GITHUB_HEADERS)
|
160
|
+
if response.status_code != 200:
|
161
|
+
print(f"Failed to fetch linked issues. Status code: {response.status_code}")
|
162
|
+
return [], None
|
163
|
+
|
164
|
+
try:
|
165
|
+
data = response.json()["data"]["repository"]["pullRequest"]
|
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
|
172
|
+
|
173
|
+
# Generate personalized comment
|
174
|
+
comment = generate_issue_comment(pr_url=data["url"], pr_summary=pr_summary)
|
175
|
+
|
176
|
+
# Update linked issues
|
177
|
+
for issue in data["closingIssuesReferences"]["nodes"]:
|
178
|
+
issue_number = issue["number"]
|
179
|
+
# Add fixed label
|
180
|
+
label_url = f"{GITHUB_API_URL}/repos/{GITHUB_REPOSITORY}/issues/{issue_number}/labels"
|
181
|
+
label_response = requests.post(label_url, json={"labels": ["fixed"]}, headers=GITHUB_HEADERS)
|
182
|
+
|
183
|
+
# Add comment
|
184
|
+
comment_url = f"{GITHUB_API_URL}/repos/{GITHUB_REPOSITORY}/issues/{issue_number}/comments"
|
185
|
+
comment_response = requests.post(comment_url, json={"body": comment}, headers=GITHUB_HEADERS)
|
186
|
+
|
187
|
+
if label_response.status_code == 200 and comment_response.status_code == 201:
|
188
|
+
print(f"Added 'fixed' label and comment to issue #{issue_number}")
|
189
|
+
else:
|
190
|
+
print(
|
191
|
+
f"Failed to update issue #{issue_number}. Label status: {label_response.status_code}, "
|
192
|
+
f"Comment status: {comment_response.status_code}"
|
193
|
+
)
|
194
|
+
|
195
|
+
return contributors, author
|
196
|
+
except KeyError as e:
|
197
|
+
print(f"Error parsing GraphQL response: {e}")
|
198
|
+
return [], None
|
199
|
+
|
200
|
+
|
201
|
+
def remove_todos_on_merge(pr_number):
|
202
|
+
"""Removes specified labels from PR."""
|
203
|
+
for label in ["TODO"]: # Can be extended with more labels in the future
|
204
|
+
requests.delete(
|
205
|
+
f"{GITHUB_API_URL}/repos/{GITHUB_REPOSITORY}/issues/{pr_number}/labels/{label}", headers=GITHUB_HEADERS
|
206
|
+
)
|
207
|
+
|
208
|
+
|
209
|
+
def main():
|
210
|
+
"""Summarize a pull request and update its description with a summary."""
|
211
|
+
pr_number = PR["number"]
|
212
|
+
|
213
|
+
print(f"Retrieving diff for PR {pr_number}")
|
214
|
+
diff = get_pr_diff(pr_number)
|
215
|
+
|
216
|
+
# Generate PR summary
|
217
|
+
print("Generating PR summary...")
|
218
|
+
summary = generate_pr_summary(GITHUB_REPOSITORY, diff)
|
219
|
+
|
220
|
+
# Update PR description
|
221
|
+
print("Updating PR description...")
|
222
|
+
status_code = update_pr_description(GITHUB_REPOSITORY, pr_number, summary)
|
223
|
+
if status_code == 200:
|
224
|
+
print("PR description updated successfully.")
|
225
|
+
else:
|
226
|
+
print(f"Failed to update PR description. Status code: {status_code}")
|
227
|
+
|
228
|
+
# Update linked issues and post thank you message if merged
|
229
|
+
if PR.get("merged"):
|
230
|
+
print("PR is merged, labeling fixed issues...")
|
231
|
+
contributors, author = label_fixed_issues(pr_number, summary)
|
232
|
+
print("Removing TODO label from PR...")
|
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)
|
239
|
+
|
240
|
+
|
241
|
+
if __name__ == "__main__":
|
242
|
+
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.25 → ultralytics_actions-0.0.30}/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.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>
|
@@ -1,140 +0,0 @@
|
|
1
|
-
# Ultralytics Actions 🚀, AGPL-3.0 license https://ultralytics.com/license
|
2
|
-
|
3
|
-
import time
|
4
|
-
|
5
|
-
import requests
|
6
|
-
|
7
|
-
from .utils import (
|
8
|
-
GITHUB_API_URL,
|
9
|
-
GITHUB_HEADERS,
|
10
|
-
GITHUB_REPOSITORY,
|
11
|
-
PR,
|
12
|
-
get_completion,
|
13
|
-
get_pr_diff,
|
14
|
-
)
|
15
|
-
|
16
|
-
# Action settings
|
17
|
-
SUMMARY_START = (
|
18
|
-
"## 🛠️ PR Summary\n\n<sub>Made with ❤️ by [Ultralytics Actions](https://github.com/ultralytics/actions)<sub>\n\n"
|
19
|
-
)
|
20
|
-
|
21
|
-
|
22
|
-
def generate_pr_summary(repo_name, diff_text):
|
23
|
-
"""Generates a concise, professional summary of a PR using OpenAI's API for Ultralytics repositories."""
|
24
|
-
if not diff_text:
|
25
|
-
diff_text = "**ERROR: DIFF IS EMPTY, THERE ARE ZERO CODE CHANGES IN THIS PR."
|
26
|
-
ratio = 3.3 # about 3.3 characters per token
|
27
|
-
limit = round(128000 * ratio * 0.5) # use up to 50% of the 128k context window for prompt
|
28
|
-
messages = [
|
29
|
-
{
|
30
|
-
"role": "system",
|
31
|
-
"content": "You are an Ultralytics AI assistant skilled in software development and technical communication. Your task is to summarize GitHub PRs from Ultralytics in a way that is accurate, concise, and understandable to both expert developers and non-expert users. Focus on highlighting the key changes and their impact in simple, concise terms.",
|
32
|
-
},
|
33
|
-
{
|
34
|
-
"role": "user",
|
35
|
-
"content": f"Summarize this '{repo_name}' PR, focusing on major changes, their purpose, and potential impact. Keep the summary clear and concise, suitable for a broad audience. Add emojis to enliven the summary. Reply directly with a summary along these example guidelines, though feel free to adjust as appropriate:\n\n"
|
36
|
-
f"### 🌟 Summary (single-line synopsis)\n"
|
37
|
-
f"### 📊 Key Changes (bullet points highlighting any major changes)\n"
|
38
|
-
f"### 🎯 Purpose & Impact (bullet points explaining any benefits and potential impact to users)\n"
|
39
|
-
f"\n\nHere's the PR diff:\n\n{diff_text[:limit]}",
|
40
|
-
},
|
41
|
-
]
|
42
|
-
reply = get_completion(messages)
|
43
|
-
if len(diff_text) > limit:
|
44
|
-
reply = "**WARNING ⚠️** this PR is very large, summary may not cover all changes.\n\n" + reply
|
45
|
-
return SUMMARY_START + reply
|
46
|
-
|
47
|
-
|
48
|
-
def update_pr_description(repo_name, pr_number, new_summary, max_retries=2):
|
49
|
-
"""Updates PR description with new summary, retrying if description is None."""
|
50
|
-
pr_url = f"{GITHUB_API_URL}/repos/{repo_name}/pulls/{pr_number}"
|
51
|
-
description = ""
|
52
|
-
for i in range(max_retries + 1):
|
53
|
-
description = requests.get(pr_url, headers=GITHUB_HEADERS).json().get("body") or ""
|
54
|
-
if description:
|
55
|
-
break
|
56
|
-
if i < max_retries:
|
57
|
-
print("No current PR description found, retrying...")
|
58
|
-
time.sleep(1)
|
59
|
-
|
60
|
-
# Check if existing summary is present and update accordingly
|
61
|
-
start = "## 🛠️ PR Summary"
|
62
|
-
if start in description:
|
63
|
-
print("Existing PR Summary found, replacing.")
|
64
|
-
updated_description = description.split(start)[0] + new_summary
|
65
|
-
else:
|
66
|
-
print("PR Summary not found, appending.")
|
67
|
-
updated_description = description + "\n\n" + new_summary
|
68
|
-
|
69
|
-
# Update the PR description
|
70
|
-
update_response = requests.patch(pr_url, json={"body": updated_description}, headers=GITHUB_HEADERS)
|
71
|
-
return update_response.status_code
|
72
|
-
|
73
|
-
|
74
|
-
def label_fixed_issues(pr_number):
|
75
|
-
"""Labels issues that are closed by this PR when it's merged."""
|
76
|
-
# GraphQL query to get closing issues
|
77
|
-
query = """
|
78
|
-
query($owner: String!, $repo: String!, $pr_number: Int!) {
|
79
|
-
repository(owner: $owner, name: $repo) {
|
80
|
-
pullRequest(number: $pr_number) {
|
81
|
-
closingIssuesReferences(first: 50) {
|
82
|
-
nodes {
|
83
|
-
number
|
84
|
-
}
|
85
|
-
}
|
86
|
-
}
|
87
|
-
}
|
88
|
-
}
|
89
|
-
"""
|
90
|
-
|
91
|
-
owner, repo = GITHUB_REPOSITORY.split("/")
|
92
|
-
variables = {"owner": owner, "repo": repo, "pr_number": pr_number}
|
93
|
-
graphql_url = "https://api.github.com/graphql"
|
94
|
-
response = requests.post(graphql_url, json={"query": query, "variables": variables}, headers=GITHUB_HEADERS)
|
95
|
-
if response.status_code != 200:
|
96
|
-
print(f"Failed to fetch linked issues. Status code: {response.status_code}")
|
97
|
-
return
|
98
|
-
|
99
|
-
try:
|
100
|
-
issues = response.json()["data"]["repository"]["pullRequest"]["closingIssuesReferences"]["nodes"]
|
101
|
-
for issue in issues:
|
102
|
-
issue_number = issue["number"]
|
103
|
-
label_url = f"{GITHUB_API_URL}/repos/{GITHUB_REPOSITORY}/issues/{issue_number}/labels"
|
104
|
-
label_response = requests.post(label_url, json={"labels": ["fixed"]}, headers=GITHUB_HEADERS)
|
105
|
-
if label_response.status_code == 200:
|
106
|
-
print(f"Added 'fixed' label to issue #{issue_number}")
|
107
|
-
else:
|
108
|
-
print(f"Failed to add label to issue #{issue_number}. Status: {label_response.status_code}")
|
109
|
-
except KeyError as e:
|
110
|
-
print(f"Error parsing GraphQL response: {e}")
|
111
|
-
return
|
112
|
-
|
113
|
-
|
114
|
-
def main():
|
115
|
-
"""Summarize a pull request and update its description with an AI-generated summary."""
|
116
|
-
pr_number = PR["number"]
|
117
|
-
|
118
|
-
print(f"Retrieving diff for PR {pr_number}")
|
119
|
-
diff = get_pr_diff(PR["number"])
|
120
|
-
|
121
|
-
# Generate PR summary
|
122
|
-
print("Generating PR summary...")
|
123
|
-
summary = generate_pr_summary(GITHUB_REPOSITORY, diff)
|
124
|
-
|
125
|
-
# Update PR description
|
126
|
-
print("Updating PR description...")
|
127
|
-
status_code = update_pr_description(GITHUB_REPOSITORY, pr_number, summary)
|
128
|
-
if status_code == 200:
|
129
|
-
print("PR description updated successfully.")
|
130
|
-
else:
|
131
|
-
print(f"Failed to update PR description. Status code: {status_code}")
|
132
|
-
|
133
|
-
# Update linked issues
|
134
|
-
if PR.get("merged"):
|
135
|
-
print("PR is merged, labeling fixed issues...")
|
136
|
-
label_fixed_issues(PR["number"])
|
137
|
-
|
138
|
-
|
139
|
-
if __name__ == "__main__":
|
140
|
-
main()
|
File without changes
|
File without changes
|
File without changes
|
{ultralytics_actions-0.0.25 → ultralytics_actions-0.0.30}/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.25 → ultralytics_actions-0.0.30}/ultralytics_actions.egg-info/SOURCES.txt
RENAMED
File without changes
|
File without changes
|
File without changes
|
{ultralytics_actions-0.0.25 → ultralytics_actions-0.0.30}/ultralytics_actions.egg-info/requires.txt
RENAMED
File without changes
|
{ultralytics_actions-0.0.25 → ultralytics_actions-0.0.30}/ultralytics_actions.egg-info/top_level.txt
RENAMED
File without changes
|