Ejemplo n.º 1
0
async def report_queue(title: str, q: queue.QueueT) -> None:
    pulls = await q.get_pulls()
    if not pulls:
        return

    print(f"* {title} {q.ref}")

    async def _get_config(
        p: github_types.GitHubPullRequestNumber,
    ) -> typing.Tuple[github_types.GitHubPullRequestNumber, int]:
        return p, (await q.get_config(p))["priority"]

    pulls_priorities: typing.Dict[github_types.GitHubPullRequestNumber,
                                  int] = dict(await
                                              asyncio.gather(*(_get_config(p)
                                                               for p in pulls)
                                                             ))

    for priority, grouped_pulls in itertools.groupby(
            pulls, key=lambda p: pulls_priorities[p]):
        try:
            fancy_priority = merge_base.PriorityAliases(priority).name
        except ValueError:
            fancy_priority = str(priority)
        formatted_pulls = ", ".join((f"#{p}" for p in grouped_pulls))
        print(f"** {formatted_pulls} (priority: {fancy_priority})")
Ejemplo n.º 2
0
    async def generate_merge_queue_summary(
        self,
        queue_rule: typing.Union[rules.EvaluatedQueueRule, rules.QueueRule],
        for_queue_pull_request: bool = False,
    ) -> str:
        description = (
            f"{self._get_embarked_refs(markdown=True)} are embarked together for merge."
        )

        if for_queue_pull_request:
            description += f"""

This pull request has been created by Mergify to speculatively check the mergeability of #{self.user_pull_request_number}.
You don't need to do anything. Mergify will close this pull request automatically when it is complete.
"""
        description += (
            f"\n\n**Required conditions of queue** `{queue_rule.name}` **for merge:**\n"
        )
        for cond in queue_rule.conditions:
            if isinstance(queue_rule, rules.EvaluatedQueueRule):
                checked = " " if cond in queue_rule.missing_conditions else "X"
            else:
                checked = " "
            description += f"\n- [{checked}] `{cond}`"
            if cond.description:
                description += f" [{cond.description}]"

        table = [
            "| | Pull request | Queue/Priority | Speculative checks |",
            "| ---: | :--- | :--- | :--- |",
        ]
        for i, pseudo_car in enumerate(self.train._iter_pseudo_cars()):
            ctxt = await self.train.repository.get_pull_request_context(
                pseudo_car.user_pull_request_number)
            try:
                fancy_priority = merge_base.PriorityAliases(
                    pseudo_car.config["priority"]).name
            except ValueError:
                fancy_priority = str(pseudo_car.config["priority"])

            speculative_checks = ""
            if isinstance(pseudo_car, TrainCar):
                if pseudo_car.state == "updated":
                    speculative_checks = "in place"
                elif pseudo_car.state == "created":
                    speculative_checks = f"#{pseudo_car.queue_pull_request_number}"

            table.append(
                f"| {i + 1} "
                f"| {ctxt.pull['title']} #{pseudo_car.user_pull_request_number} "
                f"| {pseudo_car.config['name']}/{fancy_priority} "
                f"| {speculative_checks} "
                "|")

        description += "\n\n**The following pull requests are queued:**\n" + "\n".join(
            table)
        description += "\n\n---\n\n"
        description += constants.MERGIFY_MERGE_QUEUE_PULL_REQUEST_DOC
        return description.strip()
Ejemplo n.º 3
0
    async def _get_queue_summary(
        self, ctxt: context.Context, rule: "rules.EvaluatedRule", q: queue.QueueBase
    ) -> str:
        summary = "**Required conditions for merge:**\n"
        for cond in rule.conditions:
            checked = " " if cond in rule.missing_conditions else "X"
            summary += f"\n- [{checked}] `{cond}`"
            if cond.description:
                summary += f" [{cond.description}]"

        pulls = await q.get_pulls()
        if pulls:
            table = [
                "| | Pull request | Priority |",
                "| ---: | :--- | :--- |",
            ]
            for i, pull_number in enumerate(pulls):
                # TODO(sileht): maybe cache pull request title to avoid this lookup
                q_pull_ctxt = await ctxt.repository.get_pull_request_context(
                    pull_number
                )
                config = await q.get_config(pull_number)
                try:
                    fancy_priority = merge_base.PriorityAliases(config["priority"]).name
                except ValueError:
                    fancy_priority = str(config["priority"])

                table.append(
                    f"| {i + 1} "
                    f"| {q_pull_ctxt.pull['title']} #{pull_number} "
                    f"| {fancy_priority} "
                    "|"
                )

            summary += "\n\n**The following pull requests are queued:**\n" + "\n".join(
                table
            )

        summary += "\n\n---\n\n"
        summary += constants.MERGIFY_PULL_REQUEST_DOC
        return summary
