2019-05-16 06:39:08 +02:00
#!/usr/bin/python3
2016-12-29 00:34:56 -06:00
2022-03-24 08:39:20 +01:00
import glob
2016-12-29 00:34:56 -06:00
import os
2018-08-13 22:47:01 -05:00
import re
2016-12-29 00:34:56 -06:00
import shutil
import subprocess
import sys
2022-02-18 10:16:17 +01:00
from lxml import etree as ET
2021-07-14 10:45:11 +01:00
2017-10-11 22:19:24 -05:00
import osc . conf
2016-12-29 00:34:56 -06:00
import osc . core
2019-05-16 13:13:25 +02:00
from osc . util . helper import decode_list
2018-08-16 23:35:10 -05:00
from osclib . conf import Config
2018-01-17 18:08:40 -06:00
from osclib . core import devel_project_get
2018-01-17 20:36:03 -06:00
from osclib . core import devel_project_fallback
2018-11-06 16:15:20 -06:00
from osclib . core import group_members
2019-09-24 11:25:47 -05:00
from osclib . core import package_kind
2021-07-07 17:17:52 +02:00
from osclib . core import create_add_role_request
2021-07-14 10:45:11 +01:00
from osc . core import show_project_meta
2021-07-26 22:21:06 +02:00
from osc . core import get_request_list
2019-05-16 06:39:08 +02:00
from urllib . error import HTTPError
2018-11-16 08:32:25 +01:00
2016-12-29 00:34:56 -06:00
import ReviewBot
2018-03-09 13:37:23 +01:00
from osclib . conf import str2bool
2016-12-29 00:34:56 -06:00
2022-02-18 17:15:48 +01:00
2016-12-29 00:34:56 -06:00
class CheckSource ( ReviewBot . ReviewBot ) :
SCRIPT_PATH = os . path . dirname ( os . path . realpath ( __file__ ) )
def __init__ ( self , * args , * * kwargs ) :
ReviewBot . ReviewBot . __init__ ( self , * args , * * kwargs )
2017-06-20 16:29:19 -05:00
# ReviewBot options.
2018-03-16 14:21:41 -05:00
self . request_default_return = True
2017-06-20 16:29:19 -05:00
2016-12-29 00:34:56 -06:00
self . skip_add_reviews = False
2017-10-11 22:19:24 -05:00
def target_project_config ( self , project ) :
# Load project config and allow for remote entries.
2018-08-16 23:35:10 -05:00
config = Config . get ( self . apiurl , project )
2017-10-11 22:19:24 -05:00
2018-06-28 12:13:26 -05:00
self . single_action_require = str2bool ( config . get ( ' check-source-single-action-require ' , ' False ' ) )
2018-03-09 13:37:23 +01:00
self . ignore_devel = not str2bool ( config . get ( ' devel-project-enforce ' , ' False ' ) )
2018-03-16 14:09:02 -05:00
self . in_air_rename_allow = str2bool ( config . get ( ' check-source-in-air-rename-allow ' , ' False ' ) )
2018-03-09 13:45:14 +01:00
self . add_review_team = str2bool ( config . get ( ' check-source-add-review-team ' , ' True ' ) )
2017-10-11 22:19:24 -05:00
self . review_team = config . get ( ' review-team ' )
2019-09-09 16:51:54 -05:00
self . mail_release_list = config . get ( ' mail-release-list ' )
2018-08-16 23:29:25 -05:00
self . staging_group = config . get ( ' staging-group ' )
2021-07-07 17:17:52 +02:00
self . required_maintainer = config . get ( ' required-source-maintainer ' , ' ' )
2017-10-11 22:19:24 -05:00
self . devel_whitelist = config . get ( ' devel-whitelist ' , ' ' ) . split ( )
2018-09-12 11:48:23 +02:00
self . skip_add_reviews = False
2017-10-11 22:19:24 -05:00
2018-06-28 12:11:24 -05:00
if self . action . type == ' maintenance_incident ' :
# The workflow effectively enforces the names to match and the
# parent code sets target_package from source_package so this check
# becomes useless and awkward to perform.
self . in_air_rename_allow = True
2018-06-28 12:13:26 -05:00
# The target project will be set to product and thus inherit
# settings, but override since real target is not product.
self . single_action_require = False
2018-06-28 12:25:24 -05:00
# It might make sense to supersede maintbot, but for now.
self . skip_add_reviews = True
2020-03-20 14:40:01 +01:00
def is_good_name ( self , package , target_package ) :
self . logger . debug ( f " is_good_name { package } <-> { target_package } " )
if target_package is None :
# if the name doesn't matter, existance is all
return package is not None
return target_package == package
def package_source_parse ( self , project , package , revision = None , target_package = None ) :
ret = self . _package_source_parse ( project , package , revision )
if self . is_good_name ( ret [ ' name ' ] , target_package ) :
return ret
d = { }
for repo in osc . core . get_repositories_of_project ( self . apiurl , project ) :
r = self . _package_source_parse ( project , package , revision , repo )
if r [ ' name ' ] is not None :
d [ r [ ' name ' ] ] = r
if len ( d ) == 1 :
# here is only one so use that
ret = d [ next ( iter ( d ) ) ]
else :
# check if any name matches
self . logger . debug ( " found multiple names %s " , ' , ' . join ( d . keys ( ) ) )
for n , r in d . items ( ) :
if n == target_package :
ret = r
break
if not self . is_good_name ( ret [ ' name ' ] , target_package ) :
self . logger . error ( " none of the names matched " )
return ret
2016-12-29 00:34:56 -06:00
def check_source_submission ( self , source_project , source_package , source_revision , target_project , target_package ) :
2022-02-18 17:44:32 +01:00
super ( CheckSource , self ) . check_source_submission ( source_project ,
source_package , source_revision , target_project , target_package )
2017-10-11 22:19:24 -05:00
self . target_project_config ( target_project )
2016-12-29 00:34:56 -06:00
2018-06-28 12:13:26 -05:00
if self . single_action_require and len ( self . request . actions ) != 1 :
self . review_messages [ ' declined ' ] = ' Only one action per request allowed '
return False
2021-05-26 15:08:59 +02:00
if source_revision is None :
self . review_messages [ ' declined ' ] = ' Submission not from a pinned source revision '
return False
2019-09-24 11:25:47 -05:00
kind = package_kind ( self . apiurl , target_project , target_package )
if kind == ' meta ' :
self . review_messages [ ' accepted ' ] = ' Skipping all checks for meta packages '
2018-03-15 15:43:37 +01:00
return True
2019-09-25 19:36:52 +08:00
elif ( kind is not None and kind != ' source ' ) :
2019-10-22 09:26:17 +02:00
self . review_messages [ ' declined ' ] = ' May not modify a non-source package of type {} ' . format ( kind )
2019-09-24 11:26:52 -05:00
return False
2018-03-15 15:43:37 +01:00
2018-06-28 12:10:19 -05:00
inair_renamed = target_package != source_package
2016-12-29 00:34:56 -06:00
if not self . ignore_devel :
2017-10-11 22:14:42 -05:00
self . logger . info ( ' checking if target package exists and has devel project ' )
2018-01-17 18:08:40 -06:00
devel_project , devel_package = devel_project_get ( self . apiurl , target_project , target_package )
2016-12-29 00:34:56 -06:00
if devel_project :
2017-02-10 11:19:25 -06:00
if ( source_project != devel_project or source_package != devel_package ) and \
not ( source_project == target_project and source_package == target_package ) :
# Not from proper devel project/package and not self-submission.
2022-02-18 17:44:32 +01:00
self . review_messages [ ' declined ' ] = ' Expected submission from devel package %s / %s ' % (
devel_project , devel_package )
2016-12-29 00:34:56 -06:00
return False
else :
# Check to see if other packages exist with the same source project
# which indicates that the project has already been used as devel.
if not self . is_devel_project ( source_project , target_project ) :
2018-01-02 13:27:10 +01:00
self . review_messages [ ' declined ' ] = (
' %s is not a devel project of %s , submit the package to a devel project first. '
' See https://en.opensuse.org/openSUSE:How_to_contribute_to_Factory#How_to_request_a_new_devel_project for details. '
) % ( source_project , target_project )
2016-12-29 00:34:56 -06:00
return False
2018-06-28 12:10:19 -05:00
else :
if source_project . endswith ( ' :Update ' ) :
# Allow for submission like:
# - source: openSUSE:Leap:15.0:Update/google-compute-engine.8258
# - target: openSUSE:Leap:15.1/google-compute-engine
# Note: home:jberry:Update would also be allowed via this condition,
# but that should be handled by leaper and human review.
2018-08-13 22:47:01 -05:00
# Ignore a dot in package name (ex. tpm2.0-abrmd) and instead
# only look for ending in dot number.
match = re . match ( r ' (.*) \ . \ d+$ ' , source_package )
if match :
inair_renamed = target_package != match . group ( 1 )
2018-06-28 12:10:19 -05:00
2021-07-07 17:17:52 +02:00
if not self . source_has_correct_maintainers ( source_project ) :
declined_msg = (
' This request cannot be accepted unless %s is a maintainer of %s . ' %
( self . required_maintainer , source_project )
)
2021-07-29 10:37:44 +02:00
req = self . __ensure_add_role_request ( source_project )
if req :
declined_msg + = ' Created the add_role request %s for addressing this problem. ' % req
2021-07-07 17:17:52 +02:00
self . review_messages [ ' declined ' ] = declined_msg
return False
2018-06-28 12:10:19 -05:00
if not self . in_air_rename_allow and inair_renamed :
self . review_messages [ ' declined ' ] = ' Source and target package names must match '
return False
2016-12-29 00:34:56 -06:00
# Checkout and see if renaming package screws up version parsing.
dir = os . path . expanduser ( ' ~/co/ %s ' % self . request . reqid )
if os . path . exists ( dir ) :
2019-05-11 14:25:02 +02:00
self . logger . warning ( ' directory %s already exists ' % dir )
2016-12-29 00:34:56 -06:00
shutil . rmtree ( dir )
os . makedirs ( dir )
os . chdir ( dir )
old_info = { ' version ' : None }
try :
CheckSource . checkout_package ( self . apiurl , target_project , target_package , pathname = dir ,
2022-02-18 17:35:33 +01:00
server_service_files = True , expand_link = True )
2016-12-29 00:34:56 -06:00
shutil . rmtree ( os . path . join ( target_package , ' .osc ' ) )
os . rename ( target_package , ' _old ' )
2017-04-19 09:21:45 -05:00
old_info = self . package_source_parse ( target_project , target_package )
2019-08-27 14:49:17 -05:00
except HTTPError as e :
if e . code == 404 :
self . logger . info ( ' target package does not exist %s / %s ' % ( target_project , target_package ) )
else :
raise e
2016-12-29 00:34:56 -06:00
CheckSource . checkout_package ( self . apiurl , source_project , source_package , revision = source_revision ,
2022-02-18 17:35:33 +01:00
pathname = dir , server_service_files = True , expand_link = True )
2016-12-29 00:34:56 -06:00
os . rename ( source_package , target_package )
shutil . rmtree ( os . path . join ( target_package , ' .osc ' ) )
2020-03-20 14:40:01 +01:00
new_info = self . package_source_parse ( source_project , source_package , source_revision , target_package )
2020-11-18 09:54:10 +01:00
filename = new_info . get ( ' filename ' , ' ' )
if not ( filename . endswith ( ' .kiwi ' ) or filename == ' Dockerfile ' ) and new_info [ ' name ' ] != target_package :
2016-12-29 00:34:56 -06:00
shutil . rmtree ( dir )
2022-02-18 17:44:32 +01:00
self . review_messages [ ' declined ' ] = " A package submitted as %s has to build as ' Name: %s ' - found Name ' %s ' " % (
target_package , target_package , new_info [ ' name ' ] )
2016-12-29 00:34:56 -06:00
return False
2022-03-24 08:25:32 +01:00
if not self . check_service_file ( target_package ) :
return False
2022-03-24 08:39:20 +01:00
if not self . check_rpmlint ( target_package ) :
return False
2017-08-18 15:18:04 -05:00
# Run check_source.pl script and interpret output.
source_checker = os . path . join ( CheckSource . SCRIPT_PATH , ' check_source.pl ' )
2016-12-29 00:34:56 -06:00
civs = ' '
new_version = None
if old_info [ ' version ' ] and old_info [ ' version ' ] != new_info [ ' version ' ] :
new_version = new_info [ ' version ' ]
civs + = " NEW_VERSION= ' {} ' " . format ( new_version )
civs + = ' LC_ALL=C perl %s _old %s 2>&1 ' % ( source_checker , target_package )
p = subprocess . Popen ( civs , shell = True , stdout = subprocess . PIPE , close_fds = True )
ret = os . waitpid ( p . pid , 0 ) [ 1 ]
2019-05-16 13:13:25 +02:00
checked = decode_list ( p . stdout . readlines ( ) )
2016-12-29 00:34:56 -06:00
2019-05-16 13:13:25 +02:00
output = ' ' . join ( checked ) . replace ( ' \033 ' , ' ' )
2016-12-29 00:34:56 -06:00
os . chdir ( ' /tmp ' )
2017-11-22 17:29:14 +08:00
# ret = 0 : Good
# ret = 1 : Bad
# ret = 2 : Bad but can be non-fatal in some cases
2022-02-18 17:44:32 +01:00
if ret > 1 and target_project . startswith ( ' openSUSE:Leap: ' ) and ( source_project . startswith ( ' SUSE:SLE-15: ' ) or
source_project . startswith ( ' openSUSE:Factory ' ) ) :
2017-11-22 17:29:14 +08:00
pass
elif ret != 0 :
2016-12-29 00:34:56 -06:00
shutil . rmtree ( dir )
self . review_messages [ ' declined ' ] = " Output of check script: \n " + output
return False
shutil . rmtree ( dir )
self . review_messages [ ' accepted ' ] = ' Check script succeeded '
if len ( checked ) :
self . review_messages [ ' accepted ' ] + = " \n \n Output of check script (non-fatal): \n " + output
if not self . skip_add_reviews :
2018-03-09 13:45:14 +01:00
if self . add_review_team and self . review_team is not None :
2017-08-18 15:15:26 -05:00
self . add_review ( self . request , by_group = self . review_team , msg = ' Please review sources ' )
2016-12-29 00:34:56 -06:00
2017-04-19 09:30:57 -05:00
if self . only_changes ( ) :
self . logger . debug ( ' only .changes modifications ' )
2018-11-06 16:15:20 -06:00
if self . staging_group and self . review_user in group_members ( self . apiurl , self . staging_group ) :
if not self . dryrun :
osc . core . change_review_state ( self . apiurl , str ( self . request . reqid ) , ' accepted ' ,
2022-02-18 17:35:33 +01:00
by_group = self . staging_group ,
message = ' skipping the staging process since only .changes modifications ' )
2018-11-06 16:15:20 -06:00
else :
self . logger . debug ( ' unable to skip staging review since not a member of staging group ' )
2016-12-29 00:34:56 -06:00
return True
def is_devel_project ( self , source_project , target_project ) :
2017-10-11 22:19:24 -05:00
if source_project in self . devel_whitelist :
2016-12-29 00:34:56 -06:00
return True
2017-07-18 17:08:02 -05:00
# Allow any projects already used as devel projects for other packages.
2016-12-29 00:34:56 -06:00
search = {
' package ' : " @project= ' %s ' and devel/@project= ' %s ' " % ( target_project , source_project ) ,
}
result = osc . core . search ( self . apiurl , * * search )
return result [ ' package ' ] . attrib [ ' matches ' ] != ' 0 '
2022-03-24 08:25:32 +01:00
def check_service_file ( self , directory ) :
ALLOWED_MODES = [ ' localonly ' , ' disabled ' , ' buildtime ' , ' manual ' ]
servicefile = os . path . join ( directory , ' _service ' )
if os . path . exists ( servicefile ) :
services = ET . parse ( servicefile )
for service in services . findall ( ' service ' ) :
mode = service . get ( ' mode ' )
if mode in ALLOWED_MODES :
continue
allowed = ' , ' . join ( ALLOWED_MODES )
self . review_messages [
' declined ' ] = f " Services are only allowed if their mode is one of { allowed } . Please change the mode of $name and use `osc service localrun/disabledrun`. "
return False
2022-03-24 08:32:08 +01:00
# remove it away to have full service from source validator
os . unlink ( servicefile )
2022-03-24 08:48:06 +01:00
for file in glob . glob ( os . path . join ( directory , " _service:* " ) ) :
file = os . path . basename ( file )
self . review_messages [ ' declined ' ] = f " Found _service generated file { file } in checkout. Please clean this up first. "
return False
2022-03-24 08:25:32 +01:00
return True
2022-03-24 08:39:20 +01:00
def check_rpmlint ( self , directory ) :
for rpmlintrc in glob . glob ( os . path . join ( directory , " *rpmlintrc " ) ) :
with open ( rpmlintrc , ' r ' ) as f :
for line in f :
if not re . match ( r ' ^ \ s*setBadness ' , line ) :
continue
self . review_messages [ ' declined ' ] = f " For product submissions, you cannot use setBadness. Use filters in { rpmlintrc } . "
return False
return True
2021-07-07 17:17:52 +02:00
def source_has_correct_maintainers ( self , source_project ) :
""" Checks whether the source project has the required maintainer
If a ' required-source-maintainer ' is set , it checks whether it is a
2021-07-26 22:25:05 +02:00
maintainer for the source project . Inherited maintainership is
2021-07-29 10:37:44 +02:00
intentionally ignored to have explicit maintainer set .
2021-07-07 17:17:52 +02:00
source_project - source project name
"""
self . logger . info (
' Checking required maintainer from the source project ( %s ) ' % self . required_maintainer
)
2022-02-18 13:42:57 +01:00
if not self . required_maintainer :
return True
2021-07-07 17:17:52 +02:00
2022-02-18 10:16:17 +01:00
meta = ET . fromstringlist ( show_project_meta ( self . apiurl , source_project ) )
2021-07-14 10:45:11 +01:00
maintainers = meta . xpath ( ' //person[@role= " maintainer " ]/@userid ' )
maintainers + = [ ' group: ' + g for g in meta . xpath ( ' //group[@role= " maintainer " ]/@groupid ' ) ]
2021-07-07 17:17:52 +02:00
return self . required_maintainer in maintainers
2021-07-29 10:37:44 +02:00
def __ensure_add_role_request ( self , source_project ) :
""" Returns add_role request ID for given source project. Creates that add role if needed. """
try :
add_roles = get_request_list ( self . apiurl , source_project ,
2022-02-18 17:35:33 +01:00
req_state = [ ' new ' , ' review ' ] , req_type = ' add_role ' )
2021-07-29 10:37:44 +02:00
add_roles = list ( filter ( self . __is_required_maintainer , add_roles ) )
if len ( add_roles ) > 0 :
return add_roles [ 0 ] . reqid
else :
add_role_msg = ' Created automatically from request %s ' % self . request . reqid
return create_add_role_request ( self . apiurl , source_project , self . required_maintainer ,
2022-02-18 13:50:43 +01:00
' maintainer ' , message = add_role_msg )
2021-07-29 10:37:44 +02:00
except HTTPError as e :
self . logger . error (
' Cannot create the corresponding add_role request for %s : %s ' % ( self . request . reqid , e )
)
def __is_required_maintainer ( self , request ) :
""" Returns true for add role requests that adds required maintainer user or group """
2021-07-26 22:21:06 +02:00
action = request . actions [ 0 ]
user = self . required_maintainer
if user . startswith ( ' group: ' ) :
group = user . replace ( ' group: ' , ' ' )
return action . group_name == group and action . group_role == ' maintainer '
else :
return action . person_name == user and action . person_role == ' maintainer '
2016-12-29 00:34:56 -06:00
@staticmethod
def checkout_package ( * args , * * kwargs ) :
_stdout = sys . stdout
2019-05-16 13:13:25 +02:00
sys . stdout = open ( os . devnull , ' w ' )
2016-12-29 00:34:56 -06:00
try :
result = osc . core . checkout_package ( * args , * * kwargs )
finally :
sys . stdout = _stdout
return result
2019-11-28 10:30:37 +01:00
def _package_source_parse ( self , project , package , revision = None , repository = None ) :
2016-12-29 00:34:56 -06:00
query = { ' view ' : ' info ' , ' parse ' : 1 }
if revision :
query [ ' rev ' ] = revision
2019-11-28 10:30:37 +01:00
if repository :
query [ ' repository ' ] = repository
2016-12-29 00:34:56 -06:00
url = osc . core . makeurl ( self . apiurl , [ ' source ' , project , package ] , query )
ret = { ' name ' : None , ' version ' : None }
try :
xml = ET . parse ( osc . core . http_GET ( url ) ) . getroot ( )
2018-11-16 08:32:25 +01:00
except HTTPError as e :
2016-12-29 00:34:56 -06:00
self . logger . error ( ' ERROR in URL %s [ %s ] ' % ( url , e ) )
return ret
2019-11-28 10:30:37 +01:00
if xml . find ( ' error ' ) is not None :
self . logger . error ( " %s / %s / %s : %s " , project , package , repository , xml . find ( ' error ' ) . text )
return ret
2016-12-29 00:34:56 -06:00
# ET boolean check fails.
if xml . find ( ' name ' ) is not None :
ret [ ' name ' ] = xml . find ( ' name ' ) . text
if xml . find ( ' version ' ) is not None :
ret [ ' version ' ] = xml . find ( ' version ' ) . text
2019-09-20 14:37:46 +02:00
if xml . find ( ' filename ' ) is not None :
ret [ ' filename ' ] = xml . find ( ' filename ' ) . text
2019-11-28 10:30:37 +01:00
self . logger . debug ( " %s / %s / %s : %s " , project , package , repository , ret )
return ret
2017-04-19 09:30:57 -05:00
def only_changes ( self ) :
u = osc . core . makeurl ( self . apiurl , [ ' request ' , self . request . reqid ] ,
{ ' cmd ' : ' diff ' , ' view ' : ' xml ' } )
try :
diff = ET . parse ( osc . core . http_POST ( u ) ) . getroot ( )
for f in diff . findall ( ' action/sourcediff/files/file/*[@name] ' ) :
if not f . get ( ' name ' ) . endswith ( ' .changes ' ) :
return False
return True
2022-02-18 11:25:26 +01:00
except HTTPError :
2017-04-19 09:30:57 -05:00
pass
return False
2016-12-29 00:34:56 -06:00
def check_action_add_role ( self , request , action ) :
# Decline add_role request (assumed the bot acting on requests to Factory or similar).
message = ' Roles to packages are granted in the devel project, not in %s . ' % action . tgt_project
if action . tgt_package is not None :
2018-01-17 20:36:03 -06:00
project , package = devel_project_fallback ( self . apiurl , action . tgt_project , action . tgt_package )
2018-01-17 18:08:40 -06:00
message + = ' Send this request to {} / {} . ' . format ( project , package )
2016-12-29 00:34:56 -06:00
self . review_messages [ ' declined ' ] = message
return False
2018-09-17 17:11:33 -05:00
def check_action_delete_package ( self , request , action ) :
2018-01-03 20:01:12 -06:00
self . target_project_config ( action . tgt_project )
2016-12-29 00:34:56 -06:00
try :
result = osc . core . show_project_sourceinfo ( self . apiurl , action . tgt_project , True , ( action . tgt_package ) )
root = ET . fromstring ( result )
2018-11-16 08:32:25 +01:00
except HTTPError :
2016-12-29 00:34:56 -06:00
return None
2017-10-12 19:11:01 +08:00
# Decline the delete request if there is another delete/submit request against the same package
query = " match=state/@name= ' new ' +and+(action/target/@project= ' {} ' +and+action/target/@package= ' {} ' ) " \
" +and+(action/@type= ' delete ' +or+action/@type= ' submit ' ) " . format ( action . tgt_project , action . tgt_package )
url = osc . core . makeurl ( self . apiurl , [ ' search ' , ' request ' ] , query )
matches = ET . parse ( osc . core . http_GET ( url ) ) . getroot ( )
if int ( matches . attrib [ ' matches ' ] ) > 1 :
ids = [ rq . attrib [ ' id ' ] for rq in matches . findall ( ' request ' ) ]
2022-02-18 17:44:32 +01:00
self . review_messages [ ' declined ' ] = " There is a pending request %s to %s / %s in process. " % (
' , ' . join ( ids ) , action . tgt_project , action . tgt_package )
2017-10-12 19:11:01 +08:00
return False
2019-01-09 12:58:54 +01:00
# Decline delete requests against linked flavor package
linked = root . find ( ' sourceinfo/linked ' )
if not ( linked is None or self . check_linked_package ( action , linked ) ) :
2016-12-29 00:34:56 -06:00
return False
2019-01-09 12:58:54 +01:00
if not self . ignore_devel :
self . devel_project_review_ensure ( request , action . tgt_project , action . tgt_package )
return True
def check_linked_package ( self , action , linked ) :
if linked . get ( ' project ' , action . tgt_project ) != action . tgt_project :
return True
linked_package = linked . get ( ' package ' )
self . review_messages [ ' declined ' ] = " Delete the package %s instead " % ( linked_package )
return False
2018-09-17 17:06:18 -05:00
def check_action_delete_project ( self , request , action ) :
# Presumably if the request is valid the bot should be disabled or
# overridden, but seems like no valid case for allowing this (see #1696).
self . review_messages [ ' declined ' ] = ' Deleting the {} project is not allowed. ' . format ( action . tgt_project )
return False
2018-09-17 17:10:01 -05:00
def check_action_delete_repository ( self , request , action ) :
2019-09-09 16:51:54 -05:00
self . target_project_config ( action . tgt_project )
if self . mail_release_list :
2019-09-09 16:57:26 -05:00
self . review_messages [ ' declined ' ] = ' Deleting repositories is not allowed. ' \
' Contact {} to discuss further. ' . format ( self . mail_release_list )
2018-09-17 17:10:01 -05:00
return False
self . review_messages [ ' accepted ' ] = ' unhandled: removing repository '
return True
2022-02-18 17:15:48 +01:00
2016-12-29 00:34:56 -06:00
class CommandLineInterface ( ReviewBot . CommandLineInterface ) :
def __init__ ( self , * args , * * kwargs ) :
ReviewBot . CommandLineInterface . __init__ ( self , args , kwargs )
self . clazz = CheckSource
def get_optparser ( self ) :
parser = ReviewBot . CommandLineInterface . get_optparser ( self )
2022-02-18 17:44:32 +01:00
parser . add_option ( ' --skip-add-reviews ' , action = ' store_true ' , default = False ,
help = ' skip adding review after completing checks ' )
2016-12-29 00:34:56 -06:00
return parser
def setup_checker ( self ) :
bot = ReviewBot . CommandLineInterface . setup_checker ( self )
bot . skip_add_reviews = self . options . skip_add_reviews
return bot
2022-02-18 17:11:46 +01:00
2016-12-29 00:34:56 -06:00
if __name__ == " __main__ " :
app = CommandLineInterface ( )
sys . exit ( app . main ( ) )