Ejemplo n.º 1
0
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)
Ejemplo n.º 2
0
def test_pull_request_rule_schema_invalid():
    for invalid, match in (
        ({
            "name": "hello",
            "conditions": ["this is wrong"],
            "actions": {},
        }, "Invalid condition "),
        ({
            "name": "hello",
            "conditions": ["head|4"],
            "actions": {},
        }, "Invalid condition "),
        ({
            "name": "hello",
            "conditions": [{
                "foo": "bar"
            }],
            "actions": {},
        }, r"expected str @ data\[0\]\['conditions'\]\[0\]"),
        ({
            "name": "hello",
            "conditions": [],
            "actions": {},
            "foobar": True,
        }, "extra keys not allowed"),
        ({
            "name": "hello",
            "conditions": [],
            "actions": {
                "merge": True,
            },
        }, r"expected a dictionary for dictionary value "
         r"@ data\[0\]\['actions'\]\['merge'\]"),
        ({
            "name": "hello",
            "conditions": [],
            "actions": {
                "backport": True,
            },
        }, r"expected a dictionary for dictionary value "
         r"@ data\[0\]\['actions'\]\['backport'\]"),
        ({
            "name": "hello",
            "conditions": [],
            "actions": {
                "merge": {
                    "strict": "yes",
                },
            },
        }, r"expected bool for dictionary value @ "
         r"data\[0\]\['actions'\]\['merge'\]\['strict'\]"),
    ):
        with pytest.raises(voluptuous.MultipleInvalid, match=match):
            rules.PullRequestRules([invalid])
Ejemplo n.º 3
0
def handle(installation_id, installation_token, subscription,
           pull_request_rules_raw, event_type, data, pull_raw):

    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(pull, match, checks)

    run_actions(installation_id, installation_token, subscription, event_type,
                data, pull, match, checks)
Ejemplo n.º 4
0
def test_pull_request_rule():
    for valid in ({
            "name": "hello",
            "conditions": [
                "head:master",
            ],
            "actions": {},
    }, {
        "name": "hello",
        "conditions": [
            "base:foo", "base:baz",
        ],
        "actions": {},
    }):
        rules.PullRequestRules([valid])
Ejemplo n.º 5
0
def test_convert_with_some_none():
    old_rules = {
        'rules': {
            'default': None,
            'branches': {
                '^stable/.*': {
                    'protection': None,
                    'merge_strategy': {
                        'method': 'rebase',
                        'rebase_fallback': "merge",
                    },
                },
                '^unstable/.*': {
                    'required_pull_request_reviews': None,
                    'required_status_checks': None,
                },
            },
        },
    }
    converted = convert.convert_config(old_rules["rules"])
    assert converted == [{
        "name":
        "^stable/.* branch",
        "conditions": ["base~=^stable/.*", "label!=no-mergify"],
        "actions": {
            "merge": {
                "method": "rebase",
                "rebase_fallback": "merge",
            },
        },
    }, {
        "name":
        "^unstable/.* branch",
        "conditions":
        ["base~=^unstable/.*", "label!=no-mergify", '#approved-reviews-by>=1'],
        "actions": {
            "merge": {
                "method": "merge",
                "rebase_fallback": "merge",
            },
        }
    }]
    # Validate generated conf with the schema
    rules.PullRequestRules(converted)
Ejemplo n.º 6
0
def test_null_branch():
    old_rules = {
        'rules': {
            'default': {
                'protection': {
                    'required_pull_request_reviews': {
                        'required_approving_review_count': 1
                    },
                    'required_status_checks': {
                        'contexts': ['continuous-integration/travis-ci'],
                    }
                },
                'merge_strategy': {
                    'method': 'rebase',
                }
            },
            'branches': {
                'gh-pages': None,
            },
        },
    }
    converted = convert.convert_config(old_rules["rules"])
    assert converted == [
        {
            "name":
            "default",
            "conditions": [
                "-base=gh-pages", "label!=no-mergify",
                "#approved-reviews-by>=1",
                "status-success=continuous-integration/travis-ci"
            ],
            "actions": {
                "merge": {
                    "method": "rebase",
                    "rebase_fallback": "merge",
                },
            },
        },
    ]
    # Validate generated conf with the schema
    rules.PullRequestRules(converted)
Ejemplo n.º 7
0
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)
Ejemplo n.º 8
0
def report(url):
    redis = utils.get_redis_for_cache()
    path = url.replace("https://github.com/", "")
    try:
        owner, repo, _, pull_number = path.split("/")
    except ValueError:
        print(f"Wrong URL: {url}")
        return
    slug = owner + "/" + repo

    integration = github.GithubIntegration(config.INTEGRATION_ID,
                                           config.PRIVATE_KEY)
    install_id = utils.get_installation_id(integration, owner, repo=repo)

    print("* INSTALLATION ID: %s" % install_id)

    cached_sub = sub_utils.get_subscription(redis, install_id)
    db_sub = sub_utils._retrieve_subscription_from_db(install_id)
    print("* SUBSCRIBED (cache/db): %s / %s" %
          (cached_sub["subscription_active"], db_sub["subscription_active"]))
    report_sub(install_id, slug, cached_sub, "ENGINE-CACHE")
    report_sub(install_id, slug, db_sub, "DASHBOARD")

    installation_token = integration.get_access_token(install_id).token

    g = github.Github(installation_token,
                      base_url="https://api.%s" % config.GITHUB_DOMAIN)
    r = g.get_repo(owner + "/" + repo)
    print("* REPOSITORY IS %s" % "PRIVATE" if r.private else "PUBLIC")

    print("* CONFIGURATION:")
    try:
        mergify_config_content = rules.get_mergify_config_content(r)
    except rules.NoRules:  # pragma: no cover
        print(".mergify.yml is missing")
    else:
        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:
        pull_request_rules_raw = mergify_config["pull_request_rules"].as_dict()
        pull_request_rules_raw["rules"].extend(
            actions_runner.MERGIFY_RULE["rules"])
        pull_request_rules = rules.PullRequestRules(**pull_request_rules_raw)

    try:
        p = r.get_pull(int(pull_number))
    except github.UnknownObjectException:
        print("Wrong pull request number")
        return g, None

    mp = mergify_pull.MergifyPull(g, p, install_id)
    print("* PULL REQUEST:")
    pprint.pprint(mp.to_dict(), width=160)
    try:
        print("is_behind: %s" % mp.is_behind())
    except github.GithubException as e:
        print("Unable to know if pull request branch is behind: %s" % e)

    print("mergeable_state: %s" % mp.g_pull.mergeable_state)

    print("* MERGIFY LAST CHECKS:")
    checks = list(check_api.get_checks(p))
    for c in checks:
        if c._rawData["app"]["id"] == config.INTEGRATION_ID:
            print("[%s]: %s | %s" %
                  (c.name, c.conclusion, c.output.get("title")))
            print("> " + "\n> ".join(c.output.get("summary").split("\n")))

    print("* MERGIFY LIVE MATCHES:")
    match = pull_request_rules.get_pull_request_rule(mp)
    summary_title, summary = actions_runner.gen_summary(
        "refresh", {}, mp, match)
    print("> %s" % summary_title)
    print(summary)

    return g, p
Ejemplo n.º 9
0
def report(url):
    redis = utils.get_redis_for_cache()
    path = url.replace("https://github.com/", "")
    try:
        owner, repo, _, pull_number = path.split("/")
    except ValueError:
        print(f"Wrong URL: {url}")
        return
    slug = owner + "/" + repo

    try:
        installation = github.get_installation(owner, repo)
    except exceptions.MergifyNotInstalled:
        print("* Mergify is not installed there")
        return

    client = github.get_client(owner, repo, installation)

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

    cached_sub = sub_utils.get_subscription(redis, client.installation["id"])
    db_sub = sub_utils._retrieve_subscription_from_db(
        client.installation["id"])
    print("* SUBSCRIBED (cache/db): %s / %s" %
          (cached_sub["subscription_active"], db_sub["subscription_active"]))
    report_sub(client.installation["id"], slug, cached_sub, "ENGINE-CACHE")
    report_sub(client.installation["id"], slug, db_sub, "DASHBOARD")

    pull_raw = client.item(f"pulls/{pull_number}")
    ctxt = mergify_context.MergifyContext(client, pull_raw)

    print("* REPOSITORY IS %s" %
          "PRIVATE" if ctxt.pull["base"]["repo"]["private"] else "PUBLIC")

    print("* CONFIGURATION:")
    try:
        mergify_config_content = rules.get_mergify_config_content(ctxt)
    except rules.NoRules:  # pragma: no cover
        print(".mergify.yml is missing")
        pull_request_rules = None
    else:
        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:
            pull_request_rules_raw = mergify_config[
                "pull_request_rules"].as_dict()
            pull_request_rules_raw["rules"].extend(
                engine.MERGIFY_RULE["rules"])
            pull_request_rules = rules.PullRequestRules(
                **pull_request_rules_raw)

    print("* PULL REQUEST:")
    pprint.pprint(ctxt.to_dict(), width=160)

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

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

    print("* MERGIFY LAST CHECKS:")
    checks = list(check_api.get_checks(ctxt, mergify_only=True))
    for c in checks:
        print("[%s]: %s | %s" %
              (c["name"], c["conclusion"], c["output"].get("title")))
        print("> " + "\n> ".join(c["output"].get("summary").split("\n")))

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

    return ctxt
