4 files changed
@@ -122,8 +122,14 @@ Accept a MR:: | |||
| 122 | 122 | ||
| 123 | 123 | mr.merge() | |
| 124 | 124 | ||
| 125 | - Cancel a MR when the build succeeds:: | ||
| 125 | + Schedule a MR to merge after the pipeline(s) succeed:: | ||
| 126 | 126 | ||
| 127 | + mr.merge(merge_when_pipeline_succeeds=True) | ||
| 128 | + | ||
| 129 | + Cancel a MR from merging when the pipeline succeeds:: | ||
| 130 | + | ||
| 131 | + # Cancel a MR from being merged that had been previously set to | ||
| 132 | + # 'merge_when_pipeline_succeeds=True' | ||
| 127 | 133 | mr.cancel_merge_when_pipeline_succeeds() | |
| 128 | 134 | ||
| 129 | 135 | List commits of a MR:: | |
@@ -165,9 +165,7 @@ class ProjectMergeRequest( | |||
| 165 | 165 | ||
| 166 | 166 | @cli.register_custom_action("ProjectMergeRequest") | |
| 167 | 167 | @exc.on_http_error(exc.GitlabMROnBuildSuccessError) | |
| 168 | - def cancel_merge_when_pipeline_succeeds( | ||
| 169 | - self, **kwargs: Any | ||
| 170 | - ) -> "ProjectMergeRequest": | ||
| 168 | + def cancel_merge_when_pipeline_succeeds(self, **kwargs: Any) -> Dict[str, str]: | ||
| 171 | 169 | """Cancel merge when the pipeline succeeds. | |
| 172 | 170 | ||
| 173 | 171 | Args: | |
@@ -179,17 +177,20 @@ def cancel_merge_when_pipeline_succeeds( | |||
| 179 | 177 | request | |
| 180 | 178 | ||
| 181 | 179 | Returns: | |
| 182 | - ProjectMergeRequest | ||
| 180 | + dict of the parsed json returned by the server | ||
| 183 | 181 | """ | |
| 184 | 182 | ||
| 185 | 183 | path = ( | |
| 186 | 184 | f"{self.manager.path}/{self.encoded_id}/cancel_merge_when_pipeline_succeeds" | |
| 187 | 185 | ) | |
| 188 | - server_data = self.manager.gitlab.http_put(path, **kwargs) | ||
| 186 | + server_data = self.manager.gitlab.http_post(path, **kwargs) | ||
| 187 | + # 2022-10-30: The docs at | ||
| 188 | + # https://docs.gitlab.com/ee/api/merge_requests.html#cancel-merge-when-pipeline-succeeds | ||
| 189 | + # are incorrect in that the return value is actually just: | ||
| 190 | + # {'status': 'success'} for a successful cancel. | ||
| 189 | 191 | if TYPE_CHECKING: | |
| 190 | 192 | assert isinstance(server_data, dict) | |
| 191 | - self._update_attrs(server_data) | ||
| 192 | - return ProjectMergeRequest(self.manager, server_data) | ||
| 193 | + return server_data | ||
| 193 | 194 | ||
| 194 | 195 | @cli.register_custom_action("ProjectMergeRequest") | |
| 195 | 196 | @exc.on_http_error(exc.GitlabListError) | |
@@ -181,11 +181,27 @@ def test_merge_request_reset_approvals(gitlab_url, project, wait_for_sidekiq): | |||
| 181 | 181 | assert mr.reset_approvals() | |
| 182 | 182 | ||
| 183 | 183 | ||
| 184 | + def test_cancel_merge_when_pipeline_succeeds(project, merge_request, wait_for_sidekiq): | ||
| 185 | + mr = merge_request(source_branch="test_merge_request_merge", create_pipeline=True) | ||
| 186 | + # Set to merge when the pipeline succeeds, which should never happen | ||
| 187 | + mr.merge(merge_when_pipeline_succeeds=True) | ||
| 188 | + wait_for_sidekiq(timeout=60) | ||
| 189 | + | ||
| 190 | + mr = project.mergerequests.get(mr.iid) | ||
| 191 | + assert mr.merged_at is None | ||
| 192 | + assert mr.merge_when_pipeline_succeeds is True | ||
| 193 | + cancel = mr.cancel_merge_when_pipeline_succeeds() | ||
| 194 | + assert cancel == {"status": "success"} | ||
| 195 | + | ||
| 196 | + | ||
| 184 | 197 | def test_merge_request_merge(project, merge_request, wait_for_sidekiq): | |
| 185 | 198 | mr = merge_request(source_branch="test_merge_request_merge") | |
| 186 | 199 | mr.merge() | |
| 187 | 200 | wait_for_sidekiq(timeout=60) | |
| 188 | 201 | ||
| 202 | + mr = project.mergerequests.get(mr.iid) | ||
| 203 | + assert mr.merged_at is not None | ||
| 204 | + assert mr.merge_when_pipeline_succeeds is False | ||
| 189 | 205 | with pytest.raises(gitlab.GitlabMRClosedError): | |
| 190 | 206 | # Two merge attempts should raise GitlabMRClosedError | |
| 191 | 207 | mr.merge() | |
@@ -379,7 +379,7 @@ def merge_request(project, wait_for_sidekiq): | |||
| 379 | 379 | ||
| 380 | 380 | to_delete = [] | |
| 381 | 381 | ||
| 382 | - def _merge_request(*, source_branch: str): | ||
| 382 | + def _merge_request(*, source_branch: str, create_pipeline: bool = False): | ||
| 383 | 383 | # Wait for processes to be done before we start... | |
| 384 | 384 | # NOTE(jlvillal): Sometimes the CI would give a "500 Internal Server | |
| 385 | 385 | # Error". Hoping that waiting until all other processes are done will | |
@@ -401,6 +401,21 @@ def _merge_request(*, source_branch: str): | |||
| 401 | 401 | "commit_message": "New commit in new branch", | |
| 402 | 402 | } | |
| 403 | 403 | ) | |
| 404 | + if create_pipeline: | ||
| 405 | + project.files.create( | ||
| 406 | + { | ||
| 407 | + "file_path": ".gitlab-ci.yml", | ||
| 408 | + "branch": source_branch, | ||
| 409 | + "content": """ | ||
| 410 | + test: | ||
| 411 | + rules: | ||
| 412 | + - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' | ||
| 413 | + script: | ||
| 414 | + - sleep 24h # We don't expect this to finish | ||
| 415 | + """, | ||
| 416 | + "commit_message": "Add a simple pipeline", | ||
| 417 | + } | ||
| 418 | + ) | ||
| 404 | 419 | mr = project.mergerequests.create( | |
| 405 | 420 | { | |
| 406 | 421 | "source_branch": source_branch, | |
0 commit comments