Skip to content

feat: add release links API support #1314

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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Feb 21, 2021
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions docs/api-objects.rst
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ API examples
gl_objects/pipelines_and_jobs
gl_objects/projects
gl_objects/protected_branches
gl_objects/releases
gl_objects/runners
gl_objects/remote_mirrors
gl_objects/repositories
Expand Down
33 changes: 0 additions & 33 deletions docs/gl_objects/projects.rst
Original file line number Diff line number Diff line change
Expand Up @@ -702,39 +702,6 @@ Delete project push rules::

pr.delete()

Project releases
================

Reference
---------

* v4 API:

+ :class:`gitlab.v4.objects.ProjectRelease`
+ :class:`gitlab.v4.objects.ProjectReleaseManager`
+ :attr:`gitlab.v4.objects.Project.releases`

* Gitlab API: https://docs.gitlab.com/ee/api/releases/index.html

Examples
--------

Get a list of releases from a project::

release = project.releases.list()

Get a single release::

release = project.releases.get('v1.2.3')

Create a release for a project tag::

release = project.releases.create({'name':'Demo Release', 'tag_name':'v1.2.3', 'description':'release notes go here'})

Delete a release::

release = p.releases.delete('v1.2.3')

Project protected tags
======================

Expand Down
77 changes: 77 additions & 0 deletions docs/gl_objects/releases.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
########
Releases
########

Project releases
================

Reference
---------

* v4 API:

+ :class:`gitlab.v4.objects.ProjectRelease`
+ :class:`gitlab.v4.objects.ProjectReleaseManager`
+ :attr:`gitlab.v4.objects.Project.releases`

* Gitlab API: https://docs.gitlab.com/ee/api/releases/index.html

Examples
--------

Get a list of releases from a project::

release = project.releases.list()

Get a single release::

release = project.releases.get('v1.2.3')

Create a release for a project tag::

release = project.releases.create({'name':'Demo Release', 'tag_name':'v1.2.3', 'description':'release notes go here'})

Delete a release::

# via its tag name from project attributes
release = project.releases.delete('v1.2.3')

# delete object directly
release.delete()

Project release links
=====================

Reference
---------

* v4 API:

+ :class:`gitlab.v4.objects.ProjectReleaseLink`
+ :class:`gitlab.v4.objects.ProjectReleaseLinkManager`
+ :attr:`gitlab.v4.objects.ProjectRelease.links`

* Gitlab API: https://docs.gitlab.com/ee/api/releases/links.html

Examples
--------

Get a list of releases from a project::

links = release.links.list()

Get a single release link::

link = release.links.get(1)

Create a release link for a release::

link = release.links.create({"url": "https://example.com/asset", "name": "asset"})

Delete a release link::

# via its ID from release attributes
release.links.delete(1)

# delete object directly
link.delete()
10 changes: 10 additions & 0 deletions gitlab/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ def default_config(tmpdir):
return str(config_path)


@pytest.fixture
def tag_name():
return "v1.0.0"


@pytest.fixture
def group(gl):
return gl.groups.get(1, lazy=True)
Expand All @@ -47,6 +52,11 @@ def project(gl):
return gl.projects.get(1, lazy=True)


@pytest.fixture
def release(project, tag_name):
return project.releases.get(tag_name, lazy=True)


@pytest.fixture
def user(gl):
return gl.users.get(1, lazy=True)
131 changes: 131 additions & 0 deletions gitlab/tests/objects/test_releases.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
"""
GitLab API:
https://docs.gitlab.com/ee/api/releases/index.html
https://docs.gitlab.com/ee/api/releases/links.html
"""
import re

import pytest
import responses

from gitlab.v4.objects import ProjectReleaseLink

encoded_tag_name = "v1%2E0%2E0"
link_name = "hello-world"
link_url = "https://gitlab.example.com/group/hello/-/jobs/688/artifacts/raw/bin/hello-darwin-amd64"
direct_url = f"https://gitlab.example.com/group/hello/-/releases/{encoded_tag_name}/downloads/hello-world"
new_link_type = "package"
link_content = {
"id": 2,
"name": link_name,
"url": link_url,
"direct_asset_url": direct_url,
"external": False,
"link_type": "other",
}

links_url = re.compile(
rf"http://localhost/api/v4/projects/1/releases/{encoded_tag_name}/assets/links"
)
link_id_url = re.compile(
rf"http://localhost/api/v4/projects/1/releases/{encoded_tag_name}/assets/links/1"
)


@pytest.fixture
def resp_list_links():
with responses.RequestsMock() as rsps:
rsps.add(
method=responses.GET,
url=links_url,
json=[link_content],
content_type="application/json",
status=200,
)
yield rsps


@pytest.fixture
def resp_get_link():
with responses.RequestsMock() as rsps:
rsps.add(
method=responses.GET,
url=link_id_url,
json=link_content,
content_type="application/json",
status=200,
)
yield rsps


@pytest.fixture
def resp_create_link():
with responses.RequestsMock() as rsps:
rsps.add(
method=responses.POST,
url=links_url,
json=link_content,
content_type="application/json",
status=200,
)
yield rsps


