Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement koji_build trigger for koji_build job #2457

Merged
merged 4 commits into from
Jul 16, 2024
Merged
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
61 changes: 61 additions & 0 deletions alembic/versions/e05e1b04de87_add_koji_build_tags.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
"""Add Koji build tags

Revision ID: e05e1b04de87
Revises: 487a77980f7e
Create Date: 2024-05-30 14:03:28.962664

"""

from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = "e05e1b04de87"
down_revision = "487a77980f7e"
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table(
"koji_build_tags",
sa.Column("id", sa.Integer(), nullable=False),
sa.Column("task_id", sa.String(), nullable=True),
sa.Column("koji_tag_name", sa.String(), nullable=True),
sa.Column("project_id", sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(
["project_id"],
["git_projects.id"],
),
sa.PrimaryKeyConstraint("id"),
)
op.create_index(
op.f("ix_koji_build_tags_task_id"), "koji_build_tags", ["task_id"], unique=False
)
op.create_index(
op.f("ix_koji_build_tags_koji_tag_name"),
"koji_build_tags",
["koji_tag_name"],
unique=False,
)
op.create_index(
op.f("ix_koji_build_tags_project_id"),
"koji_build_tags",
["project_id"],
unique=False,
)
op.execute("ALTER TYPE projecteventtype ADD VALUE 'koji_build_tag'")
nforro marked this conversation as resolved.
Show resolved Hide resolved
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_index(op.f("ix_koji_build_tags_project_id"), table_name="koji_build_tags")
op.drop_index(
op.f("ix_koji_build_tags_koji_tag_name"), table_name="koji_build_tags"
)
op.drop_index(op.f("ix_koji_build_tags_task_id"), table_name="koji_build_tags")
op.drop_table("koji_build_tags")
# ### end Alembic commands ###
78 changes: 78 additions & 0 deletions packit_service/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,7 @@ class ProjectEventModelType(str, enum.Enum):
branch_push = "branch_push"
release = "release"
issue = "issue"
koji_build_tag = "koji_build_tag"


class BuildsAndTestsConnector:
Expand Down Expand Up @@ -456,6 +457,7 @@ class GitProjectModel(Base):
branches = relationship("GitBranchModel", back_populates="project")
releases = relationship("ProjectReleaseModel", back_populates="project")
issues = relationship("IssueModel", back_populates="project")
koji_build_tags = relationship("KojiBuildTagModel", back_populates="project")
sync_release_pull_requests = relationship(
"SyncReleasePullRequestModel", back_populates="project"
)
Expand Down Expand Up @@ -1252,11 +1254,63 @@ def __repr__(self):
)


class KojiBuildTagModel(BuildsAndTestsConnector, Base):
__tablename__ = "koji_build_tags"
id = Column(Integer, primary_key=True) # our database PK
task_id = Column(String, index=True)
koji_tag_name = Column(String, index=True)
project_id = Column(Integer, ForeignKey("git_projects.id"), index=True)
project = relationship("GitProjectModel", back_populates="koji_build_tags")

job_config_trigger_type = JobConfigTriggerType.koji_build
project_event_model_type = ProjectEventModelType.koji_build_tag

@classmethod
def get_or_create(
cls,
task_id: str,
koji_tag_name: str,
namespace: str,
repo_name: str,
project_url: str,
) -> "KojiBuildTagModel":
with sa_session_transaction(commit=True) as session:
project = GitProjectModel.get_or_create(
namespace=namespace, repo_name=repo_name, project_url=project_url
)
koji_build_tag = (
session.query(KojiBuildTagModel)
.filter_by(
task_id=task_id, koji_tag_name=koji_tag_name, project_id=project.id
)
.first()
)
if not koji_build_tag:
koji_build_tag = KojiBuildTagModel()
koji_build_tag.task_id = task_id
koji_build_tag.koji_tag_name = koji_tag_name
koji_build_tag.project_id = project.id
session.add(koji_build_tag)
return koji_build_tag

@classmethod
def get_by_id(cls, id_: int) -> Optional["KojiBuildTagModel"]:
with sa_session_transaction() as session:
return session.query(KojiBuildTagModel).filter_by(id=id_).first()

