diff --git a/scripts/release-notes.py b/scripts/release-notes.py index 1356f6d510c..4976fa58516 100755 --- a/scripts/release-notes.py +++ b/scripts/release-notes.py @@ -43,6 +43,23 @@ def num_commits_since_prev_tag(token, base_url): print(f"There are {num_commits} new commits since {prev_release_tag}") return num_commits +UNCATTEGORIZED = 'Uncategorized' +categories = [ + {'title': '#### ⛔ Breaking Changes', 'label': 'changelog:breaking-change'}, + {'title': '#### ✨ New Features', 'label': 'changelog:new-feature'}, + {'title': '#### 🐞 Bug fixes, Minor Improvements', 'label': 'changelog:bugfix-or-minor-feature'}, + {'title': '#### 🚧 Experimental Features', 'label': 'changelog:exprimental'}, + {'title': '#### 👷 CI Improvements', 'label': 'changelog:ci'}, + {'title': None, 'label': 'changelog:test'}, + {'title': None, 'label': 'changelog:skip'} +] + +def categorize_pull_request(label): + for category, prefix in categories.items(): + if label.startswith(prefix): + return category + return UNCATTEGORIZED # Default category if no matching prefix is found + def main(token, repo, num_commits, exclude_dependabot): accept_header = "application/vnd.github.groot-preview+json" @@ -66,6 +83,10 @@ def main(token, repo, num_commits, exclude_dependabot): print('Retrieved', len(commits), 'commits') # Load PR for each commit and print summary + category_results = {category['title']: [] for category in categories} + other_results = [] + commits_with_multiple_labels = [] + for commit in commits: sha = commit['sha'] author = commit['author']['login'] @@ -88,17 +109,73 @@ def main(token, repo, num_commits, exclude_dependabot): if not pulls: short_sha = sha[:7] commit_url = commit['html_url'] - print(f'* {msg} ([@{author}]({author_url}) in [{short_sha}]({commit_url}))') + + result = f'* {msg} ([@{author}]({author_url}) in [{short_sha}]({commit_url}))' + other_results.append(result) continue pull = pulls[0] pull_id = pull['number'] pull_url = pull['html_url'] msg = msg.replace(f'(#{pull_id})', '').strip() - print(f'* {msg} ([@{author}]({author_url}) in [#{pull_id}]({pull_url}))') + + # Check if the pull request has changelog label + pull_labels = get_pull_request_labels(token, args.repo, pull_id) + changelog_labels = [label for label in pull_labels if label.startswith('changelog:')] + + # Handle multiple changelog labels + if len(changelog_labels) > 1: + commits_with_multiple_labels.append((sha, pull_id, changelog_labels)) + continue + + category = UNCATTEGORIZED + if changelog_labels: + for cat in categories: + if changelog_labels[0].startswith(cat['label']): + category = cat['title'] + break + + result = f'* {msg} ([@{author}]({author_url}) in [#{pull_id}]({pull_url}))' + if category == UNCATTEGORIZED: + other_results.append(result) + else: + category_results[category].append(result) + + # Print categorized pull requests + print() + for category, results in category_results.items(): + if results and category: + print(f'{category}:\n') + for result in results: + print(result) + print() + + # Print pull requests in the 'UNCATTEGORIZED' category + if other_results: + print(f'#### {UNCATTEGORIZED}:') + for result in other_results: + print(result) + print() + + # Print warnings for commits with more than one changelog label + if commits_with_multiple_labels: + print("Warnings: Commits with more than one changelog label found. Please fix them:\n") + for sha, pull_id, labels in commits_with_multiple_labels: + pr_url = f"https://github.com/jaegertracing/{repo}/pull/{pull_id}" + print(f"Commit {sha} associated with multiple changelog labels: {', '.join(labels)}") + print(f"Pull Request URL: {pr_url}\n") + print() if skipped_dependabot: - print(f"\n(Skipped {skipped_dependabot} dependabot commit{'' if skipped_dependabot == 1 else 's'})") + print(f"(Skipped {skipped_dependabot} dependabot commit{'' if skipped_dependabot == 1 else 's'})") + + +def get_pull_request_labels(token, repo, pull_number): + labels_url = f"https://api.github.com/repos/jaegertracing/{repo}/issues/{pull_number}/labels" + req = Request(labels_url) + req.add_header('Authorization', f'token {token}') + labels = json.loads(urlopen(req).read()) + return [label['name'] for label in labels] if __name__ == "__main__":