Ejemplo n.º 1
0
    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={})
Ejemplo n.º 2
0
 def test_check_names(self) -> List[str]:
     if not self._test_check_names:
         self._test_check_names = [
             PRCheckName.get_testing_farm_check(chroot)
             for chroot in self.tests_chroots
         ]
     return self._test_check_names
Ejemplo n.º 3
0
    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
Ejemplo n.º 4
0
 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
Ejemplo n.º 5
0
    def run(self) -> HandlerResults:

        logger.debug(f"Received testing-farm result:\n{self.event.result}")
        logger.debug(
            f"Received testing-farm test results:\n{self.event.tests}")

        if self.event.result == TestingFarmResult.passed:
            status = "success"
            passed = True
        else:
            status = "failure"
            passed = False

        if (len(self.event.tests) == 1
                and self.event.tests[0].name == "/install/copr-build"):
            logger.debug("No-fmf scenario discovered.")
            short_msg = "Installation passed" if passed else "Installation failed"
        else:
            short_msg = self.event.message

        r = BuildStatusReporter(self.project, self.event.commit_sha)
        r.report(
            state=status,
            description=short_msg,
            url=self.event.log_url,
            check_names=PRCheckName.get_testing_farm_check(
                self.event.copr_chroot),
        )

        return HandlerResults(success=True, details={})
Ejemplo n.º 6
0
def test_copr_build_just_tests_defined(copr_build_start, pc_tests, 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_tests)
    flexmock(PRCheckName).should_receive("get_build_check").and_return(
        PACKIT_STG_CHECK)
    flexmock(PRCheckName).should_receive("get_testing_farm_check").and_return(
        PACKIT_STG_TESTING_FARM_CHECK)

    flexmock(CoprBuild).should_receive("get_by_build_id").and_return(
        copr_build)
    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)

    flexmock(CoprBuild).should_receive("set_status").with_args("pending")
    flexmock(CoprBuild).should_receive("set_build_logs_url")
    # check if packit-service sets the correct PR status
    flexmock(BuildStatusReporter).should_receive("report").with_args(
        state="pending",
        description="RPM build has started...",
        url=url,
        check_names=PACKIT_STG_CHECK,
    ).never()

    flexmock(BuildStatusReporter).should_receive("report").with_args(
        state="pending",
        description="RPM build has started...",
        url=url,
        check_names=PRCheckName.get_testing_farm_check(
            copr_build_start["chroot"]),
    ).once()

    steve.process_message(copr_build_start)
Ejemplo n.º 7
0
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)
Ejemplo n.º 8
0
 def report_status_to_test_for_chroot(self,
                                      description,
                                      state,
                                      url: str = "",
                                      chroot: str = ""):
     if self.job_tests and chroot in self.tests_chroots:
         self.status_reporter.report(
             description=description,
             state=state,
             url=url,
             check_names=PRCheckName.get_testing_farm_check(chroot),
         )
Ejemplo n.º 9
0
 def _process_failed_srpm_build(self, ex):
     sentry_integration.send_to_sentry(ex)
     msg = f"Failed to create a SRPM: {ex}"
     self.status_reporter.report(
         state="failure",
         description=str(ex),
         check_names=PRCheckName.get_srpm_build_check(),
     )
     self.status_reporter.report_tests_failed_because_of_the_build(
         test_check_names=self.test_check_names
     )
     return HandlerResults(success=False, details={"msg": msg})
Ejemplo n.º 10
0
 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,
         )
Ejemplo n.º 11
0
    def run(self) -> HandlerResults:
        self.local_project = LocalProject(
            git_project=self.project, working_dir=self.config.command_handler_work_dir
        )

        r = BuildStatusReporter(self.project, self.event.commit_sha)
        if self.event.result == TestingFarmResult.passed:
            status = "success"
        else:
            status = "failure"

        r.report(
            status,
            self.event.message,
            None,
            self.event.log_url,
            check_names=PRCheckName.get_testing_farm_check(self.event.copr_chroot),
        )

        return HandlerResults(success=True, details={})