Ejemplo n.º 10
0
def test_get_pull_request_rule():
    g = mock.Mock()

    team = mock.Mock()
    team.slug = "my-reviewers"
    team.get_members.return_value = [
        mock.Mock(login="******"),
        mock.Mock(login="******")
    ]
    org = mock.Mock()
    org.get_teams.return_value = [team]
    g.get_organization.return_value = org

    g_pull = mock.Mock()
    g_pull.assignees = []
    g_pull.labels = []
    g_pull.get_review_requests.return_value = ([], [])
    g_pull.author = "jd"
    g_pull.base.ref = "master"
    g_pull.head.ref = "myfeature"
    g_pull.base.repo.get_collaborator_permission.return_value = "write"
    g_pull._rawData = {'locked': False}
    g_pull.title = "My awesome job"
    g_pull.body = "I rock"
    g_pull.user.login = "******"
    file1 = mock.Mock()
    file1.filename = "README.rst"
    file2 = mock.Mock()
    file2.filename = "setup.py"
    g_pull.get_files.return_value = [file1, file2]

    review = mock.Mock()
    review.user.login = "******"
    review.state = "APPROVED"
    review._rawData = {"author_association": "MEMBER"}
    g_pull.get_reviews.return_value = [review]

    pull_request = mergify_pull.MergifyPull(g=g,
                                            g_pull=g_pull,
                                            installation_id=123)

    # Don't catch data in these tests
    pull_request.to_dict = pull_request._get_consolidated_data

    fake_ci = mock.Mock()
    fake_ci.context = "continuous-integration/fake-ci"
    fake_ci.state = "success"
    pull_request._get_checks = mock.Mock()
    pull_request._get_checks.return_value = [fake_ci]

    # Empty conditions
    pull_request_rules = rules.PullRequestRules([{
        "name": "default",
        "conditions": [],
        "actions": {}
    }])

    match = pull_request_rules.get_pull_request_rule(pull_request)
    assert [r['name'] for r in match.rules] == ["default"]
    assert [r['name'] for r, _ in match.matching_rules] == ["default"]
    assert [(r, []) for r in match.rules] == match.matching_rules
    for rule in match.rules:
        assert rule['actions'] == {}

    pull_request_rules = rules.PullRequestRules([{
        "name": "hello",
        "conditions": [
            "base:master",
        ],
        "actions": {}
    }])

    match = pull_request_rules.get_pull_request_rule(pull_request)
    assert [r['name'] for r in match.rules] == ["hello"]
    assert [r['name'] for r, _ in match.matching_rules] == ["hello"]
    assert [(r, []) for r in match.rules] == match.matching_rules
    for rule in match.rules:
        assert rule['actions'] == {}

    pull_request_rules = rules.PullRequestRules([{
        "name": "hello",
        "conditions": [
            "base:master",
        ],
        "actions": {}
    }, {
        "name": "backport",
        "conditions": [
            "base:master",
        ],
        "actions": {}
    }])

    match = pull_request_rules.get_pull_request_rule(pull_request)
    assert [r['name'] for r in match.rules] == ["hello", "backport"]
    assert [r['name']
            for r, _ in match.matching_rules] == ["hello", "backport"]
    assert [(r, []) for r in match.rules] == match.matching_rules
    for rule in match.rules:
        assert rule['actions'] == {}

    pull_request_rules = rules.PullRequestRules([{
        "name": "hello",
        "conditions": [
            "#files=3",
        ],
        "actions": {}
    }, {
        "name": "backport",
        "conditions": [
            "base:master",
        ],
        "actions": {}
    }])

    match = pull_request_rules.get_pull_request_rule(pull_request)
    assert [r['name'] for r in match.rules] == ["hello", "backport"]
    assert [r['name'] for r, _ in match.matching_rules] == ["backport"]
    for rule in match.rules:
        assert rule['actions'] == {}

    pull_request_rules = rules.PullRequestRules([{
        "name": "hello",
        "conditions": [
            "#files=2",
        ],
        "actions": {}
    }, {
        "name": "backport",
        "conditions": [
            "base:master",
        ],
        "actions": {}
    }])

    match = pull_request_rules.get_pull_request_rule(pull_request)
    assert [r['name'] for r in match.rules] == ["hello", "backport"]
    assert [r['name']
            for r, _ in match.matching_rules] == ["hello", "backport"]
    assert [(r, []) for r in match.rules] == match.matching_rules
    for rule in match.rules:
        assert rule['actions'] == {}

    # No match
    pull_request_rules = rules.PullRequestRules([{
        "name":
        "merge",
        "conditions": [
            "base=xyz",
            "status-success=continuous-integration/fake-ci",
            "#approved-reviews-by>=1",
        ],
        "actions": {}
    }])

    match = pull_request_rules.get_pull_request_rule(pull_request)
    assert [r['name'] for r in match.rules] == ["merge"]
    assert [r['name'] for r, _ in match.matching_rules] == []

    pull_request_rules = rules.PullRequestRules([{
        "name":
        "merge",
        "conditions": [
            "base=master",
            "status-success=continuous-integration/fake-ci",
            "#approved-reviews-by>=1",
        ],
        "actions": {}
    }])

    match = pull_request_rules.get_pull_request_rule(pull_request)
    assert [r['name'] for r in match.rules] == ["merge"]
    assert [r['name'] for r, _ in match.matching_rules] == ["merge"]
    assert [(r, []) for r in match.rules] == match.matching_rules
    for rule in match.rules:
        assert rule['actions'] == {}

    pull_request_rules = rules.PullRequestRules([{
        "name":
        "merge",
        "conditions": [
            "base=master",
            "status-success=continuous-integration/fake-ci",
            "#approved-reviews-by>=2",
        ],
        "actions": {}
    }, {
        "name":
        "fast merge",
        "conditions": [
            "base=master",
            "label=fast-track",
            "status-success=continuous-integration/fake-ci",
            "#approved-reviews-by>=1",
        ],
        "actions": {}
    }, {
        "name":
        "fast merge with alternate ci",
        "conditions": [
            "base=master",
            "label=fast-track",
            "status-success=continuous-integration/fake-ci-bis",
            "#approved-reviews-by>=1",
        ],
        "actions": {}
    }, {
        "name":
        "fast merge from a bot",
        "conditions": [
            "base=master",
            "author=mybot",
            "status-success=continuous-integration/fake-ci",
        ],
        "actions": {}
    }])
    match = pull_request_rules.get_pull_request_rule(pull_request)

    assert [r['name'] for r in match.rules] == [
        "merge", "fast merge", "fast merge with alternate ci",
        "fast merge from a bot"
    ]
    assert [r['name'] for r, _ in match.matching_rules
            ] == ["merge", "fast merge", "fast merge with alternate ci"]
    for rule in match.rules:
        assert rule['actions'] == {}

    assert match.matching_rules[0][0]['name'] == "merge"
    assert len(match.matching_rules[0][1]) == 1
    assert str(match.matching_rules[0][1][0]) == "#approved-reviews-by>=2"

    assert match.matching_rules[1][0]['name'] == "fast merge"
    assert len(match.matching_rules[1][1]) == 1
    assert str(match.matching_rules[1][1][0]) == "label=fast-track"

    assert match.matching_rules[2][0]['name'] == "fast merge with alternate ci"
    assert len(match.matching_rules[2][1]) == 2
    assert str(match.matching_rules[2][1][0]) == "label=fast-track"
    assert (str(match.matching_rules[2][1][1]) ==
            "status-success=continuous-integration/fake-ci-bis")

    # Team conditions with one review missing
    pull_request_rules = rules.PullRequestRules([{
        "name":
        "default",
        "conditions": [
            "approved-reviews-by=@orgs/my-reviewers",
            "#approved-reviews-by>=2",
        ],
        "actions": {}
    }])

    match = pull_request_rules.get_pull_request_rule(pull_request)
    assert [r['name'] for r in match.rules] == ["default"]
    assert [r['name'] for r, _ in match.matching_rules] == ["default"]

    assert match.matching_rules[0][0]['name'] == "default"
    assert len(match.matching_rules[0][1]) == 1
    assert str(match.matching_rules[0][1][0]) == "#approved-reviews-by>=2"

    review2 = mock.Mock()
    review2.user.login = "******"
    review2.state = "APPROVED"
    review2._rawData = {"author_association": "MEMBER"}
    g_pull.get_reviews.return_value = [review, review2]

    # Team conditions with no review missing
    pull_request_rules = rules.PullRequestRules([{
        "name":
        "default",
        "conditions": [
            "approved-reviews-by=@orgs/my-reviewers",
            "#approved-reviews-by>=2",
        ],
        "actions": {}
    }])

    match = pull_request_rules.get_pull_request_rule(pull_request)
    assert [r['name'] for r in match.rules] == ["default"]
    assert [r['name'] for r, _ in match.matching_rules] == ["default"]

    assert match.matching_rules[0][0]['name'] == "default"
    assert len(match.matching_rules[0][1]) == 0

    # Forbidden labels, when no label set
    pull_request_rules = rules.PullRequestRules([{
        "name":
        "default",
        "conditions": ["-label~=^(status/wip|status/blocked|review/need2)$"],
        "actions": {}
    }])

    match = pull_request_rules.get_pull_request_rule(pull_request)
    assert [r['name'] for r in match.rules] == ["default"]
    assert [r['name'] for r, _ in match.matching_rules] == ["default"]
    assert match.matching_rules[0][0]['name'] == "default"
    assert len(match.matching_rules[0][1]) == 0

    # Forbidden labels, when forbiden label set
    label = mock.Mock()
    label.name = "status/wip"
    pull_request.g_pull.labels = [label]

    match = pull_request_rules.get_pull_request_rule(pull_request)
    assert [r['name'] for r in match.rules] == ["default"]
    assert [r['name'] for r, _ in match.matching_rules] == ["default"]
    assert match.matching_rules[0][0]['name'] == "default"
    assert len(match.matching_rules[0][1]) == 1
    assert str(match.matching_rules[0][1][0]) == (
        "-label~=^(status/wip|status/blocked|review/need2)$")

    # Forbidden labels, when other label set
    label = mock.Mock()
    label.name = "allowed"
    pull_request.g_pull.labels = [label]

    match = pull_request_rules.get_pull_request_rule(pull_request)
    assert [r['name'] for r in match.rules] == ["default"]
    assert [r['name'] for r, _ in match.matching_rules] == ["default"]
    assert match.matching_rules[0][0]['name'] == "default"
    assert len(match.matching_rules[0][1]) == 0

    # Test team expander
    pull_request_rules = rules.PullRequestRules([{
        "name":
        "default",
        "conditions": ["author~=^(user1|user2|another-jd)$"],
        "actions": {}
    }])
    match = pull_request_rules.get_pull_request_rule(pull_request)
    assert [r['name'] for r in match.rules] == ["default"]
    assert [r['name'] for r, _ in match.matching_rules] == ["default"]
    assert match.matching_rules[0][0]['name'] == "default"
    assert len(match.matching_rules[0][1]) == 0
