Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

feat: add support for deployment approval endpoint#2254

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
nejch merged 1 commit intomainfromjlvillal/deploy_approve
Aug 28, 2022
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletionsdocs/gl_objects/deployments.rst
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -40,6 +40,18 @@ Update a deployment::
deployment.status = "failed"
deployment.save()

Approve a deployment::

deployment = project.deployments.get(42)
# `status` must be either "approved" or "rejected".
deployment.approval(status="approved")

Reject a deployment::

deployment = project.deployments.get(42)
# Using the optional `comment` and `represented_as` arguments
deployment.approval(status="rejected", comment="Fails CI", represented_as="security")

Merge requests associated with a deployment
===========================================

Expand Down
4 changes: 4 additions & 0 deletionsgitlab/exceptions.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -301,6 +301,10 @@ class GitlabUserRejectError(GitlabOperationError):
pass


class GitlabDeploymentApprovalError(GitlabOperationError):
pass


# For an explanation of how these type-hints work see:
# https://mypy.readthedocs.io/en/stable/generics.html#declaring-decorators
#
Expand Down
52 changes: 51 additions & 1 deletiongitlab/v4/objects/deployments.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
from typing import Any, cast, Union
"""
GitLab API:
https://docs.gitlab.com/ee/api/deployments.html
"""
from typing import Any, cast, Dict, Optional, TYPE_CHECKING, Union

from gitlab import cli
from gitlab import exceptions as exc
from gitlab.base import RESTManager, RESTObject
from gitlab.mixins import CreateMixin, RetrieveMixin, SaveMixin, UpdateMixin
from gitlab.types import RequiredOptional
Expand All@@ -15,6 +21,50 @@
class ProjectDeployment(SaveMixin, RESTObject):
mergerequests: ProjectDeploymentMergeRequestManager

@cli.register_custom_action(
"ProjectDeployment",
mandatory=("status",),
optional=("comment", "represented_as"),
)
@exc.on_http_error(exc.GitlabDeploymentApprovalError)
def approval(
self,
status: str,
comment: Optional[str] = None,
represented_as: Optional[str] = None,
**kwargs: Any,
) -> Dict[str, Any]:
"""Approve or reject a blocked deployment.

Args:
status: Either "approved" or "rejected"
comment: A comment to go with the approval
represented_as: The name of the User/Group/Role to use for the
approval, when the user belongs to multiple
approval rules.
**kwargs: Extra options to send to the server (e.g. sudo)

Raises:
GitlabAuthenticationError: If authentication is not correct
GitlabMRApprovalError: If the approval failed

Returns:
A dict containing the result.

https://docs.gitlab.com/ee/api/deployments.html#approve-or-reject-a-blocked-deployment
"""
path = f"{self.manager.path}/{self.encoded_id}/approval"
data = {"status": status}
if comment is not None:
data["comment"] = comment
if represented_as is not None:
data["represented_as"] = represented_as

server_data = self.manager.gitlab.http_post(path, post_data=data, **kwargs)
if TYPE_CHECKING:
assert isinstance(server_data, dict)
return server_data


class ProjectDeploymentManager(RetrieveMixin, CreateMixin, UpdateMixin, RESTManager):
_path = "/projects/{project_id}/deployments"
Expand Down
134 changes: 132 additions & 2 deletionstests/unit/objects/test_deployments.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,7 +6,25 @@


@pytest.fixture
def resp_deployment():
def resp_deployment_get():
with responses.RequestsMock() as rsps:
rsps.add(
method=responses.GET,
url="http://localhost/api/v4/projects/1/deployments/42",
json=response_get_content,
content_type="application/json",
status=200,
)
yield rsps


@pytest.fixture
def deployment(project):
return project.deployments.get(42, lazy=True)


@pytest.fixture
def resp_deployment_create():
content = {"id": 42, "status": "success", "ref": "main"}

with responses.RequestsMock() as rsps:
Expand All@@ -31,7 +49,42 @@ def resp_deployment():
yield rsps


def test_deployment(project, resp_deployment):
@pytest.fixture
def resp_deployment_approval():
content = {
"user": {
"id": 100,
"username": "security-user-1",
"name": "security user-1",
"state": "active",
"avatar_url": "https://www.gravatar.com/avatar/e130fcd3a1681f41a3de69d10841afa9?s=80&d=identicon",
"web_url": "http://localhost:3000/security-user-1",
},
"status": "approved",
"created_at": "2022-02-24T20:22:30.097Z",
"comment": "Looks good to me",
}

with responses.RequestsMock() as rsps:
rsps.add(
method=responses.POST,
url="http://localhost/api/v4/projects/1/deployments/42/approval",
json=content,
content_type="application/json",
status=200,
)
yield rsps


def test_deployment_get(project, resp_deployment_get):
deployment = project.deployments.get(42)
assert deployment.id == 42
assert deployment.iid == 2
assert deployment.status == "success"
assert deployment.ref == "main"


def test_deployment_create(project, resp_deployment_create):
deployment = project.deployments.create(
{
"environment": "Test",
Expand All@@ -48,3 +101,80 @@ def test_deployment(project, resp_deployment):
deployment.status = "failed"
deployment.save()
assert deployment.status == "failed"


def test_deployment_approval(deployment, resp_deployment_approval) -> None:
result = deployment.approval(status="approved")
assert result["status"] == "approved"
assert result["comment"] == "Looks good to me"


response_get_content = {
"id": 42,
"iid": 2,
"ref": "main",
"sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a",
"created_at": "2016-08-11T11:32:35.444Z",
"updated_at": "2016-08-11T11:34:01.123Z",
"status": "success",
"user": {
"name": "Administrator",
"username": "root",
"id": 1,
"state": "active",
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
"web_url": "http://localhost:3000/root",
},
"environment": {
"id": 9,
"name": "production",
"external_url": "https://about.gitlab.com",
},
"deployable": {
"id": 664,
"status": "success",
"stage": "deploy",
"name": "deploy",
"ref": "main",
"tag": False,
"coverage": None,
"created_at": "2016-08-11T11:32:24.456Z",
"started_at": None,
"finished_at": "2016-08-11T11:32:35.145Z",
"user": {
"id": 1,
"name": "Administrator",
"username": "root",
"state": "active",
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
"web_url": "http://gitlab.dev/root",
"created_at": "2015-12-21T13:14:24.077Z",
"bio": None,
"location": None,
"skype": "",
"linkedin": "",
"twitter": "",
"website_url": "",
"organization": "",
},
"commit": {
"id": "a91957a858320c0e17f3a0eca7cfacbff50ea29a",
"short_id": "a91957a8",
"title": "Merge branch 'rename-readme' into 'main'\r",
"author_name": "Administrator",
"author_email": "admin@example.com",
"created_at": "2016-08-11T13:28:26.000+02:00",
"message": "Merge branch 'rename-readme' into 'main'\r\n\r\nRename README\r\n\r\n\r\n\r\nSee merge request !2",
},
"pipeline": {
"created_at": "2016-08-11T07:43:52.143Z",
"id": 42,
"ref": "main",
"sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a",
"status": "success",
"updated_at": "2016-08-11T07:43:52.143Z",
"web_url": "http://gitlab.dev/root/project/pipelines/5",
},
"runner": None,
},
}

[8]ページ先頭

©2009-2025 Movatter.jp