Skip to content

Commit c8c2fa7

Browse files
nejchJohnVillalovos
authored andcommitted
feat(objects): add a complete artifacts manager
1 parent 0ab0fc1 commit c8c2fa7

File tree

3 files changed

+133
-81
lines changed

3 files changed

+133
-81
lines changed

gitlab/v4/objects/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from .access_requests import *
1919
from .appearance import *
2020
from .applications import *
21+
from .artifacts import *
2122
from .audit_events import *
2223
from .award_emojis import *
2324
from .badges import *

gitlab/v4/objects/artifacts.py

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
"""
2+
GitLab API:
3+
https://docs.gitlab.com/ee/api/job_artifacts.html
4+
"""
5+
import warnings
6+
from typing import Any, Callable, Optional, TYPE_CHECKING
7+
8+
import requests
9+
10+
from gitlab import cli
11+
from gitlab import exceptions as exc
12+
from gitlab import utils
13+
from gitlab.base import RESTManager, RESTObject
14+
15+
__all__ = ["ProjectArtifact", "ProjectArtifactManager"]
16+
17+
18+
class ProjectArtifact(RESTObject):
19+
"""Dummy object to manage custom actions on artifacts"""
20+
_id_attr = "ref_name"
21+
22+
23+
class ProjectArtifactManager(RESTManager):
24+
_obj_cls = ProjectArtifact
25+
_path = "/projects/{project_id}/jobs/artifacts"
26+
_from_parent_attrs = {"project_id": "id"}
27+
28+
@cli.register_custom_action(
29+
"Project", ("ref_name", "job"), ("job_token",), custom_action="artifacts"
30+
)
31+
def __call__(
32+
self,
33+
*args: Any,
34+
**kwargs: Any,
35+
) -> Optional[bytes]:
36+
warnings.warn(
37+
"The project.artifacts() method is deprecated and will be "
38+
"removed in a future version. Use project.artifacts.download() instead.\n",
39+
DeprecationWarning,
40+
)
41+
return self.download(
42+
*args,
43+
**kwargs,
44+
)
45+
46+
@cli.register_custom_action(
47+
"ProjectArtifactManager", ("ref_name", "job"), ("job_token",)
48+
)
49+
@exc.on_http_error(exc.GitlabGetError)
50+
def download(
51+
self,
52+
ref_name: str,
53+
job: str,
54+
streamed: bool = False,
55+
action: Optional[Callable] = None,
56+
chunk_size: int = 1024,
57+
**kwargs: Any,
58+
) -> Optional[bytes]:
59+
"""Get the job artifacts archive from a specific tag or branch.
60+
Args:
61+
ref_name: Branch or tag name in repository. HEAD or SHA references
62+
are not supported.
63+
job: The name of the job.
64+
job_token: Job token for multi-project pipeline triggers.
65+
streamed: If True the data will be processed by chunks of
66+
`chunk_size` and each chunk is passed to `action` for
67+
treatment
68+
action: Callable responsible of dealing with chunk of
69+
data
70+
chunk_size: Size of each chunk
71+
**kwargs: Extra options to send to the server (e.g. sudo)
72+
Raises:
73+
GitlabAuthenticationError: If authentication is not correct
74+
GitlabGetError: If the artifacts could not be retrieved
75+
Returns:
76+
The artifacts if `streamed` is False, None otherwise.
77+
"""
78+
path = f"{self.path}/{ref_name}/download"
79+
result = self.gitlab.http_get(
80+
path, job=job, streamed=streamed, raw=True, **kwargs
81+
)
82+
if TYPE_CHECKING:
83+
assert isinstance(result, requests.Response)
84+
return utils.response_content(result, streamed, action, chunk_size)
85+
86+
@cli.register_custom_action("ProjectArtifactManager", ("ref_name", "artifact_path", "job"))
87+
@exc.on_http_error(exc.GitlabGetError)
88+
def raw(
89+
self,
90+
ref_name: str,
91+
artifact_path: str,
92+
job: str,
93+
streamed: bool = False,
94+
action: Optional[Callable] = None,
95+
chunk_size: int = 1024,
96+
**kwargs: Any,
97+
) -> Optional[bytes]:
98+
"""Download a single artifact file from a specific tag or branch from
99+
within the job's artifacts archive.
100+
Args:
101+
ref_name: Branch or tag name in repository. HEAD or SHA references
102+
are not supported.
103+
artifact_path: Path to a file inside the artifacts archive.
104+
job: The name of the job.
105+
streamed: If True the data will be processed by chunks of
106+
`chunk_size` and each chunk is passed to `action` for
107+
treatment
108+
action: Callable responsible of dealing with chunk of
109+
data
110+
chunk_size: Size of each chunk
111+
**kwargs: Extra options to send to the server (e.g. sudo)
112+
Raises:
113+
GitlabAuthenticationError: If authentication is not correct
114+
GitlabGetError: If the artifacts could not be retrieved
115+
Returns:
116+
The artifact if `streamed` is False, None otherwise.
117+
"""
118+
path = f"{self.path}/{ref_name}/raw/{artifact_path}"
119+
result = self.gitlab.http_get(
120+
path, streamed=streamed, raw=True, job=job, **kwargs
121+
)
122+
if TYPE_CHECKING:
123+
assert isinstance(result, requests.Response)
124+
return utils.response_content(result, streamed, action, chunk_size)

