Skip to content

Commit 28d7518

Browse files
committed
feat(objects): add Release Links API support
1 parent 649385c commit 28d7518

File tree

6 files changed

+180
-14
lines changed

6 files changed

+180
-14
lines changed

gitlab/tests/conftest.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ def default_config(tmpdir):
3737
return str(config_path)
3838

3939

40+
@pytest.fixture
41+
def tag_name():
42+
return "v1.0.0"
43+
44+
4045
@pytest.fixture
4146
def group(gl):
4247
return gl.groups.get(1, lazy=True)
@@ -47,6 +52,11 @@ def project(gl):
4752
return gl.projects.get(1, lazy=True)
4853

4954

55+
@pytest.fixture
56+
def release(project, tag_name):
57+
return project.releases.get(tag_name, lazy=True)
58+
59+
5060
@pytest.fixture
5161
def user(gl):
5262
return gl.users.get(1, lazy=True)

gitlab/tests/objects/test_releases.py

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
"""
2+
GitLab API:
3+
https://docs.gitlab.com/ee/api/releases/index.html
4+
https://docs.gitlab.com/ee/api/releases/links.html
5+
"""
6+
import re
7+
8+
import pytest
9+
import responses
10+
11+
from gitlab.v4.objects import ProjectReleaseLink
12+
13+
encoded_tag_name = "v1%2E0%2E0"
14+
link_name = "hello-world"
15+
link_url = "https://gitlab.example.com/group/hello/-/jobs/688/artifacts/raw/bin/hello-darwin-amd64"
16+
direct_url = f"https://gitlab.example.com/group/hello/-/releases/{encoded_tag_name}/downloads/hello-world"
17+
new_link_type = "package"
18+
link_content = {
19+
"id": 2,
20+
"name": link_name,
21+
"url": link_url,
22+
"direct_asset_url": direct_url,
23+
"external": False,
24+
"link_type": "other",
25+
}
26+
27+
links_url = re.compile(
28+
rf"http://localhost/api/v4/projects/1/releases/{encoded_tag_name}/assets/links"
29+
)
30+
link_id_url = re.compile(
31+
rf"http://localhost/api/v4/projects/1/releases/{encoded_tag_name}/assets/links/1"
32+
)
33+
34+
35+
@pytest.fixture
36+
def resp_list_links():
37+
with responses.RequestsMock() as rsps:
38+
rsps.add(
39+
method=responses.GET,
40+
url=links_url,
41+
json=[link_content],
42+
content_type="application/json",
43+
status=200,
44+
)
45+
yield rsps
46+
47+
48+
@pytest.fixture
49+
def resp_get_link():
50+
with responses.RequestsMock() as rsps:
51+
rsps.add(
52+
method=responses.GET,
53+
url=link_id_url,
54+
json=link_content,
55+
content_type="application/json",
56+
status=200,
57+
)
58+
yield rsps
59+
60+
61+
@pytest.fixture
62+
def resp_create_link():
63+
with responses.RequestsMock() as rsps:
64+
rsps.add(
65+
method=responses.POST,
66+
url=links_url,
67+
json=link_content,
68+
content_type="application/json",
69+
status=200,
70+
)
71+
yield rsps
72+
73+
74+
@pytest.fixture
75+
def resp_update_link():
76+
updated_content = dict(link_content)
77+
updated_content["link_type"] = new_link_type
78+
79+
with responses.RequestsMock() as rsps:
80+
rsps.add(
81+
method=responses.PUT,
82+
url=link_id_url,
83+
json=updated_content,
84+
content_type="application/json",
85+
status=200,
86+
)
87+
yield rsps
88+
89+
90+
@pytest.fixture
91+
def resp_delete_link(no_content):
92+
with responses.RequestsMock() as rsps:
93+
rsps.add(
94+
method=responses.DELETE,
95+
url=link_id_url,
96+
json=link_content,
97+
content_type="application/json",
98+
status=204,
99+
)
100+
yield rsps
101+
102+
103+
def test_list_release_links(release, resp_list_links):
104+
links = release.links.list()
105+
assert isinstance(links, list)
106+
assert isinstance(links[0], ProjectReleaseLink)
107+
assert links[0].url == link_url
108+
109+
110+
def test_get_release_link(release, resp_get_link):
111+
link = release.links.get(1)
112+
assert isinstance(link, ProjectReleaseLink)
113+
assert link.url == link_url
114+
115+
116+
def test_create_release_link(release, resp_create_link):
117+
link = release.links.create({"url": link_url, "name": link_name})
118+
assert isinstance(link, ProjectReleaseLink)
119+
assert link.url == link_url
120+
121+
122+
def test_update_release_link(release, resp_update_link):
123+
link = release.links.get(1, lazy=True)
124+
link.link_type = new_link_type
125+
link.save()
126+
assert link.link_type == new_link_type
127+
128+
129+
def test_delete_release_link(release, resp_delete_link):
130+
link = release.links.get(1, lazy=True)
131+
link.delete()