Ejemplo n.º 11
0
def test_get_pull_request_rule():

    client = mock.Mock()

    get_reviews = [{
        "user": {
            "login": "******",
            "type": "User"
        },
        "state": "APPROVED",
        "author_association": "MEMBER",
    }]
    get_files = [{"filename": "README.rst"}, {"filename": "setup.py"}]
    get_team_members = [{"login": "******"}, {"login": "******"}]

    get_checks = []
    get_statuses = [{
        "context": "continuous-integration/fake-ci",
        "state": "success"
    }]
    client.item.return_value = {"permission": "write"}  # get review user perm

    def client_items(url, *args, **kwargs):
        if url == "/repos/another-jd/name/pulls/1/reviews":
            return get_reviews
        elif url == "/repos/another-jd/name/pulls/1/files":
            return get_files
        elif url == "/repos/another-jd/name/commits/<sha>/check-runs":
            return get_checks
        elif url == "/repos/another-jd/name/commits/<sha>/status":
            return get_statuses
        elif url == "/orgs/orgs/teams/my-reviewers/members":
            return get_team_members
        else:
            raise RuntimeError(f"not handled url {url}")

    client.items.side_effect = client_items

    ctxt = context.Context(
        client,
        {
            "number": 1,
            "html_url": "<html_url>",
            "state": "closed",
            "merged_by": None,
            "merged_at": None,
            "merged": False,
            "draft": False,
            "milestone": None,
            "mergeable_state": "unstable",
            "assignees": [],
            "labels": [],
            "base": {
                "ref": "master",
                "repo": {
                    "name": "name",
                    "private": False
                },
                "user": {
                    "login": "******"
                },
                "sha": "mew",
            },
            "head": {
                "ref": "myfeature",
                "sha": "<sha>"
            },
            "locked": False,
            "requested_reviewers": [],
            "requested_teams": [],
            "title": "My awesome job",
            "body": "I rock",
            "user": {
                "login": "******"
            },
        },
        {},
    )

    # Empty conditions
    pull_request_rules = rules.PullRequestRules(
        [rules.Rule(name="default", conditions=[], actions={})])

    match = pull_request_rules.get_pull_request_rule(ctxt)
    assert [r.name for r in match.rules] == ["default"]
    assert [r.name for r in match.matching_rules] == ["default"]
    assert [rules.EvaluatedRule.from_rule(r, [])
            for r in match.rules] == match.matching_rules
    for rule in match.rules:
        assert rule.actions == {}

    pull_request_rules = pull_request_rule_from_list([{
        "name":
        "hello",
        "conditions": ["base:master"],
        "actions": {}
    }])

    match = pull_request_rules.get_pull_request_rule(ctxt)
    assert [r.name for r in match.rules] == ["hello"]
    assert [r.name for r in match.matching_rules] == ["hello"]
    assert [rules.EvaluatedRule.from_rule(r, [])
            for r in match.rules] == match.matching_rules
    for rule in match.rules:
        assert rule.actions == {}

    pull_request_rules = pull_request_rule_from_list([
        {
            "name": "hello",
            "conditions": ["base:master"],
            "actions": {}
        },
        {
            "name": "backport",
            "conditions": ["base:master"],
            "actions": {}
        },
    ])

    match = pull_request_rules.get_pull_request_rule(ctxt)
    assert [r.name for r in match.rules] == ["hello", "backport"]
    assert [r.name for r in match.matching_rules] == ["hello", "backport"]
    assert [rules.EvaluatedRule.from_rule(r, [])
            for r in match.rules] == match.matching_rules
    for rule in match.rules:
        assert rule.actions == {}

    pull_request_rules = pull_request_rule_from_list([
        {
            "name": "hello",
            "conditions": ["author:foobar"],
            "actions": {}
        },
        {
            "name": "backport",
            "conditions": ["base:master"],
            "actions": {}
        },
    ])

    match = pull_request_rules.get_pull_request_rule(ctxt)
    assert [r.name for r in match.rules] == ["hello", "backport"]
    assert [r.name for r in match.matching_rules] == ["backport"]
    for rule in match.rules:
        assert rule.actions == {}

    pull_request_rules = pull_request_rule_from_list([
        {
            "name": "hello",
            "conditions": ["author:another-jd"],
            "actions": {}
        },
        {
            "name": "backport",
            "conditions": ["base:master"],
            "actions": {}
        },
    ])

    match = pull_request_rules.get_pull_request_rule(ctxt)
    assert [r.name for r in match.rules] == ["hello", "backport"]
    assert [r.name for r in match.matching_rules] == ["hello", "backport"]
    assert [rules.EvaluatedRule.from_rule(r, [])
            for r in match.rules] == match.matching_rules
    for rule in match.rules:
        assert rule.actions == {}

    # No match
    pull_request_rules = pull_request_rule_from_list([{
        "name":
        "merge",
        "conditions": [
            "base=xyz",
            "check-success=continuous-integration/fake-ci",
            "#approved-reviews-by>=1",
        ],
        "actions": {},
    }])

    match = pull_request_rules.get_pull_request_rule(ctxt)
    assert [r.name for r in match.rules] == ["merge"]
    assert [r.name for r in match.matching_rules] == []

    pull_request_rules = pull_request_rule_from_list([{
        "name":
        "merge",
        "conditions": [
            "base=master",
            "check-success=continuous-integration/fake-ci",
            "#approved-reviews-by>=1",
        ],
        "actions": {},
    }])

    match = pull_request_rules.get_pull_request_rule(ctxt)
    assert [r.name for r in match.rules] == ["merge"]
    assert [r.name for r in match.matching_rules] == ["merge"]
    assert [rules.EvaluatedRule.from_rule(r, [])
            for r in match.rules] == match.matching_rules
    for rule in match.rules:
        assert rule.actions == {}

    pull_request_rules = pull_request_rule_from_list([
        {
            "name":
            "merge",
            "conditions": [
                "base=master",
                "check-success=continuous-integration/fake-ci",
                "#approved-reviews-by>=2",
            ],
            "actions": {},
        },
        {
            "name":
            "fast merge",
            "conditions": [
                "base=master",
                "label=fast-track",
                "check-success=continuous-integration/fake-ci",
                "#approved-reviews-by>=1",
            ],
            "actions": {},
        },
        {
            "name":
            "fast merge with alternate ci",
            "conditions": [
                "base=master",
                "label=fast-track",
                "check-success=continuous-integration/fake-ci-bis",
                "#approved-reviews-by>=1",
            ],
            "actions": {},
        },
        {
            "name":
            "fast merge from a bot",
            "conditions": [
                "base=master",
                "author=mybot",
                "check-success=continuous-integration/fake-ci",
            ],
            "actions": {},
        },
    ])
    match = pull_request_rules.get_pull_request_rule(ctxt)

    assert [r.name for r in match.rules] == [
        "merge",
        "fast merge",
        "fast merge with alternate ci",
        "fast merge from a bot",
    ]
    assert [r.name for r in match.matching_rules] == [
        "merge",
        "fast merge",
        "fast merge with alternate ci",
    ]
    for rule in match.rules:
        assert rule.actions == {}

    assert match.matching_rules[0].name == "merge"
    assert len(match.matching_rules[0].missing_conditions) == 1
    assert (str(match.matching_rules[0].missing_conditions[0]) ==
            "#approved-reviews-by>=2")

    assert match.matching_rules[1].name == "fast merge"
    assert len(match.matching_rules[1].missing_conditions) == 1
    assert str(
        match.matching_rules[1].missing_conditions[0]) == "label=fast-track"

    assert match.matching_rules[2].name == "fast merge with alternate ci"
    assert len(match.matching_rules[2].missing_conditions) == 2
    assert str(
        match.matching_rules[2].missing_conditions[0]) == "label=fast-track"
    assert (str(match.matching_rules[2].missing_conditions[1]) ==
            "check-success=continuous-integration/fake-ci-bis")

    # Team conditions with one review missing
    pull_request_rules = pull_request_rule_from_list([{
        "name":
        "default",
        "conditions": [
            "approved-reviews-by=@orgs/my-reviewers",
            "#approved-reviews-by>=2",
        ],
        "actions": {},
    }])

    match = pull_request_rules.get_pull_request_rule(ctxt)
    assert [r.name for r in match.rules] == ["default"]
    assert [r.name for r in match.matching_rules] == ["default"]

    assert match.matching_rules[0].name == "default"
    assert len(match.matching_rules[0].missing_conditions) == 1
    assert (str(match.matching_rules[0].missing_conditions[0]) ==
            "#approved-reviews-by>=2")

    get_reviews.append({
        "user": {
            "login": "******",
            "type": "User"
        },
        "state": "APPROVED",
        "author_association": "MEMBER",
    })

    del ctxt.__dict__["reviews"]
    del ctxt.__dict__["consolidated_reviews"]

    # Team conditions with no review missing
    pull_request_rules = pull_request_rule_from_list([{
        "name":
        "default",
        "conditions": [
            "approved-reviews-by=@orgs/my-reviewers",
            "#approved-reviews-by>=2",
        ],
        "actions": {},
    }])

    match = pull_request_rules.get_pull_request_rule(ctxt)
    assert [r.name for r in match.rules] == ["default"]
    assert [r.name for r in match.matching_rules] == ["default"]

    assert match.matching_rules[0].name == "default"
    assert len(match.matching_rules[0].missing_conditions) == 0

    # Forbidden labels, when no label set
    pull_request_rules = pull_request_rule_from_list([{
        "name":
        "default",
        "conditions": ["-label~=^(status/wip|status/blocked|review/need2)$"],
        "actions": {},
    }])

    match = pull_request_rules.get_pull_request_rule(ctxt)
    assert [r.name for r in match.rules] == ["default"]
    assert [r.name for r in match.matching_rules] == ["default"]
    assert match.matching_rules[0].name == "default"
    assert len(match.matching_rules[0].missing_conditions) == 0

    # Forbidden labels, when forbiden label set
    ctxt.pull["labels"] = [{"name": "status/wip"}]

    match = pull_request_rules.get_pull_request_rule(ctxt)
    assert [r.name for r in match.rules] == ["default"]
    assert [r.name for r in match.matching_rules] == ["default"]
    assert match.matching_rules[0].name == "default"
    assert len(match.matching_rules[0].missing_conditions) == 1
    assert str(match.matching_rules[0].missing_conditions[0]) == (
        "-label~=^(status/wip|status/blocked|review/need2)$")

    # Forbidden labels, when other label set
    ctxt.pull["labels"] = [{"name": "allowed"}]

    match = pull_request_rules.get_pull_request_rule(ctxt)
    assert [r.name for r in match.rules] == ["default"]
    assert [r.name for r in match.matching_rules] == ["default"]
    assert match.matching_rules[0].name == "default"
    assert len(match.matching_rules[0].missing_conditions) == 0

    # Test team expander
    pull_request_rules = pull_request_rule_from_list([{
        "name":
        "default",
        "conditions": ["author~=^(user1|user2|another-jd)$"],
        "actions": {},
    }])
    match = pull_request_rules.get_pull_request_rule(ctxt)
    assert [r.name for r in match.rules] == ["default"]
    assert [r.name for r in match.matching_rules] == ["default"]
    assert match.matching_rules[0].name == "default"
    assert len(match.matching_rules[0].missing_conditions) == 0
