Skip to content

Commit

Permalink
Rework handler for Koji scratch build reporting
Browse files Browse the repository at this point in the history
So that it can be used for both upstream and downstream reporting.
  • Loading branch information
lbarcziova committed Nov 22, 2024
1 parent 29a3ee9 commit 110a4f9
Show file tree
Hide file tree
Showing 6 changed files with 232 additions and 39 deletions.
7 changes: 7 additions & 0 deletions packit_service/worker/checker/koji.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

import logging

from ogr.services.pagure import PagureProject

from packit_service.constants import (
KOJI_PRODUCTION_BUILDS_ISSUE,
PERMISSIONS_ERROR_WRITE_OR_ADMIN,
Expand All @@ -25,6 +27,11 @@ def pre_check(self) -> bool:
return self.koji_build_helper.is_job_config_trigger_matching(self.job_config)


class IsUpstreamKojiScratchBuild(Checker, GetKojiBuildJobHelperMixin):
def pre_check(self) -> bool:
return not isinstance(self.koji_build_helper.project, PagureProject)


class PermissionOnKoji(Checker, GetKojiBuildJobHelperMixin):
def pre_check(self) -> bool:
if (
Expand Down
1 change: 1 addition & 0 deletions packit_service/worker/handlers/abstract.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ class TaskName(str, enum.Enum):
openscanhub_task_finished = "task.openscanhub_task_finished"
openscanhub_task_started = "task.openscanhub_task_started"
downstream_koji_scratch_build = "task.run_downstream_koji_scratch_build_handler"
downstream_koji_scratch_build_report = "task.run_downstream_koji_scratch_build_report_handler"


class Handler(PackitAPIProtocol, Config):
Expand Down
135 changes: 96 additions & 39 deletions packit_service/worker/handlers/koji.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"""

import logging
from abc import ABC, abstractmethod
from datetime import datetime
from os import getenv
from typing import Optional
Expand Down Expand Up @@ -40,6 +41,7 @@
from packit_service.worker.checker.abstract import Checker
from packit_service.worker.checker.koji import (
IsJobConfigTriggerMatching,
IsUpstreamKojiScratchBuild,
PermissionOnKoji,
SidetagExists,
)
Expand All @@ -62,13 +64,15 @@
TaskName,
configured_as,
reacts_to,
reacts_to_as_fedora_ci,
run_for_check_rerun,
run_for_comment,
)
from packit_service.worker.handlers.bodhi import BodhiUpdateFromSidetagHandler
from packit_service.worker.handlers.distgit import DownstreamKojiBuildHandler
from packit_service.worker.handlers.mixin import GetKojiBuildJobHelperMixin
from packit_service.worker.helpers.build.koji_build import KojiBuildJobHelper
from packit_service.worker.helpers.fedora_ci import FedoraCIHelper
from packit_service.worker.helpers.sidetag import SidetagHelper
from packit_service.worker.mixin import (
ConfigFromEventMixin,
Expand Down Expand Up @@ -130,16 +134,9 @@ def run(self) -> TaskResults:
return self.koji_build_helper.run_koji_build()


@configured_as(job_type=JobType.production_build)
@configured_as(job_type=JobType.upstream_koji_build)
@reacts_to(event=KojiTaskEvent)
class KojiTaskReportHandler(
JobHandler,
PackitAPIWithDownstreamMixin,
ConfigFromEventMixin,
class AbstractKojiTaskReportHandler(
ABC, JobHandler, PackitAPIWithDownstreamMixin, ConfigFromEventMixin
):
task_name = TaskName.upstream_koji_build_report

def __init__(
self,
package_config: PackageConfig,
Expand All @@ -156,6 +153,14 @@ def __init__(
self._db_project_event: Optional[ProjectEventModel] = None
self._build: Optional[KojiBuildTargetModel] = None

@abstractmethod
def report(self, description: str, commit_status: BaseCommitStatus, url: str): ...

@abstractmethod
def notify_about_failure_if_configured(
self, packit_dashboard_url: str, external_dashboard_url: str, logs_url: str
): ...

@property
def build(self) -> Optional[KojiBuildTargetModel]:
if not self._build:
Expand All @@ -171,45 +176,33 @@ def db_project_event(self) -> Optional[ProjectEventModel]:
return self._db_project_event

def run(self):
build = KojiBuildTargetModel.get_by_task_id(
task_id=str(self.koji_task_event.task_id),
)

if not build:
if not self.build:
msg = f"Koji task {self.koji_task_event.task_id} not found in the database."
logger.warning(msg)
return TaskResults(success=False, details={"msg": msg})

logger.debug(
f"Build on {build.target} in koji changed state "
f"Build on {self.build.target} in Koji changed state "
f"from {self.koji_task_event.old_state} to {self.koji_task_event.state}.",
)

build.set_build_start_time(
self.build.set_build_start_time(
(
datetime.utcfromtimestamp(self.koji_task_event.start_time)
if self.koji_task_event.start_time
else None
),
)

build.set_build_finished_time(
self.build.set_build_finished_time(
(
datetime.utcfromtimestamp(self.koji_task_event.completion_time)
if self.koji_task_event.completion_time
else None
),
)

url = get_koji_build_info_url(build.id)
build_job_helper = KojiBuildJobHelper(
service_config=self.service_config,
package_config=self.package_config,
project=self.project,
metadata=self.data,
db_project_event=self.db_project_event,
job_config=self.job_config,
)
url = get_koji_build_info_url(self.build.id)

new_commit_status = {
KojiTaskState.free: BaseCommitStatus.pending,
Expand All @@ -233,7 +226,7 @@ def run(self):
logger.debug(
f"We don't react to this koji build state change: {self.koji_task_event.state}",
)
elif new_commit_status.value == build.status:
elif new_commit_status.value == self.build.status:
logger.debug(
"Status was already processed (status in the DB is the "
"same as the one about to report)",
Expand All @@ -244,38 +237,102 @@ def run(self):
)

else:
build.set_status(new_commit_status.value)
build_job_helper.report_status_to_all_for_chroot(
description=description,
state=new_commit_status,
url=url,
chroot=build.target,
)
self.build.set_status(new_commit_status.value)
self.report(description, new_commit_status, url)
koji_build_logs = self.koji_task_event.get_koji_build_rpm_tasks_logs_urls(
self.service_config.koji_logs_url,
)

build.set_build_logs_urls(koji_build_logs)
self.build.set_build_logs_urls(koji_build_logs)
koji_rpm_task_web_url = KojiTaskEvent.get_koji_rpm_build_web_url(
rpm_build_task_id=int(build.task_id),
rpm_build_task_id=int(self.build.task_id),
koji_web_url=self.service_config.koji_web_url,
)
build.set_web_url(koji_rpm_task_web_url)
self.build.set_web_url(koji_rpm_task_web_url)

if self.koji_task_event.state == KojiTaskState.failed:
build_job_helper.notify_about_failure_if_configured(
self.notify_about_failure_if_configured(
packit_dashboard_url=url,
external_dashboard_url=koji_rpm_task_web_url,
logs_url=koji_build_logs,
)

msg = (
f"Build on {build.target} in koji changed state "
f"Build on {self.build.target} in koji changed state "
f"from {self.koji_task_event.old_state} to {self.koji_task_event.state}."
)
return TaskResults(success=True, details={"msg": msg})


@configured_as(job_type=JobType.production_build)
@configured_as(job_type=JobType.upstream_koji_build)
@reacts_to(event=KojiTaskEvent)
class KojiTaskReportHandler(AbstractKojiTaskReportHandler):
task_name = TaskName.upstream_koji_build_report
_helper: Optional[KojiBuildJobHelper] = None

@property
def helper(self):
if not self._helper:
self._helper = KojiBuildJobHelper(
service_config=self.service_config,
package_config=self.package_config,
project=self.project,
metadata=self.data,
db_project_event=self.db_project_event,
job_config=self.job_config,
)
return self._helper

@staticmethod
def get_checkers() -> tuple[type[Checker], ...]:
return (IsUpstreamKojiScratchBuild,)

def report(self, description: str, commit_status: BaseCommitStatus, url: str):
self.helper.report_status_to_all_for_chroot(
description=description,
state=commit_status,
url=url,
chroot=self.build.target,
)

def notify_about_failure_if_configured(
self, packit_dashboard_url: str, external_dashboard_url: str, logs_url: str
):
self.helper.notify_about_failure_if_configured(
packit_dashboard_url=packit_dashboard_url,
external_dashboard_url=external_dashboard_url,
logs_url=logs_url,
)


@reacts_to_as_fedora_ci(event=KojiTaskEvent)
class KojiTaskReportDownstreamHandler(AbstractKojiTaskReportHandler):
task_name = TaskName.downstream_koji_build_report
_helper: Optional[FedoraCIHelper] = None

@property
def helper(self):
if not self._helper:
self._helper = FedoraCIHelper(
project=self.project,
metadata=self.data,
)
return self._helper

def report(self, description: str, commit_status: BaseCommitStatus, url: str):
self.helper.report(
state=commit_status,
description=description,
url=url,
)

def notify_about_failure_if_configured(
self, packit_dashboard_url: str, external_dashboard_url: str, logs_url: str
):
pass


@configured_as(job_type=JobType.koji_build)
@configured_as(job_type=JobType.bodhi_update)
@reacts_to(event=KojiBuildEvent)
Expand Down
11 changes: 11 additions & 0 deletions packit_service/worker/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
from packit_service.worker.handlers.koji import (
KojiBuildReportHandler,
KojiBuildTagHandler,
KojiTaskReportDownstreamHandler,
)
from packit_service.worker.handlers.usage import check_onboarded_projects
from packit_service.worker.helpers.build.babysit import (
Expand Down Expand Up @@ -396,6 +397,16 @@ def run_koji_build_report_handler(event: dict, package_config: dict, job_config:
return get_handlers_task_results(handler.run_job(), event)


@celery_app.task(name=TaskName.downstream_koji_scratch_build_report, base=TaskWithRetry)
def run_downstream_koji_scratch_build_report_handler(
event: dict, package_config: dict, job_config: dict
):
handler = KojiTaskReportDownstreamHandler(
package_config=load_package_config(package_config),
job_config=load_job_config(job_config),
event=event,
)
return get_handlers_task_results(handler.run_job(), event)


@celery_app.task(bind=True, name=TaskName.downstream_koji_scratch_build, base=TaskWithRetry)
Expand Down
58 changes: 58 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,64 @@ def koji_build_pr():
return koji_build_model


@pytest.fixture()
def koji_build_pr_downstream():
project_model = flexmock(
repo_name="packit",
namespace="rpms",
project_url="https://src.fedoraproject.org/rpms/packit",
)
pr_model = flexmock(
id=1,
pr_id=123,
project=project_model,
job_config_trigger_type=JobConfigTriggerType.pull_request,
project_event_model_type=ProjectEventModelType.pull_request,
commit_sha="0011223344",
)
project_event_model = flexmock(
id=2,
type=ProjectEventModelType.pull_request,
event_id=1,
get_project_event_object=lambda: pr_model,
)
runs = []
srpm_build = flexmock(logs="asdsdf", url=None, runs=runs)
koji_build_model = flexmock(
id=1,
task_id="1",
commit_sha="0011223344",
project_name="some-project",
owner="some-owner",
web_url="https://some-url",
target="some-target",
status="some-status",
runs=runs,
)
koji_build_model._srpm_build_for_mocking = srpm_build
koji_build_model.get_project_event_object = lambda: pr_model
koji_build_model.get_srpm_build = lambda: srpm_build
koji_build_model.should_receive("get_project_event_model").and_return(
project_event_model,
)

flexmock(ProjectEventModel).should_receive("get_or_create").with_args(
type=pr_model.project_event_model_type,
event_id=pr_model.id,
commit_sha="0011223344",
).and_return(project_event_model)

run_model = flexmock(
id=3,
job_project_event=project_event_model,
srpm_build=srpm_build,
copr_build=koji_build_model,
)
runs.append(run_model)

return koji_build_model


@pytest.fixture()
def add_pull_request_event_with_sha_123456():
db_project_object = flexmock(
Expand Down
Loading

0 comments on commit 110a4f9

Please sign in to comment.