From 1c693ca2e97eb5717818185449350e5811486e47 Mon Sep 17 00:00:00 2001 From: Bastien Abadie Date: Wed, 14 Jan 2026 15:11:04 +0100 Subject: [PATCH 1/3] Run on github revision --- bot/code_review_bot/backend.py | 9 +++++ bot/code_review_bot/revisions/github.py | 52 +++++++++++++++++++++++++ bot/code_review_bot/workflow.py | 9 ++++- 3 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 bot/code_review_bot/revisions/github.py diff --git a/bot/code_review_bot/backend.py b/bot/code_review_bot/backend.py index 17019b5b3..400a41954 100644 --- a/bot/code_review_bot/backend.py +++ b/bot/code_review_bot/backend.py @@ -9,6 +9,7 @@ from code_review_bot import taskcluster from code_review_bot.config import GetAppUserAgent, settings +from code_review_bot.revisions.github import GithubRevision from code_review_bot.tasks.lint import MozLintIssue logger = structlog.get_logger(__name__) @@ -46,6 +47,10 @@ def publish_revision(self, revision): logger.warn("Skipping revision publication on backend") return + if isinstance(revision, GithubRevision): + logger.warn("Skipping revision publication for github") + return {} + # Check the repositories are urls for url in (revision.base_repository, revision.head_repository): assert isinstance(url, str), "Repository must be a string" @@ -115,6 +120,10 @@ def publish_issues(self, issues, revision): logger.warn("Skipping issues publication on backend") return + if isinstance(revision, GithubRevision): + logger.warn("Skipping issues publication for github") + return {} + published = 0 assert ( revision.issues_url is not None diff --git a/bot/code_review_bot/revisions/github.py b/bot/code_review_bot/revisions/github.py new file mode 100644 index 000000000..54123a482 --- /dev/null +++ b/bot/code_review_bot/revisions/github.py @@ -0,0 +1,52 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import requests +import structlog + +from code_review_bot.revisions import Revision + +logger = structlog.get_logger(__name__) + + +class GithubRevision(Revision): + """ + A revision from a github pull-request + """ + + def __init__(self, repo_url, branch, pull_number, pull_head_sha): + super().__init__() + + self.repo_url = repo_url + self.branch = branch + self.pull_number = pull_number + self.pull_head_sha = pull_head_sha + + # Load the patch from Github + self.patch = self.load_patch() + + def __str__(self): + return f"Github pull request {self.repo_url} #{self.pull_number} ({self.pull_head_sha[:8]})" + + def __repr__(self): + return f"GithubRevision repo_url={self.repo_url} branch={self.branch} pull_number={self.pull_number} sha={self.pull_head_sha}" + + def load_patch(self): + """ + Load the patch content for the current pull request HEAD + """ + # TODO: use specific sha + url = f"{self.repo_url}/pull/{self.pull_number}.diff" + logger.info("Loading github patch", url=url) + resp = requests.get(url, allow_redirects=True) + resp.raise_for_status() + return resp.content.decode() + + def as_dict(self): + return { + "repo_url": self.repo_url, + "branch": self.branch, + "pull_number": self.pull_number, + "pull_head_sha": self.pull_head_sha, + } diff --git a/bot/code_review_bot/workflow.py b/bot/code_review_bot/workflow.py index 260a638e3..6aba938ba 100644 --- a/bot/code_review_bot/workflow.py +++ b/bot/code_review_bot/workflow.py @@ -20,7 +20,7 @@ from code_review_bot.config import settings from code_review_bot.mercurial import MercurialWorker, Repository, robust_checkout from code_review_bot.report.debug import DebugReporter -from code_review_bot.revisions import PhabricatorRevision, Revision +from code_review_bot.revisions import GithubRevision, PhabricatorRevision, Revision from code_review_bot.sources.phabricator import ( PhabricatorActions, PhabricatorBuildState, @@ -678,6 +678,13 @@ def update_status(self, revision, state): "Only Phabricator revisions are supported for now" ) assert isinstance(state, BuildState) + + if isinstance(revision, GithubRevision): + logger.warning( + "No github status update yet", revision=revision, status=state + ) + return + if not revision.build_target_phid: logger.info( "No build target found, skipping HarborMaster update", state=state.value From df39a04657ce8dbe67ed7eb9fab87dcd760ecdf2 Mon Sep 17 00:00:00 2001 From: Bastien Abadie Date: Tue, 20 Jan 2026 16:31:42 +0100 Subject: [PATCH 2/3] github in all --- bot/code_review_bot/revisions/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bot/code_review_bot/revisions/__init__.py b/bot/code_review_bot/revisions/__init__.py index 10d4224fa..f98bd00a7 100644 --- a/bot/code_review_bot/revisions/__init__.py +++ b/bot/code_review_bot/revisions/__init__.py @@ -3,6 +3,7 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. from code_review_bot.revisions.base import ImprovementPatch, Revision +from code_review_bot.revisions.github import GithubRevision from code_review_bot.revisions.phabricator import PhabricatorRevision -__all__ = [ImprovementPatch, Revision, PhabricatorRevision] +__all__ = [ImprovementPatch, Revision, PhabricatorRevision, GithubRevision] From 6418884b81bd010f814a4910acfcb74afca2ab07 Mon Sep 17 00:00:00 2001 From: Bastien Abadie Date: Tue, 20 Jan 2026 17:04:36 +0100 Subject: [PATCH 3/3] Process github revision --- bot/code_review_bot/report/lando.py | 9 ++++----- bot/code_review_bot/revisions/base.py | 13 ++++++++----- bot/code_review_bot/revisions/phabricator.py | 5 +++-- bot/code_review_bot/workflow.py | 5 +---- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/bot/code_review_bot/report/lando.py b/bot/code_review_bot/report/lando.py index 21ed73771..a6758bec6 100644 --- a/bot/code_review_bot/report/lando.py +++ b/bot/code_review_bot/report/lando.py @@ -6,7 +6,7 @@ from code_review_bot import Level from code_review_bot.report.base import Reporter -from code_review_bot.revisions import PhabricatorRevision +from code_review_bot.revisions import GithubRevision logger = structlog.get_logger(__name__) @@ -30,10 +30,9 @@ def publish(self, issues, revision, task_failures, links, reviewers): """ Send an email to administrators """ - if not isinstance(revision, PhabricatorRevision): - raise NotImplementedError( - "Only Phabricator revisions are supported for now" - ) + if isinstance(revision, GithubRevision): + logger.warning("No Lando publication for Github yet") + return assert ( revision.phabricator_id and revision.phabricator_phid and revision.diff diff --git a/bot/code_review_bot/revisions/base.py b/bot/code_review_bot/revisions/base.py index 1cd319401..962a50db6 100644 --- a/bot/code_review_bot/revisions/base.py +++ b/bot/code_review_bot/revisions/base.py @@ -240,14 +240,17 @@ def as_dict(self): @staticmethod def from_try_task(try_task: dict, decision_task: dict, phabricator: PhabricatorAPI): """ - Load identifiers from Phabricator, using the remote task description + Load identifiers from Phabricator or Github, using the remote task description """ + from code_review_bot.revisions.github import GithubRevision from code_review_bot.revisions.phabricator import PhabricatorRevision # Load build target phid from the task env code_review = try_task["extra"]["code-review"] - # TODO: support github revision here too - return PhabricatorRevision.from_try_task( - code_review, decision_task, phabricator - ) + if "github" in code_review: + return GithubRevision(**code_review["github"]) + else: + return PhabricatorRevision.from_try_task( + code_review, decision_task, phabricator + ) diff --git a/bot/code_review_bot/revisions/phabricator.py b/bot/code_review_bot/revisions/phabricator.py index 8970e19ae..e50632ee8 100644 --- a/bot/code_review_bot/revisions/phabricator.py +++ b/bot/code_review_bot/revisions/phabricator.py @@ -130,12 +130,13 @@ def __str__(self): return f"Phabricator #{self.diff_id} - {self.diff_phid}" @staticmethod - def from_try_task(try_task: dict, decision_task: dict, phabricator: PhabricatorAPI): + def from_try_task( + code_review: dict, decision_task: dict, phabricator: PhabricatorAPI + ): """ Load identifiers from Phabricator, using the remote task description """ # Load build target phid from the task env - code_review = try_task["extra"]["code-review"] build_target_phid = code_review.get("phabricator-diff") or code_review.get( "phabricator-build-target" ) diff --git a/bot/code_review_bot/workflow.py b/bot/code_review_bot/workflow.py index 6aba938ba..d107c4aed 100644 --- a/bot/code_review_bot/workflow.py +++ b/bot/code_review_bot/workflow.py @@ -673,10 +673,6 @@ def update_status(self, revision, state): """ Update build status on HarborMaster """ - if not isinstance(revision, PhabricatorRevision): - raise NotImplementedError( - "Only Phabricator revisions are supported for now" - ) assert isinstance(state, BuildState) if isinstance(revision, GithubRevision): @@ -708,6 +704,7 @@ def publish_link(self, revision: Revision, slug: str, name: str, url: str): raise NotImplementedError( "Only Phabricator revisions are supported for now" ) + if not revision.build_target_phid: logger.info( "No build target found, skipping HarborMaster link creation",