@pytest.fixture
def resp_update_link():
updated_content = dict(link_content)
updated_content["link_type"] = new_link_type

with responses.RequestsMock() as rsps:
rsps.add(
method=responses.PUT,
url=link_id_url,
json=updated_content,
content_type="application/json",
status=200,
)
yield rsps


@pytest.fixture
def resp_delete_link(no_content):
with responses.RequestsMock() as rsps:
rsps.add(
method=responses.DELETE,
url=link_id_url,
json=link_content,
content_type="application/json",
status=204,
)
yield rsps


def test_list_release_links(release, resp_list_links):
links = release.links.list()
assert isinstance(links, list)
assert isinstance(links[0], ProjectReleaseLink)
assert links[0].url == link_url


def test_get_release_link(release, resp_get_link):
link = release.links.get(1)
assert isinstance(link, ProjectReleaseLink)
assert link.url == link_url


def test_create_release_link(release, resp_create_link):
link = release.links.create({"url": link_url, "name": link_name})
assert isinstance(link, ProjectReleaseLink)
assert link.url == link_url


def test_update_release_link(release, resp_update_link):
link = release.links.get(1, lazy=True)
link.link_type = new_link_type
link.save()
assert link.link_type == new_link_type


def test_delete_release_link(release, resp_delete_link):
link = release.links.get(1, lazy=True)
link.delete()
1 change: 1 addition & 0 deletions gitlab/v4/objects/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
from .pipelines import *
from .projects import *
from .push_rules import *
from .releases import *
from .runners import *
from .services import *
from .settings import *
Expand Down
5 changes: 3 additions & 2 deletions gitlab/v4/objects/projects.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,15 @@
from .pages import ProjectPagesDomainManager
from .pipelines import ProjectPipelineManager, ProjectPipelineScheduleManager
from .push_rules import ProjectPushRulesManager
from .releases import ProjectReleaseManager
from .runners import ProjectRunnerManager
from .services import ProjectServiceManager
from .snippets import ProjectSnippetManager
from .statistics import (
ProjectAdditionalStatisticsManager,
ProjectIssuesStatisticsManager,
)
from .tags import ProjectProtectedTagManager, ProjectReleaseManager, ProjectTagManager
from .tags import ProjectProtectedTagManager, ProjectTagManager
from .triggers import ProjectTriggerManager
from .users import ProjectUserManager
from .variables import ProjectVariableManager
Expand Down Expand Up @@ -86,7 +87,7 @@ class GroupProjectManager(ListMixin, RESTManager):
)


class Project(SaveMixin, ObjectDeleteMixin, RESTObject):
class Project(RefreshMixin, SaveMixin, ObjectDeleteMixin, RESTObject):
_short_print_attr = "path"
_managers = (
("accessrequests", "ProjectAccessRequestManager"),
Expand Down
36 changes: 36 additions & 0 deletions gitlab/v4/objects/releases.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from gitlab import cli
from gitlab import exceptions as exc
from gitlab.base import * # noqa
from gitlab.mixins import * # noqa


__all__ = [
"ProjectRelease",
"ProjectReleaseManager",
"ProjectReleaseLink",
"ProjectReleaseLinkManager",
]


class ProjectRelease(RESTObject):
_id_attr = "tag_name"
_managers = (("links", "ProjectReleaseLinkManager"),)


class ProjectReleaseManager(NoUpdateMixin, RESTManager):
_path = "/projects/%(project_id)s/releases"
_obj_cls = ProjectRelease
_from_parent_attrs = {"project_id": "id"}
_create_attrs = (("name", "tag_name", "description"), ("ref", "assets"))


class ProjectReleaseLink(RESTObject, ObjectDeleteMixin, SaveMixin):
pass


class ProjectReleaseLinkManager(CRUDMixin, RESTManager):
_path = "/projects/%(project_id)s/releases/%(tag_name)s/assets/links"
_obj_cls = ProjectReleaseLink
_from_parent_attrs = {"project_id": "project_id", "tag_name": "tag_name"}
_create_attrs = (("name", "url"), ("filepath", "link_type"))
_update_attrs = ((), ("name", "url", "filepath", "link_type"))
13 changes: 0 additions & 13 deletions gitlab/v4/objects/tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
"ProjectTagManager",
"ProjectProtectedTag",
"ProjectProtectedTagManager",
"ProjectRelease",
"ProjectReleaseManager",
]


Expand Down Expand Up @@ -71,14 +69,3 @@ class ProjectProtectedTagManager(NoUpdateMixin, RESTManager):
_obj_cls = ProjectProtectedTag
_from_parent_attrs = {"project_id": "id"}
_create_attrs = (("name",), ("create_access_level",))


class ProjectRelease(RESTObject):
_id_attr = "tag_name"


class ProjectReleaseManager(NoUpdateMixin, RESTManager):
_path = "/projects/%(project_id)s/releases"
_obj_cls = ProjectRelease
_from_parent_attrs = {"project_id": "id"}
_create_attrs = (("name", "tag_name", "description"), ("ref", "assets"))
Loading