1
+ import os
2
+ import re
3
+ import requests
4
+
5
+ ORG_NAME = 'ydb-platform'
6
+ PROJECT_ID = '45'
7
+ query_template = """
8
+ {
9
+ organization(login: "%s") {
10
+ projectV2(number: %s) {
11
+ id
12
+ title
13
+ items(first: 100, after: %s) {
14
+ nodes {
15
+ content {
16
+ ... on Issue {
17
+ id
18
+ title
19
+ url
20
+ state
21
+ body
22
+ createdAt
23
+ }
24
+ }
25
+ fieldValues(first: 20) {
26
+ nodes {
27
+ ... on ProjectV2ItemFieldSingleSelectValue {
28
+ field {
29
+ ... on ProjectV2SingleSelectField {
30
+ name
31
+ }
32
+ }
33
+ name
34
+ id
35
+ updatedAt
36
+ }
37
+ ... on ProjectV2ItemFieldLabelValue {
38
+ labels(first: 20) {
39
+ nodes {
40
+ id
41
+ name
42
+ }
43
+ }
44
+ }
45
+ ... on ProjectV2ItemFieldTextValue {
46
+ text
47
+ id
48
+ updatedAt
49
+ creator {
50
+ url
51
+ }
52
+ }
53
+ ... on ProjectV2ItemFieldMilestoneValue {
54
+ milestone {
55
+ id
56
+ }
57
+ }
58
+ ... on ProjectV2ItemFieldRepositoryValue {
59
+ repository {
60
+ id
61
+ url
62
+ }
63
+ }
64
+ }
65
+ }
66
+ }
67
+ pageInfo {
68
+ hasNextPage
69
+ endCursor
70
+ }
71
+ }
72
+ }
73
+ }
74
+ }
75
+ """
76
+
77
+
78
+ def run_query (query , headers ):
79
+ request = requests .post ('https://api.github.com/graphql' , json = {'query' : query }, headers = headers )
80
+ if request .status_code == 200 :
81
+ return request .json ()
82
+ else :
83
+ raise Exception (f"Query failed to run by returning code of { request .status_code } . { query } " )
84
+
85
+
86
+ def fetch_all_issues (org_name , project_id ):
87
+ issues = []
88
+ has_next_page = True
89
+ end_cursor = "null"
90
+
91
+ while has_next_page :
92
+ query = query_template % (org_name , project_id , end_cursor )
93
+ GITHUB_TOKEN = os .environ ["GITHUB_TOKEN" ]
94
+ headers = {"Authorization" : f"Bearer { GITHUB_TOKEN } " }
95
+ result = run_query (query , headers )
96
+
97
+ if result :
98
+ project_items = result ['data' ]['organization' ]['projectV2' ]['items' ]
99
+ issues .extend (project_items ['nodes' ])
100
+
101
+ page_info = project_items ['pageInfo' ]
102
+ has_next_page = page_info ['hasNextPage' ]
103
+ end_cursor = f"\" { page_info ['endCursor' ]} \" " if page_info ['endCursor' ] else "null"
104
+ else :
105
+ has_next_page = False
106
+
107
+ return issues
108
+
109
+
110
+ def parse_body (body ):
111
+ tests = []
112
+ branches = []
113
+ prepared_body = ''
114
+ start_mute_list = "<!--mute_list_start-->"
115
+ end_mute_list = "<!--mute_list_end-->"
116
+ start_branch_list = "<!--branch_list_start-->"
117
+ end_branch_list = "<!--branch_list_end-->"
118
+
119
+ # tests
120
+ if all (x in body for x in [start_mute_list , end_mute_list ]):
121
+ idx1 = body .find (start_mute_list )
122
+ idx2 = body .find (end_mute_list )
123
+ lines = body [idx1 + len (start_mute_list ) + 1 : idx2 ].split ('\n ' )
124
+ else :
125
+ if body .startswith ('Mute:' ):
126
+ prepared_body = body .split ('Mute:' , 1 )[1 ].strip ()
127
+ elif body .startswith ('Mute' ):
128
+ prepared_body = body .split ('Mute' , 1 )[1 ].strip ()
129
+ elif body .startswith ('ydb' ):
130
+ prepared_body = body
131
+ lines = prepared_body .split ('**Add line to' )[0 ].split ('\n ' )
132
+ tests = [line .strip () for line in lines if line .strip ().startswith ('ydb/' )]
133
+
134
+ # branch
135
+ if all (x in body for x in [start_branch_list , end_branch_list ]):
136
+ idx1 = body .find (start_branch_list )
137
+ idx2 = body .find (end_branch_list )
138
+ branches = body [idx1 + len (start_branch_list ) + 1 : idx2 ].split ('\n ' )
139
+ else :
140
+ branches = ['main' ]
141
+
142
+ return tests , branches
143
+
144
+
145
+ def get_issues_and_tests_from_project (ORG_NAME , PROJECT_ID ):
146
+ issues = fetch_all_issues (ORG_NAME , PROJECT_ID )
147
+ issues_prepared = {}
148
+ for issue in issues :
149
+ content = issue ['content' ]
150
+ if content :
151
+ body = content ['body' ]
152
+
153
+ # for debug
154
+ if content ['id' ] == 'I_kwDOGzZjoM6V3BoE' :
155
+ print (1 )
156
+ #
157
+
158
+ tests , branches = parse_body (body )
159
+
160
+ field_values = issue .get ('fieldValues' , {}).get ('nodes' , [])
161
+ for field_value in field_values :
162
+ field_name = field_value .get ('field' , {}).get ('name' , '' ).lower ()
163
+
164
+ if field_name == "status" and 'name' in field_value :
165
+ status = field_value .get ('name' , 'N/A' )
166
+ status_updated = field_value .get ('updatedAt' , '1970-01-0901T00:00:01Z' )
167
+ elif field_name == "owner" and 'name' in field_value :
168
+ owner = field_value .get ('name' , 'N/A' )
169
+
170
+ print (f"Issue ID: { content ['id' ]} " )
171
+ print (f"Title: { content ['title' ]} " )
172
+ print (f"URL: { content ['url' ]} " )
173
+ print (f"State: { content ['state' ]} " )
174
+ print (f"CreatedAt: { content ['createdAt' ]} " )
175
+ print (f"Status: { status } " )
176
+ print (f"Status updated: { status_updated } " )
177
+ print (f"Owner: { owner } " )
178
+ print ("Tests:" )
179
+
180
+ issues_prepared [content ['id' ]] = {}
181
+ issues_prepared [content ['id' ]]['title' ] = content ['title' ]
182
+ issues_prepared [content ['id' ]]['url' ] = content ['url' ]
183
+ issues_prepared [content ['id' ]]['state' ] = content ['state' ]
184
+ issues_prepared [content ['id' ]]['createdAt' ] = content ['createdAt' ]
185
+ issues_prepared [content ['id' ]]['status_updated' ] = status_updated
186
+ issues_prepared [content ['id' ]]['status' ] = status
187
+ issues_prepared [content ['id' ]]['owner' ] = owner
188
+ issues_prepared [content ['id' ]]['tests' ] = []
189
+ issues_prepared [content ['id' ]]['branches' ] = branches
190
+
191
+ for test in tests :
192
+ issues_prepared [content ['id' ]]['tests' ].append (test )
193
+ print (f"- { test } " )
194
+ print ('\n ' )
195
+
196
+ return issues_prepared
197
+
198
+
199
+ def get_muted_tests ():
200
+ issues = get_issues_and_tests_from_project (ORG_NAME , PROJECT_ID )
201
+ muted_tests = {}
202
+ for issue in issues :
203
+ if issues [issue ]["status" ] == "Muted" :
204
+ for test in issues [issue ]['tests' ]:
205
+ if test not in muted_tests :
206
+ muted_tests [test ] = []
207
+ muted_tests [test ].append (
208
+ {
209
+ 'url' : issues [issue ]['url' ],
210
+ 'createdAt' : issues [issue ]['createdAt' ],
211
+ 'status_updated' : issues [issue ]['status_updated' ],
212
+ }
213
+ )
214
+
215
+ return muted_tests
216
+
217
+
218
+ def main ():
219
+ if "GITHUB_TOKEN" not in os .environ :
220
+ print ("Error: Env variable GITHUB_TOKEN is missing, skipping" )
221
+ return 1
222
+ get_muted_tests ()
223
+
224
+
225
+ if __name__ == "__main__" :
226
+ main ()
0 commit comments