Skip to content

Commit

Permalink
Inspire PR contributors on merge (#322)
Browse files Browse the repository at this point in the history
Signed-off-by: Glenn Jocher <[email protected]>
Co-authored-by: UltralyticsAssistant <[email protected]>
  • Loading branch information
glenn-jocher and UltralyticsAssistant authored Dec 21, 2024
1 parent 96bef7d commit 1511dee
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 15 deletions.
2 changes: 1 addition & 1 deletion actions/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@
# ├── test_summarize_pr.py
# └── ...

__version__ = "0.0.27"
__version__ = "0.0.28"
83 changes: 69 additions & 14 deletions actions/summarize_pr.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
GITHUB_REPOSITORY,
PR,
get_completion,
get_github_username,
get_pr_diff,
)

Expand All @@ -19,22 +20,55 @@
)


def generate_issue_comment(pr_url, pr_body):
def generate_merge_message(pr_author, contributors, pr_summary=None):
"""Generates an AI thank you message for merged PRs using OpenAI."""
contributors_str = ", ".join(f"@{c}" for c in contributors if c != pr_author)
mention_str = f"@{pr_author}"
if contributors_str:
mention_str += f" and {contributors_str}"

messages = [
{
"role": "system",
"content": "You are an Ultralytics AI assistant. Generate meaningful, inspiring messages to GitHub users.",
},
{
"role": "user",
"content": f"Write a friendly thank you for a merged PR by these GitHub contributors: {mention_str}. "
f"Context from PR:\n{pr_summary}\n\n"
f"Start with the exciting message that this PR is now merged, and weave in an inspiring quote "
f"from a famous figure in science, philosophy or stoicism. "
f"Make the message relevant to the specific contributions in this PR. "
f"We want them to feel their hard work is acknowledged and will make a difference in the world.",
},
]
return get_completion(messages)


def post_merge_message(pr_number, pr_author, contributors, summary):
"""Posts AI-generated thank you message on PR after merge."""
message = generate_merge_message(pr_author, contributors, summary)
comment_url = f"{GITHUB_API_URL}/repos/{GITHUB_REPOSITORY}/issues/{pr_number}/comments"
response = requests.post(comment_url, json={"body": message}, headers=GITHUB_HEADERS)
return response.status_code == 201