def __repr__(self):
return (
f"KojiBuildTagModel(task_id={self.task_id}, koji_tag_name={self.koji_tag_name}, "
f"project={self.project})"
)


AbstractProjectObjectDbType = Union[
PullRequestModel,
ProjectReleaseModel,
GitBranchModel,
IssueModel,
KojiBuildTagModel,
]

MODEL_FOR_PROJECT_EVENT: Dict[
Expand All @@ -1266,6 +1320,7 @@ def __repr__(self):
ProjectEventModelType.branch_push: GitBranchModel,
ProjectEventModelType.release: ProjectReleaseModel,
ProjectEventModelType.issue: IssueModel,
ProjectEventModelType.koji_build_tag: KojiBuildTagModel,
}


Expand Down Expand Up @@ -1383,6 +1438,29 @@ def add_issue_event(
)
return (issue, event)

@classmethod
def add_koji_build_tag_event(
cls,
task_id: str,
koji_tag_name: str,
namespace: str,
repo_name: str,
project_url: str,
) -> Tuple[KojiBuildTagModel, "ProjectEventModel"]:
koji_build_tag = KojiBuildTagModel.get_or_create(
task_id=task_id,
koji_tag_name=koji_tag_name,
namespace=namespace,
repo_name=repo_name,
project_url=project_url,
)
event = ProjectEventModel.get_or_create(
type=koji_build_tag.project_event_model_type,
event_id=koji_build_tag.id,
commit_sha=None,
)
return (koji_build_tag, event)

