Skip to content

Commit 9bb51cf

Browse files
committed
feat: Add support for Protected Environments
- https://docs.gitlab.com/ee/api/protected_environments.html - #1130 no write operation are implemented yet as I have no use case right now and am not sure how it should be done
1 parent 8342f53 commit 9bb51cf

File tree

6 files changed

+109
-3
lines changed

6 files changed

+109
-3
lines changed

docs/api-objects.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ API examples
4343
gl_objects/projects
4444
gl_objects/project_access_tokens
4545
gl_objects/protected_branches
46+
gl_objects/protected_environments
4647
gl_objects/releases
4748
gl_objects/runners
4849
gl_objects/remote_mirrors

docs/gl_objects/environments.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ Delete an environment for a project::
3939
# or
4040
environment.delete()
4141

42-
Stop an environments::
42+
Stop an environment::
4343

4444
environment.stop()
45+
46+
To manage protected environments, see :doc:`/gl_objects/protected_environments`.
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
######################
2+
Protected environments
3+
######################
4+
5+
You can list and manage protected environments in a project.
6+
7+
References
8+
----------
9+
10+
* v4 API:
11+
12+
+ :class:`gitlab.v4.objects.ProjectProtectedEnvironment`
13+
+ :class:`gitlab.v4.objects.ProjectProtectedEnvironmentManager`
14+
+ :attr:`gitlab.v4.objects.Project.protected_environment`
15+
16+
* GitLab API: https://docs.gitlab.com/ee/api/protected_environments.html
17+
18+
Examples
19+
--------
20+
21+
Get the list of protected environments for a project::
22+
23+
p_environments = project.protected_environments.list()
24+
25+
Get a single protected environment::
26+
27+
p_environments = project.protected_environments.get('production')
28+
29+
Protect an existing environment::
30+
31+
p_environment = project.protected_environments.create(
32+
{
33+
'name': 'production',
34+
'deploy_access_levels': [
35+
{'access_level': 40}
36+
],
37+
}
38+
)
39+
40+
41+
Unprotect a protected environment::
42+
43+
p_environment = project.protected_environments.delete('prod')
44+
# or
45+
p_environment.delete()

gitlab/v4/objects/environments.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
__all__ = [
1919
"ProjectEnvironment",
2020
"ProjectEnvironmentManager",
21+
"ProjectProtectedEnvironment",
22+
"ProjectProtectedEnvironmentManager",
2123
]
2224

2325

@@ -55,3 +57,30 @@ def get(
5557
self, id: Union[str, int], lazy: bool = False, **kwargs: Any
5658
) -> ProjectEnvironment:
5759
return cast(ProjectEnvironment, super().get(id=id, lazy=lazy, **kwargs))
60+
61+
62+
class ProjectProtectedEnvironment(ObjectDeleteMixin, RESTObject):
63+
_id_attr = "name"
64+
_repr_attr = "name"
65+
66+
67+
class ProjectProtectedEnvironmentManager(
68+
RetrieveMixin, CreateMixin, DeleteMixin, RESTManager
69+
):
70+
_path = "/projects/{project_id}/protected_environments"
71+
_obj_cls = ProjectProtectedEnvironment
72+
_from_parent_attrs = {"project_id": "id"}
73+
_create_attrs = RequiredOptional(
74+
required=(
75+
"name",
76+
"deploy_access_levels",
77+
),
78+
optional=("required_approval_count", "approval_rules"),
79+
)
80+
81+
def get(
82+
self, id: Union[str, int], lazy: bool = False, **kwargs: Any
83+
) -> ProjectProtectedEnvironment:
84+
return cast(
85+
ProjectProtectedEnvironment, super().get(id=id, lazy=lazy, **kwargs)
86+
)

gitlab/v4/objects/projects.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,10 @@
3131
from .deploy_keys import ProjectKeyManager # noqa: F401
3232
from .deploy_tokens import ProjectDeployTokenManager # noqa: F401
3333
from .deployments import ProjectDeploymentManager # noqa: F401
34-
from .environments import ProjectEnvironmentManager # noqa: F401
34+
from .environments import ( # noqa: F401
35+
ProjectEnvironmentManager,
36+
ProjectProtectedEnvironmentManager,
37+
)
3538
from .events import ProjectEventManager # noqa: F401
3639
from .export_import import ProjectExportManager, ProjectImportManager # noqa: F401
3740
from .files import ProjectFileManager # noqa: F401
@@ -175,6 +178,7 @@ class Project(RefreshMixin, SaveMixin, ObjectDeleteMixin, RepositoryMixin, RESTO
175178
pagesdomains: ProjectPagesDomainManager
176179
pipelines: ProjectPipelineManager
177180
pipelineschedules: ProjectPipelineScheduleManager
181+
protected_environments: ProjectProtectedEnvironmentManager
178182
protectedbranches: ProjectProtectedBranchManager
179183
protectedtags: ProjectProtectedTagManager
180184
pushrules: ProjectPushRulesManager

tests/unit/objects/test_environments.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import pytest
55
import responses
66

7-
from gitlab.v4.objects import ProjectEnvironment
7+
from gitlab.v4.objects import ProjectEnvironment, ProjectProtectedEnvironment
88

99

1010
@pytest.fixture
@@ -22,9 +22,34 @@ def resp_get_environment():
2222
yield rsps
2323

2424

25+
@pytest.fixture
26+
def resp_get_protected_environment():
27+
content = {
28+
"name": "protected_environment_name",
29+
"last_deployment": "my birthday",
30+
}
31+
32+
with responses.RequestsMock() as rsps:
33+
rsps.add(
34+
method=responses.GET,
35+
url="http://localhost/api/v4/projects/1/protected_environments/2",
36+
json=content,
37+
content_type="application/json",
38+
status=200,
39+
)
40+
yield rsps
41+
42+
2543
def test_project_environments(project, resp_get_environment):
2644
environment = project.environments.get(1)
2745
assert isinstance(environment, ProjectEnvironment)
2846
assert environment.id == 1
2947
assert environment.last_deployment == "sometime"
3048
assert environment.name == "environment_name"
49+
50+
51+
def test_project_protected_environments(project, resp_get_protected_environment):
52+
protected_environment = project.protected_environments.get(2)
53+
assert isinstance(protected_environment, ProjectProtectedEnvironment)
54+
assert protected_environment.last_deployment == "my birthday"
55+
assert protected_environment.name == "protected_environment_name"

0 commit comments

Comments
 (0)