def generate_issue_comment(pr_url, pr_summary):
"""Generates a personalized issue comment using AI based on the PR context."""
messages = [
{
"role": "system",
"content": "You are the Ultralytics AI assistant. Generate friendly GitHub issue comments. No @ mentions or direct addressing.",
"content": "You are an Ultralytics AI assistant. Generate friendly GitHub issue comments. No @ mentions or direct addressing.",
},
{
"role": "user",
"content": f"Write a comment for a GitHub issue where a potential fix has been merged in PR: {pr_url}\n\n"
f"Context from PR:\n{pr_body}\n\n"
f"Context from PR:\n{pr_summary}\n\n"
f"Include:\n"
f"1. Note that changes addressing this issue have been merged\n"
f"2. Key changes and testing options:\n"
f"1. An explanation of key changes from the PR that may resolve this issue\n"
f"2. Testing options:\n"
f" - pip install git+https://github.com/ultralytics/ultralytics.git@main # test latest changes\n"
f" - or await next release\n"
f" - or await next official PyPI release\n"
f"3. Request feedback on whether these changes resolve the issue\n"
f"4. Thank 🙏 for reporting the issue and welcome any further feedback if the issue persists\n\n",
},
Expand Down Expand Up @@ -94,8 +128,8 @@ def update_pr_description(repo_name, pr_number, new_summary, max_retries=2):
return update_response.status_code


def label_fixed_issues(pr_number):
"""Labels issues closed by this PR when merged and notifies users about the fix with AI-generated comments."""
def label_fixed_issues(pr_number, pr_summary):
"""Labels issues closed by this PR when merged, notifies users, and returns PR contributors."""
query = """
query($owner: String!, $repo: String!, $pr_number: Int!) {
repository(owner: $owner, name: $repo) {
Expand All @@ -107,6 +141,13 @@ def label_fixed_issues(pr_number):
}
url
body
author { login }
reviews(first: 50) {
nodes { author { login } }
}
comments(first: 50) {
nodes { author { login } }
}
}
}
}
Expand All @@ -118,22 +159,29 @@ def label_fixed_issues(pr_number):
response = requests.post(graphql_url, json={"query": query, "variables": variables}, headers=GITHUB_HEADERS)
if response.status_code != 200:
print(f"Failed to fetch linked issues. Status code: {response.status_code}")
return
return [], None

try:
data = response.json()["data"]["repository"]["pullRequest"]
issues = data["closingIssuesReferences"]["nodes"]
author = data["author"]["login"]

# Get unique contributors from reviews and comments
contributors = {review["author"]["login"] for review in data["reviews"]["nodes"]}
contributors.update(comment["author"]["login"] for comment in data["comments"]["nodes"])
contributors.discard(author) # Remove author from contributors list

# Generate personalized comment
comment = generate_issue_comment(pr_url=data["url"], pr_body=data["body"])
comment = generate_issue_comment(pr_url=data["url"], pr_summary=pr_summary)

# Update linked issues
for issue in issues:
issue_number = issue["number"]
# Add fixed label
label_url = f"{GITHUB_API_URL}/repos/{GITHUB_REPOSITORY}/issues/{issue_number}/labels"
label_response = requests.post(label_url, json={"labels": ["fixed"]}, headers=GITHUB_HEADERS)

# Add AI-generated comment
# Add comment
comment_url = f"{GITHUB_API_URL}/repos/{GITHUB_REPOSITORY}/issues/{issue_number}/comments"
comment_response = requests.post(comment_url, json={"body": comment}, headers=GITHUB_HEADERS)

Expand All @@ -144,9 +192,11 @@ def label_fixed_issues(pr_number):
f"Failed to update issue #{issue_number}. Label status: {label_response.status_code}, "
f"Comment status: {comment_response.status_code}"
)

return contributors, author
except KeyError as e:
print(f"Error parsing GraphQL response: {e}")
return
return [], None


def remove_todos_on_merge(pr_number):
Expand Down Expand Up @@ -176,12 +226,17 @@ def main():
else:
print(f"Failed to update PR description. Status code: {status_code}")

# Update linked issues
# Update linked issues and post thank you message if merged
if PR.get("merged"):
print("PR is merged, labeling fixed issues...")
label_fixed_issues(pr_number)
contributors, author = label_fixed_issues(pr_number, summary)
print("Removing TODO label from PR...")
remove_todos_on_merge(pr_number)
username = get_github_username() # get GITHUB_TOKEN username
if author and author != username:
print("Posting PR author thank you message...")
contributors.discard(username)
post_merge_message(pr_number, author, contributors, summary)


if __name__ == "__main__":
Expand Down
2 changes: 2 additions & 0 deletions actions/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
PR,
check_pypi_version,
get_github_data,
get_github_username,
get_pr_diff,
graphql_request,
ultralytics_actions_info,
Expand All @@ -38,6 +39,7 @@
"OPENAI_API_KEY",
"OPENAI_MODEL",
"get_completion",
"get_github_username",
"check_pypi_version",
"ultralytics_actions_info",
)
21 changes: 21 additions & 0 deletions actions/utils/github_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,27 @@
DISCUSSION = EVENT_DATA.get("discussion", {})


def get_github_username():
"""Gets username associated with the GitHub token in GITHUB_HEADERS."""
query = """
query {
viewer {
login
}
}
"""
response = requests.post("https://api.github.com/graphql", json={"query": query}, headers=GITHUB_HEADERS)
if response.status_code != 200:
print(f"Failed to fetch authenticated user. Status code: {response.status_code}")
return None

try:
return response.json()["data"]["viewer"]["login"]
except KeyError as e:
print(f"Error parsing authenticated user response: {e}")
return None


def get_pr_diff(pr_number: int) -> str:
"""Retrieves the diff content for a specified pull request in a GitHub repository."""
url = f"{GITHUB_API_URL}/repos/{GITHUB_REPOSITORY}/pulls/{pr_number}"
Expand Down

0 comments on commit 1511dee

Please sign in to comment.