Ejemplo n.º 12
0
async def test_get_pull_request_rule(redis_cache: utils.RedisCache) -> None:

    client = mock.Mock()

    get_reviews = [{
        "user": {
            "login": "******",
            "id": 12321,
            "type": "User"
        },
        "state": "APPROVED",
        "author_association": "MEMBER",
    }]
    get_files = [{"filename": "README.rst"}, {"filename": "setup.py"}]
    get_team_members = [{
        "login": "******",
        "id": 12321
    }, {
        "login": "******",
        "id": 2644
    }]

    get_checks: typing.List[github_types.GitHubCheckRun] = []
    get_statuses: typing.List[github_types.GitHubStatus] = [{
        "context": "continuous-integration/fake-ci",
        "state": "success",
        "description": "foobar",
        "target_url": "http://example.com",
        "avatar_url": "",
    }]

    async def client_item(url, *args, **kwargs):
        if url == "/repos/another-jd/name/collaborators/sileht/permission":
            return {"permission": "write"}
        elif url == "/repos/another-jd/name/collaborators/jd/permission":
            return {"permission": "write"}
        raise RuntimeError(f"not handled url {url}")

    client.item.side_effect = client_item

    async def client_items(url, *args, **kwargs):
        if url == "/repos/another-jd/name/pulls/1/reviews":
            for r in get_reviews:
                yield r
        elif url == "/repos/another-jd/name/pulls/1/files":
            for f in get_files:
                yield f
        elif url == "/repos/another-jd/name/commits/<sha>/check-runs":
            for c in get_checks:
                yield c
        elif url == "/repos/another-jd/name/commits/<sha>/status":
            for s in get_statuses:
                yield s
        elif url == "/orgs/another-jd/teams/my-reviewers/members":
            for tm in get_team_members:
                yield tm
        else:
            raise RuntimeError(f"not handled url {url}")

    client.items.side_effect = client_items

    installation = context.Installation(
        github_types.GitHubAccountIdType(2644),
        github_types.GitHubLogin("another-jd"),
        subscription.Subscription(redis_cache, 0, False, "", frozenset()),
        client,
        redis_cache,
    )
    repository = context.Repository(
        installation,
        github_types.GitHubRepositoryName("name"),
        github_types.GitHubRepositoryIdType(123321),
    )
    ctxt = await context.Context.create(
        repository,
        github_types.GitHubPullRequest({
            "id":
            github_types.GitHubPullRequestId(0),
            "number":
            github_types.GitHubPullRequestNumber(1),
            "commits":
            1,
            "html_url":
            "<html_url>",
            "merge_commit_sha":
            None,
            "maintainer_can_modify":
            True,
            "rebaseable":
            True,
            "state":
            "closed",
            "merged_by":
            None,
            "merged_at":
            None,
            "merged":
            False,
            "draft":
            False,
            "mergeable_state":
            "unstable",
            "labels": [],
            "changed_files":
            1,
            "base": {
                "label": "repo",
                "ref": github_types.GitHubRefType("master"),
                "repo": {
                    "id": github_types.GitHubRepositoryIdType(123321),
                    "name": github_types.GitHubRepositoryName("name"),
                    "full_name": "another-jd/name",
                    "private": False,
                    "archived": False,
                    "url": "",
                    "default_branch": github_types.GitHubRefType(""),
                    "owner": {
                        "login": github_types.GitHubLogin("another-jd"),
                        "id": github_types.GitHubAccountIdType(2644),
                        "type": "User",
                        "avatar_url": "",
                    },
                },
                "user": {
                    "login": github_types.GitHubLogin("another-jd"),
                    "id": github_types.GitHubAccountIdType(2644),
                    "type": "User",
                    "avatar_url": "",
                },
                "sha": github_types.SHAType("mew"),
            },
            "head": {
                "label": "foo",
                "ref": github_types.GitHubRefType("myfeature"),
                "sha": github_types.SHAType("<sha>"),
                "repo": {
                    "id": github_types.GitHubRepositoryIdType(123321),
                    "name": github_types.GitHubRepositoryName("head"),
                    "full_name": "another-jd/head",
                    "private": False,
                    "archived": False,
                    "url": "",
                    "default_branch": github_types.GitHubRefType(""),
                    "owner": {
                        "login": github_types.GitHubLogin("another-jd"),
                        "id": github_types.GitHubAccountIdType(2644),
                        "type": "User",
                        "avatar_url": "",
                    },
                },
                "user": {
                    "login": github_types.GitHubLogin("another-jd"),
                    "id": github_types.GitHubAccountIdType(2644),
                    "type": "User",
                    "avatar_url": "",
                },
            },
            "title":
            "My awesome job",
            "user": {
                "login": github_types.GitHubLogin("another-jd"),
                "id": github_types.GitHubAccountIdType(2644),
                "type": "User",
                "avatar_url": "",
            },
        }),
    )

    # Empty conditions
    pull_request_rules = rules.PullRequestRules([
        rules.Rule(name="default",
                   conditions=rules.RuleConditions([]),
                   actions={})
    ])

    match = await pull_request_rules.get_pull_request_rule(ctxt)
    assert [r.name for r in match.rules] == ["default"]
    assert [r.name for r in match.matching_rules] == ["default"]
    assert [
        rules.EvaluatedRule.from_rule(r, rules.RuleMissingConditions([]), [])
        for r in match.rules
    ] == match.matching_rules
    for rule in match.rules:
        assert rule.actions == {}

    pull_request_rules = pull_request_rule_from_list([{
        "name":
        "hello",
        "conditions": ["base:master"],
        "actions": {}
    }])

    match = await pull_request_rules.get_pull_request_rule(ctxt)
    assert [r.name for r in match.rules] == ["hello"]
    assert [r.name for r in match.matching_rules] == ["hello"]
    assert [
        rules.EvaluatedRule.from_rule(r, rules.RuleMissingConditions([]), [])
        for r in match.rules
    ] == match.matching_rules
    for rule in match.rules:
        assert rule.actions == {}

    pull_request_rules = pull_request_rule_from_list([
        {
            "name": "hello",
            "conditions": ["base:master"],
            "actions": {}
        },
        {
            "name": "backport",
            "conditions": ["base:master"],
            "actions": {}
        },
    ])

    match = await pull_request_rules.get_pull_request_rule(ctxt)
    assert [r.name for r in match.rules] == ["hello", "backport"]
    assert [r.name for r in match.matching_rules] == ["hello", "backport"]
    assert [
        rules.EvaluatedRule.from_rule(r, rules.RuleMissingConditions([]), [])
        for r in match.rules
    ] == match.matching_rules
    for rule in match.rules:
        assert rule.actions == {}

    pull_request_rules = pull_request_rule_from_list([
        {
            "name": "hello",
            "conditions": ["author:foobar"],
            "actions": {}
        },
        {
            "name": "backport",
            "conditions": ["base:master"],
            "actions": {}
        },
    ])

    match = await pull_request_rules.get_pull_request_rule(ctxt)
    assert [r.name for r in match.rules] == ["hello", "backport"]
    assert [r.name for r in match.matching_rules] == ["backport"]
    for rule in match.rules:
        assert rule.actions == {}

    pull_request_rules = pull_request_rule_from_list([
        {
            "name": "hello",
            "conditions": ["author:another-jd"],
            "actions": {}
        },
        {
            "name": "backport",
            "conditions": ["base:master"],
            "actions": {}
        },
    ])

    match = await pull_request_rules.get_pull_request_rule(ctxt)
    assert [r.name for r in match.rules] == ["hello", "backport"]
    assert [r.name for r in match.matching_rules] == ["hello", "backport"]
    assert [
        rules.EvaluatedRule.from_rule(r, rules.RuleMissingConditions([]), [])
        for r in match.rules
    ] == match.matching_rules
    for rule in match.rules:
        assert rule.actions == {}

    # No match
    pull_request_rules = pull_request_rule_from_list([{
        "name":
        "merge",
        "conditions": [
            "base=xyz",
            "check-success=continuous-integration/fake-ci",
            "#approved-reviews-by>=1",
        ],
        "actions": {},
    }])

    match = await pull_request_rules.get_pull_request_rule(ctxt)
    assert [r.name for r in match.rules] == ["merge"]
    assert [r.name for r in match.matching_rules] == []

    pull_request_rules = pull_request_rule_from_list([{
        "name":
        "merge",
        "conditions": [
            "base=master",
            "check-success=continuous-integration/fake-ci",
            "#approved-reviews-by>=1",
        ],
        "actions": {},
    }])

    match = await pull_request_rules.get_pull_request_rule(ctxt)
    assert [r.name for r in match.rules] == ["merge"]
    assert [r.name for r in match.matching_rules] == ["merge"]
    assert [
        rules.EvaluatedRule.from_rule(r, rules.RuleMissingConditions([]), [])
        for r in match.rules
    ] == match.matching_rules
    for rule in match.rules:
        assert rule.actions == {}

    pull_request_rules = pull_request_rule_from_list([
        {
            "name":
            "merge",
            "conditions": [
                "base=master",
                "check-success=continuous-integration/fake-ci",
                "#approved-reviews-by>=2",
            ],
            "actions": {},
        },
        {
            "name":
            "fast merge",
            "conditions": [
                "base=master",
                "label=fast-track",
                "check-success=continuous-integration/fake-ci",
                "#approved-reviews-by>=1",
            ],
            "actions": {},
        },
        {
            "name":
            "fast merge with alternate ci",
            "conditions": [
                "base=master",
                "label=fast-track",
                "check-success=continuous-integration/fake-ci-bis",
                "#approved-reviews-by>=1",
            ],
            "actions": {},
        },
        {
            "name":
            "fast merge from a bot",
            "conditions": [
                "base=master",
                "author=mybot",
                "check-success=continuous-integration/fake-ci",
            ],
            "actions": {},
        },
    ])
    match = await pull_request_rules.get_pull_request_rule(ctxt)

    assert [r.name for r in match.rules] == [
        "merge",
        "fast merge",
        "fast merge with alternate ci",
        "fast merge from a bot",
    ]
    assert [r.name for r in match.matching_rules] == [
        "merge",
        "fast merge",
        "fast merge with alternate ci",
    ]
    for rule in match.rules:
        assert rule.actions == {}

    assert match.matching_rules[0].name == "merge"
    assert len(match.matching_rules[0].missing_conditions) == 1
    assert (str(match.matching_rules[0].missing_conditions[0]) ==
            "#approved-reviews-by>=2")

    assert match.matching_rules[1].name == "fast merge"
    assert len(match.matching_rules[1].missing_conditions) == 1
    assert str(
        match.matching_rules[1].missing_conditions[0]) == "label=fast-track"

    assert match.matching_rules[2].name == "fast merge with alternate ci"
    assert len(match.matching_rules[2].missing_conditions) == 2
    assert str(
        match.matching_rules[2].missing_conditions[0]) == "label=fast-track"
    assert (str(match.matching_rules[2].missing_conditions[1]) ==
            "check-success=continuous-integration/fake-ci-bis")

    # Team conditions with one review missing
    pull_request_rules = pull_request_rule_from_list([{
        "name":
        "default",
        "conditions": [
            "approved-reviews-by=@another-jd/my-reviewers",
            "#approved-reviews-by>=2",
        ],
        "actions": {},
    }])

    match = await pull_request_rules.get_pull_request_rule(ctxt)
    assert [r.name for r in match.rules] == ["default"]
    assert [r.name for r in match.matching_rules] == ["default"]

    assert match.matching_rules[0].name == "default"
    assert len(match.matching_rules[0].missing_conditions) == 1
    assert (str(match.matching_rules[0].missing_conditions[0]) ==
            "#approved-reviews-by>=2")

    get_reviews.append({
        "user": {
            "login": "******",
            "id": 2644,
            "type": "User"
        },
        "state": "APPROVED",
        "author_association": "MEMBER",
    })

    del ctxt._cache["reviews"]
    del ctxt._cache["consolidated_reviews"]

    # Team conditions with no review missing
    pull_request_rules = pull_request_rule_from_list([{
        "name":
        "default",
        "conditions": [
            "approved-reviews-by=@another-jd/my-reviewers",
            "#approved-reviews-by>=2",
        ],
        "actions": {},
    }])

    match = await pull_request_rules.get_pull_request_rule(ctxt)
    assert [r.name for r in match.rules] == ["default"]
    assert [r.name for r in match.matching_rules] == ["default"]

    assert match.matching_rules[0].name == "default"
    assert len(match.matching_rules[0].missing_conditions) == 0

    # Forbidden labels, when no label set
    pull_request_rules = pull_request_rule_from_list([{
        "name":
        "default",
        "conditions": ["-label~=^(status/wip|status/blocked|review/need2)$"],
        "actions": {},
    }])

    match = await pull_request_rules.get_pull_request_rule(ctxt)
    assert [r.name for r in match.rules] == ["default"]
    assert [r.name for r in match.matching_rules] == ["default"]
    assert match.matching_rules[0].name == "default"
    assert len(match.matching_rules[0].missing_conditions) == 0

    # Forbidden labels, when forbiden label set
    ctxt.pull["labels"] = [{
        "id": 0,
        "color": "#1234",
        "default": False,
        "name": "status/wip"
    }]

    match = await pull_request_rules.get_pull_request_rule(ctxt)
    assert [r.name for r in match.rules] == ["default"]
    assert [r.name for r in match.matching_rules] == ["default"]
    assert match.matching_rules[0].name == "default"
    assert len(match.matching_rules[0].missing_conditions) == 1
    assert str(match.matching_rules[0].missing_conditions[0]) == (
        "-label~=^(status/wip|status/blocked|review/need2)$")

    # Forbidden labels, when other label set
    ctxt.pull["labels"] = [{
        "id": 0,
        "color": "#1234",
        "default": False,
        "name": "allowed"
    }]

    match = await pull_request_rules.get_pull_request_rule(ctxt)
    assert [r.name for r in match.rules] == ["default"]
    assert [r.name for r in match.matching_rules] == ["default"]
    assert match.matching_rules[0].name == "default"
    assert len(match.matching_rules[0].missing_conditions) == 0

    # Test team expander
    pull_request_rules = pull_request_rule_from_list([{
        "name":
        "default",
        "conditions": ["author~=^(user1|user2|another-jd)$"],
        "actions": {},
    }])
    match = await pull_request_rules.get_pull_request_rule(ctxt)
    assert [r.name for r in match.rules] == ["default"]
    assert [r.name for r in match.matching_rules] == ["default"]
    assert match.matching_rules[0].name == "default"
    assert len(match.matching_rules[0].missing_conditions) == 0

    # branch protection
    async def client_item_with_branch_protection_enabled(url, *args, **kwargs):
        if url == "/repos/another-jd/name/branches/master":
            return {
                "protection": {
                    "enabled": True,
                    "required_status_checks": {
                        "contexts": ["awesome-ci"]
                    },
                },
            }
        raise RuntimeError(f"not handled url {url}")

    client.item.side_effect = client_item_with_branch_protection_enabled
    pull_request_rules = pull_request_rule_from_list([{
        "name": "default",
        "conditions": [],
        "actions": {
            "merge": {},
            "comment": {
                "message": "yo"
            }
        },
    }])
    match = await pull_request_rules.get_pull_request_rule(ctxt)

    assert [r.name for r in match.rules] == ["default", "default"]
    assert list(match.matching_rules[0].actions.keys()) == ["merge"]
    assert [str(c) for c in match.matching_rules[0].conditions
            ] == ["check-success=awesome-ci"]
    assert [str(c) for c in match.matching_rules[0].missing_conditions
            ] == ["check-success=awesome-ci"]
    assert list(match.matching_rules[1].actions.keys()) == ["comment"]
    assert match.matching_rules[1].conditions == []
