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})")
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()
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
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