Beispiel #1
0
def trigger_hook(hook_group_id, hook_id, hook_payload):
    hooks = Hooks({'rootUrl': get_root_url(True)})
    response = hooks.triggerHook(hook_group_id, hook_id, hook_payload)

    logger.info('Task seen here: {}/tasks/{}'.format(
        get_root_url(os.environ.get('TASKCLUSTER_PROXY_URL')),
        response['status']['taskId']))
Beispiel #2
0
    def __init__(self,
                 publish=False,
                 risk_analysis_reviewers=[],
                 community_config=None,
                 *args,
                 **kwargs):
        super().__init__(*args, **kwargs)
        self.publish = publish
        logger.info("Phabricator publication is {}".format(
            self.publish and "enabled" or "disabled"))

        # Setup Taskcluster community hooks for risk analysis
        if community_config is not None:
            self.community_hooks = Hooks({
                "rootUrl": "https://community-tc.services.mozilla.com",
                "credentials": {
                    "clientId": community_config["client_id"],
                    "accessToken": community_config["access_token"],
                },
            })
            logger.info("Risk analysis trigger is enabled")
        else:
            self.community_hooks = None
            logger.info(
                "No taskcluster_community in secret, risk analysis is disabled"
            )

        self.risk_analysis_reviewers = risk_analysis_reviewers
Beispiel #3
0
def trigger_hook(hook_group_id, hook_id, hook_payload):
    hooks = Hooks({"rootUrl": get_root_url(True)})
    response = hooks.triggerHook(hook_group_id, hook_id, hook_payload)

    logger.info("Task seen here: {}/tasks/{}".format(
        get_root_url(os.environ.get("TASKCLUSTER_PROXY_URL")),
        response["status"]["taskId"],
    ))
Beispiel #4
0
    def __init__(self,
                 publish=False,
                 risk_analysis_reviewers=[],
                 community_config=None,
                 user_blacklist=[],
                 *args,
                 **kwargs):
        super().__init__(*args, **kwargs)
        self.publish = publish
        logger.info("Phabricator publication is {}".format(
            self.publish and "enabled" or "disabled"))

        # Setup Taskcluster community hooks for risk analysis
        if community_config is not None:
            self.community_hooks = Hooks({
                "rootUrl": "https://community-tc.services.mozilla.com",
                "credentials": {
                    "clientId": community_config["client_id"],
                    "accessToken": community_config["access_token"],
                },
            })
            logger.info("Risk analysis trigger is enabled")
        else:
            self.community_hooks = None
            logger.info(
                "No taskcluster_community in secret, risk analysis is disabled"
            )

        self.risk_analysis_reviewers = risk_analysis_reviewers

        # Load the blacklisted users
        if user_blacklist:
            self.user_blacklist = {
                user["phid"]: user["fields"]["username"]
                for user in self.api.search_users(
                    constraints={"usernames": user_blacklist})
            }
            logger.info("Blacklisted users",
                        names=self.user_blacklist.values())
        else:
            self.user_blacklist = {}
            logger.info("No blacklisted user")