Ejemplo n.º 13
0
def test_convert_simple():
    old_rules = {
        'rules': {
            'default': {
                'automated_backport_labels': {
                    'backport-to-3.1': 'stable/3.1',
                    'backport-to-3.0': 'stable/3.0',
                },
                'protection': {
                    'required_pull_request_reviews': {
                        'required_approving_review_count': 2
                    },
                    'required_status_checks': {
                        'contexts': ['continuous-integration/travis-ci'],
                        'strict': True
                    }
                },
                'merge_strategy': {
                    'method': 'rebase'
                }
            },
            'branches': {
                '^stable/.*': {
                    'protection': {
                        'required_pull_request_reviews': {
                            'required_approving_review_count': 1
                        }
                    }
                }
            }
        }
    }
    converted = convert.convert_config(old_rules["rules"])
    assert converted == [
        {
            "name":
            "default",
            "conditions": [
                "-base~=^stable/.*", "label!=no-mergify",
                "#approved-reviews-by>=2",
                "status-success=continuous-integration/travis-ci"
            ],
            "actions": {
                "merge": {
                    "method": "rebase",
                    "rebase_fallback": "merge",
                    "strict": True,
                },
            },
        },
        {
            "name":
            "backport stable/3.0",
            "conditions": [
                "-base~=^stable/.*", "label!=no-mergify",
                "label=backport-to-3.0"
            ],
            "actions": {
                "backport": {
                    "branches": ["stable/3.0"],
                },
            },
        },
        {
            "name":
            "backport stable/3.1",
            "conditions": [
                "-base~=^stable/.*", "label!=no-mergify",
                "label=backport-to-3.1"
            ],
            "actions": {
                "backport": {
                    "branches": ["stable/3.1"],
                },
            },
        },
        {
            "name":
            "^stable/.* branch",
            "conditions": [
                "base~=^stable/.*", "label!=no-mergify",
                "#approved-reviews-by>=1",
                "status-success=continuous-integration/travis-ci"
            ],
            "actions": {
                "merge": {
                    "method": "rebase",
                    "rebase_fallback": "merge",
                    "strict": True,
                },
            },
        },
        {
            "name":
            "backport stable/3.0 from ^stable/.*",
            "conditions":
            ["base~=^stable/.*", "label!=no-mergify", "label=backport-to-3.0"],
            "actions": {
                "backport": {
                    "branches": ["stable/3.0"],
                },
            }
        },
        {
            "name":
            "backport stable/3.1 from ^stable/.*",
            "conditions":
            ["base~=^stable/.*", "label!=no-mergify", "label=backport-to-3.1"],
            "actions": {
                "backport": {
                    "branches": ["stable/3.1"],
                },
            },
        },
    ]
    # Validate generated conf with the schema
    rules.PullRequestRules(converted)
