def run(self) -> HandlerResults:
        collaborators = self.project.who_can_merge_pr()
        if self.event.github_login not in collaborators | self.config.admins:
            msg = "Only collaborators can trigger Packit-as-a-Service"
            self.project.pr_comment(self.event.pr_id, msg)
            return HandlerResults(success=True, details={"msg": msg})

        cbh = CoprBuildJobHelper(self.config, self.package_config,
                                 self.project, self.event)
        handler_results = cbh.run_copr_build()

        return handler_results
    def handle_pull_request(self):

        collaborators = self.project.who_can_merge_pr()
        cbh = CoprBuildJobHelper(self.config, self.package_config,
                                 self.project, self.event)
        if self.event.github_login not in collaborators | self.config.admins:
            msg = "Only collaborators can trigger Packit-as-a-Service"
            cbh.report_status_to_all("failure", msg)
            return HandlerResults(success=False, details={"msg": msg})

        handler_results = cbh.run_copr_build()

        return handler_results
Ejemplo n.º 3
0
    def _check_pr_event(
        self,
        event: Union[PullRequestGithubEvent, PullRequestCommentGithubEvent,
                     MergeRequestGitlabEvent,
                     MergeRequestCommentGitlabEvent, ],
        project: GitProject,
        service_config: ServiceConfig,
        job_configs: Iterable[JobConfig],
    ) -> bool:
        actor_name = event.actor
        if not actor_name:
            raise KeyError(
                f"Failed to get login of the actor from {type(event)}")

        project_url = self._strip_protocol_and_add_git(event.project_url)

        namespace_approved = self.is_approved(project_url)
        user_approved = (project.can_merge_pr(actor_name)
                         or project.get_pr(event.pr_id).author == actor_name)

        if namespace_approved and user_approved:
            # TODO: clear failing check when present
            return True

        msg = (
            f"Project {project_url} is not on our allowlist!"
            if not namespace_approved else
            f"Account {actor_name} has no write access nor is author of PR!")
        logger.debug(msg)
        if isinstance(
                event,
            (PullRequestCommentGithubEvent, MergeRequestCommentGitlabEvent)):
            project.get_pr(event.pr_id).comment(msg)
        else:
            for job_config in job_configs:
                job_helper = CoprBuildJobHelper(
                    service_config=service_config,
                    package_config=event.get_package_config(),
                    project=project,
                    metadata=EventData.from_event_dict(event.get_dict()),
                    db_trigger=event.db_trigger,
                    job_config=job_config,
                    targets_override=event.targets_override,
                )
                msg = ("Namespace is not allowed!"
                       if not namespace_approved else "User cannot trigger!")
                job_helper.report_status_to_all(description=msg,
                                                state=BaseCommitStatus.neutral,
                                                url=FAQ_URL)

        return False
Ejemplo n.º 4
0
    def run(self) -> HandlerResults:
        collaborators = self.project.who_can_merge_pr()
        if self.event.github_login not in collaborators | self.config.admins:
            self.project.pr_comment(self.event.pr_id,
                                    PERMISSIONS_ERROR_WRITE_OR_ADMIN)
            return HandlerResults(
                success=True,
                details={"msg": PERMISSIONS_ERROR_WRITE_OR_ADMIN})

        cbh = CoprBuildJobHelper(self.config, self.package_config,
                                 self.project, self.event)
        handler_results = cbh.run_copr_build()

        return handler_results
Ejemplo n.º 5
0
 def copr_build_helper(self) -> CoprBuildJobHelper:
     if not self._copr_build_helper:
         self._copr_build_helper = CoprBuildJobHelper(
             config=self.config,
             package_config=self.package_config,
             project=self.project,
             event=self.event,
             job=self.job_config,
         )
     return self._copr_build_helper
Ejemplo n.º 6
0
    def set_srpm_url(self, build_job_helper: CoprBuildJobHelper) -> None:
        srpm_build = self.build.get_srpm_build()

        if srpm_build.url is not None:
            # URL has been already set
            return

        srpm_url = build_job_helper.get_build(
            self.copr_event.build_id).source_package.get("url")
        srpm_build.set_url(srpm_url)
