Skip to content

Commit 7f48808

Browse files
benedikt-voelkelBenedikt Volkel
andauthored
Add tool to fetch PR information based on assigned labels (#1478)
* applicable to different repos * distinguishes between merged and other (simply closed or still open) PRs * dumps the output into a simple text file for further proessing Co-authored-by: Benedikt Volkel <benedikt.volkel@cern.ch>
1 parent d24070e commit 7f48808

File tree

1 file changed

+141
-0
lines changed

1 file changed

+141
-0
lines changed
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
#!/usr/bin/env python3
2+
3+
# Get list of PRs from provided repo that have a certain label assigned
4+
# Can be used to figure out which PRs should be ported
5+
6+
import sys
7+
import argparse
8+
import requests
9+
10+
11+
def organise_prs(prs):
12+
"""
13+
Sort PRs by time merged, starting from old to recent
14+
"""
15+
# collect merged PRs
16+
prs_merged = []
17+
# collect the time of merged PRs
18+
merged_at = []
19+
# other PRs, open, closed and not merged
20+
prs_other = []
21+
22+
for pr in prs:
23+
if not pr['merged_at']:
24+
# that has not been merged
25+
prs_other.append(pr)
26+
continue
27+
# get the PR itself and the merged timestamp
28+
prs_merged.append(pr)
29+
merged_at.append(pr['merged_at'])
30+
31+
# sort the merged PRs by their merged timestamp
32+
prs_merged = [pr for _, pr in sorted(zip(merged_at, prs))]
33+
34+
return prs_merged, prs_other
35+
36+
37+
def get_prs(owner, repo, prod_label, pr_state, include_unmerged, per_page=50, start_page=1, pages=1):
38+
"""
39+
Get PRs according to some selection
40+
"""
41+
# GitHub API endpoint for listing closed pull requests with a specific label
42+
merged_token = '&is:merged=true' if not include_unmerged else ''
43+
prs_return = []
44+
45+
has_error = False
46+
for page in range(start_page, pages + 1):
47+
url = f'https://api.github.com/repos/{owner}/{repo}/pulls?state={pr_state}{merged_token}&page={page}&per_page={per_page}'
48+
print(f'Fetch PRs accrodring to {url}')
49+
50+
# Send GET request to GitHub API
51+
response = requests.get(url)
52+
53+
# Check if the request was successful (status code 200)
54+
if response.status_code == 200:
55+
# Parse JSON response
56+
prs = response.json()
57+
# PRs to return because we filter on a specific label
58+
for pr in prs:
59+
labels = pr['labels']
60+
accept = False
61+
for label in labels:
62+
if label['name'] == prod_label:
63+
# only with the correct the label will be accepted
64+
accept = True
65+
break
66+
if not accept:
67+
continue
68+
# we will end up here if accepted, so append
69+
prs_return.append(pr)
70+
71+
else:
72+
print(f'Failed to retrieve data: {response.status_code} - {response.text}')
73+
has_error = True
74+
break
75+
76+
if has_error:
77+
return None, None
78+
79+
# organise PRs into different lists (merged and others)
80+
return organise_prs(prs_return)
81+
82+
83+
def make_report(prs_merged, prs_other, outfile):
84+
"""
85+
Make a report
86+
87+
simply dump into text file
88+
"""
89+
90+
with open(outfile, 'w') as f:
91+
f.write('# FROM OLDEST TO RECENT\n')
92+
# our common header
93+
f.write('| Date of next tag | Requestor | Package | PR | Data or MC | Comment | JIRA (if it exists) | Accepted | In production | Validated by requestor |\n')
94+
f.write('| ---------------- | ------------ | ------- | --------------------------------------------------------:|:--------------------------------------------- | ------------------- | ---------------- | ------------- |-------------| ------------------|\n')
95+
96+
# first put the merged PRs
97+
for pr in prs_merged:
98+
mc_data = []
99+
100+
for label in pr['labels']:
101+
if label['name'] in ('MC', 'DATA'):
102+
# get assigned MC or DATA label if this PR has it
103+
mc_data.append(label['name'])
104+
105+
# if no specific MC or DATA label, assume valid for both
106+
mc_data = ','.join(mc_data) if mc_data else 'MC,DATA'
107+
# add the full line to the output file
108+
f.write(f'| {args.date} | {pr["user"]["login"]} | {args.repo} | [PR]({pr["html_url"]}) | {mc_data} | {pr["title"]} | | | | |\n')
109+
110+
# add all the other commits
111+
f.write('OTHER PRs\n')
112+
for pr in prs_other:
113+
f.write(f'| {args.date} | {pr["user"]["login"]} | {args.repo} | [PR]({pr["html_url"]}) | | {pr["title"]} | | | | |\n')
114+
115+
116+
if __name__ == '__main__':
117+
# Parse command-line arguments
118+
parser = argparse.ArgumentParser(description='Retrieve closed pull requests with a specific label from a GitHub repository')
119+
parser.add_argument('--owner', help='GitHub repository owner', default='AliceO2Group')
120+
parser.add_argument('--repo', required=True, help='GitHub repository name, e.g. O2DPG or AliceO2')
121+
parser.add_argument('--prod-label', dest='prod_label', required=True, help='Production label to filter PRs')
122+
parser.add_argument('--pr-state', dest='pr_state', default='closed', help='The state of the PR')
123+
parser.add_argument('--include-unmerged', dest='include_unmerged', action='store_true', help='To fetch also unmerged PRs')
124+
parser.add_argument('--output', default='o2dpg_pr_report.txt')
125+
parser.add_argument('--date', help='The date tag to be put', required=True)
126+
parser.add_argument('--per-page', dest='per_page', default=50, help='How many results per page')
127+
parser.add_argument('--start-page', dest='start_page', type=int, default=1, help='Start on this page')
128+
parser.add_argument('--pages', type=int, default=1, help='Number of pages')
129+
130+
131+
args = parser.parse_args()
132+
133+
# Retrieve closed pull requests with the specified label
134+
prs_merged, prs_other = get_prs(args.owner, args.repo, args.prod_label, args.pr_state, args.include_unmerged, args.per_page, args.start_page, args.pages)
135+
if prs_merged is None:
136+
print('ERROR: There was a problem fetching the info.')
137+
sys.exit(1)
138+
139+
make_report(prs_merged, prs_other, args.output)
140+
141+
sys.exit(0)

0 commit comments

Comments
 (0)