Ejemplo n.º 14
0
def test_pull_request_rule_schema_invalid():
    for invalid, match in (
        (
            {
                "name": "hello",
                "conditions": ["this is wrong"],
                "actions": {}
            },
            "Invalid condition ",
        ),
        (
            {
                "name": "invalid regexp",
                "conditions": ["head~=(lol"],
                "actions": {}
            },
            r"Invalid condition 'head~=\(lol'. Invalid arguments: "
            r"missing \), "
            r"unterminated subpattern at position 0 @ ",
        ),
        (
            {
                "name": "hello",
                "conditions": ["head|4"],
                "actions": {}
            },
            "Invalid condition ",
        ),
        (
            {
                "name": "hello",
                "conditions": [{
                    "foo": "bar"
                }],
                "actions": {}
            },
            r"expected str @ data\[0\]\['conditions'\]\[0\]",
        ),
        (
            {
                "name": "hello",
                "conditions": [],
                "actions": {},
                "foobar": True
            },
            "extra keys not allowed",
        ),
        (
            {
                "name": "hello",
                "conditions": [],
                "actions": {
                    "merge": True
                }
            },
            r"expected a dictionary for dictionary value "
            r"@ data\[0\]\['actions'\]\['merge'\]",
        ),
        (
            {
                "name": "hello",
                "conditions": [],
                "actions": {
                    "backport": {
                        "regexes": ["(azerty"]
                    }
                },
            },
            r"missing \), unterminated subpattern at position 0 "
            r"@ data\[0\]\['actions'\]\['backport'\]\['regexes'\]\[0\]",
        ),
        (
            {
                "name": "hello",
                "conditions": [],
                "actions": {
                    "backport": True
                }
            },
            r"expected a dictionary for dictionary value "
            r"@ data\[0\]\['actions'\]\['backport'\]",
        ),
        (
            {
                "name": "hello",
                "conditions": [],
                "actions": {
                    "merge": {
                        "strict": "yes"
                    }
                },
            },
            r"expected bool for dictionary value @ "
            r"data\[0\]\['actions'\]\['merge'\]\['strict'\]",
        ),
    ):
        with pytest.raises(voluptuous.MultipleInvalid, match=match):
            print(invalid)
            rules.PullRequestRules([invalid])