gitlab/v4/objects/projects.py

Lines changed: 8 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
)
1919

2020
from .access_requests import ProjectAccessRequestManager # noqa: F401
21+
from .artifacts import ProjectArtifactManager # noqa: F401
2122
from .audit_events import ProjectAuditEventManager # noqa: F401
2223
from .badges import ProjectBadgeManager # noqa: F401
2324
from .boards import ProjectBoardManager # noqa: F401
@@ -136,6 +137,7 @@ class Project(RefreshMixin, SaveMixin, ObjectDeleteMixin, RepositoryMixin, RESTO
136137
additionalstatistics: ProjectAdditionalStatisticsManager
137138
approvalrules: ProjectApprovalRuleManager
138139
approvals: ProjectApprovalManager
140+
artifacts: ProjectArtifactManager
139141
audit_events: ProjectAuditEventManager
140142
badges: ProjectBadgeManager
141143
boards: ProjectBoardManager
@@ -553,94 +555,19 @@ def transfer_project(self, *args: Any, **kwargs: Any) -> None:
553555
)
554556
return self.transfer(*args, **kwargs)
555557

556-
@cli.register_custom_action("Project", ("ref_name", "job"), ("job_token",))
557-
@exc.on_http_error(exc.GitlabGetError)
558-
def artifacts(
559-
self,
560-
ref_name: str,
561-
job: str,
562-
streamed: bool = False,
563-
action: Optional[Callable] = None,
564-
chunk_size: int = 1024,
565-
**kwargs: Any,
566-
) -> Optional[bytes]:
567-
"""Get the job artifacts archive from a specific tag or branch.
568-
569-
Args:
570-
ref_name: Branch or tag name in repository. HEAD or SHA references
571-
are not supported.
572-
artifact_path: Path to a file inside the artifacts archive.
573-
job: The name of the job.
574-
job_token: Job token for multi-project pipeline triggers.
575-
streamed: If True the data will be processed by chunks of
576-
`chunk_size` and each chunk is passed to `action` for
577-
treatment
578-
action: Callable responsible of dealing with chunk of
579-
data
580-
chunk_size: Size of each chunk
581-
**kwargs: Extra options to send to the server (e.g. sudo)
582-
583-
Raises:
584-
GitlabAuthenticationError: If authentication is not correct
585-
GitlabGetError: If the artifacts could not be retrieved
586-
587-
Returns:
588-
The artifacts if `streamed` is False, None otherwise.
589-
"""
590-
path = f"/projects/{self.encoded_id}/jobs/artifacts/{ref_name}/download"
591-
result = self.manager.gitlab.http_get(
592-
path, job=job, streamed=streamed, raw=True, **kwargs
593-
)
594-
if TYPE_CHECKING:
595-
assert isinstance(result, requests.Response)
596-
return utils.response_content(result, streamed, action, chunk_size)
597-
598558
@cli.register_custom_action("Project", ("ref_name", "artifact_path", "job"))
599559
@exc.on_http_error(exc.GitlabGetError)
600560
def artifact(
601561
self,
602-
ref_name: str,
603-
artifact_path: str,
604-
job: str,
605-
streamed: bool = False,
606-
action: Optional[Callable] = None,
607-
chunk_size: int = 1024,
562+
*args: Any,
608563
**kwargs: Any,
609564
) -> Optional[bytes]:
610-
"""Download a single artifact file from a specific tag or branch from
611-
within the job’s artifacts archive.
612-
613-
Args:
614-
ref_name: Branch or tag name in repository. HEAD or SHA references
615-
are not supported.
616-
artifact_path: Path to a file inside the artifacts archive.
617-
job: The name of the job.
618-
streamed: If True the data will be processed by chunks of
619-
`chunk_size` and each chunk is passed to `action` for
620-
treatment
621-
action: Callable responsible of dealing with chunk of
622-
data
623-
chunk_size: Size of each chunk
624-
**kwargs: Extra options to send to the server (e.g. sudo)
625-
626-
Raises:
627-
GitlabAuthenticationError: If authentication is not correct
628-
GitlabGetError: If the artifacts could not be retrieved
629-
630-
Returns:
631-
The artifacts if `streamed` is False, None otherwise.
632-
"""
633-
634-
path = (
635-
f"/projects/{self.encoded_id}/jobs/artifacts/{ref_name}/raw/"
636-
f"{artifact_path}?job={job}"
637-
)
638-
result = self.manager.gitlab.http_get(
639-
path, streamed=streamed, raw=True, **kwargs
565+
warnings.warn(
566+
"The project.artifact() method is deprecated and will be "
567+
"removed in a future version. Use project.artifacts.raw() instead.",
568+
DeprecationWarning,
640569
)
641-
if TYPE_CHECKING:
642-
assert isinstance(result, requests.Response)
643-
return utils.response_content(result, streamed, action, chunk_size)
570+
return self.artifacts.raw(*args, **kwargs)
644571

645572

646573
class ProjectManager(CRUDMixin, RESTManager):

0 commit comments

Comments
 (0)