def handle(installation_id, pull_request_rules_raw, event_type, data): installation_token = utils.get_installation_token(installation_id) if not installation_token: return # Some mandatory rules pull_request_rules_raw["rules"].extend(MERGIFY_RULE["rules"]) pull_request_rules = rules.PullRequestRules(**pull_request_rules_raw) pull = mergify_pull.MergifyPull.from_raw( installation_id, installation_token, data["pull_request"] ) match = pull_request_rules.get_pull_request_rule(pull) checks = dict( (c.name, c) for c in check_api.get_checks(pull.g_pull, mergify_only=True) ) summary_check = checks.get(SUMMARY_NAME) previous_conclusions = load_conclusions(pull, summary_check) conclusions = run_actions( installation_id, installation_token, event_type, data, pull, match, checks, previous_conclusions, ) post_summary(event_type, data, pull, match, summary_check, conclusions)
def run_command(installation_id, event_type, data, comment, rerun=False): installation_token = utils.get_installation_token(installation_id) if not installation_token: return pull = mergify_pull.MergifyPull.from_raw( installation_id, installation_token, data["pull_request"] ) # Run command only if this is a pending task or if user have permission to do it. if ( rerun or data["comment"]["user"]["id"] == config.BOT_USER_ID or pull.g_pull.base.repo.get_collaborator_permission( data["comment"]["user"]["login"] ) in ["admin", "write"] ): action = load_action(comment) if action: command, method = action statsd.increment("engine.commands.count", tags=["name:%s" % command]) report = method.run( installation_id, installation_token, event_type, data, pull, [] ) if report: conclusion, title, summary = report if conclusion is None: if rerun: return conclusion = "pending" result = "**Command `{command}`: {conclusion}**\n> **{title}**\n{summary}\n".format( command=command, conclusion=conclusion, title=title, summary=("\n> ".join(summary.split("\n"))).strip(), ) else: result = "**Command `{}`: success**".format(command) else: result = UNKNOWN_COMMAND_MESSAGE if "@mergifyio" not in comment: # @mergify have been used instead result += "\n\n" + WRONG_ACCOUNT_MESSAGE else: result = "@{} is not allowed to run commands".format( data["comment"]["user"]["login"] ) try: pull.g_pull.create_issue_comment(result) except github.GithubException as e: # pragma: no cover pull.log.error( "fail to post comment on the pull request", status=e.status, error=e.data["message"], )
def _handle(installation_id, subscription, branch_rules, event_type, data, event_pull_raw): installation_token = utils.get_installation_token(installation_id) if not installation_token: return pull = MergifyPullV1.from_raw(installation_id, installation_token, event_pull_raw) MergifyEngine(installation_id, installation_token, subscription, pull.g_pull.base.repo).handle(branch_rules, event_type, data, pull)
def handle(installation_id, pull_request_rules_raw, event_type, data, pull_raw): installation_token = utils.get_installation_token(installation_id) if not installation_token: return # Some mandatory rules pull_request_rules_raw["rules"].extend(MERGIFY_RULE["rules"]) pull_request_rules = rules.PullRequestRules(**pull_request_rules_raw) pull = mergify_pull.MergifyPull.from_raw(installation_id, installation_token, pull_raw) match = pull_request_rules.get_pull_request_rule(pull) checks = dict((c.name, c) for c in check_api.get_checks(pull.g_pull) if c._rawData['app']['id'] == config.INTEGRATION_ID) post_summary(event_type, data, pull, match, checks) run_actions(installation_id, installation_token, event_type, data, pull, match, checks)
def run(event_type, data): """Everything starts here.""" installation_id = data["installation"]["id"] installation_token = utils.get_installation_token(installation_id) if not installation_token: return g = github.Github(installation_token, base_url="https://api.%s" % config.GITHUB_DOMAIN) if config.LOG_RATELIMIT: # pragma: no cover rate = g.get_rate_limit().rate LOG.info("ratelimit: %s/%s, reset at %s", rate.remaining, rate.limit, rate.reset, repository=data["repository"]["name"]) repo = g.get_repo(data["repository"]["owner"]["login"] + "/" + data["repository"]["name"]) event_pull = get_github_pull_from_event(repo, event_type, data) if not event_pull: # pragma: no cover LOG.info("No pull request found in the event %s, " "ignoring", event_type) return LOG.info("Pull request found in the event %s", event_type, repo=repo.full_name, pull_request=event_pull) subscription = sub_utils.get_subscription(utils.get_redis_for_cache(), installation_id) if repo.private and not subscription["subscription_active"]: check_api.set_check_run( event_pull, "Summary", "completed", "failure", output={ "title": "Mergify is disabled", "summary": subscription["subscription_reason"], }) return if ("base" not in event_pull.raw_data or "repo" not in event_pull.raw_data["base"] or len(list(event_pull.raw_data["base"]["repo"].keys())) < 70): LOG.warning("the pull request payload looks suspicious", event_type=event_type, data=data, pull_request=event_pull.raw_data, repo=repo.fullname) if (event_type == "status" and event_pull.head.sha != data["sha"]): # pragma: no cover LOG.info("No need to proceed queue (got status of an old commit)", repo=repo.full_name, pull_request=event_pull) return elif (event_type in ["status", "check_suite", "check_run"] and event_pull.merged): # pragma: no cover LOG.info("No need to proceed queue (got status of a merged " "pull request)", repo=repo.full_name, pull_request=event_pull) return elif (event_type in ["check_suite", "check_run"] and event_pull.head.sha != data[event_type]["head_sha"] ): # pragma: no cover LOG.info("No need to proceed queue (got %s of an old " "commit)", event_type, repo=repo.full_name, pull_request=event_pull) return if check_configuration_changes(event_pull): LOG.info("Configuration changed, ignoring", repo=repo.full_name, pull_request=event_pull) return # BRANCH CONFIGURATION CHECKING try: mergify_config = rules.get_mergify_config(repo) except rules.NoRules: # pragma: no cover LOG.info("No need to proceed queue (.mergify.yml is missing)", repo=repo.full_name, pull_request=event_pull) return except rules.InvalidRules as e: # pragma: no cover # Not configured, post status check with the error message if (event_type == "pull_request" and data["action"] in ["opened", "synchronize"]): check_api.set_check_run( event_pull, "Summary", "completed", "failure", output={ "title": "The Mergify configuration is invalid", "summary": str(e) }) return create_metrics(event_type, data) v2.handle.s( installation_id, mergify_config["pull_request_rules"].as_dict(), event_type, data, event_pull.raw_data ).apply_async()
def run(event_type, data): """Everything starts here.""" installation_id = data["installation"]["id"] installation_token = utils.get_installation_token(installation_id) if not installation_token: return g = github.Github(installation_token, base_url="https://api.%s" % config.GITHUB_DOMAIN) if config.LOG_RATELIMIT: # pragma: no cover rate = g.get_rate_limit().rate LOG.info( "ratelimit: %s/%s, reset at %s", rate.remaining, rate.limit, rate.reset, repository=data["repository"]["name"], ) try: repo = g.get_repo(data["repository"]["owner"]["login"] + "/" + data["repository"]["name"]) except github.UnknownObjectException: # pragma: no cover LOG.info("Repository not found in the event %s, ignoring", event_type) return event_pull = get_github_pull_from_event(repo, event_type, data) if not event_pull: # pragma: no cover LOG.info("No pull request found in the event %s, " "ignoring", event_type) return # Override pull_request with the updated one data["pull_request"] = event_pull.raw_data LOG.info( "Pull request found in the event %s", event_type, repo=repo.full_name, pull_request=event_pull, ) if ("base" not in event_pull.raw_data or "repo" not in event_pull.raw_data["base"] or len(list(event_pull.raw_data["base"]["repo"].keys())) < 70): LOG.warning( "the pull request payload looks suspicious", event_type=event_type, data=data, pull_request=event_pull.raw_data, repo=repo.fullname, ) if (event_type == "status" and event_pull.head.sha != data["sha"]): # pragma: no cover LOG.info( "No need to proceed queue (got status of an old commit)", repo=repo.full_name, pull_request=event_pull, ) return elif (event_type in ["status", "check_suite", "check_run"] and event_pull.merged): # pragma: no cover LOG.info( "No need to proceed queue (got status of a merged " "pull request)", repo=repo.full_name, pull_request=event_pull, ) return elif (event_type in ["check_suite", "check_run"] and event_pull.head.sha != data[event_type]["head_sha"]): # pragma: no cover LOG.info( "No need to proceed queue (got %s of an old " "commit)", event_type, repo=repo.full_name, pull_request=event_pull, ) return if check_configuration_changes(event_pull): LOG.info( "Configuration changed, ignoring", repo=repo.full_name, pull_request=event_pull, ) return # BRANCH CONFIGURATION CHECKING try: mergify_config = rules.get_mergify_config(repo) except rules.NoRules: # pragma: no cover LOG.info( "No need to proceed queue (.mergify.yml is missing)", repo=repo.full_name, pull_request=event_pull, ) return except rules.InvalidRules as e: # pragma: no cover # Not configured, post status check with the error message if event_type == "pull_request" and data["action"] in [ "opened", "synchronize" ]: check_api.set_check_run( event_pull, "Summary", "completed", "failure", output={ "title": "The Mergify configuration is invalid", "summary": str(e), }, ) return subscription = sub_utils.get_subscription(utils.get_redis_for_cache(), installation_id) if repo.private and not subscription["subscription_active"]: check_api.set_check_run( event_pull, "Summary", "completed", "failure", output={ "title": "Mergify is disabled", "summary": subscription["subscription_reason"], }, ) return # CheckRun are attached to head sha, so when user add commits or force push # we can't directly get the previous Mergify Summary. So we copy it here, then # anything that looks at it in next celery tasks will find it. if event_type == "pull_request" and data["action"] == "synchronize": copy_summary_from_previous_head_sha(event_pull, data["before"]) commands_runner.spawn_pending_commands_tasks(installation_id, event_type, data, event_pull) if event_type == "issue_comment": commands_runner.run_command.s(installation_id, event_type, data, data["comment"]["body"]).apply_async() else: actions_runner.handle.s( installation_id, mergify_config["pull_request_rules"].as_dict(), event_type, data, ).apply_async()
def run(event_type, data, subscription): """Everything starts here.""" installation_id = data["installation"]["id"] installation_token = utils.get_installation_token(installation_id) if not installation_token: return g = github.Github(installation_token, base_url="https://api.%s" % config.GITHUB_DOMAIN) try: if config.LOG_RATELIMIT: # pragma: no cover rate = g.get_rate_limit().rate LOG.info("ratelimit: %s/%s, reset at %s", rate.remaining, rate.limit, rate.reset, repository=data["repository"]["name"]) repo = g.get_repo(data["repository"]["owner"]["login"] + "/" + data["repository"]["name"]) event_pull = get_github_pull_from_event(g, repo, installation_id, installation_token, event_type, data) if not event_pull: # pragma: no cover LOG.info("No pull request found in the event %s, " "ignoring", event_type) return LOG.info("Pull request found in the event %s", event_type, repo=repo.full_name, pull_request=event_pull) if ("base" not in event_pull.raw_data or "repo" not in event_pull.raw_data["base"] or len(list(event_pull.raw_data["base"]["repo"].keys())) < 70): LOG.warning("the pull request payload looks suspicious", event_type=event_type, data=data, pull_request=event_pull.raw_data, repo=repo.fullname) if (event_type == "status" and event_pull.head.sha != data["sha"]): # pragma: no cover LOG.info("No need to proceed queue (got status of an old commit)", repo=repo.full_name, pull_request=event_pull) return elif (event_type in ["status", "check_suite", "check_run"] and event_pull.merged): # pragma: no cover LOG.info( "No need to proceed queue (got status of a merged " "pull request)", repo=repo.full_name, pull_request=event_pull) return elif (event_type in ["check_suite", "check_run"] and event_pull.head.sha != data[event_type]["head_sha"]): # pragma: no cover LOG.info("No need to proceed queue (got %s of an old " "commit)", event_type, repo=repo.full_name, pull_request=event_pull) return if check_configuration_changes(event_type, data, event_pull): LOG.info("Configuration changed, ignoring", repo=repo.full_name, pull_request=event_pull) return # BRANCH CONFIGURATION CHECKING try: mergify_config = rules.get_mergify_config(repo) except rules.NoRules: # pragma: no cover LOG.info("No need to proceed queue (.mergify.yml is missing)", repo=repo.full_name, pull_request=event_pull) return except rules.InvalidRules as e: # pragma: no cover # Not configured, post status check with the error message if (event_type == "pull_request" and data["action"] in ["opened", "synchronize"]): check_api.set_check_run( event_pull, "current-config-checker", "completed", "failure", output={ "title": "The Mergify configuration is invalid", "summary": str(e) }) return create_metrics(event_type, data) # NOTE(sileht): At some point we may need to reget the # installation_token within each next tasks, in case we reach the # expiration if "rules" in mergify_config: v1.handle.s(installation_id, subscription, mergify_config["rules"], event_type, data, event_pull.raw_data).apply_async() elif "pull_request_rules" in mergify_config: v2.handle.s(installation_id, subscription, mergify_config["pull_request_rules"].as_dict(), event_type, data, event_pull.raw_data).apply_async() else: # pragma: no cover raise RuntimeError("Unexpected configuration version") except github.BadCredentialsException: # pragma: no cover LOG.error("token for install %d is no longuer valid (%s)", data["installation"]["id"], data["repository"]["full_name"]) except github.RateLimitExceededException: # pragma: no cover LOG.error("rate limit reached for install %d (%s)", data["installation"]["id"], data["repository"]["full_name"])