def process_comment_jobs( self, event: Union[PullRequestCommentEvent, IssueCommentEvent] ) -> HandlerResults: # packit_command can be `/packit propose-update` msg = f"PR comment '{event.comment[:35]}'" try: (packit_mark, *packit_command) = event.comment.split(maxsplit=3) except ValueError: return HandlerResults(success=False, details={"msg": f"{msg} is empty."}) if REQUESTED_PULL_REQUEST_COMMENT != packit_mark: return HandlerResults( success=False, details={"msg": f"{msg} is not handled by packit-service."}, ) if not packit_command: return HandlerResults( success=False, details={ "msg": f"{msg} does not contain a packit-service command." }, ) # packit has command `copr-build`. But PullRequestCommentAction has enum `copr_build`. try: packit_action = CommentAction[packit_command[0].replace("-", "_")] except KeyError: return HandlerResults( success=False, details={ "msg": f"{msg} does not contain a valid packit-service command." }, ) handler_kls: Type[ CommentActionHandler] = COMMENT_ACTION_HANDLER_MAPPING.get( packit_action, None) if not handler_kls: return HandlerResults( success=False, details={"msg": f"{msg} is not a packit-service command."}, ) handler = handler_kls(self.config, event) try: # check whitelist approval for every job to be able to track down which jobs # failed because of missing whitelist approval whitelist = Whitelist() if not whitelist.check_and_report(event, event.get_project()): handlers_results = HandlerResults( success=False, details={"msg": "Account is not whitelisted!"}) return handlers_results handlers_results = handler.run() finally: handler.clean() return handlers_results
def process_comment_jobs( self, event: Union[PullRequestCommentEvent, IssueCommentEvent] ) -> HandlerResults: # packit_command can be `/packit propose-update` msg = f"comment '{event.comment[:35]}'" try: (packit_mark, *packit_command) = event.comment.split(maxsplit=3) except ValueError: return HandlerResults(success=True, details={"msg": f"{msg} is empty."}) if packit_mark != REQUESTED_PULL_REQUEST_COMMENT: return HandlerResults( success=True, details={"msg": f"{msg} is not handled by packit-service."}, ) if not packit_command: return HandlerResults( success=True, details={ "msg": f"{msg} does not contain a packit-service command." }, ) # packit has command `copr-build`. But PullRequestCommentAction has enum `copr_build`. try: packit_action = CommentAction[packit_command[0].replace("-", "_")] except KeyError: return HandlerResults( success=True, details={ "msg": f"{msg} does not contain a valid packit-service command." }, ) handler_kls: Type[ CommentActionHandler] = COMMENT_ACTION_HANDLER_MAPPING.get( packit_action, None) if not handler_kls: return HandlerResults( success=True, details={"msg": f"{msg} is not a packit-service command."}) # check whitelist approval for every job to be able to track down which jobs # failed because of missing whitelist approval whitelist = Whitelist() github_login = getattr(event, "github_login", None) if github_login and github_login in self.config.admins: logger.info(f"{github_login} is admin, you shall pass") elif not whitelist.check_and_report( event, event.get_project(), config=self.config): return HandlerResults( success=True, details={"msg": "Account is not whitelisted!"}) return handler_kls(self.config, event).run_n_clean()
def process_jobs(self, event: Event) -> Dict[str, HandlerResults]: """ Run a job handler (if trigger matches) for every job defined in config. """ handlers_results = {} if not event.package_config: # this happens when service receives events for repos which # don't have packit config, this is not an error # success=True - it's not an error that people don't have packit.yaml in their repo handlers_results[event.trigger.value] = HandlerResults( success=True, details={"msg": "No packit config in repo"} ) return handlers_results handler_classes = get_handlers_for_event(event, event.package_config) if not handler_classes: logger.warning(f"There is no handler for {event.trigger} event.") return handlers_results for handler_kls in handler_classes: job_configs = get_config_for_handler_kls( handler_kls=handler_kls, event=event, package_config=event.package_config, ) # check whitelist approval for every job to be able to track down which jobs # failed because of missing whitelist approval whitelist = Whitelist() user_login = getattr(event, "user_login", None) if user_login and user_login in self.config.admins: logger.info(f"{user_login} is admin, you shall pass.") elif not whitelist.check_and_report( event, event.project, config=self.config ): for job_config in job_configs: handlers_results[job_config.type.value] = HandlerResults( success=False, details={"msg": "Account is not whitelisted!"} ) return handlers_results # we want to run handlers for all possible jobs, not just the first one for job_config in job_configs: logger.debug(f"Running handler: {str(handler_kls)} for {job_config}") handler = handler_kls( config=self.config, job_config=job_config, event=event ) if handler.pre_check(): current_time = datetime.datetime.now().strftime(DATETIME_FORMAT) result_key = f"{job_config.type.value}-{current_time}" handlers_results[result_key] = handler.run_n_clean() return handlers_results
def process_jobs(self, event: Event) -> Dict[str, TaskResults]: """ Create a Celery task for a job handler (if trigger matches) for every job defined in config. """ processing_results = {} if not event.package_config: # this happens when service receives events for repos which don't have packit config # success=True - it's not an error that people don't have packit.yaml in their repo processing_results[event.trigger.value] = TaskResults( success=True, details={"msg": "No packit config in repo"}) return processing_results handler_classes = get_handlers_for_event(event, event.package_config) if not handler_classes: logger.warning(f"There is no handler for {event.trigger} event.") return processing_results job_configs = [] for handler_kls in handler_classes: job_configs = get_config_for_handler_kls( handler_kls=handler_kls, event=event, package_config=event.package_config, ) # check whitelist approval for every job to be able to track down which jobs # failed because of missing whitelist approval whitelist = Whitelist() user_login = getattr(event, "user_login", None) if user_login and user_login in self.service_config.admins: logger.info(f"{user_login} is admin, you shall pass.") elif not whitelist.check_and_report( event, event.project, service_config=self.service_config, job_configs=job_configs, ): for job_config in job_configs: processing_results[job_config.type.value] = TaskResults( success=False, details={"msg": "Account is not whitelisted!"}) return processing_results # we want to run handlers for all possible jobs, not just the first one signatures = [ handler_kls.get_signature(event=event, job=job_config) for job_config in job_configs ] # https://docs.celeryproject.org/en/stable/userguide/canvas.html#groups group(signatures).apply_async() return get_processing_results(event=event, jobs=job_configs)
def test_check_and_report(whitelist: Whitelist, events: List[Tuple[AbstractGithubEvent, bool]]): """ :param whitelist: fixture :param events: fixture: [(Event, should-be-approved)] """ flexmock( GithubProject, pr_comment=lambda *args, **kwargs: None, set_commit_status=lambda *args, **kwargs: None, issue_comment=lambda *args, **kwargs: None, ) flexmock(PullRequestEvent).should_receive("get_package_config").and_return( flexmock(jobs=[ JobConfig( job=JobType.tests, trigger=JobTriggerType.pull_request, metadata={"targets": ["fedora-rawhide"]}, ) ], )) git_project = GithubProject("", GithubService(), "") for event, is_valid in events: if isinstance(event, PullRequestEvent) and not is_valid: # Report the status flexmock(CoprHelper).should_receive("get_copr_client").and_return( Client( config={ "copr_url": "https://copr.fedorainfracloud.org", "username": "******", })) flexmock(LocalProject).should_receive( "refresh_the_arguments").and_return(None) flexmock(LocalProject).should_receive("checkout_pr").and_return( None) flexmock(Model).should_receive("save").and_return(None) flexmock(StatusReporter).should_receive("report").with_args( description="Account is not whitelisted!", state="error", url=FAQ_URL, check_names=[EXPECTED_TESTING_FARM_CHECK_NAME], ).once() assert (whitelist.check_and_report( event, git_project, config=flexmock(deployment=Deployment.stg, command_handler_work_dir=""), ) is is_valid)
def process_jobs(self, event: Event) -> Dict[str, HandlerResults]: """ Run a job handler (if trigger matches) for every job defined in config. """ handlers_results = {} package_config = event.get_package_config() if not package_config: # this happens when service receives events for repos which # don't have packit config, this is not an error # success=True - it's not an error that people don't have packit.yaml in their repo handlers_results[event.trigger.value] = HandlerResults( success=True, details={"msg": "No packit config in repo"} ) return handlers_results handler_classes = get_handlers_for_event(event, package_config) if not handler_classes: logger.warning(f"There is no handler for {event.trigger} event.") return handlers_results for handler_kls in handler_classes: job = get_config_for_handler_kls( handler_kls=handler_kls, event=event, package_config=package_config ) # check whitelist approval for every job to be able to track down which jobs # failed because of missing whitelist approval whitelist = Whitelist() github_login = getattr(event, "github_login", None) if github_login and github_login in self.config.admins: logger.info(f"{github_login} is admin, you shall pass") elif not whitelist.check_and_report( event, event.get_project(), config=self.config ): handlers_results[job.type.value] = HandlerResults( success=False, details={"msg": "Account is not whitelisted!"} ) return handlers_results logger.debug(f"Running handler: {str(handler_kls)}") handler = handler_kls(config=self.config, job_config=job, event=event) if handler.pre_check(): handlers_results[job.type.value] = handler.run_n_clean() # don't break here, other handlers may react to the same event return handlers_results
def process_comment_jobs( self, event: Union[PullRequestCommentEvent, IssueCommentEvent] ) -> HandlerResults: msg = f"comment '{event.comment}'" packit_command, pr_comment_error_msg = self.find_packit_command( str(event.comment)) if pr_comment_error_msg: return HandlerResults( success=True, details={"msg": pr_comment_error_msg}, ) # packit has command `copr-build`. But PullRequestCommentAction has enum `copr_build`. try: packit_action = CommentAction[packit_command[0].replace("-", "_")] except KeyError: return HandlerResults( success=True, details={ "msg": f"{msg} does not contain a valid packit-service command." }, ) handler_kls: Type[ CommentActionHandler] = MAP_COMMENT_ACTION_TO_HANDLER.get( packit_action, None) if not handler_kls: return HandlerResults( success=True, details={"msg": f"{msg} is not a packit-service command."}) # check whitelist approval for every job to be able to track down which jobs # failed because of missing whitelist approval whitelist = Whitelist() github_login = getattr(event, "github_login", None) if github_login and github_login in self.config.admins: logger.info(f"{github_login} is admin, you shall pass") elif not whitelist.check_and_report( event, event.get_project(), config=self.config): return HandlerResults( success=True, details={"msg": "Account is not whitelisted!"}) handler_instance: Handler = handler_kls(config=self.config, event=event) return handler_instance.run_n_clean()
def process_jobs(self, event: Event) -> Dict[str, HandlerResults]: """ Run a job handler (if trigger matches) for every job defined in config. """ handlers_results = {} package_config = event.get_package_config() if not package_config: # this happens when service receives events for repos which # don't have packit config, this is not an error msg = "Failed to obtain package config!" logger.info(msg) handlers_results[event.trigger.value] = HandlerResults( success=False, details={"msg": msg}) return handlers_results for job in package_config.jobs: if event.trigger == job.trigger: handler_kls: Type[JobHandler] = JOB_NAME_HANDLER_MAPPING.get( job.job, None) if not handler_kls: logger.warning(f"There is no handler for job {job}") continue handler = handler_kls(self.config, job, event) try: # check whitelist approval for every job to be able to track down which jobs # failed because of missing whitelist approval whitelist = Whitelist() if not whitelist.check_and_report(event, event.get_project()): handlers_results[job.job.value] = HandlerResults( success=False, details={"msg": "Account is not whitelisted!"}, ) return handlers_results logger.debug(f"Running handler: {str(handler_kls)}") handlers_results[job.job.value] = handler.run() # don't break here, other handlers may react to the same event finally: handler.clean() return handlers_results
def test_check_and_report(event, should_pass): w = Whitelist() w.db = { "anakin": { "status": "approved_manually" }, "yoda": { "status": "approved_manually" }, "naboo": { "status": "approved_manually" }, } flexmock( GithubProject, pr_comment=lambda *args, **kwargs: None, set_commit_status=lambda *args, **kwargs: None, issue_comment=lambda *args, **kwargs: None, ) git_project = GithubProject("", GithubService(), "") assert w.check_and_report(event, git_project) == should_pass
def test_check_and_report(whitelist: Whitelist, events: List[Tuple[AbstractGithubEvent, bool]]): """ :param whitelist: fixture :param events: fixture: [(Event, should-be-approved)] """ flexmock( GithubProject, pr_comment=lambda *args, **kwargs: None, set_commit_status=lambda *args, **kwargs: None, issue_comment=lambda *args, **kwargs: None, ) flexmock(PullRequestEvent).should_receive("get_package_config").and_return( flexmock(jobs=[ JobConfig(job=JobType.tests, trigger=JobTriggerType.pull_request, metadata={}) ])) git_project = GithubProject("", GithubService(), "") for event in events: assert (whitelist.check_and_report( event[0], git_project, config=flexmock(deployment=Deployment.stg)) is event[1])
def process_comment_jobs( self, event: Union[ PullRequestCommentGithubEvent, PullRequestCommentPagureEvent, IssueCommentEvent, ], ) -> Dict[str, HandlerResults]: msg = f"comment '{event.comment}'" packit_command, pr_comment_error_msg = self.find_packit_command( str(event.comment) ) if pr_comment_error_msg: return { event.trigger.value: HandlerResults( success=True, details={"msg": pr_comment_error_msg}, ) } # packit has command `copr-build`. But PullRequestCommentAction has enum `copr_build`. try: packit_action = CommentAction[packit_command[0].replace("-", "_")] except KeyError: return { event.trigger.value: HandlerResults( success=True, details={ "msg": f"{msg} does not contain a valid packit-service command." }, ) } if packit_action == CommentAction.test and isinstance( event.db_trigger, PullRequestModel ): if not event.db_trigger.get_copr_builds(): packit_action = CommentAction.build handler_kls: Type[CommentActionHandler] = MAP_COMMENT_ACTION_TO_HANDLER.get( packit_action, None ) if not handler_kls: return { event.trigger.value: HandlerResults( success=True, details={"msg": f"{msg} is not a packit-service command."}, ) } # check whitelist approval for every job to be able to track down which jobs # failed because of missing whitelist approval whitelist = Whitelist() user_login = getattr(event, "user_login", None) if user_login and user_login in self.config.admins: logger.info(f"{user_login} is admin, you shall pass.") elif not whitelist.check_and_report(event, event.project, config=self.config): return { event.trigger.value: HandlerResults( success=True, details={"msg": f"Account is not whitelisted!"} ) } # VERY UGLY # TODO: REFACTOR !!! if handler_kls == GitHubPullRequestCommentCoprBuildHandler and isinstance( event, PullRequestCommentPagureEvent ): handler_kls = PagurePullRequestCommentCoprBuildHandler handlers_results: Dict[str, HandlerResults] = {} jobs = get_config_for_handler_kls( handler_kls=handler_kls, event=event, package_config=event.package_config, ) for job in jobs: handler_instance: Handler = handler_kls( config=self.config, event=event, job=job ) result_key = ( f"{job.type.value}-{datetime.datetime.now().strftime(DATETIME_FORMAT)}" ) handlers_results[result_key] = handler_instance.run_n_clean() return handlers_results
def process_comment_jobs( self, event: Union[PullRequestCommentGithubEvent, PullRequestCommentPagureEvent, IssueCommentEvent, MergeRequestCommentGitlabEvent, IssueCommentGitlabEvent, ], ) -> Dict[str, TaskResults]: msg = f"comment '{event.comment}'" packit_command, pr_comment_error_msg = self.find_packit_command( str(event.comment)) if pr_comment_error_msg: return { event.trigger.value: TaskResults( success=True, details={"msg": pr_comment_error_msg}, ) } # packit has command `copr-build`. But PullRequestCommentAction has enum `copr_build`. try: packit_action = CommentAction[packit_command[0].replace("-", "_")] except KeyError: return { event.trigger.value: TaskResults( success=True, details={ "msg": f"{msg} does not contain a valid packit-service command." }, ) } if (packit_action == CommentAction.test and isinstance(event.db_trigger, PullRequestModel) and not event.db_trigger.get_copr_builds()): packit_action = CommentAction.build handler_kls: Type[ CommentActionHandler] = MAP_COMMENT_ACTION_TO_HANDLER.get( packit_action, None) if not handler_kls: return { event.trigger.value: TaskResults( success=True, details={"msg": f"{msg} is not a packit-service command."}, ) } # check whitelist approval for every job to be able to track down which jobs # failed because of missing whitelist approval whitelist = Whitelist() user_login = getattr(event, "user_login", None) jobs = get_config_for_handler_kls( handler_kls=handler_kls, event=event, package_config=event.package_config, ) if user_login and user_login in self.service_config.admins: logger.info(f"{user_login} is admin, you shall pass.") elif not whitelist.check_and_report(event, event.project, service_config=self.service_config, job_configs=jobs): return { event.trigger.value: TaskResults(success=True, details={"msg": "Account is not whitelisted!"}) } # VERY UGLY # TODO: REFACTOR !!! if handler_kls == GitHubPullRequestCommentCoprBuildHandler and isinstance( event, PullRequestCommentPagureEvent): handler_kls = PagurePullRequestCommentCoprBuildHandler signatures = [ handler_kls.get_signature(event=event, job=job) for job in jobs ] # https://docs.celeryproject.org/en/stable/userguide/canvas.html#groups group(signatures).apply_async() return get_processing_results(event=event, jobs=jobs)
def test_check_and_report(whitelist: Whitelist, events: List[Tuple[AbstractGithubEvent, bool]]): """ :param whitelist: fixture :param events: fixture: [(Event, should-be-approved)] """ flexmock( GithubProject, pr_comment=lambda *args, **kwargs: None, set_commit_status=lambda *args, **kwargs: None, issue_comment=lambda *args, **kwargs: None, ) flexmock(PullRequestGithubEvent).should_receive( "get_package_config").and_return( flexmock(jobs=[ JobConfig( type=JobType.tests, trigger=JobConfigTriggerType.pull_request, metadata=JobMetadataConfig(targets=["fedora-rawhide"]), ) ], )) git_project = GithubProject("", GithubService(), "") for event, is_valid in events: if isinstance(event, PullRequestGithubEvent) and not is_valid: # Report the status flexmock(CoprHelper).should_receive("get_copr_client").and_return( Client( config={ "copr_url": "https://copr.fedorainfracloud.org", "username": "******", })) flexmock(LocalProject).should_receive( "refresh_the_arguments").and_return(None) flexmock(LocalProject).should_receive("checkout_pr").and_return( None) flexmock(StatusReporter).should_receive("report").with_args( description="Account is not whitelisted!", state=CommitStatus.error, url=FAQ_URL, check_names=[EXPECTED_TESTING_FARM_CHECK_NAME], ).once() # get_account returns the whitelist object if it exists # returns nothing if it isn't whitelisted # then inside the whitelist.py file, a function checks if the status is # one of the approved statuses # this exact code is used twice above but mypy has an issue with this one only whitelist_mock = flexmock(DBWhitelist).should_receive("get_account") if not TYPE_CHECKING: if is_valid: whitelist_mock.and_return( DBWhitelist(status="approved_manually")) else: whitelist_mock.and_return(None) assert (whitelist.check_and_report( event, git_project, config=flexmock(deployment=Deployment.stg, command_handler_work_dir=""), ) is is_valid)
def process_jobs(self, event: Event) -> List[TaskResults]: """ Create a Celery task for a job handler (if trigger matches) for every job defined in config. """ if isinstance( event, (PushGitHubEvent, PushGitlabEvent, PushPagureEvent)) and event.commit_sha.startswith("0000000"): return [ TaskResults.create_from( success=True, msg="Triggered by deleting a branch", job_config=None, event=event, ) ] if not event.package_config: # this happens when service receives events for repos which don't have packit config # success=True - it's not an error that people don't have packit.yaml in their repo return [ TaskResults.create_from( success=True, msg="No packit config found in the repository.", job_config=None, event=event, ) ] if isinstance( event, ( PullRequestCommentGithubEvent, PullRequestCommentPagureEvent, IssueCommentEvent, MergeRequestCommentGitlabEvent, IssueCommentGitlabEvent, ), ): if not event.project.can_merge_pr(event.user_login): logger.debug( f"User {event.user_login} not allowed to trigger packit via comments." ) return [ TaskResults.create_from( success=True, msg= f"User {event.user_login} not allowed to trigger packit via comments.", job_config=None, event=event, ) ] handler_classes = get_handlers_for_event(event, event.package_config) if not handler_classes: logger.debug( f"There is no handler for {event} event suitable for the configuration." ) return [] job_configs = [] for handler_kls in handler_classes: # TODO: merge to to get_handlers_for_event so # so we don't need to go through the similar process twice. job_configs = get_config_for_handler_kls( handler_kls=handler_kls, event=event, package_config=event.package_config, ) # check whitelist approval for every job to be able to track down which jobs # failed because of missing whitelist approval whitelist = Whitelist() user_login = getattr(event, "user_login", None) if user_login and user_login in self.service_config.admins: logger.info(f"{user_login} is admin, you shall pass.") elif not whitelist.check_and_report( event, event.project, service_config=self.service_config, job_configs=job_configs, ): processing_results = [] for job_config in job_configs: processing_results.append( TaskResults.create_from( success=False, msg="Account is not whitelisted!", job_config=job_config, event=event, )) return processing_results # we want to run handlers for all possible jobs, not just the first one signatures = [ handler_kls.get_signature(event=event, job=job_config) for job_config in job_configs ] # https://docs.celeryproject.org/en/stable/userguide/canvas.html#groups group(signatures).apply_async() processing_results = [] for job_config in job_configs: processing_results.append( TaskResults.create_from( success=True, msg="Job created.", job_config=job_config, event=event, )) return processing_results