diff --git a/docs/gl_objects/pipelines_and_jobs.rst b/docs/gl_objects/pipelines_and_jobs.rst index 7faf6579d..eb9e23a00 100644 --- a/docs/gl_objects/pipelines_and_jobs.rst +++ b/docs/gl_objects/pipelines_and_jobs.rst @@ -292,6 +292,11 @@ Get the artifacts of a job:: build_or_job.artifacts() +Get the artifacts of a job by its name from the latest successful pipeline of +a branch or tag: + + project.artifacts(ref_name='master', job='build') + .. warning:: Artifacts are entirely stored in memory in this example. diff --git a/gitlab/tests/objects/test_commits.py b/gitlab/tests/objects/test_commits.py index 9d11508c6..6b9811700 100644 --- a/gitlab/tests/objects/test_commits.py +++ b/gitlab/tests/objects/test_commits.py @@ -88,7 +88,13 @@ def test_create_commit(project, resp_create_commit): data = { "branch": "master", "commit_message": "Commit message", - "actions": [{"action": "create", "file_path": "README", "content": "",}], + "actions": [ + { + "action": "create", + "file_path": "README", + "content": "", + } + ], } commit = project.commits.create(data) assert commit.short_id == "ed899a2f" diff --git a/gitlab/tests/objects/test_job_artifacts.py b/gitlab/tests/objects/test_job_artifacts.py new file mode 100644 index 000000000..c441b4b12 --- /dev/null +++ b/gitlab/tests/objects/test_job_artifacts.py @@ -0,0 +1,31 @@ +""" +GitLab API: https://docs.gitlab.com/ee/api/job_artifacts.html +""" + +import pytest +import responses + + +ref_name = "master" +job = "build" + + +@pytest.fixture +def resp_artifacts_by_ref_name(binary_content): + url = f"http://localhost/api/v4/projects/1/jobs/artifacts/{ref_name}/download?job={job}" + + with responses.RequestsMock() as rsps: + rsps.add( + method=responses.GET, + url=url, + body=binary_content, + content_type="application/octet-stream", + status=200, + ) + yield rsps + + +def test_download_artifacts_by_ref_name(gl, binary_content, resp_artifacts_by_ref_name): + project = gl.projects.get(1, lazy=True) + artifacts = project.artifacts(ref_name=ref_name, job=job) + assert artifacts == binary_content diff --git a/gitlab/tests/objects/test_runners.py b/gitlab/tests/objects/test_runners.py index 490ba36a0..30fdb41b5 100644 --- a/gitlab/tests/objects/test_runners.py +++ b/gitlab/tests/objects/test_runners.py @@ -167,7 +167,9 @@ def resp_runner_delete(): status=200, ) rsps.add( - method=responses.DELETE, url=pattern, status=204, + method=responses.DELETE, + url=pattern, + status=204, ) yield rsps @@ -177,7 +179,9 @@ def resp_runner_disable(): with responses.RequestsMock() as rsps: pattern = re.compile(r".*?/(groups|projects)/1/runners/6") rsps.add( - method=responses.DELETE, url=pattern, status=204, + method=responses.DELETE, + url=pattern, + status=204, ) yield rsps @@ -187,7 +191,9 @@ def resp_runner_verify(): with responses.RequestsMock() as rsps: pattern = re.compile(r".*?/runners/verify") rsps.add( - method=responses.POST, url=pattern, status=200, + method=responses.POST, + url=pattern, + status=200, ) yield rsps diff --git a/gitlab/v4/objects.py b/gitlab/v4/objects.py index 2a3615fa3..528963543 100644 --- a/gitlab/v4/objects.py +++ b/gitlab/v4/objects.py @@ -711,8 +711,14 @@ class ProjectDeployTokenManager(ListMixin, CreateMixin, DeleteMixin, RESTManager _from_parent_attrs = {"project_id": "id"} _obj_cls = ProjectDeployToken _create_attrs = ( - ("name", "scopes",), - ("expires_at", "username",), + ( + "name", + "scopes", + ), + ( + "expires_at", + "username", + ), ) @@ -725,8 +731,14 @@ class GroupDeployTokenManager(ListMixin, CreateMixin, DeleteMixin, RESTManager): _from_parent_attrs = {"group_id": "id"} _obj_cls = GroupDeployToken _create_attrs = ( - ("name", "scopes",), - ("expires_at", "username",), + ( + "name", + "scopes", + ), + ( + "expires_at", + "username", + ), ) @@ -4181,7 +4193,11 @@ class ProjectServiceManager(GetMixin, UpdateMixin, DeleteMixin, ListMixin, RESTM ), ), "jira": ( - ("url", "username", "password",), + ( + "url", + "username", + "password", + ), ( "api_url", "active", @@ -5071,6 +5087,40 @@ def transfer_project(self, to_namespace, **kwargs): path, post_data={"namespace": to_namespace}, **kwargs ) + @cli.register_custom_action("Project", ("ref_name", "job"), ("job_token",)) + @exc.on_http_error(exc.GitlabGetError) + def artifacts( + self, ref_name, job, streamed=False, action=None, chunk_size=1024, **kwargs + ): + """Get the job artifacts archive from a specific tag or branch. + + Args: + ref_name (str): Branch or tag name in repository. HEAD or SHA references + are not supported. + artifact_path (str): Path to a file inside the artifacts archive. + job (str): The name of the job. + job_token (str): Job token for multi-project pipeline triggers. + streamed (bool): If True the data will be processed by chunks of + `chunk_size` and each chunk is passed to `action` for + treatment + action (callable): Callable responsible of dealing with chunk of + data + chunk_size (int): Size of each chunk + **kwargs: Extra options to send to the server (e.g. sudo) + + Raises: + GitlabAuthenticationError: If authentication is not correct + GitlabGetError: If the artifacts could not be retrieved + + Returns: + str: The artifacts if `streamed` is False, None otherwise. + """ + path = "/projects/%s/jobs/artifacts/%s/download" % (self.get_id(), ref_name) + result = self.manager.gitlab.http_get( + path, job=job, streamed=streamed, raw=True, **kwargs + ) + return utils.response_content(result, streamed, action, chunk_size) + @cli.register_custom_action("Project", ("ref_name", "artifact_path", "job")) @exc.on_http_error(exc.GitlabGetError) def artifact( diff --git a/tools/python_test_v4.py b/tools/python_test_v4.py index 6ecaf24b4..8c548bef0 100644 --- a/tools/python_test_v4.py +++ b/tools/python_test_v4.py @@ -701,7 +701,12 @@ # Remove once https://gitlab.com/gitlab-org/gitlab/-/issues/211878 is fixed deploy_token = deploy_token_group.deploytokens.create( - {"name": "foo", "username": "", "expires_at": "", "scopes": ["read_repository"],} + { + "name": "foo", + "username": "", + "expires_at": "", + "scopes": ["read_repository"], + } ) assert len(deploy_token_group.deploytokens.list()) == 1