Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion packit_service/events/github/push.py
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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
Expand All @@ -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:
Expand Down
10 changes: 7 additions & 3 deletions packit_service/events/gitlab/push.py
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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
Expand All @@ -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:
Expand Down
12 changes: 11 additions & 1 deletion packit_service/service/db_project_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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

Expand Down
55 changes: 54 additions & 1 deletion packit_service/worker/checker/copr.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about we create another Mixin class, which will use the existing get_pr_files_diff function in ogr to retrieve the files diff? It should return a dictionary, so we would need to process it into a list of files changed.

// dictionary representing files diff
files_changed = project.get_pr_files_diff(pr_id=id_from_pr_event) 

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does not seem to be available for github and gitlab? https://github.com/search?q=repo%3Apackit%2Fogr%20get_pr_files_diff&type=code And I think the internal API would not make it efficient to query that format. Maybe we go through packit/ogr#921?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, you're right. In that case using packit/ogr#921 sounds good to me.

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)
Comment on lines +180 to +181

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you think this might be unnecessary?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking about the usage of the method get_package_config_for. In some other parts I see that the method is not used and I assume it would already be processed when self.package_config is used.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, it seems that the get_package_config_for is used to get the config from a config for multiple packages (usually named packages_config) based on a specific job config. In other existing code, I only see packages_config.get_package_config_for being used, but never package_config.get_package_config_for. I think using self.package_config directly might be the right way to do it, but I'm not exactly sure. Tests should hopefully reveal what it right.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, worst case this is just a no-op, but if anyone with more experience could chyme in and confirm it quickly then we can resolve this one way or the other. Let's keep this open for a bit.

# 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
Comment on lines +189 to +193
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, what do we do if we have an empty commit, like the Fedora rebuild commits? Should it be a special case to skip this check?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

like the Fedora rebuild commits?

those wouldn't be happening in upstream, so I don't think we have to think about that, or am I missing something?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean if they want to have that behaviour. I occasionally do that 1, but if it's documented that it is or it is not supported, than that's fine as well.

Footnotes

  1. https://github.com/LecrisUT/FedoraRPM-atuin/commit/99555ccec9f6ed94fe474767e3b88f18aa835387

2 changes: 2 additions & 0 deletions packit_service/worker/handlers/copr.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
)
from packit_service.worker.checker.abstract import Checker
from packit_service.worker.checker.copr import (
AreFilesChanged,
AreOwnerAndProjectMatchingJob,
BuildNotAlreadyStarted,
CanActorRunTestsJob,
Expand Down Expand Up @@ -116,6 +117,7 @@ def get_checkers() -> tuple[type[Checker], ...]:
IsJobConfigTriggerMatching,
IsGitForgeProjectAndEventOk,
CanActorRunTestsJob,
AreFilesChanged,
)

def run(self) -> TaskResults:
Expand Down
14 changes: 11 additions & 3 deletions packit_service/worker/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -561,13 +566,16 @@ 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,
git_ref=ref,
project_url=repo_url,
commit_sha=head_commit,
commit_sha_before=before,
commits=commits,
)

@staticmethod
Expand Down
Loading