ultralytics-actions 0.0.22__tar.gz → 0.0.27__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.22/ultralytics_actions.egg-info → ultralytics_actions-0.0.27}/PKG-INFO +1 -1
- {ultralytics_actions-0.0.22 → ultralytics_actions-0.0.27}/actions/__init__.py +1 -1
- {ultralytics_actions-0.0.22 → ultralytics_actions-0.0.27}/actions/first_interaction.py +2 -2
- {ultralytics_actions-0.0.22 → ultralytics_actions-0.0.27}/actions/summarize_pr.py +94 -2
- {ultralytics_actions-0.0.22 → ultralytics_actions-0.0.27}/actions/utils/github_utils.py +7 -2
- {ultralytics_actions-0.0.22 → ultralytics_actions-0.0.27/ultralytics_actions.egg-info}/PKG-INFO +1 -1
- {ultralytics_actions-0.0.22 → ultralytics_actions-0.0.27}/LICENSE +0 -0
- {ultralytics_actions-0.0.22 → ultralytics_actions-0.0.27}/README.md +0 -0
- {ultralytics_actions-0.0.22 → ultralytics_actions-0.0.27}/actions/summarize_release.py +0 -0
- {ultralytics_actions-0.0.22 → ultralytics_actions-0.0.27}/actions/update_markdown_code_blocks.py +0 -0
- {ultralytics_actions-0.0.22 → ultralytics_actions-0.0.27}/actions/utils/__init__.py +0 -0
- {ultralytics_actions-0.0.22 → ultralytics_actions-0.0.27}/actions/utils/common_utils.py +0 -0
- {ultralytics_actions-0.0.22 → ultralytics_actions-0.0.27}/actions/utils/openai_utils.py +0 -0
- {ultralytics_actions-0.0.22 → ultralytics_actions-0.0.27}/pyproject.toml +0 -0
- {ultralytics_actions-0.0.22 → ultralytics_actions-0.0.27}/setup.cfg +0 -0
- {ultralytics_actions-0.0.22 → ultralytics_actions-0.0.27}/ultralytics_actions.egg-info/SOURCES.txt +0 -0
- {ultralytics_actions-0.0.22 → ultralytics_actions-0.0.27}/ultralytics_actions.egg-info/dependency_links.txt +0 -0
- {ultralytics_actions-0.0.22 → ultralytics_actions-0.0.27}/ultralytics_actions.egg-info/entry_points.txt +0 -0
- {ultralytics_actions-0.0.22 → ultralytics_actions-0.0.27}/ultralytics_actions.egg-info/requires.txt +0 -0
- {ultralytics_actions-0.0.22 → ultralytics_actions-0.0.27}/ultralytics_actions.egg-info/top_level.txt +0 -0
{ultralytics_actions-0.0.22/ultralytics_actions.egg-info → ultralytics_actions-0.0.27}/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.27
|
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
|
]
|
@@ -13,12 +13,34 @@ from .utils import (
|
|
13
13
|
get_pr_diff,
|
14
14
|
)
|
15
15
|
|
16
|
-
#
|
16
|
+
# Constants
|
17
17
|
SUMMARY_START = (
|
18
18
|
"## 🛠️ PR Summary\n\n<sub>Made with ❤️ by [Ultralytics Actions](https://github.com/ultralytics/actions)<sub>\n\n"
|
19
19
|
)
|
20
20
|
|
21
21
|
|
22
|
+
def generate_issue_comment(pr_url, pr_body):
|
23
|
+
"""Generates a personalized issue comment using AI based on the PR context."""
|
24
|
+
messages = [
|
25
|
+
{
|
26
|
+
"role": "system",
|
27
|
+
"content": "You are the Ultralytics AI assistant. Generate friendly GitHub issue comments. No @ mentions or direct addressing.",
|
28
|
+
},
|
29
|
+
{
|
30
|
+
"role": "user",
|
31
|
+
"content": f"Write a comment for a fixed GitHub issue using this merged PR context:\n\n{pr_body}\n\n"
|
32
|
+
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",
|
39
|
+
},
|
40
|
+
]
|
41
|
+
return get_completion(messages)
|
42
|
+
|
43
|
+
|
22
44
|
def generate_pr_summary(repo_name, diff_text):
|
23
45
|
"""Generates a concise, professional summary of a PR using OpenAI's API for Ultralytics repositories."""
|
24
46
|
if not diff_text:
|
@@ -71,12 +93,75 @@ def update_pr_description(repo_name, pr_number, new_summary, max_retries=2):
|
|
71
93
|
return update_response.status_code
|
72
94
|
|
73
95
|
|
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."""
|
98
|
+
query = """
|
99
|
+
query($owner: String!, $repo: String!, $pr_number: Int!) {
|
100
|
+
repository(owner: $owner, name: $repo) {
|
101
|
+
pullRequest(number: $pr_number) {
|
102
|
+
closingIssuesReferences(first: 50) {
|
103
|
+
nodes {
|
104
|
+
number
|
105
|
+
}
|
106
|
+
}
|
107
|
+
url
|
108
|
+
body
|
109
|
+
}
|
110
|
+
}
|
111
|
+
}
|
112
|
+
"""
|
113
|
+
|
114
|
+
owner, repo = GITHUB_REPOSITORY.split("/")
|
115
|
+
variables = {"owner": owner, "repo": repo, "pr_number": pr_number}
|
116
|
+
graphql_url = "https://api.github.com/graphql"
|
117
|
+
response = requests.post(graphql_url, json={"query": query, "variables": variables}, headers=GITHUB_HEADERS)
|
118
|
+
if response.status_code != 200:
|
119
|
+
print(f"Failed to fetch linked issues. Status code: {response.status_code}")
|
120
|
+
return
|
121
|
+
|
122
|
+
try:
|
123
|
+
data = response.json()["data"]["repository"]["pullRequest"]
|
124
|
+
issues = data["closingIssuesReferences"]["nodes"]
|
125
|
+
|
126
|
+
# Generate personalized comment
|
127
|
+
comment = generate_issue_comment(pr_url=data["url"], pr_body=data["body"])
|
128
|
+
|
129
|
+
for issue in issues:
|
130
|
+
issue_number = issue["number"]
|
131
|
+
# Add fixed label
|
132
|
+
label_url = f"{GITHUB_API_URL}/repos/{GITHUB_REPOSITORY}/issues/{issue_number}/labels"
|
133
|
+
label_response = requests.post(label_url, json={"labels": ["fixed"]}, headers=GITHUB_HEADERS)
|
134
|
+
|
135
|
+
# Add AI-generated comment
|
136
|
+
comment_url = f"{GITHUB_API_URL}/repos/{GITHUB_REPOSITORY}/issues/{issue_number}/comments"
|
137
|
+
comment_response = requests.post(comment_url, json={"body": comment}, headers=GITHUB_HEADERS)
|
138
|
+
|
139
|
+
if label_response.status_code == 200 and comment_response.status_code == 201:
|
140
|
+
print(f"Added 'fixed' label and comment to issue #{issue_number}")
|
141
|
+
else:
|
142
|
+
print(
|
143
|
+
f"Failed to update issue #{issue_number}. Label status: {label_response.status_code}, "
|
144
|
+
f"Comment status: {comment_response.status_code}"
|
145
|
+
)
|
146
|
+
except KeyError as e:
|
147
|
+
print(f"Error parsing GraphQL response: {e}")
|
148
|
+
return
|
149
|
+
|
150
|
+
|
151
|
+
def remove_todos_on_merge(pr_number):
|
152
|
+
"""Removes specified labels from PR."""
|
153
|
+
for label in ["TODO"]: # Can be extended with more labels in the future
|
154
|
+
requests.delete(
|
155
|
+
f"{GITHUB_API_URL}/repos/{GITHUB_REPOSITORY}/issues/{pr_number}/labels/{label}", headers=GITHUB_HEADERS
|
156
|
+
)
|
157
|
+
|
158
|
+
|
74
159
|
def main():
|
75
160
|
"""Summarize a pull request and update its description with an AI-generated summary."""
|
76
161
|
pr_number = PR["number"]
|
77
162
|
|
78
163
|
print(f"Retrieving diff for PR {pr_number}")
|
79
|
-
diff = get_pr_diff(
|
164
|
+
diff = get_pr_diff(pr_number)
|
80
165
|
|
81
166
|
# Generate PR summary
|
82
167
|
print("Generating PR summary...")
|
@@ -90,6 +175,13 @@ def main():
|
|
90
175
|
else:
|
91
176
|
print(f"Failed to update PR description. Status code: {status_code}")
|
92
177
|
|
178
|
+
# Update linked issues
|
179
|
+
if PR.get("merged"):
|
180
|
+
print("PR is merged, labeling fixed issues...")
|
181
|
+
label_fixed_issues(pr_number)
|
182
|
+
print("Removing TODO label from PR...")
|
183
|
+
remove_todos_on_merge(pr_number)
|
184
|
+
|
93
185
|
|
94
186
|
if __name__ == "__main__":
|
95
187
|
main()
|
@@ -23,8 +23,6 @@ if GITHUB_EVENT_PATH:
|
|
23
23
|
PR = EVENT_DATA.get("pull_request", {})
|
24
24
|
DISCUSSION = EVENT_DATA.get("discussion", {})
|
25
25
|
|
26
|
-
INPUTS = {k[6:].lower(): v for k, v in os.environ.items() if k.startswith("INPUT_")} # actions inputs dictionary
|
27
|
-
|
28
26
|
|
29
27
|
def get_pr_diff(pr_number: int) -> str:
|
30
28
|
"""Retrieves the diff content for a specified pull request in a GitHub repository."""
|
@@ -57,8 +55,12 @@ def graphql_request(query: str, variables: dict = None) -> dict:
|
|
57
55
|
|
58
56
|
def check_pypi_version(pyproject_toml="pyproject.toml"):
|
59
57
|
"""Compares local and PyPI package versions to determine if a new version should be published."""
|
58
|
+
import re
|
59
|
+
|
60
60
|
import tomllib # requires Python>=3.11
|
61
61
|
|
62
|
+
version_pattern = re.compile(r"^\d+\.\d+\.\d+$") # e.g. 0.0.0
|
63
|
+
|
62
64
|
with open(pyproject_toml, "rb") as f:
|
63
65
|
pyproject = tomllib.load(f)
|
64
66
|
|
@@ -73,6 +75,9 @@ def check_pypi_version(pyproject_toml="pyproject.toml"):
|
|
73
75
|
local_version = next(line.split("=")[1].strip().strip("'\"") for line in f if line.startswith(attr_name))
|
74
76
|
|
75
77
|
print(f"Local Version: {local_version}")
|
78
|
+
if not bool(version_pattern.match(local_version)):
|
79
|
+
print("WARNING: Incorrect local version pattern")
|
80
|
+
return "0.0.0", "0.0.0", False
|
76
81
|
|
77
82
|
# Get online version from PyPI
|
78
83
|
response = requests.get(f"https://pypi.org/pypi/{package_name}/json")
|
{ultralytics_actions-0.0.22 → ultralytics_actions-0.0.27/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.27
|
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
|
{ultralytics_actions-0.0.22 → ultralytics_actions-0.0.27}/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
|
{ultralytics_actions-0.0.22 → ultralytics_actions-0.0.27}/ultralytics_actions.egg-info/SOURCES.txt
RENAMED
File without changes
|
File without changes
|
File without changes
|
{ultralytics_actions-0.0.22 → ultralytics_actions-0.0.27}/ultralytics_actions.egg-info/requires.txt
RENAMED
File without changes
|
{ultralytics_actions-0.0.22 → ultralytics_actions-0.0.27}/ultralytics_actions.egg-info/top_level.txt
RENAMED
File without changes
|