Ejemplo n.º 7
0
 def copr_build_helper(self) -> CoprBuildJobHelper:
     if not self._copr_build_helper:
         self._copr_build_helper = CoprBuildJobHelper(
             service_config=self.service_config,
             package_config=self.package_config,
             project=self.project,
             metadata=self.data,
             db_trigger=self.data.db_trigger,
             job_config=self.job_config,
         )
     return self._copr_build_helper
Ejemplo n.º 8
0
    def run(self) -> TaskResults:
        user_can_merge_pr = self.project.can_merge_pr(self.data.user_login)
        if not (user_can_merge_pr
                or self.data.user_login in self.service_config.admins):
            self.project.pr_comment(self.db_trigger.pr_id,
                                    PERMISSIONS_ERROR_WRITE_OR_ADMIN)
            return TaskResults(
                success=True,
                details={"msg": PERMISSIONS_ERROR_WRITE_OR_ADMIN})

        cbh = CoprBuildJobHelper(
            service_config=self.service_config,
            package_config=self.package_config,
            project=self.project,
            metadata=self.data,
            db_trigger=self.db_trigger,
            job_config=self.job_config,
        )
        handler_results = cbh.run_copr_build()

        return handler_results
Ejemplo n.º 9
0
    def run(self) -> HandlerResults:
        user_can_merge_pr = self.event.project.can_merge_pr(
            self.event.user_login)
        if not (user_can_merge_pr
                or self.event.user_login in self.config.admins):
            self.event.project.pr_comment(self.event.pr_id,
                                          PERMISSIONS_ERROR_WRITE_OR_ADMIN)
            return HandlerResults(
                success=True,
                details={"msg": PERMISSIONS_ERROR_WRITE_OR_ADMIN})

        cbh = CoprBuildJobHelper(
            config=self.config,
            package_config=self.event.package_config,
            project=self.event.project,
            event=self.event,
            job=self.job,
        )
        handler_results = cbh.run_copr_build()

        return handler_results
Ejemplo n.º 10
0
 def copr_build_helper(self) -> CoprBuildJobHelper:
     if not self._copr_build_helper:
         self._copr_build_helper = CoprBuildJobHelper(
             service_config=self.service_config,
             package_config=self.package_config,
             project=self.project,
             metadata=self.data,
             db_trigger=self.data.db_trigger,
             job_config=self.job_config,
             targets_override=self.data.targets_override,
             pushgateway=self.pushgateway,
         )
     return self._copr_build_helper
Ejemplo n.º 11
0
    def run(self):
        build_job_helper = CoprBuildJobHelper(
            service_config=self.service_config,
            package_config=self.package_config,
            project=self.project,
            metadata=self.data,
            db_trigger=self.db_trigger,
            job_config=self.job_config,
            pushgateway=self.pushgateway,
        )

        if self.copr_event.chroot == "srpm-builds":
            # we don't want to set the check status for this
            msg = "SRPM build in copr has started."
            logger.debug(msg)
            return TaskResults(success=True, details={"msg": msg})

        if not self.build:
            msg = f"Copr build {self.copr_event.build_id} not in CoprBuildDB."
            logger.warning(msg)
            return TaskResults(success=False, details={"msg": msg})

        self.pushgateway.copr_builds_started.inc()
        start_time = (datetime.utcfromtimestamp(self.copr_event.timestamp)
                      if self.copr_event.timestamp else None)
        self.build.set_start_time(start_time)
        url = get_copr_build_info_url(self.build.id)
        self.build.set_status("pending")
        copr_build_logs = self.copr_event.get_copr_build_logs_url()
        self.build.set_build_logs_url(copr_build_logs)

        build_job_helper.report_status_to_all_for_chroot(
            description="RPM build is in progress...",
            state=BaseCommitStatus.running,
            url=url,
            chroot=self.copr_event.chroot,
        )
        msg = f"Build on {self.copr_event.chroot} in copr has started..."
        return TaskResults(success=True, details={"msg": msg})
Ejemplo n.º 12
0
 def copr_build_helper(self) -> CoprBuildJobHelper:
     # when reporting state of SRPM build built in Copr
     targets_override = ({
         build.target
         for build in CoprBuildModel.get_all_by_build_id(
             str(self.copr_event.build_id))
     } if self.copr_event.chroot == COPR_SRPM_CHROOT else None)
     if not self._copr_build_helper:
         self._copr_build_helper = CoprBuildJobHelper(
             service_config=self.service_config,
             package_config=self.package_config,
             project=self.project,
             metadata=self.data,
             db_trigger=self.db_trigger,
             job_config=self.job_config,
             pushgateway=self.pushgateway,
             targets_override=targets_override,
         )
     return self._copr_build_helper
Ejemplo n.º 13
0
    def check_and_report(self, event: Optional[Any], project: GitProject,
                         config: ServiceConfig) -> bool:
        """
        Check if account is approved and report status back in case of PR
        :param config: service config
        :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
            # FIXME:
            #  Why check account_name when we whitelist namespace only (in whitelist.add_account())?
            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:
                    job_helper = CoprBuildJobHelper(
                        config=config,
                        package_config=event.get_package_config(),
                        project=project,
                        event=event,
                    )
                    msg = "Account is not whitelisted!"  # needs to be shorter
                    job_helper.report_status_to_all(description=msg,
                                                    state="error",
                                                    url=FAQ_URL)
                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)}")
            namespace = event.base_repo_namespace
            # FIXME:
            #  Why check account_name when we whitelist namespace only (in whitelist.add_account())?
            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)
                project.issue_comment(event.issue_id, msg)
                # TODO also check blacklist,
                # but for that we need to know who triggered the action
                return False
            return True

        msg = f"Failed to validate account: Unrecognized event type {type(event)}."
        logger.error(msg)
        raise PackitException(msg)
Ejemplo n.º 14
0
    def run(self):
        build_job_helper = CoprBuildJobHelper(
            service_config=self.service_config,
            package_config=self.package_config,
            project=self.project,
            metadata=self.data,
            db_trigger=self.db_trigger,
            job_config=self.job_config,
            pushgateway=self.pushgateway,
        )

        if self.copr_event.chroot == "srpm-builds":
            # we don't want to set check for this
            msg = "SRPM build in copr has finished."
            logger.debug(msg)
            return TaskResults(success=True, details={"msg": msg})

        if not self.build:
            # TODO: how could this happen?
            msg = f"Copr build {self.copr_event.build_id} not in CoprBuildDB."
            logger.warning(msg)
            return TaskResults(success=False, details={"msg": msg})
        if self.build.status in [
                PG_COPR_BUILD_STATUS_FAILURE,
                PG_COPR_BUILD_STATUS_SUCCESS,
        ]:
            msg = (f"Copr build {self.copr_event.build_id} is already"
                   f" processed (status={self.copr_event.build.status}).")
            logger.info(msg)
            return TaskResults(success=True, details={"msg": msg})

        self.pushgateway.copr_builds_finished.inc()

        # if the build is needed only for test, it doesn't have the task_accepted_time
        if self.build.task_accepted_time:
            copr_build_time = measure_time(end=datetime.now(timezone.utc),
                                           begin=self.build.task_accepted_time)
            self.pushgateway.copr_build_finished_time.observe(copr_build_time)

        end_time = (datetime.utcfromtimestamp(self.copr_event.timestamp)
                    if self.copr_event.timestamp else None)
        self.build.set_end_time(end_time)

        self.set_srpm_url(build_job_helper)

        url = get_copr_build_info_url(self.build.id)

        # https://pagure.io/copr/copr/blob/master/f/common/copr_common/enums.py#_42
        if self.copr_event.status != COPR_API_SUCC_STATE:
            failed_msg = "RPMs failed to be built."
            build_job_helper.report_status_to_all_for_chroot(
                state=BaseCommitStatus.failure,
                description=failed_msg,
                url=url,
                chroot=self.copr_event.chroot,
            )
            self.build.set_status(PG_COPR_BUILD_STATUS_FAILURE)
            return TaskResults(success=False, details={"msg": failed_msg})

        if (build_job_helper.job_build and build_job_helper.job_build.trigger
                == JobConfigTriggerType.pull_request and self.copr_event.pr_id
                and isinstance(self.project, (GithubProject, GitlabProject))
                and not self.was_last_packit_comment_with_congratulation() and
                self.job_config.notifications.pull_request.successful_build):
            msg = (
                f"Congratulations! One of the builds has completed. :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.copr_event.owner}/{self.copr_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.get_pr(self.copr_event.pr_id).comment(msg)

        build_job_helper.report_status_to_build_for_chroot(
            state=BaseCommitStatus.success,
            description="RPMs were built successfully.",
            url=url,
            chroot=self.copr_event.chroot,
        )
        build_job_helper.report_status_to_test_for_chroot(
            state=BaseCommitStatus.pending,
            description="RPMs were built successfully.",
            url=url,
            chroot=self.copr_event.chroot,
        )
        self.build.set_status(PG_COPR_BUILD_STATUS_SUCCESS)

        built_packages = build_job_helper.get_built_packages(
            int(self.build.build_id), self.build.target)
        self.build.set_built_packages(built_packages)

        if (build_job_helper.job_tests
                and self.copr_event.chroot in build_job_helper.tests_targets):
            signature(
                TaskName.testing_farm.value,
                kwargs={
                    "package_config": dump_package_config(self.package_config),
                    "job_config": dump_job_config(build_job_helper.job_tests),
                    "event": self.data.get_dict(),
                    "chroot": self.copr_event.chroot,
                    "build_id": self.build.id,
                },
            ).apply_async()
        else:
            logger.debug("Testing farm not in the job config.")

        return TaskResults(success=True, details={})
Ejemplo n.º 15
0
    def check_and_report(
        self,
        event: Optional[Any],
        project: GitProject,
        service_config: ServiceConfig,
        job_configs: Iterable[JobConfig],
    ) -> bool:
        """
        Check if account is approved and report status back in case of PR
        :param service_config: service config
        :param event: PullRequest and Release TODO: handle more
        :param project: GitProject
        :param job_configs: iterable of jobconfigs - so we know how to update status of the PR
        :return:
        """

        # whitelist checks dont apply to CentOS (Pagure, Gitlab)
        if isinstance(
                event,
            (
                PushPagureEvent,
                PullRequestPagureEvent,
                PullRequestCommentPagureEvent,
                MergeRequestCommentGitlabEvent,
                IssueCommentGitlabEvent,
                MergeRequestGitlabEvent,
                PushGitlabEvent,
            ),
        ):
            logger.info(
                "Centos (Pagure, Gitlab) events don't require whitelist checks."
            )
            return True

        # TODO: modify event hierarchy so we can use some abstract classes instead
        if isinstance(event, (ReleaseEvent, PushGitHubEvent)):
            account_name = event.repo_namespace
            if not account_name:
                raise KeyError(
                    f"Failed to get account_name from {type(event)!r}")
            if not self.is_approved(account_name):
                logger.info(
                    "Refusing release event on not whitelisted repo namespace."
                )
                return False
            return True
        if isinstance(
                event,
            (
                CoprBuildEvent,
                TestingFarmResultsEvent,
                DistGitEvent,
                InstallationEvent,
                KojiBuildEvent,
            ),
        ):
            return True
        if isinstance(event,
                      (PullRequestGithubEvent, PullRequestCommentGithubEvent)):
            account_name = event.user_login
            if not account_name:
                raise KeyError(
                    f"Failed to get account_name from {type(event)}")
            namespace = event.target_repo_namespace
            # FIXME:
            #  Why check account_name when we whitelist namespace only (in whitelist.add_account())?
            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)
                if event.trigger == TheJobTriggerType.pr_comment:
                    project.pr_comment(event.pr_id, msg)
                else:
                    for job_config in job_configs:
                        job_helper = CoprBuildJobHelper(
                            service_config=service_config,
                            package_config=event.get_package_config(),
                            project=project,
                            metadata=EventData.from_event_dict(
                                event.get_dict()),
                            db_trigger=event.db_trigger,
                            job_config=job_config,
                        )
                        msg = "Account is not whitelisted!"  # needs to be shorter
                        job_helper.report_status_to_all(
                            description=msg,
                            state=CommitStatus.error,
                            url=FAQ_URL)
                return False
            # TODO: clear failing check when present
            return True
        if isinstance(event, IssueCommentEvent):
            account_name = event.user_login
            if not account_name:
                raise KeyError(
                    f"Failed to get account_name from {type(event)}")
            namespace = event.repo_namespace
            # FIXME:
            #  Why check account_name when we whitelist namespace only (in whitelist.add_account())?
            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)
                project.issue_comment(event.issue_id, msg)
                return False
            return True

        msg = f"Failed to validate account: Unrecognized event type {type(event)!r}."
        logger.error(msg)
        raise PackitException(msg)