-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Improve release notes script (#3379)
* Improve release notes script Signed-off-by: albertteoh <[email protected]> * Add --token option Signed-off-by: albertteoh <[email protected]> * Better plural handling Signed-off-by: albertteoh <[email protected]> * Read from token file Signed-off-by: albertteoh <[email protected]> * Place trunk name in variable Signed-off-by: albertteoh <[email protected]>
- Loading branch information
1 parent
eac737b
commit 745587a
Showing
2 changed files
with
119 additions
and
53 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,67 +1,134 @@ | ||
|
||
# This script can read N latest commits from one of Jaeger repos | ||
# and output them in the release notes format: | ||
# {title} ({author} in {pull_request}) | ||
# * {title} ({author} in {pull_request}) | ||
# | ||
# Requires personal GitHub token with default permissions: | ||
# https://docs.github.com/en/github/authenticating-to-github/keeping-your-account-and-data-secure/creating-a-personal-access-token | ||
# https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token | ||
# | ||
# Usage: python release-notes.py <github_token> <jaeger-repo> <num-commits> | ||
# Usage: python release-notes.py --help | ||
# | ||
|
||
import argparse | ||
import json | ||
import os.path | ||
import urllib.parse | ||
from os.path import expanduser | ||
import sys | ||
from urllib.request import ( | ||
urlopen, | ||
Request | ||
) | ||
import urllib.parse | ||
import sys | ||
|
||
|
||
def eprint(*args, **kwargs): | ||
print(*args, file=sys.stderr, **kwargs) | ||
|
||
if len(sys.argv) < 4: | ||
eprint("Usage: python release-notes.py <github_token> <jaeger-repo> <num-commits>") | ||
sys.exit(1) | ||
|
||
token=sys.argv[1] | ||
repo=sys.argv[2] | ||
num_commits=sys.argv[3] | ||
|
||
accept_header="application/vnd.github.groot-preview+json" | ||
commits_url='https://api.github.com/repos/jaegertracing/{repo}/commits'.format(repo=repo) | ||
pulls_url="{commits_url}/{commit_sha}/pulls" | ||
|
||
# load commits | ||
data = urllib.parse.urlencode({'per_page': num_commits}) | ||
req=Request(commits_url + '?' + data) | ||
print(req.full_url) | ||
req.add_header('Authorization', 'token {token}'.format(token=token)) | ||
commits=json.loads(urlopen(req).read()) | ||
print('Retrieved', len(commits), 'commits') | ||
|
||
# load PR for each commit and print summary | ||
for commit in commits: | ||
sha = commit['sha'] | ||
msg_lines = commit['commit']['message'].split('\n') | ||
msg = msg_lines[0] | ||
req = Request(pulls_url.format(commits_url=commits_url,commit_sha=sha)) | ||
req.add_header('accept', accept_header) | ||
req.add_header('Authorization', 'token {token}'.format(token=token)) | ||
pulls = json.loads(urlopen(req).read()) | ||
if len(pulls) > 1: | ||
print("More than one pull request for commit {commit}".format(commit=sha)) | ||
# TODO handle commits without pull requests | ||
pull = pulls[0] | ||
pull_no = pull['number'] | ||
pull_url = pull['html_url'] | ||
author = pull['user']['login'] | ||
author_url = pull['user']['html_url'] | ||
msg = msg.replace('(#{pull})'.format(pull=pull_no), '').strip() | ||
print('* {msg} ([@{author}]({author_url}) in [#{pull}]({pull_url}))'.format( | ||
msg=msg, | ||
author=author, | ||
author_url=author_url, | ||
pull=pull_no, | ||
pull_url=pull_url, | ||
)) | ||
|
||
def num_commits_since_prev_tag(token, base_url): | ||
tags_url = f"{base_url}/tags" | ||
trunk = "master" | ||
|
||
req = Request(tags_url) | ||
req.add_header("Authorization", f"token {token}") | ||
tags = json.loads(urlopen(req).read()) | ||
prev_release_tag = tags[0]['name'] | ||
compare_url = f"{base_url}/compare/{trunk}...{prev_release_tag}" | ||
req = Request(compare_url) | ||
req.add_header("Authorization", f"token {token}") | ||
compare_results = json.loads(urlopen(req).read()) | ||
num_commits = compare_results['behind_by'] | ||
|
||
print(f"There are {num_commits} new commits since {prev_release_tag}") | ||
return num_commits | ||
|
||
|
||
def main(token, repo, num_commits, exclude_dependabot): | ||
accept_header = "application/vnd.github.groot-preview+json" | ||
base_url = f"https://api.github.com/repos/jaegertracing/{repo}" | ||
commits_url = f"{base_url}/commits" | ||
skipped_dependabot = 0 | ||
|
||
# If num_commits isn't set, get the number of commits made since the previous release tag. | ||
if not num_commits: | ||
num_commits = num_commits_since_prev_tag(token, base_url) | ||
|
||
if not num_commits: | ||
return | ||
|
||
# Load commits | ||
data = urllib.parse.urlencode({'per_page': num_commits}) | ||
req = Request(commits_url + '?' + data) | ||
print(req.full_url) | ||
req.add_header('Authorization', f'token {token}') | ||
commits = json.loads(urlopen(req).read()) | ||
print('Retrieved', len(commits), 'commits') | ||
|
||
# Load PR for each commit and print summary | ||
for commit in commits: | ||
sha = commit['sha'] | ||
author = commit['author']['login'] | ||
|
||
if exclude_dependabot and author == "dependabot[bot]": | ||
skipped_dependabot += 1 | ||
continue | ||
|
||
author_url = commit['author']['html_url'] | ||
msg_lines = commit['commit']['message'].split('\n') | ||
msg = msg_lines[0] | ||
req = Request(f"{commits_url}/{sha}/pulls") | ||
req.add_header('accept', accept_header) | ||
req.add_header('Authorization', f'token {token}') | ||
pulls = json.loads(urlopen(req).read()) | ||
if len(pulls) > 1: | ||
print(f"WARNING: More than one pull request for commit {sha}") | ||
|
||
# Handle commits without pull requests. | ||
if not pulls: | ||
short_sha = sha[:7] | ||
commit_url = commit['html_url'] | ||
print(f'* {msg} ([@{author}]({author_url}) in [{short_sha}]({commit_url}))') | ||
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}))') | ||
|
||
if skipped_dependabot: | ||
print(f"\n(Skipped {skipped_dependabot} dependabot commit{'' if skipped_dependabot == 1 else 's'})") | ||
|
||
|
||
if __name__ == "__main__": | ||
parser = argparse.ArgumentParser(description='List changes based on git log for release notes.') | ||
|
||
parser.add_argument('--token-file', type=str, default="~/.github_token", | ||
help='The file containing your personal github token to access the github API. ' + | ||
'(default: ~/.github_token)') | ||
parser.add_argument('--repo', type=str, default='jaeger', | ||
help='The repository name to fetch commit logs from. (default: jaeger)') | ||
parser.add_argument('--exclude-dependabot', action='store_true', | ||
help='Excludes dependabot commits. (default: false)') | ||
parser.add_argument('--num-commits', type=int, | ||
help='Print this number of commits from git log. ' + | ||
'(default: number of commits before the previous tag)') | ||
|
||
args = parser.parse_args() | ||
generate_token_url = "https://github.com/settings/tokens/new?description=GitHub%20Changelog%20Generator%20token" | ||
generate_err_msg = (f"Please generate a token from this URL: {generate_token_url} and " | ||
f"place it in the token-file. Protect the file so only you can read it: chmod 0600 <file>.") | ||
|
||
token_file = expanduser(args.token_file) | ||
|
||
if not os.path.exists(token_file): | ||
eprint(f"No such token-file: {token_file}.\n{generate_err_msg}") | ||
sys.exit(1) | ||
|
||
with open(token_file, 'r') as file: | ||
token = file.read().replace('\n', '') | ||
|
||
if not token: | ||
eprint(f"{token_file} is missing your personal github token.\n{generate_err_msg}") | ||
sys.exit(1) | ||
|
||
main(token, args.repo, args.num_commits, args.exclude_dependabot) |