Ejemplo n.º 12
0
    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),
        )
Ejemplo n.º 13
0
 def _process_failed_command(self, 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)
     sentry_integration.send_to_sentry(output)
     msg = "Failed to create a SRPM."
     self.status_reporter.report(
         state="failure",
         description=msg,
         check_names=PRCheckName.get_srpm_build_check(),
     )
     return HandlerResults(success=False, details={"msg": msg})
Ejemplo n.º 14
0
    def run(self) -> HandlerResults:
        self.local_project = LocalProject(
            git_project=self.project,
            working_dir=self.config.command_handler_work_dir)

        logger.info("Running testing farm")

        r = BuildStatusReporter(self.project, self.event.commit_sha)

        chroots = self.job.metadata.get("targets")
        logger.debug(f"Testing farm chroots: {chroots}")
        for chroot in chroots:
            pipeline_id = str(uuid.uuid4())
            logger.debug(f"Pipeline id: {pipeline_id}")
            payload: dict = {
                "pipeline": {
                    "id": pipeline_id
                },
                "api": {
                    "token": self.config.testing_farm_secret
                },
            }

            logger.debug(f"Payload: {payload}")

            stg = "-stg" if self.config.deployment == Deployment.stg else ""
            copr_repo_name = (
                f"packit/{self.project.namespace}-{self.project.repo}-"
                f"{self.event.pr_id}{stg}")

            payload["artifact"] = {
                "repo-name": self.event.base_repo_name,
                "repo-namespace": self.event.base_repo_namespace,
                "copr-repo-name": copr_repo_name,
                "copr-chroot": chroot,
                "commit-sha": self.event.commit_sha,
                "git-url": self.event.project_url,
                "git-ref": self.base_ref,
            }

            logger.debug("Sending testing farm request...")
            logger.debug(payload)

            req = self.send_testing_farm_request(TESTING_FARM_TRIGGER_URL,
                                                 "POST", {},
                                                 json.dumps(payload))
            logger.debug(f"Request sent: {req}")
            if not req:
                msg = "Failed to post request to testing farm API."
                logger.debug("Failed to post request to testing farm API.")
                r.report(
                    "failure",
                    msg,
                    None,
                    "",
                    check_names=PRCheckName.get_testing_farm_check(chroot),
                )
                return HandlerResults(success=False, details={"msg": msg})
            else:
                logger.debug(
                    f"Submitted to testing farm with return code: {req.status_code}"
                )
                """
                Response:
                {
                    "id": "9fa3cbd1-83f2-4326-a118-aad59f5",
                    "success": true,
                    "url": "https://console-testing-farm.apps.ci.centos.org/pipeline/<id>"
                }
                """

                # success set check on pending
                if req.status_code != 200:
                    # something went wrong
                    msg = req.json()["message"]
                    r.report(
                        "failure",
                        msg,
                        None,
                        check_names=PRCheckName.get_testing_farm_check(chroot),
                    )
                    return HandlerResults(success=False, details={"msg": msg})

                r.report(
                    "pending",
                    "Tests are running ...",
                    None,
                    req.json()["url"],
                    check_names=PRCheckName.get_testing_farm_check(chroot),
                )

        return HandlerResults(success=True, details={})
