Skip to content

Commit

Permalink
Handle /packit koji-tag dist-git PR comment command (#2507)
Browse files Browse the repository at this point in the history
Handle `/packit koji-tag` dist-git PR comment command

Fixes #2468.

Reviewed-by: Maja Massarini
Reviewed-by: Nikola Forró
Reviewed-by: Matej Focko
  • Loading branch information
softwarefactory-project-zuul[bot] authored Aug 27, 2024
2 parents 6f08bb5 + 3fa84a2 commit aab0ccd
Show file tree
Hide file tree
Showing 11 changed files with 280 additions and 66 deletions.
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ repos:
additional_dependencies:
[
types-jwt,
types-pkg_resources,
types-setuptools,
types-redis,
types-requests,
types-Flask,
Expand Down
23 changes: 16 additions & 7 deletions packit_service/worker/checker/distgit.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@

from packit.config.aliases import get_branches
from packit_service.constants import MSG_GET_IN_TOUCH
from packit_service.utils import pr_labels_match_configuration
from packit_service.utils import (
pr_labels_match_configuration,
get_packit_commands_from_comment,
)
from packit_service.worker.checker.abstract import Checker, ActorChecker
from packit_service.worker.checker.helper import DistgitAccountsChecker
from packit_service.worker.events import (
Expand Down Expand Up @@ -93,24 +96,30 @@ def pre_check(self) -> bool:
)
return False
elif self.data.event_type in (PullRequestCommentPagureEvent.__name__,):
comment = self.data.event_dict.get("comment", "")
commands = get_packit_commands_from_comment(
comment, self.service_config.comment_command_prefix
)
command = commands[0] if commands else ""
commenter = self.data.actor
logger.debug(
f"Triggering downstream koji build through comment by: {commenter}"
f"{'Tagging' if command == 'koji-tag' else 'Triggering'} "
f"downstream koji build through comment by: {commenter}"
)
if not self.is_packager(commenter):
msg = (
f"koji-build retriggering through comment "
f"on PR identifier {self.data.pr_id} "
f"koji-build {'tagging' if command == 'koji-tag' else 'retriggering'} "
f"through comment on PR identifier {self.data.pr_id} "
f"and project {self.data.project_url} "
f"done by {commenter} which is not a packager."
f"done by {commenter} who is not a packager."
)
logger.info(msg)
report_in_issue_repository(
issue_repository=self.job_config.issue_repository,
service_config=self.service_config,
title=(
"Re-triggering downstream koji build "
"through comment in dist-git PR failed"
f"{'Tagging' if command == 'koji-tag' else 'Re-triggering'} "
"downstream koji build through comment in dist-git PR failed"
),
message=msg + MSG_GET_IN_TOUCH,
comment_to_existing=msg,
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 @@ -190,6 +190,7 @@ class TaskName(str, enum.Enum):
pull_from_upstream = "task.pull_from_upstream"
check_onboarded_projects = "task.check_onboarded_projects"
koji_build_tag = "task.koji_build_tag"
tag_into_sidetag = "task.tag_into_sidetag"


class Handler(PackitAPIProtocol, Config):
Expand Down
13 changes: 2 additions & 11 deletions packit_service/worker/handlers/bodhi.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,19 +129,10 @@ def get_builds_in_sidetag(self, dist_git_branch: str) -> Tuple[str, List[str]]:
missing = dependencies - tagged_packages
raise PackitException(f"Missing dependencies for Bodhi update: {missing}")

if not (candidate_tag := self.koji_helper.get_candidate_tag(dist_git_branch)):
raise PackitException(f"Failed to get candidate tag for {dist_git_branch}")

stable_tags = self.koji_helper.get_stable_tags(candidate_tag)

nvrs = []
for package in dependencies:
latest_stable_nvr = max(
(
self.koji_helper.get_latest_nvr_in_tag(package=package, tag=t)
for t in stable_tags + [candidate_tag]
),
key=lambda nvr: NEVR.from_string(nvr),
latest_stable_nvr = self.koji_helper.get_latest_stable_nvr(
package, dist_git_branch, include_candidate=True
)
latest_build_in_sidetag = max(
(b for b in builds if b["package_name"] == package),
Expand Down
81 changes: 81 additions & 0 deletions packit_service/worker/handlers/distgit.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from ogr.abstract import PullRequest, AuthMethod
from ogr.services.github import GithubService
from packit.config import JobConfig, JobType, Deployment
from packit.config import aliases
from packit.config.package_config import PackageConfig
from packit.exceptions import (
PackitException,
Expand Down Expand Up @@ -1015,3 +1016,83 @@ def get_trigger_type_description(self) -> str:
f"Fedora Koji build was re-triggered "
f"by comment in issue {self.data.issue_id}."
)


@configured_as(job_type=JobType.koji_build)
@run_for_comment(command="koji-tag")
@reacts_to(event=PullRequestCommentPagureEvent)
class TagIntoSidetagHandler(
RetriableJobHandler,
ConfigFromEventMixin,
PackitAPIWithDownstreamMixin,
GetPagurePullRequestMixin,
):
task_name = TaskName.tag_into_sidetag

_koji_helper: Optional[KojiHelper] = None

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

@staticmethod
def get_checkers() -> Tuple[Type[Checker], ...]:
return (PermissionOnDistgit,)

def run_for_branch(self, job_config: JobConfig, branch: str) -> None:
sidetag_group = SidetagGroupModel.get_or_create(job_config.sidetag_group)
sidetag = SidetagModel.get_or_create(sidetag_group, branch)
# we need Kerberos ticket to tag a build into sidetag
# and to create a new sidetag (if needed)
self.packit_api.init_kerberos_ticket()
if not sidetag.koji_name or not self.koji_helper.get_tag_info(
sidetag.koji_name
):
tag_info = self.koji_helper.create_sidetag(branch)
if not tag_info:
logger.error(f"Failed to create sidetag for {branch}")
return
sidetag.set_koji_name(tag_info["name"])
if not (
nvr := self.koji_helper.get_latest_stable_nvr(
job_config.downstream_package_name, branch
)
):
logger.debug(
"Failed to get the latest stable build "
f"of {job_config.downstream_package_name} for {branch}"
)
return
logger.debug(f"Tagging {nvr} into {sidetag.koji_name}")
self.koji_helper.tag_build(nvr, sidetag.koji_name)

def run(self) -> TaskResults:
comment = self.data.event_dict.get("comment")
commands = get_packit_commands_from_comment(
comment, self.service_config.comment_command_prefix
)
args = commands[1:] if len(commands) > 1 else ""
for job in self.package_config.get_job_views():
if (
job.type == JobType.koji_build
and job.sidetag_group
and job.dist_git_branches
):
configured_branches = aliases.get_branches(
*job.dist_git_branches, default_dg_branch="rawhide"
)
if "--all-branches" in args:
branches = configured_branches
elif self.pull_request.target_branch not in configured_branches:
continue
else:
branches = {self.pull_request.target_branch}
logger.debug(
"Running downstream Koji build tagging "
f"of {job.downstream_package_name} for {branches}"
)
for branch in branches:
self.run_for_branch(job, branch)
return TaskResults(success=True, details={})
12 changes: 3 additions & 9 deletions packit_service/worker/handlers/mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,16 +242,10 @@ def koji_helper(self) -> KojiHelper:

def _get_latest_build(self) -> dict:
if not (
candidate_tag := self.koji_helper.get_candidate_tag(self._dist_git_branch)
):
raise PackitException(
f"Failed to get candidate tag for {self._dist_git_branch}"
build := self.koji_helper.get_latest_candidate_build(
self.project.repo, self._dist_git_branch
)
build = self.koji_helper.get_latest_build_in_tag(
package=self.project.repo,
tag=candidate_tag,
)
if not build:
):
raise PackitException(
f"No build found for package={self.project.repo} "
f"and branch={self._dist_git_branch}"
Expand Down
14 changes: 14 additions & 0 deletions packit_service/worker/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
DownstreamKojiBuildHandler,
RetriggerDownstreamKojiBuildHandler,
PullFromUpstreamHandler,
TagIntoSidetagHandler,
)
from packit_service.worker.handlers.forges import GithubFasVerificationHandler
from packit_service.worker.handlers.koji import (
Expand Down Expand Up @@ -594,6 +595,19 @@ def run_koji_build_tag_handler(event: dict, package_config: dict, job_config: di
return get_handlers_task_results(handler.run_job(), event)


@celery_app.task(bind=True, name=TaskName.tag_into_sidetag, base=TaskWithRetry)
def run_tag_into_sidetag_handler(
self, event: dict, package_config: dict, job_config: dict
):
handler = TagIntoSidetagHandler(
package_config=load_package_config(package_config),
job_config=load_job_config(job_config),
event=event,
celery_task=self,
)
return get_handlers_task_results(handler.run_job(), event)


def get_handlers_task_results(results: dict, event: dict) -> dict:
# include original event to provide more info
return {"job": results, "event": event}
Expand Down
18 changes: 8 additions & 10 deletions tests/integration/test_bodhi_update.py
Original file line number Diff line number Diff line change
Expand Up @@ -909,17 +909,15 @@ def test_bodhi_update_from_sidetag(koji_build_tagged, missing_dependency):
sidetag_name
).and_return(builds_in_sidetag)

flexmock(KojiHelper).should_receive("get_candidate_tag").with_args(
"f40"
).and_return("f40-updates-candidate")
flexmock(KojiHelper).should_receive("get_stable_tags").with_args(
"f40-updates-candidate"
).and_return(["f40-updates", "f40"])
flexmock(KojiHelper).should_receive("get_latest_nvr_in_tag").with_args(
package="python-specfile", tag=str
flexmock(KojiHelper).should_receive("get_latest_stable_nvr").with_args(
"python-specfile",
"f40",
include_candidate=True,
).and_return("python-specfile-0.30.0-1.fc40")
flexmock(KojiHelper).should_receive("get_latest_nvr_in_tag").with_args(
package="packit", tag=str
flexmock(KojiHelper).should_receive("get_latest_stable_nvr").with_args(
"packit",
"f40",
include_candidate=True,
).and_return("packit-0.98.0-1.fc40")
flexmock(KojiHelper).should_receive("remove_sidetag").with_args(sidetag_name).times(
0 if missing_dependency else 1
Expand Down
14 changes: 4 additions & 10 deletions tests/integration/test_issue_comment.py
Original file line number Diff line number Diff line change
Expand Up @@ -420,11 +420,8 @@ def test_issue_comment_retrigger_bodhi_update_handler(
koji_builds=["python-teamcity-messages.fc38"],
sidetag=None,
).and_return(("alias", "url"))
flexmock(KojiHelper).should_receive("get_candidate_tag").with_args(
"f38"
).and_return("f38-updates-candidate")
flexmock(KojiHelper).should_receive("get_latest_build_in_tag").with_args(
package="python-teamcity-messages", tag="f38-updates-candidate"
flexmock(KojiHelper).should_receive("get_latest_candidate_build").with_args(
"python-teamcity-messages", "f38"
).and_return(
{
"nvr": "python-teamcity-messages.fc38",
Expand All @@ -439,11 +436,8 @@ def test_issue_comment_retrigger_bodhi_update_handler(
koji_builds=["python-teamcity-messages.fc37"],
sidetag=None,
).and_return(("alias", "url"))
flexmock(KojiHelper).should_receive("get_candidate_tag").with_args(
"f37"
).and_return("f37-updates-candidate")
flexmock(KojiHelper).should_receive("get_latest_build_in_tag").with_args(
package="python-teamcity-messages", tag="f37-updates-candidate"
flexmock(KojiHelper).should_receive("get_latest_candidate_build").with_args(
"python-teamcity-messages", "f37"
).and_return(
{
"nvr": "python-teamcity-messages.fc37",
Expand Down
Loading

0 comments on commit aab0ccd

Please sign in to comment.