@classmethod
def get_or_create(
cls, type: ProjectEventModelType, event_id: int, commit_sha: str
Expand Down
3 changes: 2 additions & 1 deletion packit_service/worker/allowlist.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
CheckRerunEvent,
)
from packit_service.worker.events.gitlab import ReleaseGitlabEvent
from packit_service.worker.events.koji import KojiBuildEvent
from packit_service.worker.events.koji import KojiBuildEvent, KojiBuildTagEvent
from packit_service.worker.events.new_hotness import NewHotnessUpdateEvent
from packit_service.worker.helpers.build import CoprBuildJobHelper
from packit_service.worker.helpers.testing_farm import TestingFarmJobHelper
Expand Down Expand Up @@ -482,6 +482,7 @@ def check_and_report(
InstallationEvent,
KojiTaskEvent,
KojiBuildEvent,
KojiBuildTagEvent,
CheckRerunEvent,
NewHotnessUpdateEvent,
): self._check_unchecked_event,
Expand Down
6 changes: 6 additions & 0 deletions packit_service/worker/checker/koji.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
KOJI_PRODUCTION_BUILDS_ISSUE,
PERMISSIONS_ERROR_WRITE_OR_ADMIN,
)
from packit_service.models import SidetagModel
from packit_service.worker.checker.abstract import Checker
from packit_service.worker.events import (
MergeRequestGitlabEvent,
Expand Down Expand Up @@ -55,3 +56,8 @@ def pre_check(self) -> bool:
return False

return True


class SidetagExists(Checker):
def pre_check(self) -> bool:
return SidetagModel.get_by_koji_name(self.data.tag_name) is not None
13 changes: 13 additions & 0 deletions packit_service/worker/events/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,19 @@ def _add_project_object_and_event(self):
repo_name=self.project.repo,
project_url=self.project_url,
)
elif self.event_type in {
"KojiBuildTagEvent",
}:
(
self._db_project_object,
self._db_project_event,
) = ProjectEventModel.add_koji_build_tag_event(
task_id=str(self.event_dict.get("event_dict", {}).get("task_id")),
koji_tag_name=self.tag_name,
namespace=self.project.namespace,
repo_name=self.project.repo,
project_url=self.project_url,
)
else:
logger.warning(
"We don't know, what to search in the database for this event data."
Expand Down
52 changes: 52 additions & 0 deletions packit_service/worker/events/koji.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from ogr.abstract import GitProject
from ogr.services.pagure import PagureProject
from packit.config import JobConfigTriggerType, PackageConfig
from packit.utils.koji_helper import KojiHelper
from packit_service.config import PackageConfigGetter
from packit_service.constants import KojiBuildState, KojiTaskState
from packit_service.models import (
Expand Down Expand Up @@ -332,3 +333,54 @@ def get_dict(self, default_dict: Optional[Dict] = None) -> dict:
result["git_ref"] = self.git_ref
result["identifier"] = self.identifier
return result


@use_for_job_config_trigger(trigger_type=JobConfigTriggerType.koji_build)
class KojiBuildTagEvent(AbstractKojiEvent):

_koji_helper: Optional[KojiHelper] = None

def __init__(
self,
build_id: int,
tag_id: int,
tag_name: str,
project_url: str,
package_name: str,
epoch: str,
version: str,
release: str,
owner: str,
):
task_id = None
if info := self.koji_helper.get_build_info(build_id):
task_id = info.get("task_id")

super().__init__(task_id=task_id)

self.build_id = build_id
self.tag_id = tag_id
self.tag_name = tag_name
self.project_url = project_url
self.package_name = package_name
self.epoch = epoch
self.version = version
self.release = release
self.owner = owner

@property
def koji_helper(self) -> KojiHelper:
if not self._koji_helper:
self._koji_helper = KojiHelper()
return self._koji_helper

@property
def commit_sha(self) -> Optional[str]: # type:ignore
return None

@property
def nvr(self) -> str:
return f"{self.package_name}-{self.version}-{self.release}"

def get_non_serializable_attributes(self):
return super().get_non_serializable_attributes() + ["_koji_helper"]
3 changes: 2 additions & 1 deletion packit_service/worker/handlers/abstract.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,8 +186,9 @@ class TaskName(str, enum.Enum):
github_fas_verification = "task.github_fas_verification"
vm_image_build = "task.run_vm_image_build_handler"
vm_image_build_result = "task.run_vm_image_build_result_handler"
pull_from_upstream = "pull_from_upstream"
pull_from_upstream = "task.pull_from_upstream"
check_onboarded_projects = "task.check_onboarded_projects"
koji_build_tag = "task.koji_build_tag"


class Handler(PackitAPIProtocol, Config):
Expand Down
20 changes: 20 additions & 0 deletions packit_service/worker/handlers/distgit.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
IssueCommentEvent,
IssueCommentGitlabEvent,
)
from packit_service.worker.events.koji import KojiBuildTagEvent
from packit_service.worker.events.new_hotness import NewHotnessUpdateEvent
from packit_service.worker.handlers.abstract import (
JobHandler,
Expand Down Expand Up @@ -795,6 +796,19 @@ def run(self) -> TaskResults:
else:
sidetag = None

# skip submitting build for a branch if dependencies
# are not satisfied within a sidetag
if sidetag and self.job_config.dependencies:
builds = self.koji_helper.get_builds_in_tag(sidetag.koji_name)
tagged_packages = {b["package_name"] for b in builds}
if set(self.job_config.dependencies) <= tagged_packages:
missing = set(self.job_config.dependencies) - tagged_packages
logger.debug(
f"Skipping downstream Koji build for branch {branch}, "
f"missing dependencies: {missing}"
)
continue

stdout = self.packit_api.build(
dist_git_branch=koji_build_model.target,
scratch=self.job_config.scratch,
Expand Down Expand Up @@ -877,6 +891,7 @@ def report_in_issue_repository(self, errors: dict[str, str]) -> None:
@run_for_comment(command="koji-build")
@reacts_to(event=PushPagureEvent)
@reacts_to(event=PullRequestCommentPagureEvent)
@reacts_to(event=KojiBuildTagEvent)
class DownstreamKojiBuildHandler(
AbstractDownstreamKojiBuildHandler,
ConfigFromEventMixin,
Expand Down Expand Up @@ -922,6 +937,11 @@ def get_trigger_type_description(self) -> str:
f"Fedora Koji build was triggered "
f"by push with sha {self.data.commit_sha}."
)
elif self.data.event_type == KojiBuildTagEvent.__name__:
trigger_type_description += (
f"Fedora Koji build was triggered "
f"by tagging of build {self.data.build_id} to {self.data.koji_tag_name}."
)
return trigger_type_description

@staticmethod
Expand Down
Loading
Loading