Ejemplo n.º 15
0
    def run_copr_build(self) -> HandlerResults:
        # 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:
            msg = "No copr_build defined"
            # we can't report it to end-user at this stage
            return HandlerResults(success=False, details={"msg": msg})

        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")
        if not job.metadata.get("targets"):
            msg = "'targets' value is required in packit config for copr_build job"
            self.project.pr_comment(self.event.pr_id, msg)
            return HandlerResults(success=False, details={"msg": msg})

        self.job_chroots = job.metadata.get("targets", [])
        for test_check_name in (f"{PRCheckName.get_testing_farm_check(x)}"
                                for x in self.job_chroots):
            self.project.set_commit_status(
                self.event.commit_sha,
                "pending",
                "",
                "Waiting for a successful RPM build",
                test_check_name,
                trim=True,
            )
        r = BuildStatusReporter(self.project, self.event.commit_sha,
                                self.copr_build_model)
        build_check_names = [
            f"{PRCheckName.get_build_check(x)}" for x in self.job_chroots
        ]
        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",
                "SRPM build has just started...",
                check_names=PRCheckName.get_srpm_build_check(),
            )
            r.report(
                "pending",
                "RPM build is waiting for succesfull SPRM build",
                check_names=build_check_names,
            )
            build_id, _ = self.api.run_copr_build(project=self.job_project,
                                                  chroots=self.job_chroots,
                                                  owner=self.job_owner)
            r.report(
                "success",
                "SRPM was built successfully.",
                check_names=PRCheckName.get_srpm_build_check(),
            )
            # provide common build url while waiting on response from copr
            url = ("https://copr.fedorainfracloud.org/coprs/"
                   f"{self.job_owner}/{self.job_project}/build/{build_id}/")
            r.report(
                "pending",
                "RPM build has just started...",
                check_names=build_check_names,
                url=url,
            )
            # Save copr build with commit information to be able to report status back
            # after fedmsg copr.build.end arrives
            copr_build_db = CoprBuildDB()
            copr_build_db.add_build(
                build_id,
                self.event.commit_sha,
                self.event.pr_id,
                self.event.base_repo_name,
                self.event.base_repo_namespace,
                self.event.base_ref,
                self.event.project_url,
            )

        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_names=build_check_names)
            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)
            import sentry_sdk

            sentry_sdk.capture_exception(output)

            msg = "Failed to create a SRPM."
            r.report("failure",
                     msg,
                     check_names=PRCheckName.get_srpm_build_check())
            return HandlerResults(success=False, details={"msg": msg})

        except FailedCreateSRPM as ex:
            # so that we don't have to have sentry sdk installed locally
            import sentry_sdk

            sentry_sdk.capture_exception(ex)

            msg = f"Failed to create a SRPM: {ex}"
            r.report("failure",
                     ex,
                     check_names=PRCheckName.get_srpm_build_check())
            return HandlerResults(success=False, details={"msg": msg})

        except Exception as ex:
            # so that we don't have to have sentry sdk installed locally
            import sentry_sdk

            sentry_sdk.capture_exception(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_names=build_check_names,
            )
            return HandlerResults(success=False, details={"msg": msg})

        self.copr_build_model.build_id = build_id
        self.copr_build_model.save()

        return HandlerResults(success=True, details={})
