1- from github import Github , Repository , GithubException
21import csv
2+ import requests
3+ import json
4+ import pytz
5+
6+ from github import Github , Repository , GithubException , PullRequest
37
48EMPTY_FIELD = 'Empty field'
9+ timezone = 'Europe/Moscow'
510
611def login (token ):
712 client = Github (login_or_token = token )
13+
814 try :
915 client .get_user ().login
1016 except GithubException as err :
@@ -30,8 +36,27 @@ def get_next_repo(client: Github, repositories):
3036 yield repo
3137
3238
39+ def get_assignee_story (github_object ):
40+ assignee_result = ""
41+ events = github_object .get_issue_events () if type (
42+ github_object ) is PullRequest .PullRequest else github_object .get_events ()
43+ for event in events :
44+ if event .event == "assigned" or event .event == "unassigned" :
45+ date = event .created_at
46+ if event .event == "assigned" :
47+ assigner = github_object .user .login
48+ assignee = event .assignee .login
49+ assignee_result += f"{ date } : { assigner } -> { assignee } ; "
50+ else :
51+ assigner = github_object .user .login
52+ assignee = event .assignee .login
53+ assignee_result += f"{ date } : { assigner } -/> { assignee } ; "
54+ return assignee_result
55+
56+
3357def log_commit_to_csv (info , csv_name ):
34- fieldnames = ['repository name' , 'commit id' , 'author name' , 'author login' , 'author email' , 'date and time' , 'changed files' ]
58+ fieldnames = ['repository name' , 'commit id' , 'author name' , 'author login' , 'author email' , 'date and time' ,
59+ 'changed files' ]
3560 with open (csv_name , 'a' , newline = '' ) as file :
3661 writer = csv .DictWriter (file , fieldnames = fieldnames )
3762 writer .writerow (info )
@@ -41,16 +66,20 @@ def log_commit_to_stdout(info):
4166 print (info )
4267
4368
44- def log_repository_commits (repository : Repository , csv_name ):
69+ def log_repository_commits (repository : Repository , csv_name , start , finish ):
4570 for commit in repository .get_commits ():
71+ if commit .commit .author .date .astimezone (
72+ pytz .timezone (timezone )) < start or commit .commit .author .date .astimezone (
73+ pytz .timezone (timezone )) > finish :
74+ continue
4675 if commit .commit is not None :
4776 info = {'repository name' : repository .full_name ,
48- 'commit id' : commit .commit .sha ,
4977 'author name' : commit .commit .author .name ,
5078 'author login' : EMPTY_FIELD ,
5179 'author email' : EMPTY_FIELD ,
5280 'date and time' : commit .commit .author .date ,
53- 'changed files' : '; ' .join ([file .filename for file in commit .files ])}
81+ 'changed files' : '; ' .join ([file .filename for file in commit .files ]),
82+ 'commit id' : commit .commit .sha }
5483
5584 if commit .author is not None :
5685 info ['author login' ] = commit .author .login
@@ -65,7 +94,9 @@ def log_repository_commits(repository: Repository, csv_name):
6594def log_issue_to_csv (info , csv_name ):
6695 fieldnames = ['repository name' , 'number' , 'title' , 'state' , 'task' , 'created at' , 'creator name' , 'creator login' ,
6796 'creator email' , 'closer name' , 'closer login' , 'closer email' , 'closed at' , 'comment body' ,
68- 'comment created at' , 'comment author name' , 'comment author login' , 'comment author email' ]
97+ 'comment created at' , 'comment author name' , 'comment author login' , 'comment author email' ,
98+ 'assignee story' , 'connected pull requests' ]
99+
69100 with open (csv_name , 'a' , newline = '' ) as file :
70101 writer = csv .DictWriter (file , fieldnames = fieldnames )
71102 writer .writerow (info )
@@ -75,8 +106,72 @@ def log_issue_to_stdout(info):
75106 print (info )
76107
77108
78- def log_repository_issues (repository : Repository , csv_name ):
109+ def get_connected_pulls (issue_number , repo_owner , repo_name , token ):
110+ access_token = token
111+ repo_owner = repo_owner .login
112+ # Формирование запроса GraphQL
113+ query = """
114+ {
115+ repository(owner: "%s", name: "%s") {
116+ issue(number: %d) {
117+ timelineItems(first: 50, itemTypes:[CONNECTED_EVENT,CROSS_REFERENCED_EVENT]) {
118+ filteredCount
119+ nodes {
120+ ... on ConnectedEvent {
121+ ConnectedEvent: subject {
122+ ... on PullRequest {
123+ number
124+ title
125+ url
126+ }
127+ }
128+ }
129+ ... on CrossReferencedEvent {
130+ CrossReferencedEvent: source {
131+ ... on PullRequest {
132+ number
133+ title
134+ url
135+ }
136+ }
137+ }
138+ }
139+ }
140+ }
141+ }
142+ }""" % (repo_owner , repo_name , issue_number )
143+
144+ # Формирование заголовков запроса
145+ headers = {
146+ "Authorization" : f"Bearer { access_token } " ,
147+ "Content-Type" : "application/json"
148+ }
149+
150+ # Отправка запроса GraphQL
151+ response = requests .post ("https://api.github.com/graphql" , headers = headers , data = json .dumps ({"query" : query }))
152+ response_data = response .json ()
153+ # Обработка полученных данных
154+ pull_request_data = response_data ["data" ]["repository" ]["issue" ]
155+ list_url = []
156+ if (pull_request_data is not None ):
157+ issues_data = pull_request_data ["timelineItems" ]["nodes" ]
158+ for pulls in issues_data :
159+ if (pulls .get ("CrossReferencedEvent" ) != None and pulls .get ("CrossReferencedEvent" ).get ("url" ) not in list_url ) :
160+ list_url .append (pulls .get ("CrossReferencedEvent" ).get ("url" ))
161+ if (pulls .get ("ConnectedEvent" ) != None and pulls .get ("ConnectedEvent" ).get ("url" ) not in list_url ):
162+ list_url .append (pulls .get ("ConnectedEvent" ).get ("url" ))
163+ if (list_url == []):
164+ return 'Empty field'
165+ else :
166+ return list_url
167+ return 'Empty field'
168+
169+
170+ def log_repository_issues (repository : Repository , csv_name , token , start , finish ):
79171 for issue in repository .get_issues (state = 'all' ):
172+ if issue .created_at .astimezone (pytz .timezone (timezone )) < start or issue .created_at .astimezone (
173+ pytz .timezone (timezone )) > finish :
174+ continue
80175 info_tmp = {
81176 'repository name' : repository .full_name , 'number' : issue .number , 'title' : issue .title ,
82177 'state' : issue .state , 'task' : issue .body ,
@@ -93,16 +188,23 @@ def log_repository_issues(repository: Repository, csv_name):
93188 'comment author name' : EMPTY_FIELD ,
94189 'comment author login' : EMPTY_FIELD ,
95190 'comment author email' : EMPTY_FIELD ,
191+ 'assignee story' : EMPTY_FIELD ,
192+ 'connected pull requests' : EMPTY_FIELD
96193 }
194+ if issue .number is not None :
195+ info_tmp ['connected pull requests' ] = get_connected_pulls (issue .number , repository .owner , repository .name ,
196+ token )
197+
198+ info_tmp ['assignee story' ] = get_assignee_story (issue )
97199
98200 if issue .user is not None :
99201 info_tmp ['creator name' ] = issue .user .name
100202 info_tmp ['creator login' ] = issue .user .login
101203
102204 if issue .closed_by is not None :
103205 info_tmp ['closed at' ] = issue .closed_at
104- info_tmp ['creator name' ] = issue .closed_by .name
105- info_tmp ['creator login' ] = issue .user .login
206+ info_tmp ['closer name' ] = issue .closed_by .name
207+ info_tmp ['closer login' ] = issue .user .login
106208
107209 if issue .get_comments ().totalCount > 0 :
108210 for comment in issue .get_comments ():
@@ -120,10 +222,11 @@ def log_repository_issues(repository: Repository, csv_name):
120222
121223
122224def log_pr_to_csv (info , csv_name ):
123- fieldnames = ['repository name' , 'title' , 'state' , 'commit into' , 'commit from' , 'created at' , 'creator name' ,
225+ fieldnames = ['repository name' , 'title' , 'id' , ' state' , 'commit into' , 'commit from' , 'created at' , 'creator name' ,
124226 'creator login' , 'creator email' ,
125227 'changed files' , 'comment body' , 'comment created at' , 'comment author name' , 'comment author login' ,
126- 'comment author email' , 'merger name' , 'merger login' , 'merger email' , 'source branch' , 'target branch' ]
228+ 'comment author email' , 'merger name' , 'merger login' , 'merger email' , 'source branch' ,
229+ 'target branch' , 'assignee story' , 'related issues' ]
127230 with open (csv_name , 'a' , newline = '' ) as file :
128231 writer = csv .DictWriter (file , fieldnames = fieldnames )
129232 writer .writerow (info )
@@ -133,11 +236,61 @@ def log_pr_to_stdout(info):
133236 print (info )
134237
135238
136- def log_repositories_pr (repository : Repository , csv_name ):
239+ def get_related_issues (pull_request_number , repo_owner , repo_name , token ):
240+ access_token = token
241+ repo_owner = repo_owner .login
242+
243+ # Формирование запроса GraphQL
244+ query = """
245+ {
246+ repository(owner: "%s", name: "%s") {
247+ pullRequest(number: %d) {
248+ id
249+ closingIssuesReferences(first: 50) {
250+ edges {
251+ node {
252+ id
253+ body
254+ number
255+ title
256+ url
257+ }
258+ }
259+ }
260+ }
261+ }
262+ }
263+ """ % (repo_owner , repo_name , pull_request_number )
264+
265+ # Формирование заголовков запроса
266+ headers = {
267+ "Authorization" : f"Bearer { access_token } " ,
268+ "Content-Type" : "application/json"
269+ }
270+
271+ # Отправка запроса GraphQL
272+ response = requests .post ("https://api.github.com/graphql" , headers = headers , data = json .dumps ({"query" : query }))
273+ response_data = response .json ()
274+ # Обработка полученных данных
275+ pull_request_data = response_data ["data" ]["repository" ]["pullRequest" ]
276+ issues_data = pull_request_data ["closingIssuesReferences" ]["edges" ]
277+ list_issues_url = []
278+ # сохранение информации об issues
279+ for issue in issues_data :
280+ issue_node = issue ["node" ]
281+ list_issues_url .append (issue_node ["url" ])
282+ return list_issues_url
283+
284+
285+ def log_repositories_pr (repository : Repository , csv_name , token , start , finish ):
137286 for pull in repository .get_pulls (state = 'all' ):
287+ if pull .created_at .astimezone (pytz .timezone (timezone )) < start or pull .created_at .astimezone (
288+ pytz .timezone (timezone )) > finish :
289+ continue
138290 info_tmp = {
139291 'repository name' : repository .full_name ,
140292 'title' : pull .title ,
293+ 'id' : pull .number ,
141294 'state' : pull .state ,
142295 'commit into' : pull .base .label ,
143296 'commit from' : pull .head .label ,
@@ -156,13 +309,19 @@ def log_repositories_pr(repository: Repository, csv_name):
156309 'merger email' : EMPTY_FIELD ,
157310 'source branch' : pull .head .ref ,
158311 'target branch' : pull .base .ref ,
312+ 'assignee story' : EMPTY_FIELD ,
313+ 'related issues' : EMPTY_FIELD
159314 }
315+ if pull .issue_url is not None :
316+ info_tmp ['related issues' ] = get_related_issues (pull .number , repository .owner , repository .name , token )
160317
161318 if pull .merged_by is not None :
162319 info_tmp ['merger name' ] = pull .merged_by .name
163320 info_tmp ['merger login' ] = pull .merged_by .login
164321 info_tmp ['merger email' ] = pull .merged_by .email
165322
323+ info_tmp ['assignee story' ] = get_assignee_story (pull )
324+
166325 if pull .get_comments ().totalCount > 0 :
167326 for comment in pull .get_comments ():
168327 info = info_tmp
@@ -178,13 +337,14 @@ def log_repositories_pr(repository: Repository, csv_name):
178337 log_pr_to_stdout (info_tmp )
179338
180339
181- def log_pull_requests (client : Github , repositories , csv_name ):
340+ def log_pull_requests (client : Github , repositories , csv_name , token , start , finish ):
182341 with open (csv_name , 'w' , newline = '' ) as file :
183342 writer = csv .writer (file )
184343 writer .writerow (
185344 (
186345 'repository name' ,
187346 'title' ,
347+ 'id' ,
188348 'state' ,
189349 'commit into' ,
190350 'commit from' ,
@@ -203,14 +363,17 @@ def log_pull_requests(client: Github, repositories, csv_name):
203363 'merger email' ,
204364 'source branch' ,
205365 'target branch' ,
366+ 'related issues'
367+ 'assignee story' ,
368+ 'related issues'
206369 )
207370 )
208371
209372 for repo in get_next_repo (client , repositories ):
210- log_repositories_pr (repo , csv_name )
373+ log_repositories_pr (repo , csv_name , token , start , finish )
211374
212375
213- def log_issues (client : Github , repositories , csv_name ):
376+ def log_issues (client : Github , repositories , csv_name , token , start , finish ):
214377 with open (csv_name , 'w' , newline = '' ) as file :
215378 writer = csv .writer (file )
216379 writer .writerow (
@@ -222,36 +385,41 @@ def log_issues(client: Github, repositories, csv_name):
222385 'task' ,
223386 'created at' ,
224387 'creator name' ,
388+ 'creator login' ,
225389 'creator email' ,
226390 'closer name' ,
391+ 'closer login' ,
227392 'closer email' ,
228393 'closed at' ,
229394 'comment body' ,
230395 'comment created at' ,
231396 'comment author name' ,
232397 'comment author login' ,
233398 'comment author email' ,
399+ 'connected pull requests'
400+ 'assignee story' ,
401+ 'connected pull requests'
234402 )
235403 )
236404
237405 for repo in get_next_repo (client , repositories ):
238- log_repository_issues (repo , csv_name )
406+ log_repository_issues (repo , csv_name , token , start , finish )
239407
240408
241- def log_commits (client : Github , repositories , csv_name ):
409+ def log_commits (client : Github , repositories , csv_name , start , finish ):
242410 with open (csv_name , 'w' , newline = '' ) as file :
243411 writer = csv .writer (file )
244412 writer .writerow (
245413 (
246414 'repository name' ,
247- 'commit id' ,
248415 'author name' ,
249416 'author login' ,
250417 'author email' ,
251418 'date and time' ,
252419 'changed files' ,
420+ 'commit id'
253421 )
254422 )
255423
256424 for repo in get_next_repo (client , repositories ):
257- log_repository_commits (repo , csv_name )
425+ log_repository_commits (repo , csv_name , start , finish )
0 commit comments