Ejemplo n.º 15
0
def test_get_pull_request_rule():

    client = mock.Mock()

    get_reviews = [{
        "user": {
            "login": "******",
            "type": "User"
        },
        "state": "APPROVED",
        "author_association": "MEMBER",
    }]
    get_files = [{"filename": "README.rst"}, {"filename": "setup.py"}]
    get_team_members = [{"login": "******"}, {"login": "******"}]

    get_checks = []
    get_statuses = [{
        "context": "continuous-integration/fake-ci",
        "state": "success"
    }]
    client.item.return_value = {"permission": "write"}  # get review user perm
    client.items.side_effect = [
        get_reviews,
        get_files,
        get_checks,
        get_statuses,
        get_team_members,
    ]

    ctxt = mergify_context.MergifyContext(
        client,
        {
            "number": 1,
            "html_url": "<html_url>",
            "state": "closed",
            "merged_by": None,
            "merged_at": None,
            "merged": False,
            "milestone": None,
            "mergeable_state": "unstable",
            "assignees": [],
            "labels": [],
            "author": "jd",
            "base": {
                "ref": "master",
                "repo": {
                    "name": "name",
                    "private": False
                },
            },
            "head": {
                "ref": "myfeature",
                "sha": "<sha>"
            },
            "locked": False,
            "requested_reviewers": [],
            "requested_teams": [],
            "title": "My awesome job",
            "body": "I rock",
            "user": {
                "login": "******"
            },
        },
    )

    # Don't catch data in these tests
    ctxt.to_dict = ctxt._get_consolidated_data

    # Empty conditions
    pull_request_rules = rules.PullRequestRules([{
        "name": "default",
        "conditions": [],
        "actions": {}
    }])

    match = pull_request_rules.get_pull_request_rule(ctxt)
    assert [r["name"] for r in match.rules] == ["default"]
    assert [r["name"] for r, _ in match.matching_rules] == ["default"]
    assert [(r, []) for r in match.rules] == match.matching_rules
    for rule in match.rules:
        assert rule["actions"] == {}

    pull_request_rules = rules.PullRequestRules([{
        "name": "hello",
        "conditions": ["base:master"],
        "actions": {}
    }])

    match = pull_request_rules.get_pull_request_rule(ctxt)
    assert [r["name"] for r in match.rules] == ["hello"]
    assert [r["name"] for r, _ in match.matching_rules] == ["hello"]
    assert [(r, []) for r in match.rules] == match.matching_rules
    for rule in match.rules:
        assert rule["actions"] == {}

    pull_request_rules = rules.PullRequestRules([
        {
            "name": "hello",
            "conditions": ["base:master"],
            "actions": {}
        },
        {
            "name": "backport",
            "conditions": ["base:master"],
            "actions": {}
        },
    ])

    match = pull_request_rules.get_pull_request_rule(ctxt)
    assert [r["name"] for r in match.rules] == ["hello", "backport"]
    assert [r["name"]
            for r, _ in match.matching_rules] == ["hello", "backport"]
    assert [(r, []) for r in match.rules] == match.matching_rules
    for rule in match.rules:
        assert rule["actions"] == {}

    pull_request_rules = rules.PullRequestRules([
        {
            "name": "hello",
            "conditions": ["#files=3"],
            "actions": {}
        },
        {
            "name": "backport",
            "conditions": ["base:master"],
            "actions": {}
        },
    ])

    match = pull_request_rules.get_pull_request_rule(ctxt)
    assert [r["name"] for r in match.rules] == ["hello", "backport"]
    assert [r["name"] for r, _ in match.matching_rules] == ["backport"]
    for rule in match.rules:
        assert rule["actions"] == {}

    pull_request_rules = rules.PullRequestRules([
        {
            "name": "hello",
            "conditions": ["#files=2"],
            "actions": {}
        },
        {
            "name": "backport",
            "conditions": ["base:master"],
            "actions": {}
        },
    ])

    match = pull_request_rules.get_pull_request_rule(ctxt)
    assert [r["name"] for r in match.rules] == ["hello", "backport"]
    assert [r["name"]
            for r, _ in match.matching_rules] == ["hello", "backport"]
    assert [(r, []) for r in match.rules] == match.matching_rules
    for rule in match.rules:
        assert rule["actions"] == {}

    # No match
    pull_request_rules = rules.PullRequestRules([{
        "name":
        "merge",
        "conditions": [
            "base=xyz",
            "status-success=continuous-integration/fake-ci",
            "#approved-reviews-by>=1",
        ],
        "actions": {},
    }])

    match = pull_request_rules.get_pull_request_rule(ctxt)
    assert [r["name"] for r in match.rules] == ["merge"]
    assert [r["name"] for r, _ in match.matching_rules] == []

    pull_request_rules = rules.PullRequestRules([{
        "name":
        "merge",
        "conditions": [
            "base=master",
            "status-success=continuous-integration/fake-ci",
            "#approved-reviews-by>=1",
        ],
        "actions": {},
    }])

    match = pull_request_rules.get_pull_request_rule(ctxt)
    assert [r["name"] for r in match.rules] == ["merge"]
    assert [r["name"] for r, _ in match.matching_rules] == ["merge"]
    assert [(r, []) for r in match.rules] == match.matching_rules
    for rule in match.rules:
        assert rule["actions"] == {}

    pull_request_rules = rules.PullRequestRules([
        {
            "name":
            "merge",
            "conditions": [
                "base=master",
                "status-success=continuous-integration/fake-ci",
                "#approved-reviews-by>=2",
            ],
            "actions": {},
        },
        {
            "name":
            "fast merge",
            "conditions": [
                "base=master",
                "label=fast-track",
                "status-success=continuous-integration/fake-ci",
                "#approved-reviews-by>=1",
            ],
            "actions": {},
        },
        {
            "name":
            "fast merge with alternate ci",
            "conditions": [
                "base=master",
                "label=fast-track",
                "status-success=continuous-integration/fake-ci-bis",
                "#approved-reviews-by>=1",
            ],
            "actions": {},
        },
        {
            "name":
            "fast merge from a bot",
            "conditions": [
                "base=master",
                "author=mybot",
                "status-success=continuous-integration/fake-ci",
            ],
            "actions": {},
        },
    ])
    match = pull_request_rules.get_pull_request_rule(ctxt)

    assert [r["name"] for r in match.rules] == [
        "merge",
        "fast merge",
        "fast merge with alternate ci",
        "fast merge from a bot",
    ]
    assert [r["name"] for r, _ in match.matching_rules] == [
        "merge",
        "fast merge",
        "fast merge with alternate ci",
    ]
    for rule in match.rules:
        assert rule["actions"] == {}

    assert match.matching_rules[0][0]["name"] == "merge"
    assert len(match.matching_rules[0][1]) == 1
    assert str(match.matching_rules[0][1][0]) == "#approved-reviews-by>=2"

    assert match.matching_rules[1][0]["name"] == "fast merge"
    assert len(match.matching_rules[1][1]) == 1
    assert str(match.matching_rules[1][1][0]) == "label=fast-track"

    assert match.matching_rules[2][0]["name"] == "fast merge with alternate ci"
    assert len(match.matching_rules[2][1]) == 2
    assert str(match.matching_rules[2][1][0]) == "label=fast-track"
    assert (str(match.matching_rules[2][1][1]) ==
            "status-success=continuous-integration/fake-ci-bis")

    # Team conditions with one review missing
    pull_request_rules = rules.PullRequestRules([{
        "name":
        "default",
        "conditions": [
            "approved-reviews-by=@orgs/my-reviewers",
            "#approved-reviews-by>=2",
        ],
        "actions": {},
    }])

    match = pull_request_rules.get_pull_request_rule(ctxt)
    assert [r["name"] for r in match.rules] == ["default"]
    assert [r["name"] for r, _ in match.matching_rules] == ["default"]

    assert match.matching_rules[0][0]["name"] == "default"
    assert len(match.matching_rules[0][1]) == 1
    assert str(match.matching_rules[0][1][0]) == "#approved-reviews-by>=2"

    get_reviews.append({
        "user": {
            "login": "******",
            "type": "User"
        },
        "state": "APPROVED",
        "author_association": "MEMBER",
    })
    client.items.side_effect = [
        get_reviews,
        get_files,
        get_checks,
        get_statuses,
        get_team_members,
    ]
    # Drop caches
    del ctxt.__dict__["checks"]
    del ctxt.__dict__["reviews"]
    del ctxt.__dict__["files"]
    del ctxt.__dict__["consolidated_reviews"]

    # Team conditions with no review missing
    pull_request_rules = rules.PullRequestRules([{
        "name":
        "default",
        "conditions": [
            "approved-reviews-by=@orgs/my-reviewers",
            "#approved-reviews-by>=2",
        ],
        "actions": {},
    }])

    match = pull_request_rules.get_pull_request_rule(ctxt)
    assert [r["name"] for r in match.rules] == ["default"]
    assert [r["name"] for r, _ in match.matching_rules] == ["default"]

    assert match.matching_rules[0][0]["name"] == "default"
    assert len(match.matching_rules[0][1]) == 0

    # Forbidden labels, when no label set
    pull_request_rules = rules.PullRequestRules([{
        "name":
        "default",
        "conditions": ["-label~=^(status/wip|status/blocked|review/need2)$"],
        "actions": {},
    }])

    match = pull_request_rules.get_pull_request_rule(ctxt)
    assert [r["name"] for r in match.rules] == ["default"]
    assert [r["name"] for r, _ in match.matching_rules] == ["default"]
    assert match.matching_rules[0][0]["name"] == "default"
    assert len(match.matching_rules[0][1]) == 0

    # Forbidden labels, when forbiden label set
    ctxt.pull["labels"] = [{"name": "status/wip"}]

    match = pull_request_rules.get_pull_request_rule(ctxt)
    assert [r["name"] for r in match.rules] == ["default"]
    assert [r["name"] for r, _ in match.matching_rules] == ["default"]
    assert match.matching_rules[0][0]["name"] == "default"
    assert len(match.matching_rules[0][1]) == 1
    assert str(match.matching_rules[0][1][0]) == (
        "-label~=^(status/wip|status/blocked|review/need2)$")

    # Forbidden labels, when other label set
    ctxt.pull["labels"] = [{"name": "allowed"}]

    match = pull_request_rules.get_pull_request_rule(ctxt)
    assert [r["name"] for r in match.rules] == ["default"]
    assert [r["name"] for r, _ in match.matching_rules] == ["default"]
    assert match.matching_rules[0][0]["name"] == "default"
    assert len(match.matching_rules[0][1]) == 0

    # Test team expander
    pull_request_rules = rules.PullRequestRules([{
        "name":
        "default",
        "conditions": ["author~=^(user1|user2|another-jd)$"],
        "actions": {},
    }])
    match = pull_request_rules.get_pull_request_rule(ctxt)
    assert [r["name"] for r in match.rules] == ["default"]
    assert [r["name"] for r, _ in match.matching_rules] == ["default"]
    assert match.matching_rules[0][0]["name"] == "default"
    assert len(match.matching_rules[0][1]) == 0
