def create_check_run_and_push_event(self, pr, name, conclusion=None, created=True, check_suite=False): if conclusion is None: status = "in_progress" else: status = "completed" check_api.set_check_run(pr, name, status, conclusion) expected_events = [] if created: expected_events.append( # Created ("check_run", { "check_run": { "conclusion": conclusion } }), ) if conclusion: expected_events.append( # Completed ("check_run", { "check_run": { "conclusion": conclusion } }), ) if check_suite: expected_events.append(("check_suite", { 'action': 'completed' }), ) self.push_events(expected_events, ordered=False)
def create_check_run_and_push_event(self, pr, name, conclusion=None, ignore_check_run_event=False, ignore_check_suite_event=False): if conclusion is None: status = "in_progress" else: status = "completed" pr_as_app = self.repo_as_app.get_pull(pr.number) check_api.set_check_run(pr_as_app, name, status, conclusion) expected_events = [] if not ignore_check_run_event: expected_events.append(("check_run", { "action": "created", "check_run": { "conclusion": conclusion } })) if not ignore_check_suite_event: expected_events.append(("check_suite", {'action': 'completed'})) self.push_events(expected_events, ordered=False)
def _handle_first_pull_in_queue(queue, pull): _, installation_id, owner, reponame, branch = queue.split("~") old_checks = [c for c in check_api.get_checks(pull.g_pull) if (c.name.endswith(" (merge)") and c._rawData['app']['id'] == config.INTEGRATION_ID)] merge_output = helpers.merge_report(pull) mergeable_state_output = helpers.output_for_mergeable_state(pull, True) if merge_output or mergeable_state_output: remove_pull(pull) conclusion, title, summary = merge_output or mergeable_state_output else: LOG.debug("updating base branch of pull request", pull=pull) redis = utils.get_redis_for_cache() method = redis.get(_get_update_method_cache_key(pull)) or "merge" conclusion, title, summary = helpers.update_pull_base_branch( pull, installation_id, method) if pull.g_pull.state == "closed": remove_pull(pull) elif conclusion == "failure": _move_pull_at_end(pull) status = "completed" if conclusion else "in_progress" for c in old_checks: check_api.set_check_run( pull.g_pull, c.name, status, conclusion, output={"title": title, "summary": summary})
def post_summary(event_type, data, pull, match, checks): summary_title, summary = gen_summary(event_type, data, pull, match) summary_name = "Summary" summary_check = checks.get(summary_name) summary_changed = (not summary_check or summary_check.output["title"] != summary_title or summary_check.output["summary"] != summary) if summary_changed: LOG.debug("summary changed", summary={ "title": summary_title, "name": summary_name, "summary": summary }) check_api.set_check_run(pull.g_pull, summary_name, "completed", "success", output={ "title": summary_title, "summary": summary }) else: LOG.debug("summary unchanged", summary={ "title": summary_title, "name": summary_name, "summary": summary })
def post_summary(event_type, data, pull, match, summary_check, conclusions): summary_title, summary = gen_summary(event_type, data, pull, match) summary += doc.MERGIFY_PULL_REQUEST_DOC summary += serialize_conclusions(conclusions) summary_changed = ( not summary_check or summary_check.output["title"] != summary_title or summary_check.output["summary"] != summary ) if summary_changed: LOG.debug( "summary changed", summary={"title": summary_title, "name": SUMMARY_NAME, "summary": summary}, ) check_api.set_check_run( pull.g_pull, SUMMARY_NAME, "completed", "success", output={"title": summary_title, "summary": summary}, ) else: LOG.debug( "summary unchanged", summary={"title": summary_title, "name": SUMMARY_NAME, "summary": summary}, )
def check_configuration_changes(event_pull): if event_pull.base.repo.default_branch == event_pull.base.ref: ref = None for f in event_pull.get_files(): if f.filename == ".mergify.yml": ref = f.contents_url.split("?ref=")[1] if ref is not None: try: rules.get_mergify_config(event_pull.base.repo, ref=ref) except rules.InvalidRules as e: # pragma: no cover # Not configured, post status check with the error message # TODO(sileht): we can annotate the .mergify.yml file in Github # UI with that API check_api.set_check_run( event_pull, "Summary", "completed", "failure", output={ "title": "The new Mergify configuration is invalid", "summary": str(e) }) else: check_api.set_check_run( event_pull, "Summary", "completed", "success", output={ "title": "The new Mergify configuration is valid", "summary": "This pull request have to be merged " "manually because it modifies Mergify configuration", }) return True return False
def update_next_pull(installation_id, installation_token, subscription, owner, reponame, branch, key, cur_key): redis = utils.get_redis_for_cache() pull_number = redis.srandmember(key) if not pull_number: LOG.debug("no more pull request to update", installation_id=installation_id, pull_number=pull_number, repo=owner + "/" + reponame, branch=branch) return LOG.debug("next pull to rebase", installation_id=installation_id, pull_number=pull_number, repo=owner + "/" + reponame, branch=branch) pull = mergify_pull.MergifyPull.from_number(installation_id, installation_token, owner, reponame, int(pull_number)) old_checks = [ c for c in check_api.get_checks(pull.g_pull) if (c.name.endswith(" (merge)") and c._rawData['app']['id'] == config.INTEGRATION_ID) ] output = output_for_mergeable_state(pull, True) if output: redis.srem(_get_cache_key(pull), pull.g_pull.number) conclusion, title, summary = output elif pull.g_pull.state == "closed": redis.srem(_get_cache_key(pull), pull.g_pull.number) if pull.g_pull.merged: conclusion = "success" title = "The pull request has been merged manually" summary = ("The pull request has been merged manually " "at *%s*" % pull.g_pull.merge_commit_sha) else: conclusion = "cancelled" title = "The pull request has been closed manually" summary = "" else: conclusion, title, summary = update_pull_base_branch( pull, subscription) redis.set(cur_key, pull_number) status = "completed" if conclusion else "in_progress" for c in old_checks: check_api.set_check_run(pull.g_pull, c.name, status, conclusion, output={ "title": title, "summary": summary })
def run_actions(installation_id, installation_token, subscription, event_type, data, pull, match, checks): # Run actions for rule, missing_conditions in match.matching_rules: for action in rule['actions']: check_name = "Mergify — Rule: %s (%s)" % (rule['name'], action) prev_check = checks.get(check_name) if missing_conditions: # NOTE(sileht): The rule was matching before, but it doesn't # anymore, since we can't remove checks, put them in cancelled # state cancel_in_progress = rule["actions"][action].cancel_in_progress if (cancel_in_progress and prev_check and prev_check.status == "in_progress"): title = ("The rule doesn't match anymore, this action " "has been cancelled") check_api.set_check_run(pull.g_pull, check_name, "completed", "cancelled", output={ "title": title, "summary": " " }) continue # NOTE(sileht): actions already done if prev_check: if prev_check.conclusion == "success": continue elif (prev_check.conclusion and event_type != "refresh"): continue report = run_action(rule, action, check_name, prev_check, installation_id, installation_token, subscription, event_type, data, pull) if not report: continue conclusion, title, summary = report if conclusion: status = "completed" else: status = "in_progress" check_api.set_check_run(pull.g_pull, check_name, status, conclusion, output={ "title": title, "summary": summary })
def update_next_pull(installation_id, installation_token, owner, reponame, branch, key, cur_key): redis = utils.get_redis_for_cache() pull_number = redis.srandmember(key) if not pull_number: LOG.debug("no more pull request to update", installation_id=installation_id, pull_number=pull_number, repo=owner + "/" + reponame, branch=branch) return LOG.debug("next pull to rebase", installation_id=installation_id, pull_number=pull_number, repo=owner + "/" + reponame, branch=branch) pull = mergify_pull.MergifyPull.from_number(installation_id, installation_token, owner, reponame, int(pull_number)) old_checks = [ c for c in check_api.get_checks(pull.g_pull) if (c.name.endswith(" (merge)") and c._rawData['app']['id'] == config.INTEGRATION_ID) ] merge_output = merge_report(pull) mergeable_state_output = output_for_mergeable_state(pull, True) if merge_output: redis.srem(_get_queue_cache_key(pull), pull.g_pull.number) conclusion, title, summary = merge_output elif mergeable_state_output: redis.srem(_get_queue_cache_key(pull), pull.g_pull.number) conclusion, title, summary = mergeable_state_output else: method = redis.get(_get_update_method_cache_key(pull)) or "merge" conclusion, title, summary = update_pull_base_branch( pull, installation_id, method) if pull.g_pull.state == "closed": redis.srem(_get_queue_cache_key(pull), pull.g_pull.number) else: redis.set(cur_key, pull_number) status = "completed" if conclusion else "in_progress" for c in old_checks: check_api.set_check_run(pull.g_pull, c.name, status, conclusion, output={ "title": title, "summary": summary })
def run_actions(installation_id, installation_token, subscription, event_type, data, pull, match, checks): # Run actions for rule, missing_conditions in match.matching_rules: for action in rule['actions']: check_name = "Mergify — Rule: %s (%s)" % (rule['name'], action) prev_check = checks.get(check_name) if missing_conditions: if not prev_check: LOG.info("action evaluation: nothing to cancel", check_name=check_name, pull_request=pull, missing_conditions=missing_conditions) continue method_name = "cancel" expected_conclusion = ["cancelled"] else: method_name = "run" expected_conclusion = ["success", "failure"] already_run = (prev_check and prev_check.conclusion in expected_conclusion and event_type != "refresh") if already_run: LOG.info("action evaluation: already in expected state", conclusion=(prev_check.conclusion if prev_check else "no-previous-check"), check_name=check_name, pull_request=pull, missing_conditions=missing_conditions) continue report = exec_action(method_name, rule, action, installation_id, installation_token, subscription, event_type, data, pull, missing_conditions) if report: conclusion, title, summary = report status = "completed" if conclusion else "in_progress" check_api.set_check_run(pull.g_pull, check_name, status, conclusion, output={ "title": title, "summary": summary }) LOG.info("action evaluation: done", report=report, check_name=check_name, pull_request=pull, missing_conditions=missing_conditions)
def _handle_first_pull_in_queue(queue, pull): _, installation_id, owner, reponame, branch = queue.split("~") old_checks = [ c for c in check_api.get_checks(pull.g_pull, mergify_only=True) if c.name.endswith(" (merge)") ] output = helpers.merge_report(pull, True) if output: conclusion, title, summary = output LOG.debug( "pull request closed in the meantime", pull=pull, conclusion=conclusion, title=title, summary=summary, ) remove_pull(pull) else: LOG.debug("updating base branch of pull request", pull=pull) redis = utils.get_redis_for_cache() method = redis.get(_get_update_method_cache_key(pull)) or "merge" conclusion, title, summary = helpers.update_pull_base_branch( pull, installation_id, method) if pull.g_pull.state == "closed": LOG.debug( "pull request closed in the meantime", pull=pull, conclusion=conclusion, title=title, summary=summary, ) remove_pull(pull) elif conclusion == "failure": LOG.debug("base branch update failed", pull=pull, title=title, summary=summary) _move_pull_at_end(pull) status = "completed" if conclusion else "in_progress" for c in old_checks: check_api.set_check_run( pull.g_pull, c.name, status, conclusion, output={ "title": title, "summary": summary }, )
def post_summary(event_type, data, pull, match, checks): # Set the summary summary_name = "Summary" deprecated_summary_name = "Mergify — " + summary_name summary = "" summary += get_already_merged_summary(event_type, data, pull, match) completed_rules = 0 for rule, missing_conditions in match.matching_rules: summary += "#### Rule: %s" % rule['name'] summary += " (%s)" % ", ".join(rule['actions']) for cond in rule['conditions']: checked = " " if cond in missing_conditions else "X" summary += "\n- [%s] `%s`" % (checked, cond) if not missing_conditions: completed_rules += 1 summary += "\n\n" potential_rules = len(match.matching_rules) - completed_rules summary_title = [] if completed_rules == 1: summary_title.append("%d rule matches" % completed_rules) elif completed_rules > 1: summary_title.append("%d rules match" % completed_rules) if potential_rules == 1: summary_title.append("%s potential rule" % potential_rules) elif potential_rules > 1: summary_title.append("%s potential rules" % potential_rules) if completed_rules == 0 and potential_rules == 0: summary_title.append("no rules match, no planned actions") summary_title = " and ".join(summary_title) summary_check = (checks.get(deprecated_summary_name) or checks.get(summary_name)) summary_changed = (not summary_check or summary_check.output["title"] != summary_title or summary_check.output["summary"] != summary) if summary_changed: check_api.set_check_run(pull.g_pull, summary_name, "completed", "success", output={ "title": summary_title, "summary": summary })
def handle_first_pull_in_queue(self, ctxt): old_checks = [ c for c in ctxt.pull_engine_check_runs if c["name"].endswith(" (merge)") ] output = helpers.merge_report(ctxt, True) if output: conclusion, title, summary = output ctxt.log.info( "pull request closed in the meantime", conclusion=conclusion, title=title, summary=summary, ) self.remove_pull(ctxt.pull["number"]) else: ctxt.log.info("updating base branch of pull request") config = self.get_config(ctxt.pull["number"]) conclusion, title, summary = helpers.update_pull_base_branch( ctxt, config["strict_method"], config["bot_account"], ) if ctxt.pull["state"] == "closed": ctxt.log.info( "pull request closed in the meantime", conclusion=conclusion, title=title, summary=summary, ) self.remove_pull(ctxt.pull["number"]) elif conclusion == "failure": ctxt.log.info("base branch update failed", title=title, summary=summary) self._move_pull_at_end(ctxt.pull["number"]) status = "completed" if conclusion else "in_progress" for c in old_checks: check_api.set_check_run( ctxt, c["name"], status, conclusion, output={ "title": title, "summary": summary }, )
def post_summary(ctxt, match, summary_check, conclusions, previous_conclusions): summary_title, summary = gen_summary(ctxt, match) summary += doc.MERGIFY_PULL_REQUEST_DOC summary += serialize_conclusions(conclusions) summary_changed = (not summary_check or summary_check["output"]["title"] != summary_title or summary_check["output"]["summary"] != summary) if summary_changed: ctxt.log.info( "summary changed", summary={ "title": summary_title, "name": SUMMARY_NAME, "summary": summary }, sources=_filterred_sources_for_logging(ctxt.sources), conclusions=conclusions, previous_conclusions=previous_conclusions, ) check_api.set_check_run( ctxt, SUMMARY_NAME, "completed", "success", output={ "title": summary_title, "summary": summary }, ) else: ctxt.log.info( "summary unchanged", summary={ "title": summary_title, "name": SUMMARY_NAME, "summary": summary }, sources=_filterred_sources_for_logging(ctxt.sources), conclusions=conclusions, previous_conclusions=previous_conclusions, )
def check_configuration_changes(ctxt): if ctxt.pull["base"]["repo"]["default_branch"] == ctxt.pull["base"]["ref"]: ref = None for f in ctxt.files: if f["filename"] in rules.MERGIFY_CONFIG_FILENAMES: ref = f["contents_url"].split("?ref=")[1] if ref is not None: try: rules.get_mergify_config(ctxt.client, ctxt.pull["base"]["repo"]["name"], ref=ref) except rules.InvalidRules as e: # Not configured, post status check with the error message check_api.set_check_run( ctxt, actions_runner.SUMMARY_NAME, "completed", "failure", output={ "title": "The new Mergify configuration is invalid", "summary": str(e), "annotations": e.get_annotations(e.filename), }, ) else: check_api.set_check_run( ctxt, actions_runner.SUMMARY_NAME, "completed", "success", output={ "title": "The new Mergify configuration is valid", "summary": "This pull request must be merged " "manually because it modifies Mergify configuration", }, ) return True return False
def test_command_refresh(self): rules = { "pull_request_rules": [{ "name": "nothing", "conditions": ["base!=master"], "actions": { "merge": {} }, }] } self.setup_repo(yaml.dump(rules)) p, commits = self.create_pr() check_api.set_check_run( p, "Summary", "completed", "success", output={ "title": "whatever", "summary": "erased" }, ) checks = list(check_api.get_checks(p)) assert len(checks) == 1 assert checks[0].name == "Summary" completed_at = checks[0].completed_at p.create_issue_comment("@mergifyio refresh") self.wait_for("issue_comment", {"action": "created"}) checks = list(check_api.get_checks(p)) assert len(checks) == 1 assert checks[0].name == "Summary" assert completed_at != checks[0].completed_at p.update() comments = list(p.get_issue_comments()) self.assertEqual("**Command `refresh`: success**", comments[-1].body)
def check_configuration_changes(ctxt): if ctxt.pull["base"]["repo"]["default_branch"] == ctxt.pull["base"]["ref"]: ref = None for f in ctxt.files: if f["filename"] in rules.MERGIFY_CONFIG_FILENAMES: ref = f["contents_url"].split("?ref=")[1] if ref is not None: try: rules.get_mergify_config(ctxt, ref=ref) except rules.InvalidRules as e: # pragma: no cover # Not configured, post status check with the error message # TODO(sileht): we can annotate the .mergify.yml file in Github # UI with that API check_api.set_check_run( ctxt, "Summary", "completed", "failure", output={ "title": "The new Mergify configuration is invalid", "summary": str(e), }, ) else: check_api.set_check_run( ctxt, "Summary", "completed", "success", output={ "title": "The new Mergify configuration is valid", "summary": "This pull request must be merged " "manually because it modifies Mergify configuration", }, ) return True return False
def copy_summary_from_previous_head_sha(ctxt, sha): checks = check_api.get_checks_for_ref( ctxt, sha, check_name=actions_runner.SUMMARY_NAME, ) checks = [c for c in checks if c["app"]["id"] == config.INTEGRATION_ID] if not checks: ctxt.log.warning( "Got synchronize event but didn't find Summary on previous head sha", ) return check_api.set_check_run( ctxt, actions_runner.SUMMARY_NAME, "completed", "success", output={ "title": checks[0]["output"]["title"], "summary": checks[0]["output"]["summary"], }, )
def copy_summary_from_previous_head_sha(ctxt, sha): checks = check_api.get_checks_for_ref( ctxt, sha, check_name=actions_runner.SUMMARY_NAME, ) checks = [c for c in checks if c["app"]["id"] == config.INTEGRATION_ID] if checks: check_api.set_check_run( ctxt, actions_runner.SUMMARY_NAME, "completed", "success", output={ "title": checks[0]["output"]["title"], "summary": checks[0]["output"]["summary"], }, ) return True else: return False
def test_comment_backwardcompat(self): rules = { "pull_request_rules": [{ "name": "comment", "conditions": ["base=master"], "actions": { "comment": { "message": "WTF?" } }, }] } self.setup_repo(yaml.dump(rules)) p, _ = self.create_pr() p.update() comments = list(p.get_issue_comments()) self.assertEqual("WTF?", comments[-1].body) # Override Summary with the old format check_api.set_check_run( p, "Summary", "completed", "success", output={ "title": "whatever", "summary": "erased" }, ) # Add a label to trigger mergify self.add_label(p, "stable") # Ensure nothing changed new_comments = list(p.get_issue_comments()) self.assertEqual(len(comments), len(new_comments)) self.assertEqual("WTF?", new_comments[-1].body)
def post_summary(pull, sources, match, summary_check, conclusions): summary_title, summary = gen_summary(pull, sources, match) summary += doc.MERGIFY_PULL_REQUEST_DOC summary += serialize_conclusions(conclusions) summary_changed = (not summary_check or summary_check.output["title"] != summary_title or summary_check.output["summary"] != summary) if summary_changed: pull.log.debug( "summary changed", summary={ "title": summary_title, "name": SUMMARY_NAME, "summary": summary }, sources=_filterred_sources_for_logging(sources), ) check_api.set_check_run( pull.g_pull, SUMMARY_NAME, "completed", "success", output={ "title": summary_title, "summary": summary }, ) else: pull.log.debug( "summary unchanged", summary={ "title": summary_title, "name": SUMMARY_NAME, "summary": summary }, sources=_filterred_sources_for_logging(sources), )
def check_configuration_changes(event_type, data, event_pull): if (event_type == "pull_request" and data["action"] in ["opened", "synchronize"] and event_pull.base.repo.default_branch == event_pull.base.ref): ref = None for f in event_pull.get_files(): if f.filename == ".mergify.yml": ref = f.contents_url.split("?ref=")[1] if ref is not None: try: mergify_config = rules.get_mergify_config(event_pull.base.repo, ref=ref) if "rules" in mergify_config: rules.get_branch_rule(mergify_config['rules'], event_pull.base.ref) except rules.InvalidRules as e: # pragma: no cover # Not configured, post status check with the error message # TODO(sileht): we can annotate the .mergify.yml file in Github # UI with that API check_api.set_check_run( event_pull, "future-config-checker", "completed", "failure", output={ "title": "The new Mergify configuration is invalid", "summary": str(e) }) else: check_api.set_check_run( event_pull, "future-config-checker", "completed", "success", output={ "title": "The new Mergify configuration is valid", "summary": "No action required", })
def copy_summary_from_previous_head_sha(ctxt, sha): checks = check_api.get_checks_for_ref( ctxt, sha, mergify_only=True, check_name=actions_runner.SUMMARY_NAME, ) if not checks: ctxt.log.warning( "Got synchronize event but didn't find Summary on previous head sha", ) return check_api.set_check_run( ctxt, actions_runner.SUMMARY_NAME, "completed", "success", output={ "title": checks[0]["output"]["title"], "summary": checks[0]["output"]["summary"], }, )
def copy_summary_from_previous_head_sha(g_pull, sha): checks = check_api.get_checks_for_ref( g_pull.base.repo, sha, {"check_name": actions_runner.SUMMARY_NAME}, mergify_only=True, ) if not checks: g_pull.log.warning( "Got synchronize event but didn't find Summary on previous head sha", ) return check_api.set_check_run( g_pull, actions_runner.SUMMARY_NAME, "completed", "success", output={ "title": checks[0].output["title"], "summary": checks[0].output["summary"], }, )
def ensure_summary_on_head_sha(ctxt): for check in ctxt.pull_engine_check_runs: if check["name"] == actions_runner.SUMMARY_NAME: return sha = actions_runner.get_last_summary_head_sha(ctxt) if sha: previous_summary = get_summary_from_sha(ctxt, sha) else: previous_summary = get_summary_from_synchronize_event(ctxt) if previous_summary: check_api.set_check_run( ctxt, actions_runner.SUMMARY_NAME, "completed", "success", output={ "title": previous_summary["output"]["title"], "summary": previous_summary["output"]["summary"], }, ) actions_runner.save_last_summary_head_sha(ctxt)
def handle_first_pull_in_queue(self, ctxt): old_checks = [ c for c in ctxt.pull_engine_check_runs if c["name"].endswith(" (merge)") ] result = helpers.merge_report(ctxt, True) if result: ctxt.log.info( "pull request closed in the meantime", result=result, ) self.remove_pull(ctxt.pull["number"]) else: ctxt.log.info("updating base branch of pull request") config = self.get_config(ctxt.pull["number"]) result = helpers.update_pull_base_branch( ctxt, config["strict_method"], config["update_bot_account"] or config["bot_account"], ) if ctxt.pull["state"] == "closed": ctxt.log.info( "pull request closed in the meantime", result=result, ) self.remove_pull(ctxt.pull["number"]) elif result.conclusion == check_api.Conclusion.FAILURE: ctxt.log.info( "base branch update failed", result=result, ) self._move_pull_at_end(ctxt.pull["number"]) for c in old_checks: check_api.set_check_run(ctxt, c["name"], result)
async def set_summary_check( self, result: check_api.Result) -> github_types.GitHubCheckRun: """Set the Mergify Summary check result.""" previous_sha = await self.get_cached_last_summary_head_sha() # NOTE(sileht): we first commit in redis the future sha, # so engine.create_initial_summary() cannot creates a second SUMMARY self._save_cached_last_summary_head_sha(self.pull["head"]["sha"]) try: return check_api.set_check_run(self, self.SUMMARY_NAME, result) except Exception: if previous_sha: # Restore previous sha in redis self._save_cached_last_summary_head_sha(previous_sha) raise
def test_truncated_check_output(self): # not used anyhow rules = { "pull_request_rules": [{ "name": "noop", "conditions": [], "actions": {} }] } self.setup_repo(yaml.dump(rules)) pr, commits = self.create_pr() check = check_api.set_check_run(pr, "Test", "completed", "success", { "summary": "a" * 70000, "title": "bla" }) assert check.output["summary"] == ("a" * 65532 + "…")
def check_configuration_changes(event_type, data, event_pull): if event_pull.base.repo.default_branch == event_pull.base.ref: ref = None for f in event_pull.get_files(): if f.filename == ".mergify.yml": ref = f.contents_url.split("?ref=")[1] if ref is not None: try: mergify_config = rules.get_mergify_config(event_pull.base.repo, ref=ref) if "rules" in mergify_config: rules.get_branch_rule(mergify_config['rules'], event_pull.base.ref) except rules.InvalidRules as e: # pragma: no cover # Not configured, post status check with the error message # TODO(sileht): we can annotate the .mergify.yml file in Github # UI with that API check_api.set_check_run( event_pull, "Mergify — future config checker", "completed", "failure", output={ "title": "The new Mergify configuration is invalid", "summary": str(e) }) else: check_api.set_check_run( event_pull, "Mergify — future config checker", "completed", "success", output={ "title": "The new Mergify configuration is valid", "summary": "No action required", }) check_api.set_check_run( event_pull, "Mergify — disabled due to configuration change", "completed", "success", output={ "title": "Mergify configuration has been modified", "summary": "The pull request needs to be merged manually", }) return True return False
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()