Ejemplo n.º 4
0
def report(
    url: str,
) -> typing.Union[context.Context, github.GithubInstallationClient, None]:
    path = url.replace("https://github.com/", "")

    pull_number: typing.Optional[str]
    repo: typing.Optional[str]

    try:
        owner, repo, _, pull_number = path.split("/")
    except ValueError:
        pull_number = None
        try:
            owner, repo = path.split("/")
        except ValueError:
            owner = path
            repo = None

    try:
        client = github.get_client(owner)
    except exceptions.MergifyNotInstalled:
        print(f"* Mergify is not installed on account {owner}")
        return None

    # Do a dumb request just to authenticate
    client.get("/")

    if client.auth.installation is None:
        print("No installation detected")
        return None

    print("* INSTALLATION ID: %s" % client.auth.installation["id"])

    if client.auth.owner_id is None:
        raise RuntimeError("Unable to get owner_id")

    cached_sub, db_sub = utils.async_run(
        subscription.Subscription.get_subscription(client.auth.owner_id),
        subscription.Subscription._retrieve_subscription_from_db(client.auth.owner_id),
    )

    if repo is None:
        slug = None
    else:
        slug = owner + "/" + repo

    print("* SUBSCRIBED (cache/db): %s / %s" % (cached_sub.active, db_sub.active))
    print("* Features (cache):")
    for f in cached_sub.features:
        print(f"  - {f.value}")
    report_sub(client.auth.installation["id"], cached_sub, "ENGINE-CACHE", slug)
    report_sub(client.auth.installation["id"], db_sub, "DASHBOARD", slug)

    utils.async_run(report_worker_status(client.auth.owner))

    if repo is not None:

        repo_info = client.item(f"/repos/{owner}/{repo}")
        print(f"* REPOSITORY IS {'PRIVATE' if repo_info['private'] else 'PUBLIC'}")

        print("* CONFIGURATION:")
        mergify_config = None
        try:
            filename, mergify_config_content = rules.get_mergify_config_content(
                client, repo
            )
        except rules.NoRules:  # pragma: no cover
            print(".mergify.yml is missing")
        else:
            print(f"Config filename: {filename}")
            print(mergify_config_content.decode())
            try:
                mergify_config = rules.UserConfigurationSchema(mergify_config_content)
            except rules.InvalidRules as e:  # pragma: no cover
                print("configuration is invalid %s" % str(e))
            else:
                mergify_config["pull_request_rules"].rules.extend(
                    engine.DEFAULT_PULL_REQUEST_RULES.rules
                )

        if pull_number is None:
            for branch in typing.cast(
                typing.List[github_types.GitHubBranch],
                client.items(f"/repos/{owner}/{repo}/branches"),
            ):
                q = queue.Queue(
                    utils.get_redis_for_cache(),
                    repo_info["owner"]["id"],
                    repo_info["owner"]["login"],
                    repo_info["id"],
                    repo_info["name"],
                    branch["name"],
                )
                pulls = q.get_pulls()
                if not pulls:
                    continue

                print(f"* QUEUES {branch['name']}:")

                for priority, grouped_pulls in itertools.groupby(
                    pulls, key=lambda v: q.get_config(v)["priority"]
                ):
                    try:
                        fancy_priority = merge_base.PriorityAliases(priority).name
                    except ValueError:
                        fancy_priority = str(priority)
                    formatted_pulls = ", ".join((f"#{p}" for p in grouped_pulls))
                    print(f"** {formatted_pulls} (priority: {fancy_priority})")
        else:
            pull_raw = client.item(f"/repos/{owner}/{repo}/pulls/{pull_number}")
            ctxt = context.Context(
                client,
                pull_raw,
                cached_sub,
                [],
            )

            # FIXME queues could also be printed if no pull number given
            q = queue.Queue.from_context(ctxt)
            print("* QUEUES: %s" % ", ".join([f"#{p}" for p in q.get_pulls()]))
            print("* PULL REQUEST:")
            pr_data = dict(ctxt.pull_request.items())
            pprint.pprint(pr_data, width=160)

            print("is_behind: %s" % ctxt.is_behind)

            print("mergeable_state: %s" % ctxt.pull["mergeable_state"])

            print("* MERGIFY LAST CHECKS:")
            for c in ctxt.pull_engine_check_runs:
                print(
                    "[%s]: %s | %s"
                    % (c["name"], c["conclusion"], c["output"].get("title"))
                )
                print(
                    "> "
                    + "\n> ".join(
                        ("No Summary",)
                        if c["output"]["summary"] is None
                        else c["output"]["summary"].split("\n")
                    )
                )

            if mergify_config is not None:
                print("* MERGIFY LIVE MATCHES:")
                match = mergify_config["pull_request_rules"].get_pull_request_rule(ctxt)
                summary_title, summary = actions_runner.gen_summary(ctxt, match)
                print("> %s" % summary_title)
                print(summary)

            return ctxt

    return client