Beispiel #5
0
class CodeReview(PhabricatorActions):
    """
    Code review workflow, receiving build notifications from HarborMaster
    and pushing on Try repositories
    """
    def __init__(self,
                 publish=False,
                 risk_analysis_reviewers=[],
                 community_config=None,
                 *args,
                 **kwargs):
        super().__init__(*args, **kwargs)
        self.publish = publish
        logger.info("Phabricator publication is {}".format(
            self.publish and "enabled" or "disabled"))

        # Setup Taskcluster community hooks for risk analysis
        if community_config is not None:
            self.community_hooks = Hooks({
                "rootUrl": "https://community-tc.services.mozilla.com",
                "credentials": {
                    "clientId": community_config["client_id"],
                    "accessToken": community_config["access_token"],
                },
            })
            logger.info("Risk analysis trigger is enabled")
        else:
            self.community_hooks = None
            logger.info(
                "No taskcluster_community in secret, risk analysis is disabled"
            )

        self.risk_analysis_reviewers = risk_analysis_reviewers

    def register(self, bus):
        self.bus = bus
        self.bus.add_queue(QUEUE_PHABRICATOR_RESULTS)

    def get_repositories(self, repositories, cache_root):
        """
        Configure repositories, and index them by phid
        """
        repositories = {
            phab_repo["phid"]: Repository(conf, cache_root)
            for phab_repo in self.api.list_repositories()
            for conf in repositories
            if phab_repo["fields"]["name"] == conf["name"]
        }
        assert len(repositories) > 0, "No repositories configured"
        logger.info("Configured repositories",
                    names=[r.name for r in repositories.values()])
        return repositories

    async def run(self):
        """
        Code review workflow to load all necessary information from Phabricator builds
        received from the webserver
        """
        while True:

            # Receive build from webserver
            build = await self.bus.receive(QUEUE_WEB_BUILDS)
            assert build is not None, "Invalid payload"
            assert isinstance(build, PhabricatorBuild)

            # Update its state
            self.update_state(build)

            if build.state == PhabricatorBuildState.Public:
                # When the build is public, load needed details
                try:
                    self.load_patches_stack(build)
                    logger.info("Loaded stack of patches", build=str(build))

                    self.load_reviewers(build)
                    logger.info("Loaded reviewers", build=str(build))
                except Exception as e:
                    logger.warning("Failed to load build details",
                                   build=str(build),
                                   error=str(e))
                    continue

                # Then send the build toward next stage
                logger.info("Send build to Mercurial", build=str(build))
                await self.bus.send(QUEUE_MERCURIAL, build)

                # Report public bug as 'working' (in progress)
                await self.bus.send(QUEUE_PHABRICATOR_RESULTS,
                                    ("work", build, {}))

                # Start risk analysis
                await self.start_risk_analysis(build)

            elif build.state == PhabricatorBuildState.Queued:
                # Requeue when nothing changed for now
                await self.bus.send(QUEUE_WEB_BUILDS, build)

    def publish_results(self, payload):
        assert self.publish is True, "Publication disabled"
        mode, build, extras = payload
        logger.debug("Publishing a Phabricator build update",
                     mode=mode,
                     build=build)

        if mode == "fail:general":
            failure = UnitResult(
                namespace="code-review",
                name="general",
                result=UnitResultState.Broken,
                details=
                "WARNING: An error occurred in the code review bot.\n\n```{}```"
                .format(extras["message"]),
                format="remarkup",
                duration=extras.get("duration", 0),
            )
            self.api.update_build_target(build.target_phid,
                                         BuildState.Fail,
                                         unit=[failure])

        elif mode == "fail:mercurial":
            failure = UnitResult(
                namespace="code-review",
                name="mercurial",
                result=UnitResultState.Fail,
                details=
                "WARNING: The code review bot failed to apply your patch.\n\n```{}```"
                .format(extras["message"]),
                format="remarkup",
                duration=extras.get("duration", 0),
            )
            self.api.update_build_target(build.target_phid,
                                         BuildState.Fail,
                                         unit=[failure])

        elif mode == "success":
            self.api.create_harbormaster_uri(
                build.target_phid,
                "treeherder",
                "Treeherder Jobs",
                extras["treeherder_url"],
            )

        elif mode == "work":
            self.api.update_build_target(build.target_phid, BuildState.Work)
            logger.info("Published public build as working", build=str(build))

        else:
            logger.warning("Unsupported publication", mode=mode, build=build)

        return True

    async def start_risk_analysis(self, build):
        """
        Run risk analysis by triggering a Taskcluster hook
        """
        assert isinstance(build, PhabricatorBuild)
        assert build.state == PhabricatorBuildState.Public
        try:
            if self.should_run_risk_analysis(build):
                task = self.community_hooks.triggerHook(
                    "project-relman",
                    "bugbug-classify-patch",
                    {"DIFF_ID": build.diff_id},
                )
                task_id = task["status"]["taskId"]
                logger.info("Triggered a new risk analysis task", id=task_id)

                # Send task to monitoring
                await self.bus.send(
                    QUEUE_MONITORING,
                    ("project-relman", "bugbug-classify-patch", task_id),
                )
        except Exception as e:
            logger.error("Failed to trigger risk analysis task", error=str(e))

    def should_run_risk_analysis(self, build):
        """
        Check if we should trigger a risk analysis for this revision:
        * when the revision is being reviewed by one of some specific reviewers
        """
        if self.community_hooks is None:
            return False

        usernames = set(
            [reviewer["fields"]["username"] for reviewer in build.reviewers])
        return len(usernames.intersection(self.risk_analysis_reviewers)) > 0