| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent e095735 commit 9c9eeb9
4 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -40,6 +40,18 @@ Update a deployment:: | |||
| 40 | 40 | deployment.status = "failed" | |
| 41 | 41 | deployment.save() | |
| 42 | 42 | ||
| 43 | + Approve a deployment:: | ||
| 44 | + | ||
| 45 | + deployment = project.deployments.get(42) | ||
| 46 | + # `status` must be either "approved" or "rejected". | ||
| 47 | + deployment.approval(status="approved") | ||
| 48 | + | ||
| 49 | + Reject a deployment:: | ||
| 50 | + | ||
| 51 | + deployment = project.deployments.get(42) | ||
| 52 | + # Using the optional `comment` and `represented_as` arguments | ||
| 53 | + deployment.approval(status="rejected", comment="Fails CI", represented_as="security") | ||
| 54 | + | ||
| 43 | 55 | Merge requests associated with a deployment | |
| 44 | 56 | =========================================== | |
| 45 | 57 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -301,6 +301,10 @@ class GitlabUserRejectError(GitlabOperationError): | |||
| 301 | 301 | pass | |
| 302 | 302 | ||
| 303 | 303 | ||
| 304 | + class GitlabDeploymentApprovalError(GitlabOperationError): | ||
| 305 | + pass | ||
| 306 | + | ||
| 307 | + | ||
| 304 | 308 | # For an explanation of how these type-hints work see: | |
| 305 | 309 | # https://mypy.readthedocs.io/en/stable/generics.html#declaring-decorators | |
| 306 | 310 | # | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,5 +1,11 @@ | |||
| 1 | - from typing import Any, cast, Union | ||
| 1 | + """ | ||
| 2 | + GitLab API: | ||
| 3 | + https://docs.gitlab.com/ee/api/deployments.html | ||
| 4 | + """ | ||
| 5 | + from typing import Any, cast, Dict, Optional, TYPE_CHECKING, Union | ||
| 2 | 6 | ||
| 7 | + from gitlab import cli | ||
| 8 | + from gitlab import exceptions as exc | ||
| 3 | 9 | from gitlab.base import RESTManager, RESTObject | |
| 4 | 10 | from gitlab.mixins import CreateMixin, RetrieveMixin, SaveMixin, UpdateMixin | |
| 5 | 11 | from gitlab.types import RequiredOptional | |
@@ -15,6 +21,50 @@ | |||
| 15 | 21 | class ProjectDeployment(SaveMixin, RESTObject): | |
| 16 | 22 | mergerequests: ProjectDeploymentMergeRequestManager | |
| 17 | 23 | ||
| 24 | + @cli.register_custom_action( | ||
| 25 | + "ProjectDeployment", | ||
| 26 | + mandatory=("status",), | ||
| 27 | + optional=("comment", "represented_as"), | ||
| 28 | + ) | ||
| 29 | + @exc.on_http_error(exc.GitlabDeploymentApprovalError) | ||
| 30 | + def approval( | ||
| 31 | + self, | ||
| 32 | + status: str, | ||
| 33 | + comment: Optional[str] = None, | ||
| 34 | + represented_as: Optional[str] = None, | ||
| 35 | + **kwargs: Any, | ||
| 36 | + ) -> Dict[str, Any]: | ||
| 37 | + """Approve or reject a blocked deployment. | ||
| 38 | + | ||
| 39 | + Args: | ||
| 40 | + status: Either "approved" or "rejected" | ||
| 41 | + comment: A comment to go with the approval | ||
| 42 | + represented_as: The name of the User/Group/Role to use for the | ||
| 43 | + approval, when the user belongs to multiple | ||
| 44 | + approval rules. | ||
| 45 | + **kwargs: Extra options to send to the server (e.g. sudo) | ||
| 46 | + | ||
| 47 | + Raises: | ||
| 48 | + GitlabAuthenticationError: If authentication is not correct | ||
| 49 | + GitlabMRApprovalError: If the approval failed | ||
| 50 | + | ||
| 51 | + Returns: | ||
| 52 | + A dict containing the result. | ||
| 53 | + | ||
| 54 | + https://docs.gitlab.com/ee/api/deployments.html#approve-or-reject-a-blocked-deployment | ||
| 55 | + """ | ||
| 56 | + path = f"{self.manager.path}/{self.encoded_id}/approval" | ||
| 57 | + data = {"status": status} | ||
| 58 | + if comment is not None: | ||
| 59 | + data["comment"] = comment | ||
| 60 | + if represented_as is not None: | ||
| 61 | + data["represented_as"] = represented_as | ||
| 62 | + | ||
| 63 | + server_data = self.manager.gitlab.http_post(path, post_data=data, **kwargs) | ||
| 64 | + if TYPE_CHECKING: | ||
| 65 | + assert isinstance(server_data, dict) | ||
| 66 | + return server_data | ||
| 67 | + | ||
| 18 | 68 | ||
| 19 | 69 | class ProjectDeploymentManager(RetrieveMixin, CreateMixin, UpdateMixin, RESTManager): | |
| 20 | 70 | _path = "/projects/{project_id}/deployments" | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -6,7 +6,25 @@ | |||
| 6 | 6 | ||
| 7 | 7 | ||
| 8 | 8 | @pytest.fixture | |
| 9 | - def resp_deployment(): | ||
| 9 | + def resp_deployment_get(): | ||
| 10 | + with responses.RequestsMock() as rsps: | ||
| 11 | + rsps.add( | ||
| 12 | + method=responses.GET, | ||
| 13 | + url="http://localhost/api/v4/projects/1/deployments/42", | ||
| 14 | + json=response_get_content, | ||
| 15 | + content_type="application/json", | ||
| 16 | + status=200, | ||
| 17 | + ) | ||
| 18 | + yield rsps | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + @pytest.fixture | ||
| 22 | + def deployment(project): | ||
| 23 | + return project.deployments.get(42, lazy=True) | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + @pytest.fixture | ||
| 27 | + def resp_deployment_create(): | ||
| 10 | 28 | content = {"id": 42, "status": "success", "ref": "main"} | |
| 11 | 29 | ||
| 12 | 30 | with responses.RequestsMock() as rsps: | |
@@ -31,7 +49,42 @@ def resp_deployment(): | |||
| 31 | 49 | yield rsps | |
| 32 | 50 | ||
| 33 | 51 | ||
| 34 | - def test_deployment(project, resp_deployment): | ||
| 52 | + @pytest.fixture | ||
| 53 | + def resp_deployment_approval(): | ||
| 54 | + content = { | ||
| 55 | + "user": { | ||
| 56 | + "id": 100, | ||
| 57 | + "username": "security-user-1", | ||
| 58 | + "name": "security user-1", | ||
| 59 | + "state": "active", | ||
| 60 | + "avatar_url": "https://www.gravatar.com/avatar/e130fcd3a1681f41a3de69d10841afa9?s=80&d=identicon", | ||
| 61 | + "web_url": "http://localhost:3000/security-user-1", | ||
| 62 | + }, | ||
| 63 | + "status": "approved", | ||
| 64 | + "created_at": "2022-02-24T20:22:30.097Z", | ||
| 65 | + "comment": "Looks good to me", | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + with responses.RequestsMock() as rsps: | ||
| 69 | + rsps.add( | ||
| 70 | + method=responses.POST, | ||
| 71 | + url="http://localhost/api/v4/projects/1/deployments/42/approval", | ||
| 72 | + json=content, | ||
| 73 | + content_type="application/json", | ||
| 74 | + status=200, | ||
| 75 | + ) | ||
| 76 | + yield rsps | ||
| 77 | + | ||
| 78 | + | ||
| 79 | + def test_deployment_get(project, resp_deployment_get): | ||
| 80 | + deployment = project.deployments.get(42) | ||
| 81 | + assert deployment.id == 42 | ||
| 82 | + assert deployment.iid == 2 | ||
| 83 | + assert deployment.status == "success" | ||
| 84 | + assert deployment.ref == "main" | ||
| 85 | + | ||
| 86 | + | ||
| 87 | + def test_deployment_create(project, resp_deployment_create): | ||
| 35 | 88 | deployment = project.deployments.create( | |
| 36 | 89 | { | |
| 37 | 90 | "environment": "Test", | |
@@ -48,3 +101,80 @@ def test_deployment(project, resp_deployment): | |||
| 48 | 101 | deployment.status = "failed" | |
| 49 | 102 | deployment.save() | |
| 50 | 103 | assert deployment.status == "failed" | |
| 104 | + | ||
| 105 | + | ||
| 106 | + def test_deployment_approval(deployment, resp_deployment_approval) -> None: | ||
| 107 | + result = deployment.approval(status="approved") | ||
| 108 | + assert result["status"] == "approved" | ||
| 109 | + assert result["comment"] == "Looks good to me" | ||
| 110 | + | ||
| 111 | + | ||
| 112 | + response_get_content = { | ||
| 113 | + "id": 42, | ||
| 114 | + "iid": 2, | ||
| 115 | + "ref": "main", | ||
| 116 | + "sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a", | ||
| 117 | + "created_at": "2016-08-11T11:32:35.444Z", | ||
| 118 | + "updated_at": "2016-08-11T11:34:01.123Z", | ||
| 119 | + "status": "success", | ||
| 120 | + "user": { | ||
| 121 | + "name": "Administrator", | ||
| 122 | + "username": "root", | ||
| 123 | + "id": 1, | ||
| 124 | + "state": "active", | ||
| 125 | + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", | ||
| 126 | + "web_url": "http://localhost:3000/root", | ||
| 127 | + }, | ||
| 128 | + "environment": { | ||
| 129 | + "id": 9, | ||
| 130 | + "name": "production", | ||
| 131 | + "external_url": "https://about.gitlab.com", | ||
| 132 | + }, | ||
| 133 | + "deployable": { | ||
| 134 | + "id": 664, | ||
| 135 | + "status": "success", | ||
| 136 | + "stage": "deploy", | ||
| 137 | + "name": "deploy", | ||
| 138 | + "ref": "main", | ||
| 139 | + "tag": False, | ||
| 140 | + "coverage": None, | ||
| 141 | + "created_at": "2016-08-11T11:32:24.456Z", | ||
| 142 | + "started_at": None, | ||
| 143 | + "finished_at": "2016-08-11T11:32:35.145Z", | ||
| 144 | + "user": { | ||
| 145 | + "id": 1, | ||
| 146 | + "name": "Administrator", | ||
| 147 | + "username": "root", | ||
| 148 | + "state": "active", | ||
| 149 | + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", | ||
| 150 | + "web_url": "http://gitlab.dev/root", | ||
| 151 | + "created_at": "2015-12-21T13:14:24.077Z", | ||
| 152 | + "bio": None, | ||
| 153 | + "location": None, | ||
| 154 | + "skype": "", | ||
| 155 | + "linkedin": "", | ||
| 156 | + "twitter": "", | ||
| 157 | + "website_url": "", | ||
| 158 | + "organization": "", | ||
| 159 | + }, | ||
| 160 | + "commit": { | ||
| 161 | + "id": "a91957a858320c0e17f3a0eca7cfacbff50ea29a", | ||
| 162 | + "short_id": "a91957a8", | ||
| 163 | + "title": "Merge branch 'rename-readme' into 'main'\r", | ||
| 164 | + "author_name": "Administrator", | ||
| 165 | + "author_email": "admin@example.com", | ||
| 166 | + "created_at": "2016-08-11T13:28:26.000+02:00", | ||
| 167 | + "message": "Merge branch 'rename-readme' into 'main'\r\n\r\nRename README\r\n\r\n\r\n\r\nSee merge request !2", | ||
| 168 | + }, | ||
| 169 | + "pipeline": { | ||
| 170 | + "created_at": "2016-08-11T07:43:52.143Z", | ||
| 171 | + "id": 42, | ||
| 172 | + "ref": "main", | ||
| 173 | + "sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a", | ||
| 174 | + "status": "success", | ||
| 175 | + "updated_at": "2016-08-11T07:43:52.143Z", | ||
| 176 | + "web_url": "http://gitlab.dev/root/project/pipelines/5", | ||
| 177 | + }, | ||
| 178 | + "runner": None, | ||
| 179 | + }, | ||
| 180 | + } | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments