diff --git a/packit_service/events/github/push.py b/packit_service/events/github/push.py index 612c900f4..22e9d5fec 100644 --- a/packit_service/events/github/push.py +++ b/packit_service/events/github/push.py @@ -1,11 +1,15 @@ # Copyright Contributors to the Packit project. # SPDX-License-Identifier: MIT -from packit_service.service.db_project_events import AddBranchPushEventToDb +from packit_service.service.db_project_events import AddBranchPushEventToDb, CommitInfo from .abstract import GithubEvent +class GithubCommitInfo(CommitInfo): + pass + + class Commit(AddBranchPushEventToDb, GithubEvent): def __init__( self, @@ -15,6 +19,7 @@ def __init__( project_url: str, commit_sha: str, commit_sha_before: str, + commits: list[GithubCommitInfo], ): super().__init__(project_url=project_url) self.repo_namespace = repo_namespace @@ -23,6 +28,7 @@ def __init__( self.commit_sha = commit_sha self.commit_sha_before = commit_sha_before self.identifier = git_ref + self.commits = commits @classmethod def event_type(cls) -> str: diff --git a/packit_service/events/gitlab/push.py b/packit_service/events/gitlab/push.py index 84af2e9a6..8755bd33a 100644 --- a/packit_service/events/gitlab/push.py +++ b/packit_service/events/gitlab/push.py @@ -1,13 +1,15 @@ # Copyright Contributors to the Packit project. # SPDX-License-Identifier: MIT -from packit_service.service.db_project_events import ( - AddBranchPushEventToDb, -) +from packit_service.service.db_project_events import AddBranchPushEventToDb, CommitInfo from .abstract import GitlabEvent +class GitlabCommitInfo(CommitInfo): + pass + + class Commit(AddBranchPushEventToDb, GitlabEvent): def __init__( self, @@ -17,6 +19,7 @@ def __init__( project_url: str, commit_sha: str, commit_sha_before: str, + commits: list[GitlabCommitInfo], ): super().__init__(project_url=project_url) self.repo_namespace = repo_namespace @@ -25,6 +28,7 @@ def __init__( self.commit_sha = commit_sha self.commit_sha_before = commit_sha_before self.identifier = git_ref + self.commits = commits @classmethod def event_type(cls) -> str: diff --git a/packit_service/service/db_project_events.py b/packit_service/service/db_project_events.py index ffa31366b..44bac0217 100644 --- a/packit_service/service/db_project_events.py +++ b/packit_service/service/db_project_events.py @@ -5,7 +5,7 @@ This file contains helper classes for events. """ -from typing import Optional +from typing import Optional, TypedDict from ogr.abstract import GitProject @@ -61,12 +61,22 @@ def get_dict(self, default_dict: Optional[dict] = None) -> dict: return result +class CommitInfo(TypedDict, total=False): + id: str + title: str + message: str + added: list[str] + modified: list[str] + removed: list[str] + + class AddBranchPushEventToDb: git_ref: str repo_namespace: str repo_name: str project_url: str commit_sha: str + commits: list[CommitInfo] _branch: GitBranchModel = None _event: ProjectEventModel = None diff --git a/packit_service/worker/checker/copr.py b/packit_service/worker/checker/copr.py index 57e36088b..50cc672ab 100644 --- a/packit_service/worker/checker/copr.py +++ b/packit_service/worker/checker/copr.py @@ -2,11 +2,14 @@ # SPDX-License-Identifier: MIT import logging +from pathlib import Path + +from packit.config import JobConfigTriggerType from packit_service.constants import ( INTERNAL_TF_BUILDS_AND_TESTS_NOT_ALLOWED, ) -from packit_service.events import gitlab +from packit_service.events import github, gitlab from packit_service.worker.checker.abstract import ( ActorChecker, Checker, @@ -138,3 +141,53 @@ def _pre_check(self) -> bool: ) return False return True + + +class AreFilesChanged(Checker, GetCoprBuildJobHelperForIdMixin, ConfigFromEventMixin): + """ + Check if any files under the current package's `paths` field is changed. + If not, then just skip the current copr build job. + """ + + def get_files_changed(self) -> list[Path]: + """ + Get the list of files changed in the current commit or the current pullrequest + """ + # Get the changes object + if self.job_config.trigger == JobConfigTriggerType.pull_request: + pr_event = self.data.to_event() + if not isinstance(pr_event, (github.pr.Action, gitlab.mr.Action)): + # TODO: What about comments? + raise NotImplementedError() + # TODO: How to handle PRs? + raise NotImplementedError() + if self.job_config.trigger == JobConfigTriggerType.commit: + push_event = self.data.to_event() + if not isinstance(push_event, (github.push.Commit, gitlab.push.Commit)): + raise NotImplementedError() + files = set() + for commit in push_event.commits: + files |= set(commit["modified"]) + files |= set(commit["added"]) + # TODO: Check what the path is relative to + return [Path(file) for file in files] + raise NotImplementedError(f"Trigger not supported: {self.job_config.trigger}") + + def pre_check(self) -> bool: + if self.job_config.trigger == JobConfigTriggerType.release: + # For releases we don't do any checks + return True + # FIXME: This is probably unnecessary + package_config = self.package_config.get_package_config_for(self.job_config) + # The paths that we need to check for files changed + paths = package_config["paths"] + # Early check if the git root was included, in which case we don't need to + # check the files changed + # TODO: refine this check when gitignore-like patterns are supported + if "./" in paths: + return True + for changed_file in self.get_files_changed(): + # Check if any of the files changed are under the paths that are being tracked + if any(changed_file.is_relative_to(p) for p in paths): + return True + return False diff --git a/packit_service/worker/handlers/copr.py b/packit_service/worker/handlers/copr.py index 2c410bff2..ee481802b 100644 --- a/packit_service/worker/handlers/copr.py +++ b/packit_service/worker/handlers/copr.py @@ -41,6 +41,7 @@ ) from packit_service.worker.checker.abstract import Checker from packit_service.worker.checker.copr import ( + AreFilesChanged, AreOwnerAndProjectMatchingJob, BuildNotAlreadyStarted, CanActorRunTestsJob, @@ -116,6 +117,7 @@ def get_checkers() -> tuple[type[Checker], ...]: IsJobConfigTriggerMatching, IsGitForgeProjectAndEventOk, CanActorRunTestsJob, + AreFilesChanged, ) def run(self) -> TaskResults: diff --git a/packit_service/worker/parser.py b/packit_service/worker/parser.py index d8dbd6e2b..78ce0cb70 100644 --- a/packit_service/worker/parser.py +++ b/packit_service/worker/parser.py @@ -9,7 +9,7 @@ from dataclasses import dataclass from datetime import datetime, timezone from os import getenv -from typing import Any, Callable, ClassVar, Optional, Union +from typing import Any, Callable, ClassVar, Optional, Union, cast from ogr.parsing import RepoUrl, parse_git_repo from packit.config import JobConfigTriggerType @@ -64,8 +64,9 @@ class _GitlabCommonData: project_url: str parsed_url: Optional[RepoUrl] ref: str - head_commit: dict + head_commit: gitlab.push.GitlabCommitInfo commit_sha_before: str + commits: list[gitlab.push.GitlabCommitInfo] @property def commit_sha(self) -> str: @@ -420,7 +421,9 @@ def get_gitlab_push_common_data(event) -> _GitlabCommonData: before = event.get("before") checkout_sha = event.get("checkout_sha") actor = event.get("user_username") - commits = event.get("commits", []) + commits = [ + cast(gitlab.push.GitlabCommitInfo, commit) for commit in event.get("commits", []) + ] number_of_commits = event.get("total_commits_count") if not Parser.is_gitlab_push_a_create_event(event): @@ -455,6 +458,7 @@ def get_gitlab_push_common_data(event) -> _GitlabCommonData: ref=ref, head_commit=head_commit, commit_sha_before=before, + commits=commits, ) @staticmethod @@ -515,6 +519,7 @@ def parse_gitlab_push_event(event) -> Optional[gitlab.push.Commit]: project_url=data.project_url, commit_sha=data.commit_sha, commit_sha_before=data.commit_sha_before, + commits=data.commits, ) @staticmethod @@ -561,6 +566,8 @@ def parse_github_push_event(event) -> Optional[github.push.Commit]: repo_url = nested_get(event, "repository", "html_url") + commits = [cast(github.push.GithubCommitInfo, commit) for commit in event.get("commits")] + return github.push.Commit( repo_namespace=repo_namespace, repo_name=repo_name, @@ -568,6 +575,7 @@ def parse_github_push_event(event) -> Optional[github.push.Commit]: project_url=repo_url, commit_sha=head_commit, commit_sha_before=before, + commits=commits, ) @staticmethod