示例#1
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={})
示例#2
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
    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 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={})
    def handle_pull_request(self):

        if not self.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})

        collaborators = self.project.who_can_merge_pr()
        r = BuildStatusReporter(self.project, self.event.commit_sha)
        if self.event.github_login not in collaborators | self.config.admins:
            msg = "Only collaborators can trigger Packit-as-a-Service"
            check_names = [
                f"{PRCheckName.get_build_check(x)}"
                for x in self.job.metadata.get("targets")
            ]
            r.report("failure", msg, check_names=check_names)
            return HandlerResults(success=False, details={"msg": msg})
        cbh = CoprBuildHandler(self.config, self.package_config, self.project,
                               self.event)
        handler_results = cbh.run_copr_build()

        return handler_results
示例#6
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),
        )
    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={})
示例#8
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={})
示例#9
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)
示例#10
0
 def status_reporter(self):
     if not self._status_reporter:
         self._status_reporter = BuildStatusReporter(
             self.project, self.event.commit_sha, self.copr_build_model
         )
     return self._status_reporter
示例#11
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)}"
                     )
                },
            )
示例#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"])
        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})