diff --git a/packit_service/events/__init__.py b/packit_service/events/__init__.py index 58382dc16..8b275a005 100644 --- a/packit_service/events/__init__.py +++ b/packit_service/events/__init__.py @@ -7,6 +7,7 @@ copr, enums, event, + forgejo, github, gitlab, koji, @@ -20,8 +21,10 @@ __all__ = [ abstract.__name__, anitya.__name__, + forgejo.__name__, github.__name__, gitlab.__name__, + forgejo.__name__, koji.__name__, openscanhub.__name__, pagure.__name__, diff --git a/packit_service/events/abstract/comment.py b/packit_service/events/abstract/comment.py index 943dba20b..e3c6bd872 100644 --- a/packit_service/events/abstract/comment.py +++ b/packit_service/events/abstract/comment.py @@ -152,6 +152,7 @@ def __init__( tag_name: str = "", comment_object: Optional[Comment] = None, dist_git_project_url=None, + commit_sha: Optional[str] = None, ) -> None: super().__init__( project_url=project_url, @@ -168,7 +169,7 @@ def __init__( # Lazy properties self._tag_name = tag_name - self._commit_sha: Optional[str] = None + self._commit_sha: Optional[str] = commit_sha self._comment_object = comment_object self._issue_object: Optional[OgrIssue] = None diff --git a/packit_service/events/forgejo/__init__.py b/packit_service/events/forgejo/__init__.py new file mode 100644 index 000000000..111d7935e --- /dev/null +++ b/packit_service/events/forgejo/__init__.py @@ -0,0 +1,6 @@ +# Copyright Contributors to the Packit project. +# SPDX-License-Identifier: MIT + +from . import abstract, issue, pr, push + +__all__ = [abstract.__name__, issue.__name__, pr.__name__, push.__name__] diff --git a/packit_service/events/forgejo/abstract.py b/packit_service/events/forgejo/abstract.py new file mode 100644 index 000000000..8debe6a51 --- /dev/null +++ b/packit_service/events/forgejo/abstract.py @@ -0,0 +1,17 @@ +# Copyright Contributors to the Packit project. +# SPDX-License-Identifier: MIT + +from typing import Optional + +from ..abstract.base import ForgeIndependent + + +class ForgejoEvent(ForgeIndependent): + def __init__(self, project_url: str, pr_id: Optional[int] = None, **kwargs): + super().__init__(pr_id=pr_id) + self.project_url: str = project_url + # git ref that can be 'git checkout'-ed + self.git_ref: Optional[str] = None + self.identifier: Optional[str] = ( + None # will be shown to users -- e.g. in logs or in the copr-project name + ) diff --git a/packit_service/events/forgejo/issue.py b/packit_service/events/forgejo/issue.py new file mode 100644 index 000000000..d2b23fec8 --- /dev/null +++ b/packit_service/events/forgejo/issue.py @@ -0,0 +1,54 @@ +# Copyright Contributors to the Packit project. +# SPDX-License-Identifier: MIT + +from typing import Optional + +from ogr.abstract import Comment as OgrComment + +from ..abstract.comment import Issue as AbstractIssueCommentEvent +from ..enums import IssueCommentAction +from .abstract import ForgejoEvent + + +class Comment(AbstractIssueCommentEvent, ForgejoEvent): + def __init__( + self, + action: IssueCommentAction, + issue_id: int, + repo_namespace: str, + repo_name: str, + target_repo: str, + project_url: str, + actor: str, + comment: str, + comment_id: int, + tag_name: str = "", + base_ref: Optional[str] = "main", + comment_object: Optional[OgrComment] = None, + dist_git_project_url=None, + ) -> None: + super().__init__( + issue_id=issue_id, + repo_namespace=repo_namespace, + repo_name=repo_name, + project_url=project_url, + comment=comment, + comment_id=comment_id, + tag_name=tag_name, + comment_object=comment_object, + dist_git_project_url=dist_git_project_url, + ) + self.action = action + self.actor = actor + self.base_ref = base_ref + self.target_repo = target_repo + self.identifier = str(issue_id) + + @classmethod + def event_type(cls) -> str: + return "forgejo.issue.Comment" + + def get_dict(self, default_dict: Optional[dict] = None) -> dict: + result = super().get_dict() + result["action"] = self.action.value + return result diff --git a/packit_service/events/forgejo/pr.py b/packit_service/events/forgejo/pr.py new file mode 100644 index 000000000..a2a531eea --- /dev/null +++ b/packit_service/events/forgejo/pr.py @@ -0,0 +1,118 @@ +# Copyright Contributors to the Packit project. +# SPDX-License-Identifier: MIT + +from typing import Optional + +from ogr.abstract import Comment as OgrComment +from ogr.abstract import GitProject + +from packit_service.service.db_project_events import AddPullRequestEventToDb + +from ..abstract.comment import PullRequest as AbstractPRCommentEvent +from ..enums import PullRequestAction, PullRequestCommentAction +from .abstract import ForgejoEvent + + +class Action(AddPullRequestEventToDb, ForgejoEvent): + def __init__( + self, + action: PullRequestAction, + pr_id: int, + base_repo_namespace: str, + base_repo_name: str, + base_ref: str, + target_repo_namespace: str, + target_repo_name: str, + project_url: str, + commit_sha: str, + commit_sha_before: str, + actor: str, + body: str, + ): + super().__init__(project_url=project_url, pr_id=pr_id) + self.action = action + self.base_repo_namespace = base_repo_namespace + self.base_repo_name = base_repo_name + self.base_ref = base_ref + self.target_repo_namespace = target_repo_namespace + self.target_repo_name = target_repo_name + self.actor = actor + self.identifier = str(pr_id) + self.commit_sha = commit_sha + self.commit_sha_before = commit_sha_before + self.body = body + + def get_dict(self, default_dict: Optional[dict] = None) -> dict: + result = super().get_dict() + result["action"] = result["action"].value + return result + + @classmethod + def event_type(cls) -> str: + return "forgejo.pr.Action" + + def get_base_project(self) -> GitProject: + return self.project.service.get_project( + namespace=self.base_repo_namespace, + repo=self.base_repo_name, + ) + + +class Comment(AbstractPRCommentEvent, ForgejoEvent): + def __init__( + self, + action: PullRequestCommentAction, + pr_id: int, + base_repo_namespace: str, + base_repo_name: Optional[str], + base_ref: Optional[str], + target_repo_namespace: str, + target_repo_name: str, + project_url: str, + actor: str, + comment: str, + comment_id: int, + commit_sha: Optional[str] = None, + comment_object: Optional[OgrComment] = None, + ) -> None: + super().__init__( + pr_id=pr_id, + project_url=project_url, + comment=comment, + comment_id=comment_id, + commit_sha=commit_sha, + comment_object=comment_object, + ) + self.action = action + self.base_repo_namespace = base_repo_namespace + self.base_repo_name = base_repo_name + self.base_ref = base_ref + self.target_repo_namespace = target_repo_namespace + self.target_repo_name = target_repo_name + self.actor = actor + self.identifier = str(pr_id) + self.git_ref = None + + @classmethod + def event_type(cls) -> str: + return "forgejo.pr.Comment" + + def get_dict(self, default_dict: Optional[dict] = None) -> dict: + """ + Override get_dict to avoid accessing properties that make API calls. + Use private attributes directly, similar to forgejo/issue.py. + """ + from ..abstract.comment import CommentEvent + + result = CommentEvent.get_dict(self, default_dict=default_dict) + result.pop("_comment_object") + result["action"] = self.action.value + result["pr_id"] = self.pr_id + result["commit_sha"] = self._commit_sha + return result + + def get_base_project(self) -> GitProject: + return self.project.service.get_project( + namespace=self.base_repo_namespace, + repo=self.base_repo_name, + ) diff --git a/packit_service/events/forgejo/push.py b/packit_service/events/forgejo/push.py new file mode 100644 index 000000000..cc88b21ba --- /dev/null +++ b/packit_service/events/forgejo/push.py @@ -0,0 +1,29 @@ +# Copyright Contributors to the Packit project. +# SPDX-License-Identifier: MIT + +from packit_service.service.db_project_events import AddBranchPushEventToDb + +from .abstract import ForgejoEvent + + +class Commit(AddBranchPushEventToDb, ForgejoEvent): + def __init__( + self, + repo_namespace: str, + repo_name: str, + git_ref: str, + project_url: str, + commit_sha: str, + commit_sha_before: str, + ): + super().__init__(project_url=project_url) + self.repo_namespace = repo_namespace + self.repo_name = repo_name + self.git_ref = git_ref + self.commit_sha = commit_sha + self.commit_sha_before = commit_sha_before + self.identifier = git_ref + + @classmethod + def event_type(cls) -> str: + return "forgejo.push.Commit" diff --git a/packit_service/service/api/webhooks.py b/packit_service/service/api/webhooks.py index 1e792f4de..048ae5c78 100644 --- a/packit_service/service/api/webhooks.py +++ b/packit_service/service/api/webhooks.py @@ -45,12 +45,7 @@ }, ) -github_webhook_calls = Counter( - "github_webhook_calls", - "Number of times the GitHub webhook is called", - # process_id = label the metric with respective process ID, so we can aggregate - ["result", "process_id"], -) + @ns.route("/github") @@ -344,3 +339,6 @@ def interested(): logger.debug(f"{event_type} {' (not interested)' if not _interested else ''}") return _interested + + + diff --git a/packit_service/worker/parser.py b/packit_service/worker/parser.py index 9a58f9db1..d492b6457 100644 --- a/packit_service/worker/parser.py +++ b/packit_service/worker/parser.py @@ -26,6 +26,7 @@ abstract, anitya, copr, + forgejo, github, gitlab, koji, @@ -104,6 +105,7 @@ class Parser: we need to have method inside the `Parser` class to create objects defined in `event.py`. """ + @staticmethod def parse_event( event: dict, @@ -129,6 +131,10 @@ def parse_event( gitlab.push.Commit, gitlab.push.Tag, gitlab.release.Release, + forgejo.pr.Comment, + forgejo.pr.Action, + forgejo.push.Commit, + forgejo.issue.Comment, koji.result.Build, koji.tag.Build, koji.result.Task, @@ -159,6 +165,7 @@ def parse_event( logger.warning("No event to process!") return None + for response in ( parser(event) for parser in ( @@ -648,7 +655,6 @@ def parse_issue_comment_event(event) -> Optional[github.issue.Comment]: # but it's needed when called from parse_event(). if nested_get(event, "issue", "pull_request"): return None - issue_id = nested_get(event, "issue", "number") action = event.get("action") if action != "created" or not issue_id: @@ -1943,6 +1949,206 @@ def parse_logdetective_analysis_event(event) -> Optional[logdetective.Result]: pr_id=pr_id, ) + @staticmethod + def parse_forgejo_push_event(event: dict) -> Optional[forgejo.push.Commit]: + if "forgejo.push" not in event.get("topic", ""): + return None + + payload = event.get("body", {}) + raw_ref = payload.get("ref") + before = payload.get("before") + after = payload.get("after") + pusher = nested_get(payload, "pusher", "login") + + if not (raw_ref and after and before and pusher): + return None + + # Forgejo sets `deleted` identically to GitHub + if payload.get("deleted"): + logger.info(f"Forgejo push event on '{raw_ref}' by {pusher} to delete ref") + + return None + + # Number of commits introduced by this push + num_commits = payload.get("total_commits") + + # Strip the ref prefix to get the branch/tag name + _, ref_type, ref_name = raw_ref.split("/", 2) + if ref_type not in ("heads", "tags"): + logger.debug(f"Forgejo push event ignored – not a branch or tag push ('{raw_ref}')") + return None + + logger.info( + f"Forgejo push event on '{ref_name}': " + f"{before[:8]} → {after[:8]} by {pusher} " + f"({num_commits} {'commit' if num_commits == 1 else 'commits'})" + ) + + repo_namespace = nested_get(payload, "repository", "owner", "login") + repo_name = nested_get(payload, "repository", "name") + repo_url = nested_get(payload, "repository", "html_url") + + if not (repo_namespace and repo_name): + logger.warning("Forgejo push event missing repository namespace/name") + return None + + return forgejo.push.Commit( + repo_namespace=repo_namespace, + repo_name=repo_name, + git_ref=ref_name, + project_url=repo_url, + commit_sha=after, + commit_sha_before=before, + ) + + @staticmethod + def parse_forgejo_pr_event(event: dict) -> Optional[forgejo.pr.Action]: + """ + Parse Forgejo PR action events, only triggering for relevant actions. + Supported actions: 'opened', 'reopened', 'synchronize'. + Skips others like 'closed'. + """ + if "forgejo.pull_request" not in event.get("topic", ""): + return None + + payload = event.get("body", {}) + action_str = payload.get("action") + # Only trigger for these actions + supported_actions = {"opened", "reopened", "synchronize"} + if action_str not in supported_actions: + logger.info(f"Skipping PR action: {action_str}") + return None + + pr = payload.get("pull_request") + if not pr: + logger.warning("No pull_request in event.") + return None + + pr_id = pr.get("number") + actor = nested_get(payload, "pull_request", "user", "login") + repo = payload.get("repository", {}) + base = pr.get("base") + head = pr.get("head") + body = pr.get("body") + + # Check all required nested fields + try: + target_repo_namespace = base["repo"]["owner"]["login"] + target_repo_name = base["repo"]["name"] + base_ref = head["sha"] + base_repo_namespace = head["repo"]["owner"]["login"] + base_repo_name = head["repo"]["name"] + project_url = repo["html_url"] + commit_sha = head["sha"] + except (TypeError, KeyError): + logger.warning("Missing required nested fields in PR event.") + return None + + return forgejo.pr.Action( + action=PullRequestAction[action_str], + pr_id=pr_id, + base_repo_namespace=base_repo_namespace, + base_repo_name=base_repo_name, + base_ref=base_ref, + target_repo_namespace=target_repo_namespace, + target_repo_name=target_repo_name, + project_url=project_url, + commit_sha=commit_sha, + commit_sha_before=payload.get("before", ""), + actor=actor, + body=body, + ) + + @staticmethod + def parse_forgejo_comment_event( + event: dict, + ) -> Optional[Union[forgejo.pr.Comment, forgejo.issue.Comment]]: + """Since Forgejo treats PR as special issues the comments are basically on issues, + we need to distinguish between Forgejo issue and PR comments and parse accordingly.""" + if "forgejo.issue_comment" not in event.get("topic", ""): + return None + + payload = event.get("body", {}) + issue_id = nested_get(payload, "issue", "number") + action = payload.get("action") + if action not in {"created", "edited"} or not issue_id: + return None + + # Only treat as PR if 'pull_request' is present and not None + issue_dict = payload.get("issue", {}) + is_pr = issue_dict.get("pull_request") is not None + comment = nested_get(payload, "comment", "body") + comment_id = nested_get(payload, "comment", "id") + logger.info( + f"Forgejo {'PR' if is_pr else 'issue'}#{issue_id} " + f"comment: {comment!r} id#{comment_id} {action!r} event." + ) + + user_login = nested_get(payload, "comment", "user", "login") + + if is_pr: + # For PR comments, extract repo info from pull_request section + base_repo_namespace = nested_get( + payload, "pull_request", "head", "repo", "owner", "login" + ) + base_repo_name = nested_get(payload, "pull_request", "head", "repo", "name") + target_repo_namespace = nested_get( + payload, "pull_request", "base", "repo", "owner", "login" + ) + else: + # For issue comments, extract from repository section + base_repo_namespace = nested_get(payload, "repository", "owner", "login") + base_repo_name = nested_get(payload, "repository", "name") + target_repo_namespace = nested_get(payload, "repository", "owner", "login") + + target_repo_name = nested_get(payload, "repository", "name") + https_url = nested_get(payload, "repository", "html_url") + + if not ( + base_repo_name and base_repo_namespace and target_repo_name and target_repo_namespace + ): + logger.warning("Missing repo info in Forgejo event.") + return None + + if not user_login: + logger.warning("No user login in comment.") + return None + + if is_pr: + base_ref = nested_get(payload, "pull_request", "head", "ref") + commit_sha = nested_get(payload, "pull_request", "head", "sha") + return forgejo.pr.Comment( + action=PullRequestCommentAction[action], + pr_id=issue_id, + base_ref=base_ref, + base_repo_namespace=base_repo_namespace, + base_repo_name=base_repo_name, + target_repo_namespace=target_repo_namespace, + target_repo_name=target_repo_name, + project_url=https_url, + actor=user_login, + comment=comment, + comment_id=comment_id, + commit_sha=commit_sha, + ) + # For issue comments, get the default branch + default_branch = nested_get(payload, "repository", "default_branch") or "main" + + return forgejo.issue.Comment( + action=IssueCommentAction[action], + issue_id=issue_id, + repo_namespace=base_repo_namespace, + repo_name=base_repo_name, + target_repo=f"{target_repo_namespace}/{target_repo_name}", + project_url=https_url, + actor=user_login, + comment=comment, + comment_id=comment_id, + tag_name="", + base_ref=default_branch, + dist_git_project_url=None, + ) + # The .__func__ are needed for Python < 3.10 MAPPING: ClassVar[dict[str, dict[str, Callable]]] = { "github": { @@ -1964,6 +2170,9 @@ def parse_logdetective_analysis_event(event) -> Optional[logdetective.Result]: "Release Hook": parse_gitlab_release_event.__func__, # type: ignore }, "fedora-messaging": { + "forgejo.push": parse_forgejo_push_event.__func__, # type: ignore + "forgejo.pull_request": parse_forgejo_pr_event.__func__, # type: ignore + "forgejo.issue_comment": parse_forgejo_comment_event.__func__, # type: ignore "pagure.pull-request.flag.added": parse_pagure_pr_flag_event.__func__, # type: ignore "pagure.pull-request.flag.updated": parse_pagure_pr_flag_event.__func__, # type: ignore "pagure.pull-request.comment.added": parse_pagure_pull_request_comment_event.__func__, # type: ignore diff --git a/packit_service/worker/reporting/reporters/base.py b/packit_service/worker/reporting/reporters/base.py index 7c9905c92..c34eaa873 100644 --- a/packit_service/worker/reporting/reporters/base.py +++ b/packit_service/worker/reporting/reporters/base.py @@ -6,6 +6,7 @@ from typing import Callable, Optional, Union from ogr.abstract import GitProject, PullRequest +from ogr.services.forgejo import ForgejoProject from ogr.services.github import GithubProject from ogr.services.gitlab import GitlabProject from ogr.services.pagure import PagureProject @@ -56,6 +57,7 @@ def get_instance( The `project` determines type of the reporter returned. All other parameters are passed to the initializer of the chosen reporter. """ + from .forgejo import StatusReporterForgejo from .github import StatusReporterGithubChecks from .gitlab import StatusReporterGitlab from .pagure import StatusReporterPagure @@ -67,6 +69,8 @@ def get_instance( reporter = StatusReporterGitlab elif isinstance(project, PagureProject): reporter = StatusReporterPagure + elif isinstance(project, ForgejoProject): + reporter = StatusReporterForgejo return reporter(project, commit_sha, packit_user, project_event_id, pr_id) @property diff --git a/packit_service/worker/reporting/reporters/forgejo.py b/packit_service/worker/reporting/reporters/forgejo.py new file mode 100644 index 000000000..76a706320 --- /dev/null +++ b/packit_service/worker/reporting/reporters/forgejo.py @@ -0,0 +1,46 @@ +# Copyright Contributors to the Packit project. +# SPDX-License-Identifier: MIT + +import logging +from typing import Optional + +from ogr.abstract import CommitStatus +from ogr.exceptions import ForgejoAPIException + +from packit_service.worker.reporting import BaseCommitStatus +from packit_service.worker.reporting.reporters.base import StatusReporter + +logger = logging.getLogger(__name__) + + +class StatusReporterForgejo(StatusReporter): + @staticmethod + def get_commit_status(state: BaseCommitStatus): + mapped_state = StatusReporter.get_commit_status(state) + + if mapped_state == CommitStatus.error: + mapped_state = CommitStatus.failure + return mapped_state + + def set_status( + self, + state: BaseCommitStatus, + description: str, + check_name: str, + url: str = "", + links_to_external_services: Optional[dict[str, str]] = None, + markdown_content: Optional[str] = None, + target_branch: Optional[str] = None, + ): + state_to_set = self.get_commit_status(state) + logger.debug(f"Setting Forgejo status '{state_to_set.name}'") + + try: + self.project_with_commit.set_commit_status( + self.commit_sha, state_to_set, url, description, check_name, trim=True + ) + + except ForgejoAPIException as e: + logger.debug(f"Failed to set status: {e}") + + self._add_commit_comment_with_status(state, description, check_name, url) diff --git a/tests/conftest.py b/tests/conftest.py index 54c68a4ea..6a79fe450 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -9,7 +9,7 @@ import pytest from deepdiff import DeepDiff from flexmock import flexmock -from ogr import GithubService, GitlabService, PagureService +from ogr import ForgejoService, GithubService, GitlabService, PagureService from packit.config import JobConfig, JobConfigTriggerType, PackageConfig from packit.config.common_package_config import Deployment @@ -45,6 +45,7 @@ def global_service_config(): GitlabService(token="token"), PagureService(instance_url="https://src.fedoraproject.org", token="token"), PagureService(instance_url="https://git.stg.centos.org", token="6789"), + ForgejoService(instance_url="https://codeberg.org", token="token"), } service_config.server_name = "localhost" service_config.github_requests_log_path = "/path" diff --git a/tests/data/fedmsg/forgejo_issue_comment.json b/tests/data/fedmsg/forgejo_issue_comment.json new file mode 100644 index 000000000..015c7d31a --- /dev/null +++ b/tests/data/fedmsg/forgejo_issue_comment.json @@ -0,0 +1,655 @@ +{ + "body": { + "action": "created", + "issue": { + "id": 131957, + "url": "https://forge.fedoraproject.org/api/v1/repos/infra/ansible/issues/3366", + "html_url": "https://forge.fedoraproject.org/infra/ansible/pulls/3366", + "number": 3366, + "user": { + "id": 2471, + "login": "jgroman", + "login_name": "", + "source_id": 0, + "full_name": "Jaroslav Groman", + "email": "jgroman@noreply.forge.fedoraproject.org", + "avatar_url": "https://forge.fedoraproject.org/avatars/83090da2cf07c84197ec3f3512f4b428bfb4f533048ce29dcd2b9c9bdbef469e", + "html_url": "https://forge.fedoraproject.org/jgroman", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2025-11-26T08:55:37Z", + "restricted": false, + "active": false, + "prohibit_login": false, + "location": "", + "pronouns": "", + "website": "", + "description": "", + "visibility": "public", + "followers_count": 0, + "following_count": 0, + "starred_repos_count": 0, + "username": "jgroman" + }, + "original_author": "", + "original_author_id": 0, + "title": "quality: blockerbugs app - update health check probes", + "body": "- update health check probes to use dedicated endpoint to reduce server and db load\r\n- add startup check to monitor app startup", + "ref": "", + "assets": [], + "labels": [], + "milestone": null, + "assignee": null, + "assignees": null, + "state": "open", + "is_locked": false, + "comments": 1, + "created_at": "2026-05-25T10:59:54Z", + "updated_at": "2026-05-25T13:14:09Z", + "closed_at": null, + "due_date": null, + "pull_request": { + "merged": false, + "merged_at": null, + "draft": false, + "html_url": "https://forge.fedoraproject.org/infra/ansible/pulls/3366" + }, + "repository": { + "id": 664, + "name": "ansible", + "owner": "infra", + "full_name": "infra/ansible" + }, + "pin_order": 0 + }, + "pull_request": { + "id": 41986, + "url": "https://forge.fedoraproject.org/infra/ansible/pulls/3366", + "number": 3366, + "user": { + "id": 2471, + "login": "jgroman", + "login_name": "", + "source_id": 0, + "full_name": "Jaroslav Groman", + "email": "jgroman@noreply.forge.fedoraproject.org", + "avatar_url": "https://forge.fedoraproject.org/avatars/83090da2cf07c84197ec3f3512f4b428bfb4f533048ce29dcd2b9c9bdbef469e", + "html_url": "https://forge.fedoraproject.org/jgroman", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2025-11-26T08:55:37Z", + "restricted": false, + "active": false, + "prohibit_login": false, + "location": "", + "pronouns": "", + "website": "", + "description": "", + "visibility": "public", + "followers_count": 0, + "following_count": 0, + "starred_repos_count": 0, + "username": "jgroman" + }, + "title": "quality: blockerbugs app - update health check probes", + "body": "- update health check probes to use dedicated endpoint to reduce server and db load\r\n- add startup check to monitor app startup", + "labels": [], + "milestone": null, + "assignee": null, + "assignees": null, + "requested_reviewers": [ + { + "id": 138, + "login": "adamwill", + "login_name": "", + "source_id": 0, + "full_name": "Adam Williamson", + "email": "adamwill@noreply.forge.fedoraproject.org", + "avatar_url": "https://seccdn.libravatar.org/avatar/c7147e0eeef52c5999f2334cfeaf0f7a?d=identicon", + "html_url": "https://forge.fedoraproject.org/adamwill", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2025-08-13T10:52:45Z", + "restricted": false, + "active": false, + "prohibit_login": false, + "location": "", + "pronouns": "", + "website": "", + "description": "", + "visibility": "public", + "followers_count": 1, + "following_count": 0, + "starred_repos_count": 0, + "username": "adamwill" + } + ], + "requested_reviewers_teams": [], + "state": "open", + "draft": false, + "is_locked": false, + "comments": 1, + "review_comments": 0, + "additions": 13, + "deletions": 6, + "changed_files": 1, + "html_url": "https://forge.fedoraproject.org/infra/ansible/pulls/3366", + "diff_url": "https://forge.fedoraproject.org/infra/ansible/pulls/3366.diff", + "patch_url": "https://forge.fedoraproject.org/infra/ansible/pulls/3366.patch", + "mergeable": true, + "merged": false, + "merged_at": null, + "merge_commit_sha": null, + "merged_by": null, + "allow_maintainer_edit": false, + "base": { + "label": "main", + "ref": "main", + "sha": "004fb438fe0c77ba1dc266a0b508f2c1ddb3d705", + "repo_id": 664, + "repo": { + "id": 664, + "owner": { + "id": 2492, + "login": "infra", + "login_name": "", + "source_id": 0, + "full_name": "Infrastructure", + "email": "", + "avatar_url": "https://forge.fedoraproject.org/avatars/3a8323a7c9fd05c0cc41d2f54f17309ca71e02cd5f713a2e05de96ebc82996f0", + "html_url": "https://forge.fedoraproject.org/infra", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2025-12-01T18:43:16Z", + "restricted": false, + "active": false, + "prohibit_login": false, + "location": "", + "pronouns": "", + "website": "", + "description": "", + "visibility": "public", + "followers_count": 21, + "following_count": 0, + "starred_repos_count": 0, + "username": "infra" + }, + "name": "ansible", + "full_name": "infra/ansible", + "description": "Fedora Infrastructure Ansible Repository", + "empty": false, + "private": false, + "fork": false, + "template": false, + "parent": null, + "mirror": false, + "size": 158866, + "language": "", + "languages_url": "https://forge.fedoraproject.org/api/v1/repos/infra/ansible/languages", + "html_url": "https://forge.fedoraproject.org/infra/ansible", + "url": "https://forge.fedoraproject.org/api/v1/repos/infra/ansible", + "link": "", + "ssh_url": "ssh://1001300000@forge.fedoraproject.org/infra/ansible.git", + "clone_url": "https://forge.fedoraproject.org/infra/ansible.git", + "original_url": "https://pagure.io/fedora-infra/ansible/", + "website": "", + "stars_count": 3, + "forks_count": 44, + "watchers_count": 23, + "open_issues_count": 0, + "open_pr_counter": 13, + "release_counter": 0, + "default_branch": "main", + "archived": false, + "created_at": "2026-02-17T14:43:41Z", + "updated_at": "2026-05-25T08:08:03Z", + "archived_at": "1970-01-01T00:00:00Z", + "permissions": { + "admin": false, + "push": false, + "pull": true + }, + "has_issues": false, + "has_wiki": false, + "has_wiki_contents": false, + "wiki_branch": "main", + "wiki_ssh_url": "ssh://1001300000@forge.fedoraproject.org/infra/ansible.wiki.git", + "wiki_clone_url": "https://forge.fedoraproject.org/infra/ansible.wiki.git", + "globally_editable_wiki": false, + "has_pull_requests": true, + "has_projects": false, + "has_releases": false, + "has_packages": false, + "has_actions": true, + "ignore_whitespace_conflicts": false, + "allow_merge_commits": false, + "allow_rebase": true, + "allow_rebase_explicit": false, + "allow_squash_merge": false, + "allow_fast_forward_only_merge": true, + "allow_rebase_update": true, + "default_delete_branch_after_merge": false, + "default_merge_style": "rebase", + "default_allow_maintainer_edit": false, + "default_update_style": "merge", + "avatar_url": "", + "internal": false, + "mirror_interval": "", + "object_format_name": "sha1", + "mirror_updated": "0001-01-01T00:00:00Z", + "repo_transfer": null, + "topics": [ + "ansible", + "fedora", + "fedora-infra" + ] + } + }, + "head": { + "label": "main", + "ref": "main", + "sha": "d0bb319af8dfa9944649231d09573ca02650ff9d", + "repo_id": 1295, + "repo": { + "id": 1295, + "owner": { + "id": 2471, + "login": "jgroman", + "login_name": "", + "source_id": 0, + "full_name": "Jaroslav Groman", + "email": "jgroman@noreply.forge.fedoraproject.org", + "avatar_url": "https://forge.fedoraproject.org/avatars/83090da2cf07c84197ec3f3512f4b428bfb4f533048ce29dcd2b9c9bdbef469e", + "html_url": "https://forge.fedoraproject.org/jgroman", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2025-11-26T08:55:37Z", + "restricted": false, + "active": false, + "prohibit_login": false, + "location": "", + "pronouns": "", + "website": "", + "description": "", + "visibility": "public", + "followers_count": 0, + "following_count": 0, + "starred_repos_count": 0, + "username": "jgroman" + }, + "name": "ansible", + "full_name": "jgroman/ansible", + "description": "Fedora Infrastructure Ansible Repository", + "empty": false, + "private": false, + "fork": true, + "template": false, + "parent": { + "id": 664, + "owner": { + "id": 2492, + "login": "infra", + "login_name": "", + "source_id": 0, + "full_name": "Infrastructure", + "email": "", + "avatar_url": "https://forge.fedoraproject.org/avatars/3a8323a7c9fd05c0cc41d2f54f17309ca71e02cd5f713a2e05de96ebc82996f0", + "html_url": "https://forge.fedoraproject.org/infra", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2025-12-01T18:43:16Z", + "restricted": false, + "active": false, + "prohibit_login": false, + "location": "", + "pronouns": "", + "website": "", + "description": "", + "visibility": "public", + "followers_count": 21, + "following_count": 0, + "starred_repos_count": 0, + "username": "infra" + }, + "name": "ansible", + "full_name": "infra/ansible", + "description": "Fedora Infrastructure Ansible Repository", + "empty": false, + "private": false, + "fork": false, + "template": false, + "parent": null, + "mirror": false, + "size": 158866, + "language": "", + "languages_url": "https://forge.fedoraproject.org/api/v1/repos/infra/ansible/languages", + "html_url": "https://forge.fedoraproject.org/infra/ansible", + "url": "https://forge.fedoraproject.org/api/v1/repos/infra/ansible", + "link": "", + "ssh_url": "ssh://1001300000@forge.fedoraproject.org/infra/ansible.git", + "clone_url": "https://forge.fedoraproject.org/infra/ansible.git", + "original_url": "https://pagure.io/fedora-infra/ansible/", + "website": "", + "stars_count": 3, + "forks_count": 44, + "watchers_count": 23, + "open_issues_count": 0, + "open_pr_counter": 13, + "release_counter": 0, + "default_branch": "main", + "archived": false, + "created_at": "2026-02-17T14:43:41Z", + "updated_at": "2026-05-25T08:08:03Z", + "archived_at": "1970-01-01T00:00:00Z", + "permissions": { + "admin": false, + "push": false, + "pull": true + }, + "has_issues": false, + "has_wiki": false, + "has_wiki_contents": false, + "wiki_branch": "main", + "wiki_ssh_url": "ssh://1001300000@forge.fedoraproject.org/infra/ansible.wiki.git", + "wiki_clone_url": "https://forge.fedoraproject.org/infra/ansible.wiki.git", + "globally_editable_wiki": false, + "has_pull_requests": true, + "has_projects": false, + "has_releases": false, + "has_packages": false, + "has_actions": true, + "ignore_whitespace_conflicts": false, + "allow_merge_commits": false, + "allow_rebase": true, + "allow_rebase_explicit": false, + "allow_squash_merge": false, + "allow_fast_forward_only_merge": true, + "allow_rebase_update": true, + "default_delete_branch_after_merge": false, + "default_merge_style": "rebase", + "default_allow_maintainer_edit": false, + "default_update_style": "merge", + "avatar_url": "", + "internal": false, + "mirror_interval": "", + "object_format_name": "sha1", + "mirror_updated": "0001-01-01T00:00:00Z", + "repo_transfer": null, + "topics": [ + "ansible", + "fedora", + "fedora-infra" + ] + }, + "mirror": false, + "size": 128149, + "language": "", + "languages_url": "https://forge.fedoraproject.org/api/v1/repos/jgroman/ansible/languages", + "html_url": "https://forge.fedoraproject.org/jgroman/ansible", + "url": "https://forge.fedoraproject.org/api/v1/repos/jgroman/ansible", + "link": "", + "ssh_url": "ssh://1001300000@forge.fedoraproject.org/jgroman/ansible.git", + "clone_url": "https://forge.fedoraproject.org/jgroman/ansible.git", + "original_url": "", + "website": "", + "stars_count": 0, + "forks_count": 0, + "watchers_count": 0, + "open_issues_count": 0, + "open_pr_counter": 0, + "release_counter": 0, + "default_branch": "main", + "archived": false, + "created_at": "2026-05-25T10:41:17Z", + "updated_at": "2026-05-25T10:56:34Z", + "archived_at": "1970-01-01T00:00:00Z", + "permissions": { + "admin": false, + "push": false, + "pull": true + }, + "has_issues": false, + "has_wiki": false, + "has_wiki_contents": false, + "wiki_ssh_url": "ssh://1001300000@forge.fedoraproject.org/jgroman/ansible.wiki.git", + "wiki_clone_url": "https://forge.fedoraproject.org/jgroman/ansible.wiki.git", + "globally_editable_wiki": false, + "has_pull_requests": true, + "has_projects": false, + "has_releases": false, + "has_packages": false, + "has_actions": false, + "ignore_whitespace_conflicts": false, + "allow_merge_commits": true, + "allow_rebase": true, + "allow_rebase_explicit": true, + "allow_squash_merge": true, + "allow_fast_forward_only_merge": true, + "allow_rebase_update": true, + "default_delete_branch_after_merge": false, + "default_merge_style": "rebase", + "default_allow_maintainer_edit": false, + "default_update_style": "merge", + "avatar_url": "", + "internal": false, + "mirror_interval": "", + "object_format_name": "sha1", + "mirror_updated": "0001-01-01T00:00:00Z", + "repo_transfer": null, + "topics": [] + } + }, + "merge_base": "004fb438fe0c77ba1dc266a0b508f2c1ddb3d705", + "due_date": null, + "created_at": "2026-05-25T10:59:54Z", + "updated_at": "2026-05-25T13:14:09Z", + "closed_at": null, + "pin_order": 0, + "flow": 0 + }, + "comment": { + "id": 759973, + "html_url": "https://forge.fedoraproject.org/infra/ansible/pulls/3366#issuecomment-759973", + "pull_request_url": "https://forge.fedoraproject.org/infra/ansible/pulls/3366", + "issue_url": "", + "user": { + "id": 19, + "login": "kparal", + "login_name": "", + "source_id": 0, + "full_name": "Kamil Páral", + "email": "kparal@noreply.forge.fedoraproject.org", + "avatar_url": "https://seccdn.libravatar.org/avatar/b8a9c0099f88846ba77fd6dc39008d95?d=identicon", + "html_url": "https://forge.fedoraproject.org/kparal", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2025-08-13T10:49:56Z", + "restricted": false, + "active": false, + "prohibit_login": false, + "location": "", + "pronouns": "", + "website": "", + "description": "", + "visibility": "public", + "followers_count": 0, + "following_count": 0, + "starred_repos_count": 0, + "username": "kparal" + }, + "original_author": "", + "original_author_id": 0, + "body": "Even though I haven't studied what the variables exactly mean (I hope infra folks do know), it looks OK to me.\r\n\r\nBut shouldn't we push the latest BBA version implementing the health probe at least to staging, so that the endpoint can be easily tested? Jaroslav, can you do that please?", + "assets": [], + "created_at": "2026-05-25T13:14:09Z", + "updated_at": "2026-05-25T13:14:09Z" + }, + "repository": { + "id": 664, + "owner": { + "id": 2492, + "login": "infra", + "login_name": "", + "source_id": 0, + "full_name": "Infrastructure", + "email": "", + "avatar_url": "https://forge.fedoraproject.org/avatars/3a8323a7c9fd05c0cc41d2f54f17309ca71e02cd5f713a2e05de96ebc82996f0", + "html_url": "https://forge.fedoraproject.org/infra", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2025-12-01T18:43:16Z", + "restricted": false, + "active": false, + "prohibit_login": false, + "location": "", + "pronouns": "", + "website": "", + "description": "", + "visibility": "public", + "followers_count": 21, + "following_count": 0, + "starred_repos_count": 0, + "username": "infra" + }, + "name": "ansible", + "full_name": "infra/ansible", + "description": "Fedora Infrastructure Ansible Repository", + "empty": false, + "private": false, + "fork": false, + "template": false, + "parent": null, + "mirror": false, + "size": 158866, + "language": "", + "languages_url": "https://forge.fedoraproject.org/api/v1/repos/infra/ansible/languages", + "html_url": "https://forge.fedoraproject.org/infra/ansible", + "url": "https://forge.fedoraproject.org/api/v1/repos/infra/ansible", + "link": "", + "ssh_url": "ssh://1001300000@forge.fedoraproject.org/infra/ansible.git", + "clone_url": "https://forge.fedoraproject.org/infra/ansible.git", + "original_url": "https://pagure.io/fedora-infra/ansible/", + "website": "", + "stars_count": 3, + "forks_count": 44, + "watchers_count": 23, + "open_issues_count": 0, + "open_pr_counter": 13, + "release_counter": 0, + "default_branch": "main", + "archived": false, + "created_at": "2026-02-17T14:43:41Z", + "updated_at": "2026-05-25T08:08:03Z", + "archived_at": "1970-01-01T00:00:00Z", + "permissions": { + "admin": false, + "push": false, + "pull": true + }, + "has_issues": false, + "has_wiki": false, + "has_wiki_contents": false, + "wiki_branch": "main", + "wiki_ssh_url": "ssh://1001300000@forge.fedoraproject.org/infra/ansible.wiki.git", + "wiki_clone_url": "https://forge.fedoraproject.org/infra/ansible.wiki.git", + "globally_editable_wiki": false, + "has_pull_requests": true, + "has_projects": false, + "has_releases": false, + "has_packages": false, + "has_actions": true, + "ignore_whitespace_conflicts": false, + "allow_merge_commits": false, + "allow_rebase": true, + "allow_rebase_explicit": false, + "allow_squash_merge": false, + "allow_fast_forward_only_merge": true, + "allow_rebase_update": true, + "default_delete_branch_after_merge": false, + "default_merge_style": "rebase", + "default_allow_maintainer_edit": false, + "default_update_style": "merge", + "avatar_url": "", + "internal": false, + "mirror_interval": "", + "object_format_name": "sha1", + "mirror_updated": "0001-01-01T00:00:00Z", + "repo_transfer": null, + "topics": [ + "ansible", + "fedora", + "fedora-infra" + ] + }, + "sender": { + "id": 19, + "login": "kparal", + "login_name": "", + "source_id": 0, + "full_name": "Kamil Páral", + "email": "kparal@noreply.forge.fedoraproject.org", + "avatar_url": "https://seccdn.libravatar.org/avatar/b8a9c0099f88846ba77fd6dc39008d95?d=identicon", + "html_url": "https://forge.fedoraproject.org/kparal", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2025-08-13T10:49:56Z", + "restricted": false, + "active": false, + "prohibit_login": false, + "location": "", + "pronouns": "", + "website": "", + "description": "", + "visibility": "public", + "followers_count": 0, + "following_count": 0, + "starred_repos_count": 0, + "username": "kparal" + }, + "is_pull": true + }, + "headers": { + "user-agent": "Go-http-client/1.1", + "authorization": "Basic 973bf765c2eb40ebada712bddfeef1ed", + "content-type": "application/json", + "x-forgejo-delivery": "0619b8b1-60f2-4242-9004-489b58c7a8eb", + "x-forgejo-event": "issue_comment", + "x-forgejo-event-type": "pull_request_comment", + "x-forgejo-signature": "518834c1f8125adc105a306a4c4a6334b4099b1606db017ef01c3ef5713b1932", + "x-github-delivery": "0619b8b1-60f2-4242-9004-489b58c7a8eb", + "x-github-event": "issue_comment", + "x-github-event-type": "pull_request_comment", + "x-gitea-delivery": "0619b8b1-60f2-4242-9004-489b58c7a8eb", + "x-gitea-event": "issue_comment", + "x-gitea-event-type": "pull_request_comment", + "x-gitea-signature": "518834c1f8125adc105a306a4c4a6334b4099b1606db017ef01c3ef5713b1932", + "x-gogs-delivery": "0619b8b1-60f2-4242-9004-489b58c7a8eb", + "x-gogs-event": "issue_comment", + "x-gogs-event-type": "pull_request_comment", + "x-gogs-signature": "518834c1f8125adc105a306a4c4a6334b4099b1606db017ef01c3ef5713b1932", + "x-hub-signature": "sha1=a1bbc0d69ca9dff5e4346e16928588af7eb55079", + "x-hub-signature-256": "sha256=518834c1f8125adc105a306a4c4a6334b4099b1606db017ef01c3ef5713b1932", + "accept-encoding": "gzip", + "x-forwarded-scheme": "https", + "x-forwarded-proto": "https", + "x-fedora-requestid": "ahRLIpyULu7F-7KMfU5pzQAAFE4", + "x-forwarded-for": "10.16.163.75", + "x-forwarded-host": "webhook.fedoraproject.org", + "x-forwarded-server": "webhook.fedoraproject.org", + "content-length": "21388", + "host": "webhook.fedoraproject.org", + "x-forwarded-port": "443", + "forwarded": "for=10.16.163.75;host=webhook.fedoraproject.org;proto=https" + }, + "agent": null, + "topic": "org.fedoraproject.prod.forgejo.issue_comment" +} diff --git a/tests/data/fedmsg/forgejo_pr.json b/tests/data/fedmsg/forgejo_pr.json new file mode 100644 index 000000000..c9d762091 --- /dev/null +++ b/tests/data/fedmsg/forgejo_pr.json @@ -0,0 +1,583 @@ +{ + "body": { + "action": "review_requested", + "number": 3366, + "pull_request": { + "id": 41986, + "url": "https://forge.fedoraproject.org/infra/ansible/pulls/3366", + "number": 3366, + "user": { + "id": 2471, + "login": "jgroman", + "login_name": "jgroman", + "source_id": 1, + "full_name": "Jaroslav Groman", + "email": "jgroman@redhat.com", + "avatar_url": "https://forge.fedoraproject.org/avatars/83090da2cf07c84197ec3f3512f4b428bfb4f533048ce29dcd2b9c9bdbef469e", + "html_url": "https://forge.fedoraproject.org/jgroman", + "language": "en-US", + "is_admin": false, + "last_login": "2026-05-21T08:41:02Z", + "created": "2025-11-26T08:55:37Z", + "restricted": false, + "active": true, + "prohibit_login": false, + "location": "", + "pronouns": "", + "website": "", + "description": "", + "visibility": "public", + "followers_count": 0, + "following_count": 0, + "starred_repos_count": 0, + "username": "jgroman" + }, + "title": "quality: blockerbugs app - update health check probes", + "body": "- update health check probes to use dedicated endpoint to reduce server and db load\r\n- add startup check to monitor app startup", + "labels": [], + "milestone": null, + "assignee": null, + "assignees": null, + "requested_reviewers": [ + { + "id": 138, + "login": "adamwill", + "login_name": "", + "source_id": 0, + "full_name": "Adam Williamson", + "email": "adamwill@noreply.forge.fedoraproject.org", + "avatar_url": "https://seccdn.libravatar.org/avatar/c7147e0eeef52c5999f2334cfeaf0f7a?d=identicon", + "html_url": "https://forge.fedoraproject.org/adamwill", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2025-08-13T10:52:45Z", + "restricted": false, + "active": false, + "prohibit_login": false, + "location": "", + "pronouns": "", + "website": "", + "description": "", + "visibility": "public", + "followers_count": 1, + "following_count": 0, + "starred_repos_count": 0, + "username": "adamwill" + } + ], + "requested_reviewers_teams": [], + "state": "open", + "draft": false, + "is_locked": false, + "comments": 0, + "review_comments": 0, + "additions": 13, + "deletions": 6, + "changed_files": 1, + "html_url": "https://forge.fedoraproject.org/infra/ansible/pulls/3366", + "diff_url": "https://forge.fedoraproject.org/infra/ansible/pulls/3366.diff", + "patch_url": "https://forge.fedoraproject.org/infra/ansible/pulls/3366.patch", + "mergeable": true, + "merged": false, + "merged_at": null, + "merge_commit_sha": null, + "merged_by": null, + "allow_maintainer_edit": false, + "base": { + "label": "main", + "ref": "main", + "sha": "004fb438fe0c77ba1dc266a0b508f2c1ddb3d705", + "repo_id": 664, + "repo": { + "id": 664, + "owner": { + "id": 2492, + "login": "infra", + "login_name": "", + "source_id": 0, + "full_name": "Infrastructure", + "email": "", + "avatar_url": "https://forge.fedoraproject.org/avatars/3a8323a7c9fd05c0cc41d2f54f17309ca71e02cd5f713a2e05de96ebc82996f0", + "html_url": "https://forge.fedoraproject.org/infra", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2025-12-01T18:43:16Z", + "restricted": false, + "active": false, + "prohibit_login": false, + "location": "", + "pronouns": "", + "website": "", + "description": "", + "visibility": "public", + "followers_count": 21, + "following_count": 0, + "starred_repos_count": 0, + "username": "infra" + }, + "name": "ansible", + "full_name": "infra/ansible", + "description": "Fedora Infrastructure Ansible Repository", + "empty": false, + "private": false, + "fork": false, + "template": false, + "parent": null, + "mirror": false, + "size": 158866, + "language": "", + "languages_url": "https://forge.fedoraproject.org/api/v1/repos/infra/ansible/languages", + "html_url": "https://forge.fedoraproject.org/infra/ansible", + "url": "https://forge.fedoraproject.org/api/v1/repos/infra/ansible", + "link": "", + "ssh_url": "ssh://1001300000@forge.fedoraproject.org/infra/ansible.git", + "clone_url": "https://forge.fedoraproject.org/infra/ansible.git", + "original_url": "https://pagure.io/fedora-infra/ansible/", + "website": "", + "stars_count": 3, + "forks_count": 44, + "watchers_count": 23, + "open_issues_count": 0, + "open_pr_counter": 13, + "release_counter": 0, + "default_branch": "main", + "archived": false, + "created_at": "2026-02-17T14:43:41Z", + "updated_at": "2026-05-25T08:08:03Z", + "archived_at": "1970-01-01T00:00:00Z", + "permissions": { + "admin": false, + "push": false, + "pull": true + }, + "has_issues": false, + "has_wiki": false, + "has_wiki_contents": false, + "wiki_branch": "main", + "wiki_ssh_url": "ssh://1001300000@forge.fedoraproject.org/infra/ansible.wiki.git", + "wiki_clone_url": "https://forge.fedoraproject.org/infra/ansible.wiki.git", + "globally_editable_wiki": false, + "has_pull_requests": true, + "has_projects": false, + "has_releases": false, + "has_packages": false, + "has_actions": true, + "ignore_whitespace_conflicts": false, + "allow_merge_commits": false, + "allow_rebase": true, + "allow_rebase_explicit": false, + "allow_squash_merge": false, + "allow_fast_forward_only_merge": true, + "allow_rebase_update": true, + "default_delete_branch_after_merge": false, + "default_merge_style": "rebase", + "default_allow_maintainer_edit": false, + "default_update_style": "merge", + "avatar_url": "", + "internal": false, + "mirror_interval": "", + "object_format_name": "sha1", + "mirror_updated": "0001-01-01T00:00:00Z", + "repo_transfer": null, + "topics": [ + "ansible", + "fedora", + "fedora-infra" + ] + } + }, + "head": { + "label": "main", + "ref": "main", + "sha": "d0bb319af8dfa9944649231d09573ca02650ff9d", + "repo_id": 1295, + "repo": { + "id": 1295, + "owner": { + "id": 2471, + "login": "jgroman", + "login_name": "", + "source_id": 0, + "full_name": "Jaroslav Groman", + "email": "jgroman@noreply.forge.fedoraproject.org", + "avatar_url": "https://forge.fedoraproject.org/avatars/83090da2cf07c84197ec3f3512f4b428bfb4f533048ce29dcd2b9c9bdbef469e", + "html_url": "https://forge.fedoraproject.org/jgroman", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2025-11-26T08:55:37Z", + "restricted": false, + "active": false, + "prohibit_login": false, + "location": "", + "pronouns": "", + "website": "", + "description": "", + "visibility": "public", + "followers_count": 0, + "following_count": 0, + "starred_repos_count": 0, + "username": "jgroman" + }, + "name": "ansible", + "full_name": "jgroman/ansible", + "description": "Fedora Infrastructure Ansible Repository", + "empty": false, + "private": false, + "fork": true, + "template": false, + "parent": { + "id": 664, + "owner": { + "id": 2492, + "login": "infra", + "login_name": "", + "source_id": 0, + "full_name": "Infrastructure", + "email": "", + "avatar_url": "https://forge.fedoraproject.org/avatars/3a8323a7c9fd05c0cc41d2f54f17309ca71e02cd5f713a2e05de96ebc82996f0", + "html_url": "https://forge.fedoraproject.org/infra", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2025-12-01T18:43:16Z", + "restricted": false, + "active": false, + "prohibit_login": false, + "location": "", + "pronouns": "", + "website": "", + "description": "", + "visibility": "public", + "followers_count": 21, + "following_count": 0, + "starred_repos_count": 0, + "username": "infra" + }, + "name": "ansible", + "full_name": "infra/ansible", + "description": "Fedora Infrastructure Ansible Repository", + "empty": false, + "private": false, + "fork": false, + "template": false, + "parent": null, + "mirror": false, + "size": 158866, + "language": "", + "languages_url": "https://forge.fedoraproject.org/api/v1/repos/infra/ansible/languages", + "html_url": "https://forge.fedoraproject.org/infra/ansible", + "url": "https://forge.fedoraproject.org/api/v1/repos/infra/ansible", + "link": "", + "ssh_url": "ssh://1001300000@forge.fedoraproject.org/infra/ansible.git", + "clone_url": "https://forge.fedoraproject.org/infra/ansible.git", + "original_url": "https://pagure.io/fedora-infra/ansible/", + "website": "", + "stars_count": 3, + "forks_count": 44, + "watchers_count": 23, + "open_issues_count": 0, + "open_pr_counter": 13, + "release_counter": 0, + "default_branch": "main", + "archived": false, + "created_at": "2026-02-17T14:43:41Z", + "updated_at": "2026-05-25T08:08:03Z", + "archived_at": "1970-01-01T00:00:00Z", + "permissions": { + "admin": true, + "push": true, + "pull": true + }, + "has_issues": false, + "has_wiki": false, + "has_wiki_contents": false, + "wiki_branch": "main", + "wiki_ssh_url": "ssh://1001300000@forge.fedoraproject.org/infra/ansible.wiki.git", + "wiki_clone_url": "https://forge.fedoraproject.org/infra/ansible.wiki.git", + "globally_editable_wiki": false, + "has_pull_requests": true, + "has_projects": false, + "has_releases": false, + "has_packages": false, + "has_actions": true, + "ignore_whitespace_conflicts": false, + "allow_merge_commits": false, + "allow_rebase": true, + "allow_rebase_explicit": false, + "allow_squash_merge": false, + "allow_fast_forward_only_merge": true, + "allow_rebase_update": true, + "default_delete_branch_after_merge": false, + "default_merge_style": "rebase", + "default_allow_maintainer_edit": false, + "default_update_style": "merge", + "avatar_url": "", + "internal": false, + "mirror_interval": "", + "object_format_name": "sha1", + "mirror_updated": "0001-01-01T00:00:00Z", + "repo_transfer": null, + "topics": [ + "ansible", + "fedora", + "fedora-infra" + ] + }, + "mirror": false, + "size": 128149, + "language": "", + "languages_url": "https://forge.fedoraproject.org/api/v1/repos/jgroman/ansible/languages", + "html_url": "https://forge.fedoraproject.org/jgroman/ansible", + "url": "https://forge.fedoraproject.org/api/v1/repos/jgroman/ansible", + "link": "", + "ssh_url": "ssh://1001300000@forge.fedoraproject.org/jgroman/ansible.git", + "clone_url": "https://forge.fedoraproject.org/jgroman/ansible.git", + "original_url": "", + "website": "", + "stars_count": 0, + "forks_count": 0, + "watchers_count": 0, + "open_issues_count": 0, + "open_pr_counter": 0, + "release_counter": 0, + "default_branch": "main", + "archived": false, + "created_at": "2026-05-25T10:41:17Z", + "updated_at": "2026-05-25T10:56:34Z", + "archived_at": "1970-01-01T00:00:00Z", + "permissions": { + "admin": true, + "push": true, + "pull": true + }, + "has_issues": false, + "has_wiki": false, + "has_wiki_contents": false, + "wiki_ssh_url": "ssh://1001300000@forge.fedoraproject.org/jgroman/ansible.wiki.git", + "wiki_clone_url": "https://forge.fedoraproject.org/jgroman/ansible.wiki.git", + "globally_editable_wiki": false, + "has_pull_requests": true, + "has_projects": false, + "has_releases": false, + "has_packages": false, + "has_actions": false, + "ignore_whitespace_conflicts": false, + "allow_merge_commits": true, + "allow_rebase": true, + "allow_rebase_explicit": true, + "allow_squash_merge": true, + "allow_fast_forward_only_merge": true, + "allow_rebase_update": true, + "default_delete_branch_after_merge": false, + "default_merge_style": "rebase", + "default_allow_maintainer_edit": false, + "default_update_style": "merge", + "avatar_url": "", + "internal": false, + "mirror_interval": "", + "object_format_name": "sha1", + "mirror_updated": "0001-01-01T00:00:00Z", + "repo_transfer": null, + "topics": [] + } + }, + "merge_base": "004fb438fe0c77ba1dc266a0b508f2c1ddb3d705", + "due_date": null, + "created_at": "2026-05-25T10:59:54Z", + "updated_at": "2026-05-25T11:00:12Z", + "closed_at": null, + "pin_order": 0, + "flow": 0 + }, + "requested_reviewer": { + "id": 138, + "login": "adamwill", + "login_name": "", + "source_id": 0, + "full_name": "Adam Williamson", + "email": "adamwill@noreply.forge.fedoraproject.org", + "avatar_url": "https://seccdn.libravatar.org/avatar/c7147e0eeef52c5999f2334cfeaf0f7a?d=identicon", + "html_url": "https://forge.fedoraproject.org/adamwill", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2025-08-13T10:52:45Z", + "restricted": false, + "active": false, + "prohibit_login": false, + "location": "", + "pronouns": "", + "website": "", + "description": "", + "visibility": "public", + "followers_count": 1, + "following_count": 0, + "starred_repos_count": 0, + "username": "adamwill" + }, + "repository": { + "id": 664, + "owner": { + "id": 2492, + "login": "infra", + "login_name": "", + "source_id": 0, + "full_name": "Infrastructure", + "email": "", + "avatar_url": "https://forge.fedoraproject.org/avatars/3a8323a7c9fd05c0cc41d2f54f17309ca71e02cd5f713a2e05de96ebc82996f0", + "html_url": "https://forge.fedoraproject.org/infra", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2025-12-01T18:43:16Z", + "restricted": false, + "active": false, + "prohibit_login": false, + "location": "", + "pronouns": "", + "website": "", + "description": "", + "visibility": "public", + "followers_count": 21, + "following_count": 0, + "starred_repos_count": 0, + "username": "infra" + }, + "name": "ansible", + "full_name": "infra/ansible", + "description": "Fedora Infrastructure Ansible Repository", + "empty": false, + "private": false, + "fork": false, + "template": false, + "parent": null, + "mirror": false, + "size": 158866, + "language": "", + "languages_url": "https://forge.fedoraproject.org/api/v1/repos/infra/ansible/languages", + "html_url": "https://forge.fedoraproject.org/infra/ansible", + "url": "https://forge.fedoraproject.org/api/v1/repos/infra/ansible", + "link": "", + "ssh_url": "ssh://1001300000@forge.fedoraproject.org/infra/ansible.git", + "clone_url": "https://forge.fedoraproject.org/infra/ansible.git", + "original_url": "https://pagure.io/fedora-infra/ansible/", + "website": "", + "stars_count": 3, + "forks_count": 44, + "watchers_count": 23, + "open_issues_count": 0, + "open_pr_counter": 13, + "release_counter": 0, + "default_branch": "main", + "archived": false, + "created_at": "2026-02-17T14:43:41Z", + "updated_at": "2026-05-25T08:08:03Z", + "archived_at": "1970-01-01T00:00:00Z", + "permissions": { + "admin": false, + "push": false, + "pull": true + }, + "has_issues": false, + "has_wiki": false, + "has_wiki_contents": false, + "wiki_branch": "main", + "wiki_ssh_url": "ssh://1001300000@forge.fedoraproject.org/infra/ansible.wiki.git", + "wiki_clone_url": "https://forge.fedoraproject.org/infra/ansible.wiki.git", + "globally_editable_wiki": false, + "has_pull_requests": true, + "has_projects": false, + "has_releases": false, + "has_packages": false, + "has_actions": true, + "ignore_whitespace_conflicts": false, + "allow_merge_commits": false, + "allow_rebase": true, + "allow_rebase_explicit": false, + "allow_squash_merge": false, + "allow_fast_forward_only_merge": true, + "allow_rebase_update": true, + "default_delete_branch_after_merge": false, + "default_merge_style": "rebase", + "default_allow_maintainer_edit": false, + "default_update_style": "merge", + "avatar_url": "", + "internal": false, + "mirror_interval": "", + "object_format_name": "sha1", + "mirror_updated": "0001-01-01T00:00:00Z", + "repo_transfer": null, + "topics": [ + "ansible", + "fedora", + "fedora-infra" + ] + }, + "sender": { + "id": 2471, + "login": "jgroman", + "login_name": "", + "source_id": 0, + "full_name": "Jaroslav Groman", + "email": "jgroman@noreply.forge.fedoraproject.org", + "avatar_url": "https://forge.fedoraproject.org/avatars/83090da2cf07c84197ec3f3512f4b428bfb4f533048ce29dcd2b9c9bdbef469e", + "html_url": "https://forge.fedoraproject.org/jgroman", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2025-11-26T08:55:37Z", + "restricted": false, + "active": false, + "prohibit_login": false, + "location": "", + "pronouns": "", + "website": "", + "description": "", + "visibility": "public", + "followers_count": 0, + "following_count": 0, + "starred_repos_count": 0, + "username": "jgroman" + }, + "commit_id": "", + "review": null + }, + "headers": { + "user-agent": "Go-http-client/1.1", + "authorization": "Basic 973bf765c2eb40ebada712bddfeef1ed", + "content-type": "application/json", + "x-forgejo-delivery": "ff00c4bb-10be-49d9-b38a-4e2787e0f205", + "x-forgejo-event": "pull_request", + "x-forgejo-event-type": "pull_request_review_request", + "x-forgejo-signature": "23a4c4d690a53661671c6c063cb96af954cbb39bdfb2d5da0b3c175d6bb747bd", + "x-github-delivery": "ff00c4bb-10be-49d9-b38a-4e2787e0f205", + "x-github-event": "pull_request", + "x-github-event-type": "pull_request_review_request", + "x-gitea-delivery": "ff00c4bb-10be-49d9-b38a-4e2787e0f205", + "x-gitea-event": "pull_request", + "x-gitea-event-type": "pull_request_review_request", + "x-gitea-signature": "23a4c4d690a53661671c6c063cb96af954cbb39bdfb2d5da0b3c175d6bb747bd", + "x-gogs-delivery": "ff00c4bb-10be-49d9-b38a-4e2787e0f205", + "x-gogs-event": "pull_request", + "x-gogs-event-type": "pull_request_review_request", + "x-gogs-signature": "23a4c4d690a53661671c6c063cb96af954cbb39bdfb2d5da0b3c175d6bb747bd", + "x-hub-signature": "sha1=14916c2df5f2dbbe6d19366c2c276d8677dadde6", + "x-hub-signature-256": "sha256=23a4c4d690a53661671c6c063cb96af954cbb39bdfb2d5da0b3c175d6bb747bd", + "accept-encoding": "gzip", + "x-forwarded-scheme": "https", + "x-forwarded-proto": "https", + "x-fedora-requestid": "ahQrvkJSPhgX7fbf4PonVwAAA0c", + "x-forwarded-for": "10.16.163.74", + "x-forwarded-host": "webhook.fedoraproject.org", + "x-forwarded-server": "webhook.fedoraproject.org", + "content-length": "18755", + "host": "webhook.fedoraproject.org", + "x-forwarded-port": "443", + "forwarded": "for=10.16.163.74;host=webhook.fedoraproject.org;proto=https" + }, + "agent": null, + "topic": "org.fedoraproject.prod.forgejo.pull_request" +} diff --git a/tests/data/fedmsg/forgejo_push.json b/tests/data/fedmsg/forgejo_push.json new file mode 100644 index 000000000..c32cbe227 --- /dev/null +++ b/tests/data/fedmsg/forgejo_push.json @@ -0,0 +1,241 @@ +{ + "body": { + "ref": "refs/heads/main", + "before": "8848429b902c7747e1b36af8b5225117b6254fb5", + "after": "139828ad0b8fd3c5d172ccc0fc695a6d7a98f4c5", + "compare_url": "https://forge.fedoraproject.org/infra/docs/compare/8848429b902c7747e1b36af8b5225117b6254fb5...139828ad0b8fd3c5d172ccc0fc695a6d7a98f4c5", + "commits": [ + { + "id": "139828ad0b8fd3c5d172ccc0fc695a6d7a98f4c5", + "message": "copr: update Pulp team slack handle\n\nWe had a meeting with @dkliban and @bmbouter today and they said they are\nmoving things to the new handle.\n", + "url": "https://forge.fedoraproject.org/infra/docs/commit/139828ad0b8fd3c5d172ccc0fc695a6d7a98f4c5", + "author": { + "name": "Jakub Kadlcik", + "email": "frostyx@email.cz", + "username": "" + }, + "committer": { + "name": "Michal Konečný", + "email": "zlopez@noreply.forge.fedoraproject.org", + "username": "zlopez" + }, + "verification": null, + "timestamp": "2026-05-20T18:11:26+02:00", + "added": [], + "removed": [], + "modified": [ + "modules/sysadmin_sops/pages/copr.adoc" + ] + } + ], + "total_commits": 1, + "head_commit": { + "id": "139828ad0b8fd3c5d172ccc0fc695a6d7a98f4c5", + "message": "copr: update Pulp team slack handle\n\nWe had a meeting with @dkliban and @bmbouter today and they said they are\nmoving things to the new handle.\n", + "url": "https://forge.fedoraproject.org/infra/docs/commit/139828ad0b8fd3c5d172ccc0fc695a6d7a98f4c5", + "author": { + "name": "Jakub Kadlcik", + "email": "frostyx@email.cz", + "username": "" + }, + "committer": { + "name": "Michal Konečný", + "email": "zlopez@noreply.forge.fedoraproject.org", + "username": "zlopez" + }, + "verification": null, + "timestamp": "2026-05-20T18:11:26+02:00", + "added": [], + "removed": [], + "modified": [ + "modules/sysadmin_sops/pages/copr.adoc" + ] + }, + "repository": { + "id": 378, + "owner": { + "id": 2492, + "login": "infra", + "login_name": "", + "source_id": 0, + "full_name": "Infrastructure", + "email": "", + "avatar_url": "https://forge.fedoraproject.org/avatars/3a8323a7c9fd05c0cc41d2f54f17309ca71e02cd5f713a2e05de96ebc82996f0", + "html_url": "https://forge.fedoraproject.org/infra", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2025-12-01T18:43:16Z", + "restricted": false, + "active": false, + "prohibit_login": false, + "location": "", + "pronouns": "", + "website": "", + "description": "", + "visibility": "public", + "followers_count": 21, + "following_count": 0, + "starred_repos_count": 0, + "username": "infra" + }, + "name": "docs", + "full_name": "infra/docs", + "description": "Fedora Infrastructure Documentation", + "empty": false, + "private": false, + "fork": false, + "template": false, + "parent": null, + "mirror": false, + "size": 6653, + "language": "", + "languages_url": "https://forge.fedoraproject.org/api/v1/repos/infra/docs/languages", + "html_url": "https://forge.fedoraproject.org/infra/docs", + "url": "https://forge.fedoraproject.org/api/v1/repos/infra/docs", + "link": "", + "ssh_url": "ssh://1001300000@forge.fedoraproject.org/infra/docs.git", + "clone_url": "https://forge.fedoraproject.org/infra/docs.git", + "original_url": "https://pagure.io/infra-docs-fpo", + "website": "", + "stars_count": 1, + "forks_count": 24, + "watchers_count": 19, + "open_issues_count": 55, + "open_pr_counter": 2, + "release_counter": 0, + "default_branch": "main", + "archived": false, + "created_at": "2025-12-12T11:19:25Z", + "updated_at": "2026-05-23T16:58:39Z", + "archived_at": "1970-01-01T00:00:00Z", + "permissions": { + "admin": true, + "push": true, + "pull": true + }, + "has_issues": true, + "internal_tracker": { + "enable_time_tracker": true, + "allow_only_contributors_to_track_time": true, + "enable_issue_dependencies": true + }, + "has_wiki": true, + "has_wiki_contents": false, + "wiki_branch": "main", + "wiki_ssh_url": "ssh://1001300000@forge.fedoraproject.org/infra/docs.wiki.git", + "wiki_clone_url": "https://forge.fedoraproject.org/infra/docs.wiki.git", + "globally_editable_wiki": false, + "has_pull_requests": true, + "has_projects": true, + "has_releases": true, + "has_packages": true, + "has_actions": true, + "ignore_whitespace_conflicts": false, + "allow_merge_commits": false, + "allow_rebase": true, + "allow_rebase_explicit": false, + "allow_squash_merge": false, + "allow_fast_forward_only_merge": true, + "allow_rebase_update": true, + "default_delete_branch_after_merge": false, + "default_merge_style": "rebase", + "default_allow_maintainer_edit": false, + "default_update_style": "rebase", + "avatar_url": "", + "internal": false, + "mirror_interval": "", + "object_format_name": "sha1", + "mirror_updated": "0001-01-01T00:00:00Z", + "repo_transfer": null, + "topics": [] + }, + "pusher": { + "id": 352, + "login": "zlopez", + "login_name": "", + "source_id": 0, + "full_name": "Michal Konečný", + "email": "zlopez@noreply.forge.fedoraproject.org", + "avatar_url": "https://forge.fedoraproject.org/avatars/b01ac19b53f5233acce19f7ec3a07ce5fd794ddb7a8f22a85def1bbe9a31f593", + "html_url": "https://forge.fedoraproject.org/zlopez", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2025-08-13T12:27:06Z", + "restricted": false, + "active": false, + "prohibit_login": false, + "location": "", + "pronouns": "", + "website": "", + "description": "", + "visibility": "public", + "followers_count": 0, + "following_count": 0, + "starred_repos_count": 0, + "username": "zlopez" + }, + "sender": { + "id": 352, + "login": "zlopez", + "login_name": "", + "source_id": 0, + "full_name": "Michal Konečný", + "email": "zlopez@noreply.forge.fedoraproject.org", + "avatar_url": "https://forge.fedoraproject.org/avatars/b01ac19b53f5233acce19f7ec3a07ce5fd794ddb7a8f22a85def1bbe9a31f593", + "html_url": "https://forge.fedoraproject.org/zlopez", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2025-08-13T12:27:06Z", + "restricted": false, + "active": false, + "prohibit_login": false, + "location": "", + "pronouns": "", + "website": "", + "description": "", + "visibility": "public", + "followers_count": 0, + "following_count": 0, + "starred_repos_count": 0, + "username": "zlopez" + } + }, + "headers": { + "user-agent": "Go-http-client/1.1", + "authorization": "Basic 973bf765c2eb40ebada712bddfeef1ed", + "content-type": "application/json", + "x-forgejo-delivery": "1b207496-d58f-4bea-a04f-d1778592875d", + "x-forgejo-event": "push", + "x-forgejo-event-type": "push", + "x-forgejo-signature": "0e07c0971310f07afe600963286d76d771c9873caceb420fc25dff17601e0190", + "x-github-delivery": "1b207496-d58f-4bea-a04f-d1778592875d", + "x-github-event": "push", + "x-github-event-type": "push", + "x-gitea-delivery": "1b207496-d58f-4bea-a04f-d1778592875d", + "x-gitea-event": "push", + "x-gitea-event-type": "push", + "x-gitea-signature": "0e07c0971310f07afe600963286d76d771c9873caceb420fc25dff17601e0190", + "x-gogs-delivery": "1b207496-d58f-4bea-a04f-d1778592875d", + "x-gogs-event": "push", + "x-gogs-event-type": "push", + "x-gogs-signature": "0e07c0971310f07afe600963286d76d771c9873caceb420fc25dff17601e0190", + "x-hub-signature": "sha1=d6530c98f4d8840904633876af00ad358d29d9d3", + "x-hub-signature-256": "sha256=0e07c0971310f07afe600963286d76d771c9873caceb420fc25dff17601e0190", + "accept-encoding": "gzip", + "x-forwarded-scheme": "https", + "x-forwarded-proto": "https", + "x-fedora-requestid": "ahQEw5hMz-OHjPDTFgSVdQAAEAU", + "x-forwarded-for": "10.16.163.77", + "x-forwarded-host": "webhook.fedoraproject.org", + "x-forwarded-server": "webhook.fedoraproject.org", + "content-length": "6705", + "host": "webhook.fedoraproject.org", + "x-forwarded-port": "443", + "forwarded": "for=10.16.163.77;host=webhook.fedoraproject.org;proto=https" + }, + "agent": null, + "topic": "org.fedoraproject.prod.forgejo.push" +} diff --git a/tests/unit/events/test_forgejo.py b/tests/unit/events/test_forgejo.py new file mode 100644 index 000000000..a9bb14cf0 --- /dev/null +++ b/tests/unit/events/test_forgejo.py @@ -0,0 +1,60 @@ +import json +import pytest + +from packit_service.events import forgejo +from packit_service.events.enums import PullRequestAction +from packit_service.worker.parser import Parser +from tests.spellbook import DATA_DIR + +@pytest.fixture() +def forgejo_push(): + with open(DATA_DIR / "fedmsg" / "forgejo_push.json") as outfile: + return json.load(outfile) + +@pytest.fixture() +def forgejo_pr(): + with open(DATA_DIR / "fedmsg" / "forgejo_pr.json") as outfile: + return json.load(outfile) + +@pytest.fixture() +def forgejo_issue_comment(): + with open(DATA_DIR / "fedmsg" / "forgejo_issue_comment.json") as outfile: + return json.load(outfile) + +def test_parse_forgejo_push(forgejo_push): + event_object = Parser.parse_event(forgejo_push) + + assert isinstance(event_object, forgejo.push.Commit) + # the repo in the datagrepper payload is probably infra/docs or similar + payload = forgejo_push.get("body", {}) + assert event_object.repo_namespace == payload["repository"]["owner"]["login"] + assert event_object.repo_name == payload["repository"]["name"] + assert event_object.commit_sha == payload["after"] + assert event_object.commit_sha_before == payload["before"] + assert event_object.project_url == payload["repository"]["html_url"] + +def test_parse_forgejo_pr(forgejo_pr): + event_object = Parser.parse_event(forgejo_pr) + + if event_object is None: + # Datagrepper might have returned a PR action that is not "opened", "reopened", or "synchronize" + pytest.skip("Datagrepper returned an unsupported PR action for this test") + + assert isinstance(event_object, forgejo.pr.Action) + payload = forgejo_pr.get("body", {}) + assert event_object.action == PullRequestAction[payload["action"]] + assert event_object.pr_id == payload["pull_request"]["number"] + assert event_object.actor == payload["pull_request"]["user"]["login"] + +def test_parse_forgejo_issue_comment(forgejo_issue_comment): + event_object = Parser.parse_event(forgejo_issue_comment) + + payload = forgejo_issue_comment.get("body", {}) + if payload["issue"].get("pull_request") is not None: + assert isinstance(event_object, forgejo.pr.Comment) + assert event_object.pr_id == payload["issue"]["number"] + else: + assert isinstance(event_object, forgejo.issue.Comment) + assert event_object.issue_id == payload["issue"]["number"] + assert event_object.actor == payload["comment"]["user"]["login"] + assert event_object.comment == payload["comment"]["body"] diff --git a/tests/unit/test_webhooks.py b/tests/unit/test_webhooks.py index b8372eead..b503aea1c 100644 --- a/tests/unit/test_webhooks.py +++ b/tests/unit/test_webhooks.py @@ -246,3 +246,45 @@ def test_interested(mock_config, headers, payload, interested): headers=headers, ): assert webhooks.GithubWebhook.interested() == interested + + +@pytest.mark.parametrize( + "headers, is_good", + [ + ( + { + "X-Forgejo-Signature": ( + "7884c9fc5f880c17920b2066e85aae7b57489505a16aa9b56806a924df78f846" + ), + }, + True, + ), + ( + { + "X-Forgejo-Signature": ( + "feedfacecafebeef920b2066e85aae7b57489505a16aa9b56806a924df78f666" + ), + }, + False, + ), + ({}, False), + ], +) +def test_validate_forgejo_token(mock_config, headers, is_good): + flexmock(ServiceConfig).should_receive("get_service_config").and_return( + flexmock(validate_webhooks=True), + ) + from packit_service.service.api import webhooks + + webhooks.config = mock_config + + with Flask(__name__).test_request_context(): + payload = {"zen": "Keep it logically awesome."} + + request._cached_data = request.data = dumps(payload).encode() + request.headers = headers + if not is_good: + with pytest.raises(ValidationFailed): + webhooks.ForgejoWebhook.validate_token(webhooks.ForgejoWebhook()) + else: + webhooks.ForgejoWebhook.validate_token(webhooks.ForgejoWebhook())