Ejemplo n.º 16
0
def test_get_pull_request_rule():
    g_pull = mock.Mock()
    g_pull.assignees = []
    g_pull.labels = []
    g_pull.get_review_requests.return_value = ([], [])
    g_pull.author = "jd"
    g_pull.base.ref = "master"
    g_pull.head.ref = "myfeature"
    g_pull.base.repo.get_collaborator_permission.return_value = "write"
    g_pull._rawData = {'locked': False}
    g_pull.title = "My awesome job"
    g_pull.body = "I rock"
    file1 = mock.Mock()
    file1.filename = "README.rst"
    file2 = mock.Mock()
    file2.filename = "setup.py"
    g_pull.get_files.return_value = [file1, file2]

    review = mock.Mock()
    review.user.login = "******"
    review.state = "APPROVED"
    review._rawData = {"author_association": "MEMBER"}
    g_pull.get_reviews.return_value = [review]

    pull_request = mergify_pull.MergifyPull(g_pull=g_pull,
                                            installation_id=123)
    fake_ci = mock.Mock()
    fake_ci.context = "continuous-integration/fake-ci"
    fake_ci.state = "success"
    pull_request._get_checks = mock.Mock()
    pull_request._get_checks.return_value = [fake_ci]

    # Empty conditions
    pull_request_rules = rules.PullRequestRules([{
        "name": "default",
        "conditions": [],
        "actions": {}
    }])

    match = pull_request_rules.get_pull_request_rule(pull_request)
    assert [r['name'] for r in match.rules] == ["default"]
    assert [r['name'] for r, _ in match.matching_rules] == ["default"]
    assert [(r, []) for r in match.rules] == match.matching_rules
    for rule in match.rules:
        assert rule['actions'] == {}

    pull_request_rules = rules.PullRequestRules([{
        "name": "hello",
        "conditions": [
            "base:master",
        ],
        "actions": {}
    }])

    match = pull_request_rules.get_pull_request_rule(pull_request)
    assert [r['name'] for r in match.rules] == ["hello"]
    assert [r['name'] for r, _ in match.matching_rules] == ["hello"]
    assert [(r, []) for r in match.rules] == match.matching_rules
    for rule in match.rules:
        assert rule['actions'] == {}

    pull_request_rules = rules.PullRequestRules([{
        "name": "hello",
        "conditions": [
            "base:master",
        ],
        "actions": {}
    }, {
        "name": "backport",
        "conditions": [
            "base:master",
        ],
        "actions": {}
    }])

    match = pull_request_rules.get_pull_request_rule(pull_request)
    assert [r['name'] for r in match.rules] == ["hello", "backport"]
    assert [r['name'] for r, _ in match.matching_rules] == ["hello",
                                                            "backport"]
    assert [(r, []) for r in match.rules] == match.matching_rules
    for rule in match.rules:
        assert rule['actions'] == {}

    pull_request_rules = rules.PullRequestRules([{
        "name": "hello",
        "conditions": [
            "#files=3",
        ],
        "actions": {}
    }, {
        "name": "backport",
        "conditions": [
            "base:master",
        ],
        "actions": {}
    }])

    match = pull_request_rules.get_pull_request_rule(pull_request)
    assert [r['name'] for r in match.rules] == ["hello", "backport"]
    assert [r['name'] for r, _ in match.matching_rules] == ["backport"]
    for rule in match.rules:
        assert rule['actions'] == {}

    pull_request_rules = rules.PullRequestRules([{
        "name": "hello",
        "conditions": [
            "#files=2",
        ],
        "actions": {}
    }, {
        "name": "backport",
        "conditions": [
            "base:master",
        ],
        "actions": {}
    }])

    match = pull_request_rules.get_pull_request_rule(pull_request)
    assert [r['name'] for r in match.rules] == ["hello", "backport"]
    assert [r['name'] for r, _ in match.matching_rules] == ["hello",
                                                            "backport"]
    assert [(r, []) for r in match.rules] == match.matching_rules
    for rule in match.rules:
        assert rule['actions'] == {}

    # No match
    pull_request_rules = rules.PullRequestRules([{
        "name": "merge",
        "conditions": [
            "base=xyz",
            "status-success=continuous-integration/fake-ci",
            "#approved-reviews-by>=1",
        ],
        "actions": {}
    }])

    match = pull_request_rules.get_pull_request_rule(pull_request)
    assert [r['name'] for r in match.rules] == ["merge"]
    assert [r['name'] for r, _ in match.matching_rules] == []

    pull_request_rules = rules.PullRequestRules([{
        "name": "merge",
        "conditions": [
            "base=master",
            "status-success=continuous-integration/fake-ci",
            "#approved-reviews-by>=1",
        ],
        "actions": {}
    }])

    match = pull_request_rules.get_pull_request_rule(pull_request)
    assert [r['name'] for r in match.rules] == ["merge"]
    assert [r['name'] for r, _ in match.matching_rules] == ["merge"]
    assert [(r, []) for r in match.rules] == match.matching_rules
    for rule in match.rules:
        assert rule['actions'] == {}

    pull_request_rules = rules.PullRequestRules([{
        "name": "merge",
        "conditions": [
            "base=master",
            "status-success=continuous-integration/fake-ci",
            "#approved-reviews-by>=2",
        ],
        "actions": {}
    }, {
        "name": "fast merge",
        "conditions": [
            "base=master",
            "label=fast-track",
            "status-success=continuous-integration/fake-ci",
            "#approved-reviews-by>=1",
        ],
        "actions": {}
    }, {
        "name": "fast merge with alternate ci",
        "conditions": [
            "base=master",
            "label=fast-track",
            "status-success=continuous-integration/fake-ci-bis",
            "#approved-reviews-by>=1",
        ],
        "actions": {}
    }, {
        "name": "fast merge from a bot",
        "conditions": [
            "base=master",
            "author=mybot",
            "status-success=continuous-integration/fake-ci",
        ],
        "actions": {}
    }])
    match = pull_request_rules.get_pull_request_rule(pull_request)

    assert [r['name'] for r in match.rules] == [
        "merge", "fast merge", "fast merge with alternate ci",
        "fast merge from a bot"]
    assert [r['name'] for r, _ in match.matching_rules] == [
        "merge", "fast merge", "fast merge with alternate ci"]
    for rule in match.rules:
        assert rule['actions'] == {}

    assert match.matching_rules[0][0]['name'] == "merge"
    assert len(match.matching_rules[0][1]) == 1
    assert str(match.matching_rules[0][1][0]) == "#approved-reviews-by>=2"

    assert match.matching_rules[1][0]['name'] == "fast merge"
    assert len(match.matching_rules[1][1]) == 1
    assert str(match.matching_rules[1][1][0]) == "label=fast-track"

    assert match.matching_rules[2][0]['name'] == "fast merge with alternate ci"
    assert len(match.matching_rules[2][1]) == 2
    assert str(match.matching_rules[2][1][0]) == "label=fast-track"
    assert (
        str(match.matching_rules[2][1][1]) ==
        "status-success=continuous-integration/fake-ci-bis"
    )
Ejemplo n.º 17
0
def report(url):
    redis = utils.get_redis_for_cache()
    path = url.replace("https://github.com/", "")
    owner, repo, _, pull_number = path.split("/")

    integration = github.GithubIntegration(config.INTEGRATION_ID,
                                           config.PRIVATE_KEY)
    install_id = utils.get_installation_id(integration, owner, repo=repo)

    print("* INSTALLATION ID: %s" % install_id)

    cached_sub = sub_utils.get_subscription(redis, install_id)
    db_sub = sub_utils._retrieve_subscription_from_db(install_id)
    print("* SUBSCRIBED (cache/db): %s / %s" %
          (cached_sub["subscription_active"], db_sub["subscription_active"]))
    print("* SUB DETAIL: %s" % db_sub["subscription_reason"])

    print("* NUMBER OF CACHED TOKENS: %d" % len(cached_sub["tokens"]))

    try:
        for login, token in cached_sub["tokens"].items():
            try:
                repos = get_repositories_setuped(token, install_id)
            except github.BadCredentialsException:
                print("** token for %s invalid" % login)
            except github.GithubException as e:
                if e.status != 401:
                    raise
                print("** token for %s invalid" % login)
            else:
                if any((r["full_name"] == owner + "/" + repo) for r in repos):
                    print("* MERGIFY INSTALLED AND ENABLED ON THIS REPOSITORY")
                else:
                    print("* MERGIFY INSTALLED BUT DISABLED "
                          "ON THIS REPOSITORY")
                break
        else:
            print("* MERGIFY DOESN'T HAVE ANY VALID OAUTH TOKENS")
    except github.UnknownObjectException:
        print("* MERGIFY SEEMS NOT INSTALLED")

    installation_token = integration.get_access_token(install_id).token

    g = github.Github(installation_token,
                      base_url="https://api.%s" % config.GITHUB_DOMAIN)
    r = g.get_repo(owner + "/" + repo)
    print("* REPOSITORY IS %s" % "PRIVATE" if r.private else "PUBLIC")

    print("* CONFIGURATION:")
    try:
        mergify_config_content = rules.get_mergify_config_content(r)
    except rules.NoRules:  # pragma: no cover
        print(".mergify.yml is missing")

    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:
        pull_request_rules_raw = mergify_config["pull_request_rules"].as_dict()
        pull_request_rules_raw["rules"].extend(
            actions_runner.MERGIFY_RULE["rules"])
        pull_request_rules = rules.PullRequestRules(**pull_request_rules_raw)

    try:
        p = r.get_pull(int(pull_number))
    except github.UnknownObjectException:
        print("Wrong pull request number")
        return g, None

    mp = mergify_pull.MergifyPull(g, p, install_id)
    print("* PULL REQUEST:")
    pprint.pprint(mp.to_dict(), width=160)
    try:
        print("is_behind: %s" % mp.is_behind())
    except github.GithubException as e:
        print("Unable to know if pull request branch is behind: %s" % e)

    print("mergeable_state: %s" % mp.g_pull.mergeable_state)

    print("* MERGIFY LAST CHECKS:")
    checks = list(check_api.get_checks(p))
    for c in checks:
        if c._rawData["app"]["id"] == config.INTEGRATION_ID:
            print("[%s]: %s | %s" %
                  (c.name, c.conclusion, c.output.get("title")))
            print("> " + "\n> ".join(c.output.get("summary").split("\n")))

    print("* MERGIFY LIVE MATCHES:")
    match = pull_request_rules.get_pull_request_rule(mp)
    summary_title, summary = actions_runner.gen_summary(
        "refresh", {}, mp, match)
    print("> %s" % summary_title)
    print(summary)

    return g, p
Ejemplo n.º 18
0
def test_convert_rebase_fallback():
    old_rules = {
        'rules': {
            'default': {
                'protection': {
                    'required_pull_request_reviews': {
                        'required_approving_review_count': 2
                    },
                    'required_status_checks': {
                        'contexts': ['continuous-integration/travis-ci'],
                        'strict': True
                    }
                },
                'merge_strategy': {
                    'method': 'rebase',
                    'rebase_fallback': "none",
                }
            },
            'branches': {
                '^stable/.*': {
                    'merge_strategy': {
                        'method': 'rebase',
                        'rebase_fallback': "merge",
                    },
                },
                '^unstable/.*': {
                    'merge_strategy': {
                        'method': 'rebase',
                        'rebase_fallback': "none",
                    },
                },
            },
        },
    }
    converted = convert.convert_config(old_rules["rules"])
    assert converted == [
        {
            "name":
            "default",
            "conditions": [
                "-base~=^stable/.*", "-base~=^unstable/.*",
                "label!=no-mergify", "#approved-reviews-by>=2",
                "status-success=continuous-integration/travis-ci"
            ],
            "actions": {
                "merge": {
                    "method": "rebase",
                    "rebase_fallback": None,
                    "strict": True,
                },
            },
        },
        {
            "name":
            "^stable/.* branch",
            "conditions": [
                "base~=^stable/.*", "label!=no-mergify",
                "#approved-reviews-by>=2",
                "status-success=continuous-integration/travis-ci"
            ],
            "actions": {
                "merge": {
                    "method": "rebase",
                    "rebase_fallback": "merge",
                    "strict": True,
                },
            },
        },
        {
            "name":
            "^unstable/.* branch",
            "conditions": [
                "base~=^unstable/.*", "label!=no-mergify",
                "#approved-reviews-by>=2",
                "status-success=continuous-integration/travis-ci"
            ],
            "actions": {
                "merge": {
                    "method": "rebase",
                    "rebase_fallback": None,
                    "strict": True,
                },
            },
        },
    ]
    # Validate generated conf with the schema
    rules.PullRequestRules(converted)