def handle_pull_request(self): if not self.job.metadata.get("targets"): logger.error( "'targets' value is required in packit config for copr_build job" ) collaborators = self.project.who_can_merge_pr() r = BuildStatusReporter(self.project, self.event.commit_sha) if self.event.github_login not in collaborators: msg = "Only collaborators can trigger Packit-as-a-Service" r.set_status("failure", msg, PRCheckName.get_build_check()) return HandlerResults(success=False, details={"msg": msg}) cbh = CoprBuildHandler(self.config, self.package_config, self.project, self.event) handler_results = cbh.run_copr_build() if handler_results["success"]: # Testing farm is triggered just once copr build is finished as it uses copr builds # todo: utilize fedmsg for this. test_job_config = self.get_tests_for_build() if test_job_config: testing_farm_handler = GithubTestingFarmHandler( self.config, test_job_config, self.event) testing_farm_handler.run() else: logger.debug("Testing farm not in the job config.") return HandlerResults(success=True, details={})
def check_and_report(self, event: Optional[Any], project: GitProject) -> bool: """ Check if account is approved and report status back in case of PR :param event: PullRequest and Release TODO: handle more :param project: GitProject :return: """ account_name = None if isinstance(event, PullRequestEvent): account_name = event.base_repo_namespace if isinstance(event, ReleaseEvent): account_name = event.repo_namespace if account_name: if not self.is_approved(account_name): logger.error( f"User {account_name} is not approved on whitelist!") # TODO also check blacklist, # but for that we need to know who triggered the action if event.trigger == JobTriggerType.pull_request: r = BuildStatusReporter(project, event.commit_sha, None) msg = "Account is not whitelisted!" r.report( "failure", msg, url=FAQ_URL, check_name=PRCheckName.get_build_check(), ) return False return True
def build_check_names(self) -> List[str]: if not self._build_check_names: self._build_check_names = [ PRCheckName.get_build_check(chroot) for chroot in self.build_chroots ] return self._build_check_names
def test_copr_build_not_comment_on_success(copr_build_end, pc_build, copr_build): steve = SteveJobs() flexmock(SteveJobs, _is_private=False) flexmock(CoprHelper).should_receive("get_copr_client").and_return( Client( config={ "copr_url": "https://copr.fedorainfracloud.org", "username": "******", })) flexmock(CoprBuildJobHelper).should_receive("copr_build_model").and_return( flexmock()) flexmock(CoprBuildEvent).should_receive("get_package_config").and_return( pc_build) flexmock(PRCheckName).should_receive("get_build_check").and_return( PACKIT_STG_CHECK) flexmock(CoprBuildEndHandler).should_receive( "was_last_build_successful").and_return(True) flexmock(GithubProject).should_receive("pr_comment").never() flexmock(CoprBuild).should_receive("get_by_build_id").and_return( copr_build) flexmock(CoprBuild).should_receive("set_status").with_args("success") flexmock(CoprBuildDB).should_receive("get_build").and_return({ "commit_sha": "XXXXX", "pr_id": 24, "repo_name": "hello-world", "repo_namespace": "packit-service", "ref": "XXXX", "https_url": "https://github.com/packit-service/hello-world", }) url = get_log_url(1) flexmock(requests).should_receive("get").and_return(requests.Response()) flexmock( requests.Response).should_receive("raise_for_status").and_return(None) # check if packit-service set correct PR status flexmock(BuildStatusReporter).should_receive("report").with_args( state="success", description="RPMs were built successfully.", url=url, check_names=PRCheckName.get_build_check(copr_build_end["chroot"]), ).once() # skip testing farm flexmock(CoprBuildJobHelper).should_receive("job_tests").and_return(None) steve.process_message(copr_build_end)
def report_status_to_build_for_chroot(self, description, state, url: str = "", chroot: str = ""): if self.job_copr_build and chroot in self.build_chroots: cs = PRCheckName.get_build_check(chroot) self.status_reporter.report( description=description, state=state, url=url, check_names=cs, )
def run(self): build = CoprBuildDB().get_build(self.event.build_id) if not build: # TODO: how could this happen? msg = f"Copr build {self.event.build_id} not in CoprBuildDB" logger.warning(msg) return HandlerResults(success=False, details={"msg": msg}) r = BuildStatusReporter(self.event.get_project(), build["commit_sha"]) if self.event.chroot == "srpm-builds": # we don't want to set check for this msg = "SRPM build in copr has started" logger.debug(msg) return HandlerResults(success=True, details={"msg": msg}) r.report( state="pending", description="RPM build has started...", url=copr_url_from_event(self.event), check_names=PRCheckName.get_build_check(self.event.chroot), )
def run_copr_build(self) -> HandlerResults: if not (self.job_copr_build or self.job_tests): msg = "No copr_build or tests job defined." # we can't report it to end-user at this stage return HandlerResults(success=False, details={"msg": msg}) try: self.report_status_to_all(description="Building SRPM ...", state="pending") # we want to get packit logs from the SRPM creation process # so we stuff them into a StringIO buffer stream = StringIO() handler = logging.StreamHandler(stream) packit_logger = logging.getLogger("packit") packit_logger.setLevel(logging.DEBUG) packit_logger.addHandler(handler) formatter = PackitFormatter(None, "%H:%M:%S") handler.setFormatter(formatter) build_id, _ = self.api.run_copr_build( project=self.job_project, chroots=self.build_chroots, owner=self.job_owner, ) packit_logger.removeHandler(handler) stream.seek(0) logs = stream.read() web_url = get_copr_build_url_for_values(self.job_owner, self.job_project, build_id) srpm_build = SRPMBuild.create(logs) status = "pending" description = "Building RPM ..." for chroot in self.build_chroots: copr_build = CoprBuild.get_or_create( pr_id=self.event.pr_id, build_id=str(build_id), commit_sha=self.event.commit_sha, repo_name=self.event.base_repo_name, namespace=self.event.base_repo_namespace, web_url=web_url, target=chroot, status=status, srpm_build=srpm_build, ) url = get_log_url(id_=copr_build.id) self.status_reporter.report( state=status, description=description, url=url, check_names=PRCheckName.get_build_check(chroot), ) if chroot in self.tests_chroots: self.status_reporter.report( state=status, description=description, url=url, check_names=PRCheckName.get_testing_farm_check(chroot), ) except SandcastleTimeoutReached: return self._process_timeout() except SandcastleCommandFailed as ex: return self._process_failed_command(ex) except ApiException as ex: return self._process_openshift_error(ex) except PackitSRPMException as ex: return self._process_failed_srpm_build(ex) except PackitCoprProjectException as ex: return self._process_copr_submit_exception(ex) except PackitCoprException as ex: return self._process_general_exception(ex) except Exception as ex: return self._process_general_exception(ex) self.copr_build_model.build_id = build_id self.copr_build_model.save() return HandlerResults(success=True, details={})
def run_copr_build(self) -> HandlerResults: check_name = PRCheckName.get_build_check() # add suffix stg when using stg app stg = "-stg" if self.config.deployment == Deployment.stg else "" default_project_name = ( f"{self.project.namespace}-{self.project.repo}-{self.event.pr_id}{stg}" ) job = self.get_job_copr_build_metadata() if not job.metadata.get("targets"): logger.error( "'targets' value is required in packit config for copr_build job" ) self.job_project = job.metadata.get("project") or default_project_name self.job_owner = job.metadata.get("owner") or self.api.copr.config.get( "username") self.job_chroots = job.metadata.get("targets") r = BuildStatusReporter(self.project, self.event.commit_sha, self.copr_build_model) msg_retrigger = ( f"You can re-trigger copr build by adding a comment (`/packit copr-build`) " f"into this pull request.") try: r.report("pending", "RPM build has just started...", check_name=check_name) build_id, repo_url = self.api.run_copr_build( project=self.job_project, chroots=self.job_chroots, owner=self.job_owner) except SandcastleTimeoutReached: msg = f"You have reached 10-minute timeout while creating the SRPM. {msg_retrigger}" self.project.pr_comment(self.event.pr_id, msg) msg = "Timeout reached while creating a SRPM." r.report("failure", msg, check_name=check_name) return HandlerResults(success=False, details={"msg": msg}) except SandcastleCommandFailed as ex: max_log_size = 1024 * 16 # is 16KB enough? if len(ex.output) > max_log_size: output = "Earlier output was truncated\n\n" + ex.output[ -max_log_size:] else: output = ex.output msg = ( f"There was an error while creating a SRPM. {msg_retrigger}\n" "\nOutput:" "\n```\n" f"{output}" "\n```" f"\nReturn code: {ex.rc}") self.project.pr_comment(self.event.pr_id, msg) msg = "Failed to create a SRPM." r.report("failure", msg, check_name=check_name) return HandlerResults(success=False, details={"msg": msg}) except FailedCreateSRPM: msg = "Failed to create a SRPM." r.report("failure", msg, check_name=check_name) return HandlerResults(success=False, details={"msg": msg}) except Exception as ex: msg = f"There was an error while running a copr build:\n```\n{ex}\n```\n" logger.error(msg) self.project.pr_comment(self.event.pr_id, f"{msg}\n{msg_retrigger}") r.report( "failure", "Build failed, check latest comment for details.", check_name=check_name, ) return HandlerResults(success=False, details={"msg": msg}) self.copr_build_model.build_id = build_id self.copr_build_model.save() timeout_config = job.metadata.get("timeout") timeout = int(timeout_config) if timeout_config else 60 * 60 * 2 build_state = self.api.watch_copr_build(build_id, timeout, report_func=r.report) if build_state == "succeeded": msg = ( f"Congratulations! The build [has finished]({repo_url})" " successfully. :champagne:\n\n" "You can install the built RPMs by following these steps:\n\n" "* `sudo yum install -y dnf-plugins-core` on RHEL 8\n" "* `sudo dnf install -y dnf-plugins-core` on Fedora\n" f"* `dnf copr enable {self.job_owner}/{self.job_project}`\n" "* And now you can install the packages.\n" "\nPlease note that the RPMs should be used only in a testing environment." ) self.project.pr_comment(self.event.pr_id, msg) return HandlerResults(success=True, details={}) else: return HandlerResults( success=False, details={ "msg": (f"Copr build {build_id} failed {build_state}." f"Copr build URL is {repo_url}." f"Handler used by Copr build is {str(self.event.trigger)}" ) }, )
def run(self): build = CoprBuildDB().get_build(self.event.build_id) if not build: # TODO: how could this happen? msg = f"Copr build {self.event.build_id} not in CoprBuildDB" logger.warning(msg) return HandlerResults(success=False, details={"msg": msg}) r = BuildStatusReporter(self.event.get_project(), build["commit_sha"]) url = copr_url_from_event(self.event) build_url = get_copr_build_url(self.event) msg = "RPMs failed to be built." gh_state = "failure" # https://pagure.io/copr/copr/blob/master/f/common/copr_common/enums.py#_42 if self.event.status == 1: if self.event.chroot == "srpm-builds": # we don't want to set check for this msg = "SRPM build in copr has finished" logger.debug(msg) return HandlerResults(success=True, details={"msg": msg}) check_msg = "RPMs were built successfully." gh_state = "success" if not self.was_last_build_successful(): msg = ( f"Congratulations! The build [has finished]({build_url})" " successfully. :champagne:\n\n" "You can install the built RPMs by following these steps:\n\n" "* `sudo yum install -y dnf-plugins-core` on RHEL 8\n" "* `sudo dnf install -y dnf-plugins-core` on Fedora\n" f"* `dnf copr enable {self.event.owner}/{self.event.project_name}`\n" "* And now you can install the packages.\n" "\nPlease note that the RPMs should be used only in a testing environment." ) self.project.pr_comment(pr_id=self.event.pr_id, body=msg) r.report( state=gh_state, description=check_msg, url=url, check_names=PRCheckName.get_build_check(self.event.chroot), ) test_job_config = self.get_tests_for_build() if test_job_config: testing_farm_handler = GithubTestingFarmHandler( self.config, test_job_config, self.event ) testing_farm_handler.run() else: logger.debug("Testing farm not in the job config.") return HandlerResults(success=True, details={}) r.report( gh_state, msg, url=url, check_names=PRCheckName.get_build_check(self.event.chroot), ) return HandlerResults(success=False, details={"msg": msg})