Skip to content

Commit 82e8581

Browse files
authored
[tool]Release issue status statistics tool (Azure#19617)
* release issue status * fix directory * debug * debug * update git repo * add storage account * delete surplus git commit * add env var * debug * code format
1 parent 680d66f commit 82e8581

File tree

3 files changed

+206
-0
lines changed

3 files changed

+206
-0
lines changed

scripts/release_issue_status/main.py

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
import time
2+
import os
3+
import re
4+
from github import Github
5+
from datetime import date, datetime
6+
import subprocess as sp
7+
from azure.storage.blob import BlobClient
8+
9+
_NULL = ' '
10+
_FILE_OUT = 'release_issue_status.csv'
11+
12+
13+
def my_print(cmd):
14+
print('==' + cmd + ' ==\n')
15+
16+
17+
def print_check(cmd):
18+
my_print(cmd)
19+
sp.check_call(cmd, shell=True)
20+
21+
22+
class IssueStatus:
23+
link = _NULL
24+
author = _NULL
25+
package = _NULL
26+
create_date = 0.0
27+
delay_from_create_date = 0
28+
latest_update = 0.0
29+
delay_from_latest_update = 0
30+
status = 'confirm'
31+
bot_advice = _NULL
32+
comment_num = 0
33+
language = _NULL
34+
author_latest_comment = _NULL
35+
36+
def output(self):
37+
return '{},{},{},{},{},{},{},{},{},{}\n'.format(self.language, self.link, self.author,
38+
self.package,
39+
str(date.fromtimestamp(self.create_date)),
40+
self.delay_from_create_date,
41+
str(date.fromtimestamp(self.latest_update)),
42+
self.delay_from_latest_update,
43+
self.status, self.bot_advice)
44+
45+
46+
def _extract(str_list, key_word):
47+
for item in str_list:
48+
if re.fullmatch(key_word, item):
49+
return item.strip()
50+
return _NULL
51+
52+
53+
def _time_format_transform(time_gmt):
54+
return str(datetime.strptime(time_gmt, '%a, %d %b %Y %H:%M:%S GMT'))
55+
56+
57+
def _judge_status(labels):
58+
for label in labels:
59+
if label.name == 'release':
60+
return 'release'
61+
return 'confirm'
62+
63+
64+
def _extract_language(labels):
65+
language = {'Python', 'JS', 'Go', 'Java', 'Ruby'}
66+
label_set = {label.name for label in labels}
67+
intersect = language.intersection(label_set)
68+
return _NULL if not intersect else intersect.pop()
69+
70+
71+
def _key_select(item):
72+
return item.package
73+
74+
75+
def _extract_author_latest_comment(comments):
76+
q = [(comment.updated_at.timestamp(), comment.user.login) for comment in comments]
77+
q.sort()
78+
79+
return _NULL if not q else q[-1][1]
80+
81+
82+
def main():
83+
# get latest issue status
84+
g = Github(os.getenv('TOKEN')) # please fill user_token
85+
repo = g.get_repo('Azure/sdk-release-request')
86+
label1 = repo.get_label('ManagementPlane')
87+
open_issues = repo.get_issues(state='open', labels=[label1])
88+
issue_status = []
89+
duplicated_issue = dict()
90+
start_time = time.time()
91+
for item in open_issues:
92+
if not item.number:
93+
continue
94+
issue = IssueStatus()
95+
issue.link = f'https://github.com/Azure/sdk-release-request/issues/{item.number}'
96+
issue.author = item.user.login
97+
issue.package = _extract(item.body.split('\n'), 'azure-.*')
98+
issue.create_date = item.created_at.timestamp()
99+
issue.delay_from_create_date = int((time.time() - item.created_at.timestamp()) / 3600 / 24)
100+
issue.latest_update = item.updated_at.timestamp()
101+
issue.delay_from_latest_update = int((time.time() - item.updated_at.timestamp()) / 3600 / 24)
102+
issue.status = _judge_status(item.labels)
103+
issue.comment_num = item.comments
104+
issue.language = _extract_language(item.labels)
105+
issue.author_latest_comment = _extract_author_latest_comment(item.get_comments())
106+
107+
issue_status.append(issue)
108+
key = (issue.language, issue.package)
109+
duplicated_issue[key] = duplicated_issue.get(key, 0) + 1
110+
111+
my_print('Have cost {} seconds'.format(int(time.time() - start_time)))
112+
113+
# rule1: if status is 'release', need to release asap
114+
# rule2: if latest comment is from author, need response asap
115+
# rule3: if comment num is 0, it is new issue, better to deal with it asap
116+
# rule4: if delay from latest update is over 7 days, better to deal with it soon.
117+
# rule5: if delay from created date is over 30 days, better to close.
118+
for item in issue_status:
119+
if item.status == 'release':
120+
item.bot_advice = 'better to release asap.'
121+
elif item.author == item.author_latest_comment:
122+
item.bot_advice = 'new comment for author.'
123+
elif item.comment_num == 0:
124+
item.bot_advice = 'new issue and better to confirm quickly.'
125+
elif item.delay_from_latest_update >= 7:
126+
item.bot_advice = 'delay for a long time and better to handle now.'
127+
elif item.delay_from_create_date >= 30:
128+
item.bot_advice = 'delay for a month and better to close.'
129+
130+
# judge whether there is duplicated issue for same package
131+
if item.package != _NULL and duplicated_issue.get((item.language, item.package)) > 1:
132+
item.bot_advice = f'Warning:There is duplicated issue for {item.package}. ' + item.bot_advice
133+
134+
# output result
135+
with open(_FILE_OUT, 'w') as file_out:
136+
file_out.write('language,issue,author,package,created date,delay from created date,latest update time,'
137+
'delay from latest update,status,bot advice\n')
138+
file_out.writelines([item.output() for item in sorted(issue_status, key=_key_select)])
139+
140+
# commit to github
141+
print_check('git add .')
142+
print_check('git commit -m \"update excel\"')
143+
print_check('git push -f origin HEAD')
144+
145+
# upload to storage account(it is created in advance)
146+
blob = BlobClient.from_connection_string(conn_str=os.getenv('CONN_STR'), container_name=os.getenv('FILE'),
147+
blob_name=_FILE_OUT)
148+
with open(_FILE_OUT, 'rb') as data:
149+
blob.upload_blob(data, overwrite=True)
150+
151+
152+
if __name__ == '__main__':
153+
main()
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Release status statistics
2+
3+
name: ReleaseIssueStatus
4+
5+
trigger:
6+
branches:
7+
exclude:
8+
- '*'
9+
10+
11+
jobs:
12+
- job: ReleaseIssueStatus
13+
displayName: ReleaseIssueStatus Python 3.8
14+
timeoutInMinutes: 30
15+
strategy:
16+
maxParallel: 3
17+
pool:
18+
vmImage: 'ubuntu-20.04'
19+
steps:
20+
- task: UsePythonVersion@0
21+
inputs:
22+
versionSpec: '3.8'
23+
addToPath: true
24+
architecture: 'x64'
25+
- bash: |
26+
script_path=$(pwd)/scripts/release_issue_status
27+
cd ..
28+
git config --global user.email "ReleaseIssueStatus"
29+
git config --global user.name "ReleaseIssueStatus"
30+
31+
# clone(REPO: https://github.com/Azure/azure-sdk-for-python.git, USR_NAME: Azure, USR_TOKEN: xxxxxxxxxxxxx)
32+
mkdir file-storage
33+
git clone ${REPO:0:8}$(USR_NAME):$(USR_TOKEN)@${REPO:8} $(pwd)/file-storage
34+
35+
# import env variable
36+
export CONN_STR=$(ENV_CONN_STR)
37+
export FILE=$(ENV_FILE)
38+
export TOKEN=$(USR_TOKEN)
39+
40+
# create virtual env
41+
python -m venv venv-sdk
42+
source venv-sdk/bin/activate
43+
pip install -r $script_path/requirement.txt
44+
45+
# checkout the target branch
46+
cd file-storage
47+
git checkout release-issue-status
48+
49+
# run
50+
python $script_path/main.py
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
PyGithub
2+
datetime
3+
azure.storage.blob==12.8.1

0 commit comments

Comments
 (0)