def test_train_batch_split(repository: context.Repository) -> None: now = datetime.datetime.utcnow() t = merge_train.Train(repository, github_types.GitHubRefType("main")) p1_two = merge_train.EmbarkedPull( t, github_types.GitHubPullRequestNumber(1), get_config("2x1"), now ) p2_two = merge_train.EmbarkedPull( t, github_types.GitHubPullRequestNumber(2), get_config("2x1"), now ) p3_two = merge_train.EmbarkedPull( t, github_types.GitHubPullRequestNumber(3), get_config("2x1"), now ) p4_five = merge_train.EmbarkedPull( t, github_types.GitHubPullRequestNumber(4), get_config("5x1"), now ) assert ([p1_two], [p2_two, p3_two, p4_five]) == t._get_next_batch( [p1_two, p2_two, p3_two, p4_five], "2x1", 1 ) assert ([p1_two, p2_two], [p3_two, p4_five]) == t._get_next_batch( [p1_two, p2_two, p3_two, p4_five], "2x1", 2 ) assert ([p1_two, p2_two, p3_two], [p4_five]) == t._get_next_batch( [p1_two, p2_two, p3_two, p4_five], "2x1", 10 ) assert ([], [p1_two, p2_two, p3_two, p4_five]) == t._get_next_batch( [p1_two, p2_two, p3_two, p4_five], "5x1", 10 )
async def test_merge_commit_message( body: str, title: str, message: str, template: typing.Optional[str], context_getter: conftest.ContextGetterFixture, ) -> None: ctxt = await context_getter(github_types.GitHubPullRequestNumber(43), body=body, title="My PR title") ctxt.repository._caches.branch_protections[github_types.GitHubRefType( "main")] = None ctxt._caches.pull_statuses.set([ github_types.GitHubStatus({ "target_url": "http://example.com", "context": "my CI", "state": "success", "description": "foobar", "avatar_url": "", }) ]) ctxt._caches.pull_check_runs.set([]) assert await ctxt.pull_request.get_commit_message(template=template) == ( title, message, )
def test_embarked_pull_old_serialization() -> None: queue_config = rules.QueueConfig( priority=0, speculative_checks=5, batch_size=1, batch_max_wait_time=datetime.timedelta(seconds=0), allow_inplace_checks=True, disallow_checks_interruption_from_queues=[], checks_timeout=None, draft_bot_account=None, ) config = queue.PullQueueConfig( name=rules.QueueName("foo"), strict_method="merge", update_method="merge", priority=0, effective_priority=0, bot_account=None, update_bot_account=None, queue_config=queue_config, ) now = date.utcnow() old_typed = merge_train.EmbarkedPull.OldSerialized( github_types.GitHubPullRequestNumber(1234), config, now ) old_untyped = json.loads(json.dumps(old_typed)) ep = merge_train.EmbarkedPull.deserialize(mock.Mock(), old_untyped) assert ep.user_pull_request_number == 1234 assert ep.config == config assert ep.queued_at == now
async def fake_train_car_create_pull( inner_self: merge_train.TrainCar, queue_rule: rules.QueueRule ) -> None: inner_self.creation_state = "created" inner_self.queue_pull_request_number = github_types.GitHubPullRequestNumber( inner_self.still_queued_embarked_pulls[-1].user_pull_request_number + 10 )
async def simulator_pull( body: SimulatorPayload, # noqa: B008 repository_ctxt: context.Repository = fastapi.Depends( # noqa: B008 security.get_repository_context ), number: int = fastapi.Path( # noqa: B008 ..., description="The pull request number" ), ) -> SimulatorResponse: config = body.get_config() try: ctxt = await repository_ctxt.get_pull_request_context( github_types.GitHubPullRequestNumber(number) ) except http.HTTPClientSideError as e: raise fastapi.HTTPException(status_code=e.status_code, detail=e.message) ctxt.sources = [{"event_type": "mergify-simulator", "data": [], "timestamp": ""}] # type: ignore[typeddict-item] match = await config["pull_request_rules"].get_pull_request_rule(ctxt) title, summary = await actions_runner.gen_summary( ctxt, config["pull_request_rules"], match ) return SimulatorResponse( title=title, summary=summary, )
async def test_pull_behind( commits_tree_generator: typing.Any, context_getter: conftest.ContextGetterFixture) -> None: expected, commits = commits_tree_generator async def get_commits(*args: typing.Any, **kwargs: typing.Any) -> typing.Any: # /pulls/X/commits for c in commits: yield c async def item(*args: typing.Any, **kwargs: typing.Any) -> typing.Any: # /branch/#foo return {"commit": {"sha": "base"}} async def get_compare(*args: typing.Any, **kwargs: typing.Any) -> typing.Any: return github_types.GitHubCompareCommits( {"behind_by": 0 if expected else 100}) client = mock.Mock() client.items.return_value = get_commits() client.item.side_effect = [item(), get_compare()] ctxt = await context_getter(github_types.GitHubPullRequestNumber(1)) ctxt.repository.installation.client = client assert expected == await ctxt.is_behind
async def test_signals(context_getter: conftest.ContextGetterFixture) -> None: signals.setup() assert len(signals.SIGNALS) == 3 ctxt = await context_getter(github_types.GitHubPullRequestNumber(1)) with mock.patch( "mergify_engine.signals.NoopSignal.__call__") as signal_method: await signals.send( ctxt.repository, ctxt.pull["number"], "action.label", signals.EventLabelMetadata({ "added": [], "removed": ["bar"] }), ) signal_method.assert_called_once_with( ctxt.repository, ctxt.pull["number"], "action.label", { "added": [], "removed": ["bar"] }, )
async def test_team_permissions_missing( context_getter: conftest.ContextGetterFixture, ) -> None: action = request_reviews.RequestReviewsAction.get_schema()({ "random_count": 2, "teams": { "foobar": 2, "@other/foobaz": 1, }, "users": { "jd": 2, "sileht": 1, }, }, ) client = mock.MagicMock() client.get = mock.AsyncMock(side_effect=http.HTTPNotFound( message="not found", response=mock.ANY, request=mock.ANY)) ctxt = await context_getter(github_types.GitHubPullRequestNumber(1)) ctxt.repository.installation.client = client result = await action.run(ctxt, None) assert result.conclusion == check_api.Conclusion.FAILURE assert result.title == "Invalid requested teams" for error in ( "Team `foobar` does not exist or has not access to this repository", "Team `@other/foobaz` is not part of the organization `Mergifyio`", ): assert error in result.summary
async def get_pulls(self) -> typing.List[github_types.GitHubPullRequestNumber]: return [ github_types.GitHubPullRequestNumber(int(pull)) for pull in await self.repository.installation.redis.zrangebyscore( self._redis_queue_key, "-inf", "+inf" ) ]
async def test_get_already_merged_summary( merged_by: str, raw_config: str, result: str, context_getter: conftest.ContextGetterFixture, ) -> None: ctxt = await context_getter( github_types.GitHubPullRequestNumber(1), merged=True, merged_by=github_types.GitHubAccount({ "id": github_types.GitHubAccountIdType(1), "login": github_types.GitHubLogin(merged_by), "type": "User", "avatar_url": "", }), ) ctxt.repository._caches.branch_protections[github_types.GitHubRefType( "main")] = None file = context.MergifyConfigFile( type="file", content="whatever", sha=github_types.SHAType("azertyuiop"), path="whatever", decoded_content=raw_config, ) config = rules.get_mergify_config(file) match = await config["pull_request_rules"].get_pull_request_rule(ctxt) assert result == await actions_runner.get_already_merged_summary( ctxt, match)
def _url_parser( url: str, ) -> typing.Tuple[github_types.GitHubLogin, typing.Optional[github_types.GitHubRepositoryName], typing.Optional[github_types.GitHubPullRequestNumber], ]: path = [ el for el in urllib.parse.urlparse(url).path.split("/") if el != "" ] pull_number: typing.Optional[str] repo: typing.Optional[str] try: owner, repo, _, pull_number = path except ValueError: pull_number = None try: owner, repo = path except ValueError: if len(path) == 1: owner = path[0] repo = None else: raise ValueError return ( github_types.GitHubLogin(owner), None if repo is None else github_types.GitHubRepositoryName(repo), None if pull_number is None else github_types.GitHubPullRequestNumber( int(pull_number)), )
async def test_get_commits_to_cherry_pick_merge( commits: mock.PropertyMock, context_getter: conftest.ContextGetterFixture, ) -> None: c1 = github_types.CachedGitHubBranchCommit({ "sha": github_types.SHAType("c1f"), "parents": [], "commit_message": "foobar", "commit_verification_verified": False, }) c2 = github_types.CachedGitHubBranchCommit({ "sha": github_types.SHAType("c2"), "parents": [c1["sha"]], "commit_message": "foobar", "commit_verification_verified": False, }) async def fake_commits( ) -> typing.List[github_types.CachedGitHubBranchCommit]: return [c1, c2] commits.return_value = fake_commits() client = mock.Mock() client.auth.get_access_token.return_value = "<token>" ctxt = await context_getter(github_types.GitHubPullRequestNumber(1)) ctxt.repository.installation.client = client base_branch = github_types.CachedGitHubBranchCommit({ "sha": github_types.SHAType("base_branch"), "parents": [], "commit_message": "foobar", "commit_verification_verified": False, }) merge_commit = github_types.CachedGitHubBranchCommit({ "sha": github_types.SHAType("merge_commit"), "parents": [base_branch["sha"], c2["sha"]], "commit_message": "foobar", "commit_verification_verified": False, }) assert await duplicate_pull._get_commits_to_cherrypick(ctxt, merge_commit) == [ c1, c2, ]
async def test_merge_commit_message_undefined( body: str, context_getter: conftest.ContextGetterFixture) -> None: ctxt = await context_getter(github_types.GitHubPullRequestNumber(43), body=body, title="My PR title") with pytest.raises(context.RenderTemplateFailure) as x: await ctxt.pull_request.get_commit_message() assert str(x) == "foobar"
async def test_signals(context_getter: conftest.ContextGetterFixture) -> None: signals.setup() assert len(signals.SIGNALS) == 3 ctxt = await context_getter(github_types.GitHubPullRequestNumber(1)) with mock.patch( "mergify_engine_signals.noop.Signal.__call__") as signal_method: await signals.send(ctxt, "action.update", {"attr": "value"}) signal_method.assert_called_once_with(ctxt, "action.update", {"attr": "value"})
async def get_pull_request_head_sha_to_number_mapping( redis_cache: utils.RedisCache, owner_id: github_types.GitHubAccountIdType, repo_id: github_types.GitHubRepositoryIdType, sha: github_types.SHAType, ) -> typing.Optional[github_types.GitHubPullRequestNumber]: ret = await redis_cache.get( context.Context.redis_last_summary_pulls_key(owner_id, repo_id, sha), ) if ret is None: return None return github_types.GitHubPullRequestNumber(int(ret))
async def test_run_command_without_rerun_and_without_user( context_getter: conftest.ContextGetterFixture, ) -> None: ctxt = await context_getter(github_types.GitHubPullRequestNumber(1)) with pytest.raises(RuntimeError) as error_msg: await commands_runner.handle( ctxt=ctxt, mergify_config=EMPTY_CONFIG, comment="@Mergifyio update", user=None, ) assert "user must be set if rerun is false" in str(error_msg.value)
async def send( redis_stream: utils.RedisStream, redis_cache: utils.RedisCache, ) -> None: score = date.utcnow().timestamp() keys = await redis_cache.zrangebyscore(DELAYED_REFRESH_KEY, "-inf", score) if not keys: return pipe = await redis_stream.pipeline() keys_to_delete = set() for subkey in keys: ( owner_id_str, owner_login, repository_id_str, repository_name, pull_request_number_str, ) = subkey.split("~") owner_id = github_types.GitHubAccountIdType(int(owner_id_str)) repository_id = github_types.GitHubRepositoryIdType( int(repository_id_str)) pull_request_number = github_types.GitHubPullRequestNumber( int(pull_request_number_str)) LOG.info( "sending delayed pull request refresh", gh_owner=owner_login, gh_repo=repository_name, action="internal", source="delayed-refresh", ) await worker.push( pipe, owner_id, owner_login, repository_id, repository_name, pull_request_number, "refresh", { "action": "internal", "ref": None, "source": "delayed-refresh", }, # type: ignore[typeddict-item] ) keys_to_delete.add(subkey) await pipe.execute() await redis_cache.zrem(DELAYED_REFRESH_KEY, *keys_to_delete)
def make_pr( repo: github_types.GitHubRepository, owner: github_types.GitHubAccount ) -> github_types.GitHubPullRequest: return github_types.GitHubPullRequest({ "id": github_types.GitHubPullRequestId(github_types.GitHubIssueId(0)), "maintainer_can_modify": False, "head": { "user": owner, "label": "", "ref": github_types.GitHubRefType(""), "sha": github_types.SHAType(""), "repo": repo, }, "user": owner, "number": github_types.GitHubPullRequestNumber( github_types.GitHubIssueNumber(0)), "rebaseable": False, "draft": False, "merge_commit_sha": None, "html_url": "", "state": "closed", "mergeable_state": "unknown", "merged_by": None, "merged": False, "merged_at": None, "labels": [], "base": { "ref": github_types.GitHubRefType("main"), "sha": github_types.SHAType(""), "label": "", "repo": repo, "user": owner, }, })
async def test_run_command_with_user( user_id: int, permission: str, comment: str, result: typing.Optional[str], context_getter: conftest.ContextGetterFixture, ) -> None: user = github_types.GitHubAccount( { "id": github_types.GitHubAccountIdType(user_id), "login": github_types.GitHubLogin("wall-e"), "type": "Bot", "avatar_url": "https://avatars.githubusercontent.com/u/583231?v=4", }, ) client = mock.Mock() client.item = mock.AsyncMock() client.item.return_value = { "permission": permission, "user": user, } client.post = mock.AsyncMock() ctxt = await context_getter(github_types.GitHubPullRequestNumber(1)) ctxt.repository.installation.client = client await commands_runner.handle( ctxt=ctxt, mergify_config=EMPTY_CONFIG, comment="unrelated", user=None, rerun=True, ) assert len(client.post.call_args_list) == 0 await commands_runner.handle( ctxt=ctxt, mergify_config=EMPTY_CONFIG, comment=comment, user=user, ) if result is None: assert len(client.post.call_args_list) == 0 else: assert len(client.post.call_args_list) == 1 assert result in client.post.call_args_list[0][1]["json"]["body"]
async def _get_github_pulls_from_sha( installation: context.Installation, repo_name: github_types.GitHubRepositoryName, sha: github_types.SHAType, pulls: typing.List[github_types.GitHubPullRequest], ) -> typing.List[github_types.GitHubPullRequestNumber]: cache_key = f"sha~{installation.owner_login}~{repo_name}~{sha}" pull_number = await installation.redis.get(cache_key) if pull_number is None: for pull in pulls: if pull["head"]["sha"] == sha: await installation.redis.set(cache_key, pull["number"], ex=SHA_EXPIRATION) return [pull["number"]] return [] else: return [github_types.GitHubPullRequestNumber(int(pull_number))]
async def test_datadog(context_getter: conftest.ContextGetterFixture) -> None: signals.setup() assert len(signals.SIGNALS) == 3 ctxt = await context_getter(github_types.GitHubPullRequestNumber(1)) with mock.patch("datadog.statsd.increment") as increment: await signals.send( ctxt.repository, ctxt.pull["number"], "action.label", { "added": [], "removed": ["bar"] }, ) increment.assert_called_once_with("engine.signals.action.count", tags=["event:label"])
async def test_run_command_with_rerun_and_without_user( context_getter: conftest.ContextGetterFixture, ) -> None: client = mock.Mock() client.post = mock.AsyncMock() ctxt = await context_getter(github_types.GitHubPullRequestNumber(1)) ctxt.repository.installation.client = client await commands_runner.handle( ctxt=ctxt, mergify_config=EMPTY_CONFIG, comment="@mergifyio something", user=None, rerun=True, ) assert len(client.post.call_args_list) == 1 assert ("Sorry but I didn't understand the command." in client.post.call_args_list[0][1]["json"]["body"])
async def test_get_rule_checks_status( conditions: typing.Any, conclusion: check_api.Conclusion, context_getter: conftest.ContextGetterFixture, fake_client: mock.Mock, ) -> None: ctxt = await context_getter(github_types.GitHubPullRequestNumber(1)) ctxt.repository.installation.client = fake_client rules = pull_request_rule_from_list([{ "name": "hello", "conditions": conditions, "actions": {}, }]) match = await rules.get_pull_request_rule(ctxt) evaluated_rule = match.matching_rules[0] assert (await checks_status.get_rule_checks_status(ctxt.log, ctxt.repository, [ctxt.pull_request], evaluated_rule)) == conclusion
async def test_disabled(context_getter: conftest.ContextGetterFixture) -> None: action = request_reviews.RequestReviewsAction.get_schema()({ "random_count": 2, "teams": { "foobar": 2, "foobaz": 1, }, "users": { "jd": 2, "sileht": 1, }, }, ) ctxt = await context_getter(github_types.GitHubPullRequestNumber(1)) result = await action.run(ctxt, None) assert result.conclusion == check_api.Conclusion.ACTION_REQUIRED assert result.title == "Random request reviews are disabled" assert result.summary == ( "⚠ The [subscription](https://dashboard.mergify.com/github/Mergifyio/subscription) " "needs to be updated to enable this feature.")
async def test_run_command_with_wrong_arg( context_getter: conftest.ContextGetterFixture, ) -> None: client = mock.Mock() client.post = mock.AsyncMock() ctxt = await context_getter(github_types.GitHubPullRequestNumber(1)) ctxt.repository.installation.client = client await commands_runner.handle( ctxt=ctxt, mergify_config=EMPTY_CONFIG, comment="@mergifyio squash invalid-arg", rerun=True, user=None, ) assert len(client.post.call_args_list) == 1 assert client.post.call_args_list[0][1]["json"]["body"].startswith( "Sorry but I didn't understand the arguments of the command `squash`")
async def test_team_permissions_ok( context_getter: conftest.ContextGetterFixture, ) -> None: action = request_reviews.RequestReviewsAction.get_schema()({ "random_count": 2, "teams": { "foobar": 2, "foobaz": 1, }, "users": { "jd": 2, "sileht": 1, }, }, ) client = mock.MagicMock() client.get = mock.AsyncMock(return_value={}) ctxt = await context_getter(github_types.GitHubPullRequestNumber(1)) ctxt.repository.installation.client = client result = await action.run(ctxt, None) assert result.summary == "" assert result.title == "No new reviewers to request" assert result.conclusion == check_api.Conclusion.SUCCESS
async def test_train_batch_max_wait_time( repository: context.Repository, context_getter: conftest.ContextGetterFixture ) -> None: with freeze_time("2021-09-22T08:00:00") as freezed_time: t = merge_train.Train(repository, github_types.GitHubRefType("main")) await t.load() config = get_config("batch-wait-time") await t.add_pull(await context_getter(1), config) await t.refresh() assert [] == get_cars_content(t) assert [1] == get_waiting_content(t) # Enought PR to batch! await t.add_pull(await context_getter(2), config) await t.refresh() assert [[1, 2]] == get_cars_content(t) assert [] == get_waiting_content(t) await t.add_pull(await context_getter(3), config) await t.refresh() assert [[1, 2]] == get_cars_content(t) assert [3] == get_waiting_content(t) d = await delayed_refresh._get_current_refresh_datetime( repository, github_types.GitHubPullRequestNumber(3) ) assert d is not None assert d == freezed_time().replace( tzinfo=datetime.timezone.utc ) + datetime.timedelta(minutes=5) with freeze_time("2021-09-22T08:05:02"): await t.refresh() assert [[1, 2], [1, 2, 3]] == get_cars_content(t) assert [] == get_waiting_content(t)
async def report( url: str, ) -> typing.Union[context.Context, github.AsyncGithubInstallationClient, None]: redis_links = redis_utils.RedisLinks(max_idle_time=0) try: owner_login, repo, pull_number = _url_parser(url) except ValueError: print(f"{url} is not valid") return None try: installation_json = await github.get_installation_from_login( owner_login) client = github.aget_client(installation_json) except exceptions.MergifyNotInstalled: print(f"* Mergify is not installed on account {owner_login}") return None # Do a dumb request just to authenticate await client.get("/") print(f"* INSTALLATION ID: {installation_json['id']}") if repo is None: slug = None else: slug = owner_login + "/" + repo owner_id = installation_json["account"]["id"] cached_sub = await subscription.Subscription.get_subscription( redis_links.cache, owner_id) db_sub = await subscription.Subscription._retrieve_subscription_from_db( redis_links.cache, owner_id) cached_tokens = await user_tokens.UserTokens.get(redis_links.cache, owner_id) if config.SAAS_MODE: db_tokens = typing.cast( user_tokens.UserTokens, (await user_tokens.UserTokensSaas._retrieve_from_db( redis_links.cache, owner_id)), ) else: db_tokens = cached_tokens print("* Features (db):") for v in sorted(f.value for f in db_sub.features): print(f" - {v}") print("* Features (cache):") for v in sorted(f.value for f in cached_sub.features): print(f" - {v}") installation = context.Installation(installation_json, cached_sub, client, redis_links) await report_dashboard_synchro(installation.installation["id"], cached_sub, cached_tokens, "ENGINE-CACHE", slug) await report_dashboard_synchro(installation.installation["id"], db_sub, db_tokens, "DASHBOARD", slug) await report_worker_status(owner_login) if repo is not None: repository = await installation.get_repository_by_name(repo) print( f"* REPOSITORY IS {'PRIVATE' if repository.repo['private'] else 'PUBLIC'}" ) print(f"* DEFAULT BRANCH: {repository.repo['default_branch']}") print("* CONFIGURATION:") mergify_config = None config_file = await repository.get_mergify_config_file() if not config_file: print(".mergify.yml is missing") else: print(f"Config filename: {config_file['path']}") print(config_file["decoded_content"]) try: mergify_config = await repository.get_mergify_config() except rules.InvalidRules as e: # pragma: no cover print(f"configuration is invalid {str(e)}") if pull_number is None: async for branch in typing.cast( typing.AsyncGenerator[github_types.GitHubBranch, None], client.items( f"/repos/{owner_login}/{repo}/branches", resource_name="branches", page_limit=100, ), ): q = merge_train.Train(repository, branch["name"]) await q.load() await report_queue("TRAIN", q) else: repository = await installation.get_repository_by_name( github_types.GitHubRepositoryName(repo)) try: ctxt = await repository.get_pull_request_context( github_types.GitHubPullRequestNumber(int(pull_number))) except http.HTTPNotFound: print(f"Pull request `{url}` does not exist") return client # FIXME queues could also be printed if no pull number given # TODO(sileht): display train if any q = await merge_train.Train.from_context(ctxt) print( f"* TRAIN: {', '.join([f'#{p}' for p in await q.get_pulls()])}" ) print("* PULL REQUEST:") pr_data = await ctxt.pull_request.items() pprint.pprint(pr_data, width=160) is_behind = await ctxt.is_behind print(f"is_behind: {is_behind}") print(f"mergeable_state: {ctxt.pull['mergeable_state']}") print("* MERGIFY LAST CHECKS:") for c in await ctxt.pull_engine_check_runs: print( f"[{c['name']}]: {c['conclusion']} | {c['output'].get('title')} | {c['html_url']}" ) print("> " + "\n> ".join( ("No Summary", ) if c["output"]["summary"] is None else c["output"]["summary"].split("\n"))) if mergify_config is not None: print("* MERGIFY LIVE MATCHES:") pull_request_rules = mergify_config["pull_request_rules"] match = await pull_request_rules.get_pull_request_rule(ctxt) summary_title, summary = await actions_runner.gen_summary( ctxt, pull_request_rules, match) print(f"[Summary]: success | {summary_title}") print("> " + "\n> ".join(summary.strip().split("\n"))) return ctxt return client
async def push_to_worker( redis_links: redis_utils.RedisLinks, event_type: github_types.GitHubEventType, event_id: str, event: github_types.GitHubEvent, score: typing.Optional[str] = None, ) -> None: pull_number = None ignore_reason = None if event_type == "pull_request": event = typing.cast(github_types.GitHubEventPullRequest, event) owner_login = event["repository"]["owner"]["login"] owner_id = event["repository"]["owner"]["id"] repo_id = event["repository"]["id"] repo_name = event["repository"]["name"] pull_number = event["pull_request"]["number"] if event["repository"]["archived"]: ignore_reason = "repository archived" elif event["action"] in ("opened", "synchronize"): try: await engine.create_initial_summary(redis_links.cache, event) except Exception as e: _log_on_exception(e, "fail to create initial summary") elif ( event["action"] == "edited" and event["sender"]["id"] == config.BOT_USER_ID and event["pull_request"]["head"]["ref"].startswith( constants.MERGE_QUEUE_BRANCH_PREFIX ) ): ignore_reason = "mergify merge-queue description update" elif event_type == "refresh": event = typing.cast(github_types.GitHubEventRefresh, event) owner_login = event["repository"]["owner"]["login"] owner_id = event["repository"]["owner"]["id"] repo_id = event["repository"]["id"] repo_name = event["repository"]["name"] if event["pull_request_number"] is not None: pull_number = event["pull_request_number"] elif event_type == "pull_request_review_comment": event = typing.cast(github_types.GitHubEventPullRequestReviewComment, event) owner_login = event["repository"]["owner"]["login"] owner_id = event["repository"]["owner"]["id"] repo_id = event["repository"]["id"] repo_name = event["repository"]["name"] if event["pull_request"] is not None: pull_number = event["pull_request"]["number"] if event["repository"]["archived"]: ignore_reason = "repository archived" elif event_type == "pull_request_review": event = typing.cast(github_types.GitHubEventPullRequestReview, event) owner_login = event["repository"]["owner"]["login"] owner_id = event["repository"]["owner"]["id"] repo_id = event["repository"]["id"] repo_name = event["repository"]["name"] pull_number = event["pull_request"]["number"] elif event_type == "issue_comment": event = typing.cast(github_types.GitHubEventIssueComment, event) owner_login = event["repository"]["owner"]["login"] owner_id = event["repository"]["owner"]["id"] repo_id = event["repository"]["id"] repo_name = event["repository"]["name"] pull_number = github_types.GitHubPullRequestNumber(event["issue"]["number"]) if event["repository"]["archived"]: ignore_reason = "repository archived" elif "pull_request" not in event["issue"]: ignore_reason = "comment is not on a pull request" elif event["action"] != "created": ignore_reason = f"comment has been {event['action']}" elif event["comment"]["user"]["id"] == config.BOT_USER_ID: ignore_reason = "comment by Mergify[bot]" else: # NOTE(sileht): nothing important should happen in this hook as we don't retry it try: await commands_runner.on_each_event(event) except Exception as e: _log_on_exception(e, "commands_runner.on_each_event failed") elif event_type == "status": event = typing.cast(github_types.GitHubEventStatus, event) owner_login = event["repository"]["owner"]["login"] owner_id = event["repository"]["owner"]["id"] repo_id = event["repository"]["id"] repo_name = event["repository"]["name"] if event["repository"]["archived"]: ignore_reason = "repository archived" pull_number = await get_pull_request_head_sha_to_number_mapping( redis_links.cache, owner_id, repo_id, event["sha"] ) elif event_type == "push": event = typing.cast(github_types.GitHubEventPush, event) owner_login = event["repository"]["owner"]["login"] owner_id = event["repository"]["owner"]["id"] repo_id = event["repository"]["id"] repo_name = event["repository"]["name"] if event["repository"]["archived"]: ignore_reason = "repository archived" elif not event["ref"].startswith("refs/heads/"): ignore_reason = f"push on {event['ref']}" elif event["repository"]["archived"]: # pragma: no cover ignore_reason = "repository archived" await context.Repository.clear_config_file_cache(redis_links.cache, repo_id) elif event_type == "check_suite": event = typing.cast(github_types.GitHubEventCheckSuite, event) owner_login = event["repository"]["owner"]["login"] owner_id = event["repository"]["owner"]["id"] repo_id = event["repository"]["id"] repo_name = event["repository"]["name"] if event["repository"]["archived"]: ignore_reason = "repository archived" elif event["action"] != "rerequested": ignore_reason = f"check_suite/{event['action']}" elif ( event[event_type]["app"]["id"] == config.INTEGRATION_ID and event["action"] != "rerequested" and event[event_type].get("external_id") != check_api.USER_CREATED_CHECKS ): ignore_reason = f"mergify {event_type}" pull_number = await get_pull_request_head_sha_to_number_mapping( redis_links.cache, owner_id, repo_id, event["check_suite"]["head_sha"] ) elif event_type == "check_run": event = typing.cast(github_types.GitHubEventCheckRun, event) owner_login = event["repository"]["owner"]["login"] owner_id = event["repository"]["owner"]["id"] repo_id = event["repository"]["id"] repo_name = event["repository"]["name"] if event["repository"]["archived"]: ignore_reason = "repository archived" elif ( event[event_type]["app"]["id"] == config.INTEGRATION_ID and event["action"] != "rerequested" and event[event_type].get("external_id") != check_api.USER_CREATED_CHECKS ): ignore_reason = f"mergify {event_type}" pull_number = await get_pull_request_head_sha_to_number_mapping( redis_links.cache, owner_id, repo_id, event["check_run"]["head_sha"] ) elif event_type == "organization": event = typing.cast(github_types.GitHubEventOrganization, event) owner_login = event["organization"]["login"] owner_id = event["organization"]["id"] repo_name = None repo_id = None ignore_reason = "organization event" if event["action"] == "deleted": await context.Installation.clear_team_members_cache_for_org( redis_links.cache, event["organization"] ) await context.Repository.clear_team_permission_cache_for_org( redis_links.cache, event["organization"] ) if event["action"] in ("deleted", "member_added", "member_removed"): await context.Repository.clear_user_permission_cache_for_org( redis_links.cache, event["organization"] ) elif event_type == "member": event = typing.cast(github_types.GitHubEventMember, event) owner_login = event["repository"]["owner"]["login"] owner_id = event["repository"]["owner"]["id"] repo_id = event["repository"]["id"] repo_name = event["repository"]["name"] ignore_reason = "member event" await context.Repository.clear_user_permission_cache_for_user( redis_links.cache, event["repository"]["owner"], event["repository"], event["member"], ) elif event_type == "membership": event = typing.cast(github_types.GitHubEventMembership, event) owner_login = event["organization"]["login"] owner_id = event["organization"]["id"] repo_name = None repo_id = None ignore_reason = "membership event" if "slug" in event["team"]: await context.Installation.clear_team_members_cache_for_team( redis_links.cache, event["organization"], event["team"]["slug"] ) await context.Repository.clear_team_permission_cache_for_team( redis_links.cache, event["organization"], event["team"]["slug"] ) else: # Deleted team await context.Installation.clear_team_members_cache_for_org( redis_links.cache, event["organization"], ) await context.Repository.clear_team_permission_cache_for_org( redis_links.cache, event["organization"] ) await context.Repository.clear_user_permission_cache_for_org( redis_links.cache, event["organization"] ) elif event_type == "team": event = typing.cast(github_types.GitHubEventTeam, event) owner_login = event["organization"]["login"] owner_id = event["organization"]["id"] repo_id = None repo_name = None ignore_reason = "team event" if event["action"] in ("edited", "deleted"): await context.Installation.clear_team_members_cache_for_team( redis_links.cache, event["organization"], event["team"]["slug"] ) await context.Repository.clear_team_permission_cache_for_team( redis_links.cache, event["organization"], event["team"]["slug"] ) if event["action"] in ( "edited", "added_to_repository", "removed_from_repository", "deleted", ): if "repository" in event: await context.Repository.clear_user_permission_cache_for_repo( redis_links.cache, event["organization"], event["repository"] ) await context.Repository.clear_team_permission_cache_for_repo( redis_links.cache, event["organization"], event["repository"] ) else: await context.Repository.clear_user_permission_cache_for_org( redis_links.cache, event["organization"] ) await context.Repository.clear_team_permission_cache_for_org( redis_links.cache, event["organization"] ) elif event_type == "team_add": event = typing.cast(github_types.GitHubEventTeamAdd, event) owner_login = event["repository"]["owner"]["login"] owner_id = event["repository"]["owner"]["id"] repo_id = event["repository"]["id"] repo_name = event["repository"]["name"] ignore_reason = "team_add event" await context.Repository.clear_user_permission_cache_for_repo( redis_links.cache, event["repository"]["owner"], event["repository"] ) await context.Repository.clear_team_permission_cache_for_repo( redis_links.cache, event["organization"], event["repository"] ) else: owner_login = "******" owner_id = "<unknown>" repo_name = "<unknown>" repo_id = "<unknown>" ignore_reason = "unexpected event_type" if ignore_reason is None: msg_action = "pushed to worker" slim_event = _extract_slim_event(event_type, event) await worker.push( redis_links.stream, owner_id, owner_login, repo_id, repo_name, pull_number, event_type, slim_event, score, ) else: slim_event = None msg_action = f"ignored: {ignore_reason}" LOG.debug( "GithubApp event %s", msg_action, event_type=event_type, event_id=event_id, sender=event["sender"]["login"], gh_owner=owner_login, gh_repo=repo_name, event=slim_event, ) if ignore_reason: raise IgnoredEvent(event_type, event_id, ignore_reason)
async def test_get_commits_to_cherry_pick_rebase( commits: mock.PropertyMock, redis_cache: utils.RedisCache, ) -> None: gh_owner = github_types.GitHubAccount({ "login": github_types.GitHubLogin("user"), "id": github_types.GitHubAccountIdType(0), "type": "User", "avatar_url": "", }) gh_repo = github_types.GitHubRepository({ "full_name": "user/name", "name": github_types.GitHubRepositoryName("name"), "private": False, "id": github_types.GitHubRepositoryIdType(0), "owner": gh_owner, "archived": False, "url": "", "html_url": "", "default_branch": github_types.GitHubRefType("ref"), }) c1 = github_types.GitHubBranchCommit({ "sha": github_types.SHAType("c1f"), "parents": [], "commit": { "message": "foobar" }, }) c2 = github_types.GitHubBranchCommit({ "sha": github_types.SHAType("c2"), "parents": [c1], "commit": { "message": "foobar" }, }) commits.return_value = [c1, c2] client = mock.Mock() client.auth.get_access_token.return_value = "<token>" client.items.side_effect = fake_get_github_pulls_from_sha installation = context.Installation( github_types.GitHubAccountIdType(123), github_types.GitHubLogin("user"), subscription.Subscription(redis_cache, 0, False, "", frozenset()), client, redis_cache, ) repository = context.Repository(installation, gh_repo) ctxt = await context.Context.create( repository, { "labels": [], "draft": False, "merge_commit_sha": github_types.SHAType(""), "title": "", "commits": 1, "rebaseable": False, "maintainer_can_modify": False, "id": github_types.GitHubPullRequestId(0), "number": github_types.GitHubPullRequestNumber(6), "merged": True, "state": "closed", "html_url": "<html_url>", "changed_files": 1, "base": { "label": "", "sha": github_types.SHAType("sha"), "user": { "login": github_types.GitHubLogin("user"), "id": github_types.GitHubAccountIdType(0), "type": "User", "avatar_url": "", }, "ref": github_types.GitHubRefType("ref"), "repo": { "full_name": "user/ref", "name": github_types.GitHubRepositoryName("name"), "private": False, "id": github_types.GitHubRepositoryIdType(0), "owner": { "login": github_types.GitHubLogin("user"), "id": github_types.GitHubAccountIdType(0), "type": "User", "avatar_url": "", }, "archived": False, "url": "", "html_url": "", "default_branch": github_types.GitHubRefType(""), }, }, "head": { "label": "", "sha": github_types.SHAType("sha"), "ref": github_types.GitHubRefType("fork"), "user": { "login": github_types.GitHubLogin("user"), "id": github_types.GitHubAccountIdType(0), "type": "User", "avatar_url": "", }, "repo": { "full_name": "fork/other", "name": github_types.GitHubRepositoryName("other"), "private": False, "archived": False, "url": "", "html_url": "", "default_branch": github_types.GitHubRefType(""), "id": github_types.GitHubRepositoryIdType(0), "owner": { "login": github_types.GitHubLogin("user"), "id": github_types.GitHubAccountIdType(0), "type": "User", "avatar_url": "", }, }, }, "user": { "login": github_types.GitHubLogin("user"), "id": github_types.GitHubAccountIdType(0), "type": "User", "avatar_url": "", }, "merged_by": None, "merged_at": None, "mergeable_state": "clean", }, ) base_branch = github_types.GitHubBranchCommitParent( {"sha": github_types.SHAType("base_branch")}) rebased_c1 = github_types.GitHubBranchCommit({ "sha": github_types.SHAType("rebased_c1"), "parents": [base_branch], "commit": { "message": "hello c1" }, }) rebased_c2 = github_types.GitHubBranchCommit({ "sha": github_types.SHAType("rebased_c2"), "parents": [rebased_c1], "commit": { "message": "hello c2" }, }) async def fake_get_github_commit_from_sha(url, api_version=None): if url.endswith("/commits/rebased_c1"): return rebased_c1 if url.endswith("/commits/rebased_c2"): return rebased_c2 raise RuntimeError(f"Unknown URL {url}") client.item.side_effect = fake_get_github_commit_from_sha assert await duplicate_pull._get_commits_to_cherrypick(ctxt, rebased_c2) == [ rebased_c1, rebased_c2, ]