diff --git a/marge/app.py b/marge/app.py index 1b6c66ee..5cab7c23 100644 --- a/marge/app.py +++ b/marge/app.py @@ -233,6 +233,12 @@ def regexp(str_regex): action='store_true', help='Skip CI when updating individual MRs when using batches' ) + parser.add_argument( + '--allow-priority-sorting', + action='store_true', + help='If enabled, within the normal merge branch sorting it will look for' + 'priority/p (where "x" is an integer from 1-9) in the labels and re-order based on it.\n' + ) parser.add_argument( '--cli', action='store_true', @@ -270,7 +276,7 @@ def regexp(str_regex): for _, (_, value) in parser._source_to_settings.get(configargparse._COMMAND_LINE_SOURCE_KEY, {}).items(): cli_args.extend(value) for bad_arg in ['--auth-token', '--ssh-key']: - if any(bad_arg in arg for arg in cli_args): + if any(bad_arg == arg for arg in cli_args) or any(arg.startswith(f"{bad_arg}=") for arg in cli_args): raise MargeBotCliArgError('"%s" can only be set via ENV var or config file.' % bad_arg) return config @@ -354,6 +360,7 @@ def main(args=None): use_merge_commit_batches=options.use_merge_commit_batches, skip_ci_batches=options.skip_ci_batches, guarantee_final_pipeline=options.guarantee_final_pipeline, + allow_priority_sorting=options.allow_priority_sorting ), batch=options.batch, cli=options.cli, diff --git a/marge/bot.py b/marge/bot.py index ab6da18e..dca9fae8 100644 --- a/marge/bot.py +++ b/marge/bot.py @@ -119,6 +119,7 @@ def _get_merge_requests(self, project, project_name): user=self.user, api=self._api, merge_order=self._config.merge_order, + prioritise_merges=self._config.merge_opts.allow_priority_sorting ) branch_regexp = self._config.branch_regexp filtered_mrs = [mr for mr in my_merge_requests diff --git a/marge/git.py b/marge/git.py index a46b023e..a21a8124 100644 --- a/marge/git.py +++ b/marge/git.py @@ -15,7 +15,7 @@ # connects. The proper solution would be to pass in known_hosts as # a commandline parameter, but in practice few people will bother anyway and # in this case the threat of MiTM seems somewhat bogus. -GIT_SSH_COMMAND = "ssh -o StrictHostKeyChecking=no " +GIT_SSH_COMMAND = os.environ.get('GIT_SSH_COMMAND', 'ssh') + " -o StrictHostKeyChecking=no " def _filter_branch_script(trailer_name, trailer_values): diff --git a/marge/job.py b/marge/job.py index c93bf556..b0daa9dc 100644 --- a/marge/job.py +++ b/marge/job.py @@ -461,6 +461,7 @@ class Fusion(enum.Enum): 'use_merge_commit_batches', 'skip_ci_batches', 'guarantee_final_pipeline', + 'allow_priority_sorting', ] @@ -477,7 +478,7 @@ def default( add_tested=False, add_part_of=False, add_reviewers=False, reapprove=False, approval_timeout=None, embargo=None, ci_timeout=None, fusion=Fusion.rebase, use_no_ff_batches=False, use_merge_commit_batches=False, skip_ci_batches=False, - guarantee_final_pipeline=False, + guarantee_final_pipeline=False, allow_priority_sorting=False ): approval_timeout = approval_timeout or timedelta(seconds=0) embargo = embargo or IntervalUnion.empty() @@ -495,6 +496,7 @@ def default( use_merge_commit_batches=use_merge_commit_batches, skip_ci_batches=skip_ci_batches, guarantee_final_pipeline=guarantee_final_pipeline, + allow_priority_sorting=allow_priority_sorting ) diff --git a/marge/merge_request.py b/marge/merge_request.py index 030b79b8..6463dc83 100644 --- a/marge/merge_request.py +++ b/marge/merge_request.py @@ -59,7 +59,7 @@ def fetch_assigned_at(cls, user, api, merge_request): return assigned_at @classmethod - def fetch_all_open_for_user(cls, project_id, user, api, merge_order): + def fetch_all_open_for_user(cls, project_id, user, api, merge_order, prioritise_merges): request_merge_order = 'created_at' if merge_order == 'assigned_at' else merge_order all_merge_request_infos = api.collect_all_pages(GET( @@ -75,6 +75,9 @@ def fetch_all_open_for_user(cls, project_id, user, api, merge_order): if merge_order == 'assigned_at': my_merge_request_infos.sort(key=lambda mri: cls.fetch_assigned_at(user, api, mri)) + if prioritise_merges: + my_merge_request_infos.sort(key=lambda mri: next((label for label in mri.get('labels', []) if label.startswith('priority/')), 'priority/9')) + return [cls(api, merge_request_info) for merge_request_info in my_merge_request_infos] @property diff --git a/tests/test_app.py b/tests/test_app.py index 91b087e6..c06d7b4c 100644 --- a/tests/test_app.py +++ b/tests/test_app.py @@ -41,6 +41,19 @@ def config_file(): tmp_config_file.close() +@contextlib.contextmanager +def auth_token_file(): + auth_content = '''ADMIN-TOKEN +''' + with tempfile.NamedTemporaryFile(mode='w', prefix='auth-token-file-') as tmp_auth_token_file: + try: + tmp_auth_token_file.write(auth_content) + tmp_auth_token_file.flush() + yield tmp_auth_token_file.name + finally: + tmp_auth_token_file.close() + + @contextlib.contextmanager def env(**kwargs): original = os.environ.copy() @@ -253,6 +266,13 @@ def test_disabled_auth_token_cli_arg(): pass +def test_auth_token_file_arg(): + with auth_token_file() as auth_file: + with env(MARGE_SSH_KEY="KEY", MARGE_GITLAB_URL='http://foo.com'): + with main('--auth-token-file=%s' % auth_file) as bot: + assert bot.config.auth_token == 'ADMIN-TOKEN' + + def test_disabled_ssh_key_cli_arg(): with env(MARGE_AUTH_TOKEN="NON-ADMIN-TOKEN", MARGE_GITLAB_URL='http://foo.com'): with pytest.raises(app.MargeBotCliArgError): diff --git a/tests/test_job.py b/tests/test_job.py index 22036d10..5345b6d1 100644 --- a/tests/test_job.py +++ b/tests/test_job.py @@ -218,6 +218,7 @@ def test_default(self): use_merge_commit_batches=False, skip_ci_batches=False, guarantee_final_pipeline=False, + allow_priority_sorting=False, ) def test_default_ci_time(self): diff --git a/tests/test_merge_request.py b/tests/test_merge_request.py index 7259ea72..9df6b3e0 100644 --- a/tests/test_merge_request.py +++ b/tests/test_merge_request.py @@ -206,7 +206,7 @@ def test_fetch_all_opened_for_me(self): user = marge.user.User(api=None, info=dict(USER_INFO, id=_MARGE_ID)) api.collect_all_pages = Mock(return_value=[mr1, mr_not_me, mr2]) result = MergeRequest.fetch_all_open_for_user( - 1234, user=user, api=api, merge_order='created_at' + 1234, user=user, api=api, merge_order='created_at', prioritise_merges=False ) api.collect_all_pages.assert_called_once_with(GET( '/projects/1234/merge_requests',