Ejemplo n.º 16
0
    def run_testing_farm(self, chroot: str) -> HandlerResults:
        if chroot not in self.tests_chroots:
            # Leaving here just to be sure that we will discover this situation if it occurs.
            # Currently not possible to trigger this situation.
            msg = f"Target '{chroot}' not defined for tests but triggered."
            logger.error(msg)
            send_to_sentry(PackitConfigException(msg))
            return HandlerResults(success=False, details={"msg": msg},)

        if chroot not in self.build_chroots:
            self.report_missing_build_chroot(chroot)
            return HandlerResults(
                success=False,
                details={
                    "msg": f"Target '{chroot}' not defined for build. "
                    f"Cannot run tests without build."
                },
            )
        check_name = PRCheckName.get_testing_farm_check(chroot)

        self.status_reporter.report(
            state="pending",
            description="Build succeeded. Submitting the tests ...",
            check_names=check_name,
        )

        pipeline_id = str(uuid.uuid4())
        logger.debug(f"Pipeline id: {pipeline_id}")
        payload: dict = {
            "pipeline": {"id": pipeline_id},
            "api": {"token": self.config.testing_farm_secret},
        }

        stg = "-stg" if self.config.deployment == Deployment.stg else ""
        copr_repo_name = (
            f"packit/{self.project.namespace}-{self.project.repo}-"
            f"{self.event.pr_id}{stg}"
        )

        payload["artifact"] = {
            "repo-name": self.event.base_repo_name,
            "repo-namespace": self.event.base_repo_namespace,
            "copr-repo-name": copr_repo_name,
            "copr-chroot": chroot,
            "commit-sha": self.event.commit_sha,
            "git-url": self.event.project_url,
            "git-ref": self.base_ref,
        }

        logger.debug("Sending testing farm request...")
        logger.debug(payload)

        req = self.send_testing_farm_request(
            TESTING_FARM_TRIGGER_URL, "POST", {}, json.dumps(payload)
        )
        logger.debug(f"Request sent: {req}")
        if not req:
            msg = "Failed to post request to testing farm API."
            logger.debug("Failed to post request to testing farm API.")
            self.status_reporter.report(
                state="failure", description=msg, check_names=check_name,
            )
            return HandlerResults(success=False, details={"msg": msg})
        else:
            logger.debug(
                f"Submitted to testing farm with return code: {req.status_code}"
            )

            """
            Response:
            {
                "id": "9fa3cbd1-83f2-4326-a118-aad59f5",
                "success": true,
                "url": "https://console-testing-farm.apps.ci.centos.org/pipeline/<id>"
            }
            """

            # success set check on pending
            if req.status_code != 200:
                # something went wrong
                if req.json() and "message" in req.json():
                    msg = req.json()["message"]
                else:
                    msg = f"Failed to submit tests: {req.reason}"
                    logger.error(msg)
                self.status_reporter.report(
                    state="failure", description=msg, check_names=check_name,
                )
                return HandlerResults(success=False, details={"msg": msg})

            self.status_reporter.report(
                state="pending",
                description="Tests are running ...",
                url=req.json()["url"],
                check_names=check_name,
            )

        return HandlerResults(success=True, details={})
Ejemplo n.º 17
0
    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:
        """
        # TODO: modify event hierarchy so we can use some abstract classes instead
        if isinstance(event, ReleaseEvent):
            account_name = event.repo_namespace
            if not account_name:
                raise KeyError(
                    f"Failed to get account_name from {type(event)}")
            if not self.is_approved(account_name):
                logger.info(
                    f"Refusing release event on not whitelisted repo namespace"
                )
                return False
            return True
        if isinstance(
                event,
            (CoprBuildEvent, TestingFarmResultsEvent, DistGitEvent,
             InstallationEvent),
        ):
            return True
        if isinstance(event, (PullRequestEvent, PullRequestCommentEvent)):
            account_name = event.github_login
            if not account_name:
                raise KeyError(
                    f"Failed to get account_name from {type(event)}")
            namespace = event.base_repo_namespace
            if not (self.is_approved(account_name)
                    or self.is_approved(namespace)):
                msg = f"Neither account {account_name} nor owner {namespace} are on our whitelist!"
                logger.error(msg)
                # TODO also check blacklist,
                # but for that we need to know who triggered the action
                if event.trigger == JobTriggerType.comment:
                    project.pr_comment(event.pr_id, msg)
                else:
                    msg = "Account is not whitelisted!"  # needs to be shorter
                    r = BuildStatusReporter(project, event.commit_sha, None)
                    r.report(
                        "failure",
                        msg,
                        url=FAQ_URL,
                        check_names=PRCheckName.get_account_check(),
                    )
                return False
            # TODO: clear failing check when present
            return True
        if isinstance(event, IssueCommentEvent):
            account_name = event.github_login
            if not account_name:
                raise KeyError(
                    f"Failed to get account_name from {type(event)}")
            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
                msg = "Account is not whitelisted!"
                project.issue_comment(event.issue_id, msg)
                return False
            return True

        msg = f"Failed to validate account: Unrecognized event type {type(event)}."
        logger.error(msg)
        raise PackitException(msg)
Ejemplo n.º 18
0
    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})
Ejemplo n.º 19
0
    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={})
Ejemplo n.º 20
0
 def report_missing_build_chroot(self, chroot: str):
     self.status_reporter.report(
         state="error",
         description=f"No build defined for the target '{chroot}'.",
         check_names=PRCheckName.get_testing_farm_check(chroot),
     )
Ejemplo n.º 21
0
    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)}"
                     )
                },
            )