diff --git a/docs/cli-examples.rst b/docs/cli-examples.rst index 2ed1c5804..4c7182c41 100644 --- a/docs/cli-examples.rst +++ b/docs/cli-examples.rst @@ -322,6 +322,12 @@ Download the artifacts zip archive of a job: $ gitlab project-job artifacts --id 10 --project-id 1 > artifacts.zip +Download one file from a job's artifacts using its path within the archive: + +.. code-block:: console + + $ gitlab project-job artifact --id 10 --project-id 1 --path reports/result.xml > result.xml + Runners ------- diff --git a/gitlab/v4/objects/jobs.py b/gitlab/v4/objects/jobs.py index f0062c989..a5244e014 100644 --- a/gitlab/v4/objects/jobs.py +++ b/gitlab/v4/objects/jobs.py @@ -224,7 +224,7 @@ def artifact( **kwargs: Any, ) -> None: ... - @cli.register_custom_action(cls_names="ProjectJob") + @cli.register_custom_action(cls_names="ProjectJob", required=("path",)) @exc.on_http_error(exc.GitlabGetError) def artifact( self, diff --git a/tests/unit/test_cli.py b/tests/unit/test_cli.py index cad27afba..f4a073609 100644 --- a/tests/unit/test_cli.py +++ b/tests/unit/test_cli.py @@ -6,6 +6,7 @@ from unittest import mock import pytest +import responses import gitlab.base from gitlab import cli @@ -13,6 +14,7 @@ from gitlab.mixins import CreateMixin, UpdateMixin from gitlab.types import RequiredOptional from gitlab.v4 import cli as v4_cli +from gitlab.v4.objects import ProjectJobManager @pytest.mark.parametrize( @@ -119,6 +121,40 @@ def test_v4_parse_args(): assert args.resource_action == "list" +@pytest.mark.parametrize( + "path", ["result.bin", "reports/result.bin", "reports/a file.bin"] +) +@responses.activate +def test_project_job_artifact_cli_passes_required_path( + gl: gitlab.Gitlab, path: str +) -> None: + args = cli._get_parser().parse_args( + ["project-job", "artifact", "--project-id", "1", "--id", "2", "--path", path] + ) + payload = b"artifact\x00\xff" + url = f"http://localhost/api/v4/projects/1/jobs/2/artifacts/{path}" + responses.add(responses.GET, url, body=payload) + + with mock.patch.object(ProjectJobManager, "_path", ProjectJobManager._path): + result = v4_cli.GitlabCLI( + gl, + args.gitlab_resource, + args.resource_action, + {"project_id": args.project_id, "id": args.id, "path": args.path}, + ).run() + + assert result == payload + assert len(responses.calls) == 1 + + +def test_project_job_artifact_cli_requires_path() -> None: + with pytest.raises(SystemExit) as error: + cli._get_parser().parse_args( + ["project-job", "artifact", "--project-id", "1", "--id", "2"] + ) + assert error.value.code == 2 + + def test_v4_parser(): parser = cli._get_parser() subparsers = next(