gitlab/v4/objects/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
from .pipelines import *
5757
from .projects import *
5858
from .push_rules import *
59+
from .releases import *
5960
from .runners import *
6061
from .services import *
6162
from .settings import *

gitlab/v4/objects/projects.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,15 @@
3333
from .pages import ProjectPagesDomainManager
3434
from .pipelines import ProjectPipelineManager, ProjectPipelineScheduleManager
3535
from .push_rules import ProjectPushRulesManager
36+
from .releases import ProjectReleaseManager
3637
from .runners import ProjectRunnerManager
3738
from .services import ProjectServiceManager
3839
from .snippets import ProjectSnippetManager
3940
from .statistics import (
4041
ProjectAdditionalStatisticsManager,
4142
ProjectIssuesStatisticsManager,
4243
)
43-
from .tags import ProjectProtectedTagManager, ProjectReleaseManager, ProjectTagManager
44+
from .tags import ProjectProtectedTagManager, ProjectTagManager
4445
from .triggers import ProjectTriggerManager
4546
from .users import ProjectUserManager
4647
from .variables import ProjectVariableManager

gitlab/v4/objects/releases.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
from gitlab import cli
2+
from gitlab import exceptions as exc
3+
from gitlab.base import * # noqa
4+
from gitlab.mixins import * # noqa
5+
6+
7+
__all__ = [
8+
"ProjectRelease",
9+
"ProjectReleaseManager",
10+
"ProjectReleaseLink",
11+
"ProjectReleaseLinkManager",
12+
]
13+
14+
15+
class ProjectRelease(RESTObject):
16+
_id_attr = "tag_name"
17+
_managers = (("links", "ProjectReleaseLinkManager"),)
18+
19+
20+
class ProjectReleaseManager(NoUpdateMixin, RESTManager):
21+
_path = "/projects/%(project_id)s/releases"
22+
_obj_cls = ProjectRelease
23+
_from_parent_attrs = {"project_id": "id"}
24+
_create_attrs = (("name", "tag_name", "description"), ("ref", "assets"))
25+
26+
27+
class ProjectReleaseLink(RESTObject, ObjectDeleteMixin, SaveMixin):
28+
pass
29+
30+
31+
class ProjectReleaseLinkManager(CRUDMixin, RESTManager):
32+
_path = "/projects/%(project_id)s/releases/%(tag_name)s/assets/links"
33+
_obj_cls = ProjectReleaseLink
34+
_from_parent_attrs = {"project_id": "project_id", "tag_name": "tag_name"}
35+
_create_attrs = (("name", "url"), ("filepath", "link_type"))
36+
_update_attrs = ((), ("name", "url", "filepath", "link_type"))

gitlab/v4/objects/tags.py

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@
99
"ProjectTagManager",
1010
"ProjectProtectedTag",
1111
"ProjectProtectedTagManager",
12-
"ProjectRelease",
13-
"ProjectReleaseManager",
1412
]
1513

1614

@@ -71,14 +69,3 @@ class ProjectProtectedTagManager(NoUpdateMixin, RESTManager):
7169
_obj_cls = ProjectProtectedTag
7270
_from_parent_attrs = {"project_id": "id"}
7371
_create_attrs = (("name",), ("create_access_level",))
74-
75-
76-
class ProjectRelease(RESTObject):
77-
_id_attr = "tag_name"
78-
79-
80-
class ProjectReleaseManager(NoUpdateMixin, RESTManager):
81-
_path = "/projects/%(project_id)s/releases"
82-
_obj_cls = ProjectRelease
83-
_from_parent_attrs = {"project_id": "id"}
84-
_create_attrs = (("name", "tag_name", "description"), ("ref", "assets"))

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy