18
18
19
19
import os
20
20
import sys
21
- from logging import info , warning , debug , getLogger , INFO , DEBUG
21
+ from logging import info , warning , debug , getLogger , INFO , DEBUG , WARNING
22
22
from json import loads
23
23
from enum import Enum
24
24
from datetime import datetime , timedelta
@@ -152,13 +152,11 @@ def rest_api(self, path_args, method=None, query=''):
152
152
r"""
153
153
Return data obtained from ``gh`` command ``api``.
154
154
"""
155
- s = self ._url .split ('/' )
156
- owner = s [3 ]
157
- repo = s [4 ]
158
155
meth = '-X GET'
159
156
if method :
160
157
meth = '-X %s' % method
161
- cmd = 'gh api %s -H \" Accept: application/vnd.github+json\" /repos/%s/%s/%s %s' % (meth , owner , repo , path_args , query )
158
+ cmd = 'gh api %s -H \" Accept: application/vnd.github+json\" %s %s' % (meth , path_args , query )
159
+ debug ('Execute command: %s' % cmd )
162
160
if method :
163
161
return check_output (cmd , shell = True )
164
162
return loads (check_output (cmd , shell = True ))
@@ -171,11 +169,12 @@ def view(self, key):
171
169
if self ._pr :
172
170
issue = 'pr'
173
171
cmd = 'gh %s view %s --json %s' % (issue , self ._url , key )
172
+ debug ('Execute command: %s' % cmd )
174
173
return loads (check_output (cmd , shell = True ))[key ]
175
174
176
175
def is_open (self ):
177
176
r"""
178
- Return if the issue res. PR is open.
177
+ Return ``True`` if the issue res. PR is open.
179
178
"""
180
179
if self ._open is not None :
181
180
return self ._open
@@ -188,7 +187,7 @@ def is_open(self):
188
187
189
188
def is_draft (self ):
190
189
r"""
191
- Return if the PR is a draft.
190
+ Return ``True`` if the PR is a draft.
192
191
"""
193
192
if self ._draft is not None :
194
193
return self ._draft
@@ -199,22 +198,55 @@ def is_draft(self):
199
198
info ('Issue %s is draft %s' % (self ._issue , self ._draft ))
200
199
return self ._draft
201
200
201
+ def is_auth_team_member (self , login ):
202
+ r"""
203
+ Return ``True`` if the user with given login belongs to an authorized
204
+ team.
205
+ """
206
+ def verify_membership (team ):
207
+ path_args = '/orgs/sagemath/teams/%s/memberships/%s' % (team , login )
208
+ try :
209
+ res = self .rest_api (path_args )
210
+ if res ['state' ] == 'active' and res ['role' ] == 'member' :
211
+ info ('User %s is a member of %s' % (login , team ))
212
+ return True
213
+ except CalledProcessError :
214
+ pass
215
+
216
+ info ('User %s is not a member of %s' % (login , team ))
217
+ return False
218
+
219
+ # check for the Triage team
220
+ if verify_membership ('triage' ):
221
+ return True
222
+
223
+ return False
224
+
225
+ def actor_authorized (self ):
226
+ r"""
227
+ Return ``True`` if the actor belongs to an authorized team.
228
+ """
229
+ return self .is_auth_team_member (self ._actor )
230
+
202
231
def clean_warnings (self ):
203
232
r"""
204
233
Remove all warnings that have been posted by ``GhLabelSynchronizer``
205
234
more than ``warning_lifetime`` ago.
206
235
"""
207
236
warning_lifetime = timedelta (minutes = 5 )
208
- time_frame = timedelta (hours = 12 ) # timedelta to search for comments
237
+ time_frame = timedelta (minutes = 730 ) # timedelta to search for comments including 10 minutes overlap with cron-cycle
209
238
per_page = 100
210
239
today = datetime .today ()
211
240
since = today - time_frame
212
241
query = '-F per_page=%s -F page={} -f since=%s' % (per_page , since .strftime (datetime_format ))
213
- path = 'issues/comments'
242
+ s = self ._url .split ('/' )
243
+ owner = s [3 ]
244
+ repo = s [4 ]
245
+ path_args = '/repos/%s/%s/issues/comments' % (owner , repo )
214
246
page = 1
215
247
comments = []
216
248
while True :
217
- comments_page = self .rest_api (path , query = query .format (page ))
249
+ comments_page = self .rest_api (path_args , query = query .format (page ))
218
250
comments += comments_page
219
251
if len (comments_page ) < per_page :
220
252
break
@@ -236,7 +268,7 @@ def clean_warnings(self):
236
268
debug ('github-actions %s %s is %s old' % (self ._warning_prefix , comment_id , lifetime ))
237
269
if lifetime > warning_lifetime :
238
270
try :
239
- self .rest_api ('%s/%s' % (path , comment_id ), method = 'DELETE' )
271
+ self .rest_api ('%s/%s' % (path_args , comment_id ), method = 'DELETE' )
240
272
info ('Comment %s on issue %s deleted' % (comment_id , issue ))
241
273
except CalledProcessError :
242
274
# the comment may have been deleted by a bot running in parallel
@@ -740,7 +772,7 @@ def run(self, action, label=None, rev_state=None):
740
772
if action is Action .submitted :
741
773
rev_state = RevState (rev_state )
742
774
if rev_state is RevState .approved :
743
- if self .positive_review_valid ():
775
+ if self .actor_authorized () and self . positive_review_valid ():
744
776
self .select_label (State .positive_review )
745
777
746
778
if rev_state is RevState .changes_requested :
@@ -799,44 +831,75 @@ def run_tests(self):
799
831
###############################################################################
800
832
# Main
801
833
###############################################################################
834
+ last_arg = None
835
+ run_tests = False
836
+ default_actor = 'sagetrac-github-bot'
802
837
cmdline_args = sys .argv [1 :]
803
838
num_args = len (cmdline_args )
804
839
805
- # getLogger().setLevel(INFO)
806
- getLogger ().setLevel (DEBUG )
840
+ if num_args :
841
+ last_arg = cmdline_args [num_args - 1 ]
842
+
843
+ if last_arg in ('-t' , '--test' ):
844
+ getLogger ().setLevel (DEBUG )
845
+ cmdline_args .pop ()
846
+ run_tests = True
847
+ elif last_arg in ('-d' , '--debug' ):
848
+ getLogger ().setLevel (DEBUG )
849
+ cmdline_args .pop ()
850
+ elif last_arg in ('-i' , '--info' ):
851
+ getLogger ().setLevel (INFO )
852
+ cmdline_args .pop ()
853
+ elif last_arg in ('-w' , '--warning' ):
854
+ getLogger ().setLevel (INFO )
855
+ info ('cmdline_args (%s) %s' % (num_args , cmdline_args ))
856
+ getLogger ().setLevel (WARNING )
857
+ cmdline_args .pop ()
858
+ else :
859
+ getLogger ().setLevel (DEBUG )
807
860
861
+ num_args = len (cmdline_args )
808
862
info ('cmdline_args (%s) %s' % (num_args , cmdline_args ))
809
863
810
- if num_args == 5 :
811
- action , url , actor , label , rev_state = cmdline_args
812
- action = Action (action )
864
+ if run_tests and num_args in (1 ,2 ):
865
+ if num_args == 2 :
866
+ url , actor = cmdline_args
867
+ else :
868
+ url , = cmdline_args
869
+ actor = default_actor
813
870
814
- info ('action: %s' % action )
815
871
info ('url: %s' % url )
816
872
info ('actor: %s' % actor )
817
- info ('label: %s' % label )
818
- info ('rev_state: %s' % rev_state )
819
873
820
874
gh = GhLabelSynchronizer (url , actor )
821
- gh .run ( action , label = label , rev_state = rev_state )
875
+ gh .run_tests ( )
822
876
823
- elif num_args == 2 :
824
- url , actor = cmdline_args
877
+ elif num_args == 5 :
878
+ action , url , actor , label , rev_state = cmdline_args
879
+ action = Action (action )
825
880
881
+ info ('action: %s' % action )
826
882
info ('url: %s' % url )
827
883
info ('actor: %s' % actor )
884
+ info ('label: %s' % label )
885
+ info ('rev_state: %s' % rev_state )
828
886
829
887
gh = GhLabelSynchronizer (url , actor )
830
- gh .run_tests ( )
888
+ gh .run ( action , label = label , rev_state = rev_state )
831
889
832
890
elif num_args == 1 :
833
891
url , = cmdline_args
834
892
835
893
info ('url: %s' % url )
836
894
837
- gh = GhLabelSynchronizer (url , 'sagetrac-github-bot' )
895
+ gh = GhLabelSynchronizer (url , default_actor )
838
896
839
897
else :
840
- print ('Need 5 arguments: action, url, actor, label, rev_state' )
841
- print ('Running tests is possible with 2 arguments: url, actor' )
842
- print ('Cleaning warning comments is possible with 1 argument: url' )
898
+ print ('Need 5 arguments to synchronize: action, url, actor, label, rev_state' )
899
+ print ('Need 1 argument to clean warning comments: url' )
900
+ print ('Need 1 argument to run tests: url' )
901
+ print ('The following options may be appended:' )
902
+ print (' -t --test to run the test suite' )
903
+ print (' -i --info to set the log-level to INFO' )
904
+ print (' -d --debug to set the log-level to DEBUG (default)' )
905
+ print (' -w --warning to set the log-level to WARNING' )
0 commit comments