From 40539a94ddec3775301dd36df4dc0f43edfd8b6a Mon Sep 17 00:00:00 2001 From: Nejc Habjan Date: Tue, 5 Jul 2022 11:48:55 +0200 Subject: [PATCH 1/4] refactor(objects): move ci lint to separate file --- gitlab/v4/objects/__init__.py | 1 + gitlab/v4/objects/ci_lint.py | 22 +++++++++++++ gitlab/v4/objects/projects.py | 17 +--------- tests/unit/objects/test_ci_lint.py | 49 +++++++++++++++++++++++++++++ tests/unit/objects/test_projects.py | 46 --------------------------- 5 files changed, 73 insertions(+), 62 deletions(-) create mode 100644 gitlab/v4/objects/ci_lint.py create mode 100644 tests/unit/objects/test_ci_lint.py diff --git a/gitlab/v4/objects/__init__.py b/gitlab/v4/objects/__init__.py index 40f9bf3fb..a390a4d5e 100644 --- a/gitlab/v4/objects/__init__.py +++ b/gitlab/v4/objects/__init__.py @@ -25,6 +25,7 @@ from .boards import * from .branches import * from .broadcast_messages import * +from .ci_lint import * from .clusters import * from .commits import * from .container_registry import * diff --git a/gitlab/v4/objects/ci_lint.py b/gitlab/v4/objects/ci_lint.py new file mode 100644 index 000000000..3d5d488f5 --- /dev/null +++ b/gitlab/v4/objects/ci_lint.py @@ -0,0 +1,22 @@ +""" +GitLab API: +https://docs.gitlab.com/ee/api/lint.html +""" + +from typing import Any, cast + +from gitlab.base import RESTManager, RESTObject +from gitlab.mixins import CreateMixin, GetWithoutIdMixin + + +class ProjectCiLint(RESTObject): + pass + + +class ProjectCiLintManager(GetWithoutIdMixin, CreateMixin, RESTManager): + _path = "/projects/{project_id}/ci/lint" + _obj_cls = ProjectCiLint + _from_parent_attrs = {"project_id": "id"} + + def get(self, **kwargs: Any) -> ProjectCiLint: + return cast(ProjectCiLint, super().get(**kwargs)) diff --git a/gitlab/v4/objects/projects.py b/gitlab/v4/objects/projects.py index 367ab6892..9d7262f7b 100644 --- a/gitlab/v4/objects/projects.py +++ b/gitlab/v4/objects/projects.py @@ -1,7 +1,6 @@ """ GitLab API: https://docs.gitlab.com/ee/api/projects.html -https://docs.gitlab.com/ee/api/lint.html """ from typing import ( Any, @@ -39,6 +38,7 @@ from .badges import ProjectBadgeManager # noqa: F401 from .boards import ProjectBoardManager # noqa: F401 from .branches import ProjectBranchManager, ProjectProtectedBranchManager # noqa: F401 +from .ci_lint import ProjectCiLint, ProjectCiLintManager # noqa: F401 from .clusters import ProjectClusterManager # noqa: F401 from .commits import ProjectCommitManager # noqa: F401 from .container_registry import ProjectRegistryRepositoryManager # noqa: F401 @@ -1063,18 +1063,3 @@ class ProjectStorageManager(GetWithoutIdMixin, RESTManager): def get(self, **kwargs: Any) -> ProjectStorage: return cast(ProjectStorage, super().get(**kwargs)) - - -class ProjectCiLint(RESTObject): - pass - - -class ProjectCiLintManager(GetWithoutIdMixin, CreateMixin, RESTManager): - """GitLab API: https://docs.gitlab.com/ee/api/lint.html""" - - _path = "/projects/{project_id}/ci/lint" - _obj_cls = ProjectCiLint - _from_parent_attrs = {"project_id": "id"} - - def get(self, **kwargs: Any) -> ProjectCiLint: - return cast(ProjectCiLint, super().get(**kwargs)) diff --git a/tests/unit/objects/test_ci_lint.py b/tests/unit/objects/test_ci_lint.py new file mode 100644 index 000000000..65911980a --- /dev/null +++ b/tests/unit/objects/test_ci_lint.py @@ -0,0 +1,49 @@ +import pytest +import responses + +ci_lint_get_content = { + "valid": True, + "merged_yaml": "---\n:test_job:\n :script: echo 1\n", + "errors": [], + "warnings": [], +} + + +@pytest.fixture +def resp_get_ci_lint(): + with responses.RequestsMock() as rsps: + rsps.add( + method=responses.GET, + url="http://localhost/api/v4/projects/1/ci/lint", + json=ci_lint_get_content, + content_type="application/json", + status=200, + ) + yield rsps + + +@pytest.fixture +def resp_create_ci_lint(): + with responses.RequestsMock() as rsps: + rsps.add( + method=responses.POST, + url="http://localhost/api/v4/projects/1/ci/lint", + json=ci_lint_get_content, + content_type="application/json", + status=200, + ) + yield rsps + + +def test_project_ci_lint_get(project, resp_get_ci_lint): + lint_result = project.ci_lint.get() + assert lint_result.valid is True + + +def test_project_ci_lint_create(project, resp_create_ci_lint): + gitlab_ci_yml = """--- +:test_job: + :script: echo 1 +""" + lint_result = project.ci_lint.create({"content": gitlab_ci_yml}) + assert lint_result.valid is True diff --git a/tests/unit/objects/test_projects.py b/tests/unit/objects/test_projects.py index 4db88356a..85bae8600 100644 --- a/tests/unit/objects/test_projects.py +++ b/tests/unit/objects/test_projects.py @@ -82,12 +82,6 @@ "status": "created", "source": "trigger", } -ci_lint_get_content = { - "valid": True, - "merged_yaml": "---\n:test_job:\n :script: echo 1\n", - "errors": [], - "warnings": [], -} @pytest.fixture @@ -547,32 +541,6 @@ def resp_artifact(): yield rsps -@pytest.fixture -def resp_get_ci_lint(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.GET, - url="http://localhost/api/v4/projects/1/ci/lint", - json=ci_lint_get_content, - content_type="application/json", - status=200, - ) - yield rsps - - -@pytest.fixture -def resp_create_ci_lint(): - with responses.RequestsMock() as rsps: - rsps.add( - method=responses.POST, - url="http://localhost/api/v4/projects/1/ci/lint", - json=ci_lint_get_content, - content_type="application/json", - status=200, - ) - yield rsps - - def test_get_project(gl, resp_get_project): data = gl.projects.get(1) assert isinstance(data, Project) @@ -788,17 +756,3 @@ def test_project_pull_mirror(project, resp_start_pull_mirroring_project): def test_project_snapshot(project, resp_snapshot_project): tar_file = project.snapshot() assert isinstance(tar_file, bytes) - - -def test_project_ci_lint_get(project, resp_get_ci_lint): - lint_result = project.ci_lint.get() - assert lint_result.valid is True - - -def test_project_ci_lint_create(project, resp_create_ci_lint): - gitlab_ci_yml = """--- -:test_job: - :script: echo 1 -""" - lint_result = project.ci_lint.create({"content": gitlab_ci_yml}) - assert lint_result.valid is True From 47bfd769e9cbe9ee71f5dba36089aae0ca6eda8d Mon Sep 17 00:00:00 2001 From: Nejc Habjan Date: Tue, 5 Jul 2022 11:51:56 +0200 Subject: [PATCH 2/4] chore(ci_lint): add create attributes --- gitlab/v4/objects/ci_lint.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gitlab/v4/objects/ci_lint.py b/gitlab/v4/objects/ci_lint.py index 3d5d488f5..4f781dcac 100644 --- a/gitlab/v4/objects/ci_lint.py +++ b/gitlab/v4/objects/ci_lint.py @@ -7,6 +7,7 @@ from gitlab.base import RESTManager, RESTObject from gitlab.mixins import CreateMixin, GetWithoutIdMixin +from gitlab.types import RequiredOptional class ProjectCiLint(RESTObject): @@ -17,6 +18,9 @@ class ProjectCiLintManager(GetWithoutIdMixin, CreateMixin, RESTManager): _path = "/projects/{project_id}/ci/lint" _obj_cls = ProjectCiLint _from_parent_attrs = {"project_id": "id"} + _create_attrs = RequiredOptional( + required=("content",), optional=("dry_run", "include_jobs", "ref") + ) def get(self, **kwargs: Any) -> ProjectCiLint: return cast(ProjectCiLint, super().get(**kwargs)) From 2eb6d7e38360cc578e493d5e0bdfdde9a7488454 Mon Sep 17 00:00:00 2001 From: Nejc Habjan Date: Tue, 5 Jul 2022 12:17:04 +0200 Subject: [PATCH 3/4] feat(cli): add support for global CI lint --- gitlab/client.py | 7 +++++ gitlab/v4/objects/ci_lint.py | 19 +++++++++++++ gitlab/v4/objects/projects.py | 6 ++-- tests/unit/objects/test_ci_lint.py | 44 ++++++++++++++++++++++-------- 4 files changed, 61 insertions(+), 15 deletions(-) diff --git a/gitlab/client.py b/gitlab/client.py index 82eebbc7d..54409c3cd 100644 --- a/gitlab/client.py +++ b/gitlab/client.py @@ -126,6 +126,8 @@ def __init__( self.broadcastmessages = objects.BroadcastMessageManager(self) """See :class:`~gitlab.v4.objects.BroadcastMessageManager`""" + self.ci_lint = objects.CiLintManager(self) + """See :class:`~gitlab.v4.objects.CiLintManager`""" self.deploykeys = objects.DeployKeyManager(self) """See :class:`~gitlab.v4.objects.DeployKeyManager`""" self.deploytokens = objects.DeployTokenManager(self) @@ -397,6 +399,11 @@ def lint(self, content: str, **kwargs: Any) -> Tuple[bool, List[str]]: Returns: (True, []) if the file is valid, (False, errors(list)) otherwise """ + utils.warn( + "`lint()` is deprecated and will be removed in a future version.\n" + "Please use `ci_lint.create()` instead.", + category=DeprecationWarning, + ) post_data = {"content": content} data = self.http_post("/ci/lint", post_data=post_data, **kwargs) if TYPE_CHECKING: diff --git a/gitlab/v4/objects/ci_lint.py b/gitlab/v4/objects/ci_lint.py index 4f781dcac..73f9d4d9d 100644 --- a/gitlab/v4/objects/ci_lint.py +++ b/gitlab/v4/objects/ci_lint.py @@ -9,6 +9,25 @@ from gitlab.mixins import CreateMixin, GetWithoutIdMixin from gitlab.types import RequiredOptional +__all__ = [ + "CiLint", + "CiLintManager", + "ProjectCiLint", + "ProjectCiLintManager", +] + + +class CiLint(RESTObject): + _id_attr = None + + +class CiLintManager(CreateMixin, RESTManager): + _path = "/ci/lint" + _obj_cls = CiLint + _create_attrs = RequiredOptional( + required=("content",), optional=("include_merged_yaml", "include_jobs") + ) + class ProjectCiLint(RESTObject): pass diff --git a/gitlab/v4/objects/projects.py b/gitlab/v4/objects/projects.py index 9d7262f7b..ab3fb2052 100644 --- a/gitlab/v4/objects/projects.py +++ b/gitlab/v4/objects/projects.py @@ -38,7 +38,7 @@ from .badges import ProjectBadgeManager # noqa: F401 from .boards import ProjectBoardManager # noqa: F401 from .branches import ProjectBranchManager, ProjectProtectedBranchManager # noqa: F401 -from .ci_lint import ProjectCiLint, ProjectCiLintManager # noqa: F401 +from .ci_lint import ProjectCiLintManager # noqa: F401 from .clusters import ProjectClusterManager # noqa: F401 from .commits import ProjectCommitManager # noqa: F401 from .container_registry import ProjectRegistryRepositoryManager # noqa: F401 @@ -102,8 +102,6 @@ "ProjectRemoteMirrorManager", "ProjectStorage", "ProjectStorageManager", - "ProjectCiLint", - "ProjectCiLintManager", ] @@ -165,7 +163,7 @@ class Project(RefreshMixin, SaveMixin, ObjectDeleteMixin, RepositoryMixin, RESTO badges: ProjectBadgeManager boards: ProjectBoardManager branches: ProjectBranchManager - ci_lint: "ProjectCiLintManager" + ci_lint: ProjectCiLintManager clusters: ProjectClusterManager commits: ProjectCommitManager customattributes: ProjectCustomAttributeManager diff --git a/tests/unit/objects/test_ci_lint.py b/tests/unit/objects/test_ci_lint.py index 65911980a..509a5ed1b 100644 --- a/tests/unit/objects/test_ci_lint.py +++ b/tests/unit/objects/test_ci_lint.py @@ -1,7 +1,15 @@ import pytest import responses -ci_lint_get_content = { +gitlab_ci_yml = """--- +:test_job: + :script: echo 1 +""" + +ci_lint_create_content = {"status": "valid", "errors": [], "warnings": []} + + +project_ci_lint_content = { "valid": True, "merged_yaml": "---\n:test_job:\n :script: echo 1\n", "errors": [], @@ -10,12 +18,25 @@ @pytest.fixture -def resp_get_ci_lint(): +def resp_create_ci_lint(): + with responses.RequestsMock() as rsps: + rsps.add( + method=responses.POST, + url="http://localhost/api/v4/ci/lint", + json=ci_lint_create_content, + content_type="application/json", + status=200, + ) + yield rsps + + +@pytest.fixture +def resp_get_project_ci_lint(): with responses.RequestsMock() as rsps: rsps.add( method=responses.GET, url="http://localhost/api/v4/projects/1/ci/lint", - json=ci_lint_get_content, + json=project_ci_lint_content, content_type="application/json", status=200, ) @@ -23,27 +44,28 @@ def resp_get_ci_lint(): @pytest.fixture -def resp_create_ci_lint(): +def resp_create_project_ci_lint(): with responses.RequestsMock() as rsps: rsps.add( method=responses.POST, url="http://localhost/api/v4/projects/1/ci/lint", - json=ci_lint_get_content, + json=project_ci_lint_content, content_type="application/json", status=200, ) yield rsps -def test_project_ci_lint_get(project, resp_get_ci_lint): +def test_ci_lint_create(gl, resp_create_ci_lint): + lint_result = gl.ci_lint.create({"content": gitlab_ci_yml}) + assert lint_result.status == "valid" + + +def test_project_ci_lint_get(project, resp_get_project_ci_lint): lint_result = project.ci_lint.get() assert lint_result.valid is True -def test_project_ci_lint_create(project, resp_create_ci_lint): - gitlab_ci_yml = """--- -:test_job: - :script: echo 1 -""" +def test_project_ci_lint_create(project, resp_create_project_ci_lint): lint_result = project.ci_lint.create({"content": gitlab_ci_yml}) assert lint_result.valid is True From 45e99eb8c86303791e6a78468abc364f6911a8f5 Mon Sep 17 00:00:00 2001 From: Nejc Habjan Date: Tue, 5 Jul 2022 14:14:40 +0200 Subject: [PATCH 4/4] docs: document CI Lint usage --- docs/api-objects.rst | 1 + docs/cli-examples.rst | 42 ++++++++++++++++++++++++++++ docs/cli-usage.rst | 2 ++ docs/gl_objects/ci_lint.rst | 53 ++++++++++++++++++++++++++++++++++++ docs/gl_objects/projects.rst | 43 ----------------------------- 5 files changed, 98 insertions(+), 43 deletions(-) create mode 100644 docs/gl_objects/ci_lint.rst diff --git a/docs/api-objects.rst b/docs/api-objects.rst index e313bd8e8..a4e852be9 100644 --- a/docs/api-objects.rst +++ b/docs/api-objects.rst @@ -13,6 +13,7 @@ API examples gl_objects/branches gl_objects/clusters gl_objects/messages + gl_objects/ci_lint gl_objects/commits gl_objects/deploy_keys gl_objects/deploy_tokens diff --git a/docs/cli-examples.rst b/docs/cli-examples.rst index 5f4e0bca9..7f21f0308 100644 --- a/docs/cli-examples.rst +++ b/docs/cli-examples.rst @@ -6,6 +6,48 @@ CLI examples For a complete list of objects and actions available, see :doc:`/cli-objects`. +CI Lint +------- + +Lint a CI YAML configuration from a string: + +.. note:: + + To see output, you will need to use the ``-v``/``--verbose`` flag. + +.. code-block:: console + + $ gitlab --verbose ci-lint create --content \ + "--- + test: + script: + - echo hello + " + +Lint a CI YAML configuration from a file (see :ref:`cli_from_files`): + +.. code-block:: console + + $ gitlab --verbose ci-lint create --content @.gitlab-ci.yml + +Lint a project's CI YAML configuration: + +.. code-block:: console + + $ gitlab --verbose project-ci-lint create --project-id group/my-project --content @.gitlab-ci.yml + +Lint a project's current CI YAML configuration: + +.. code-block:: console + + $ gitlab --verbose project-ci-lint get --project-id group/my-project + +Lint a project's current CI YAML configuration on a specific branch: + +.. code-block:: console + + $ gitlab --verbose project-ci-lint get --project-id group/my-project --ref my-branch + Projects -------- diff --git a/docs/cli-usage.rst b/docs/cli-usage.rst index 6546f6674..5091ccba1 100644 --- a/docs/cli-usage.rst +++ b/docs/cli-usage.rst @@ -288,6 +288,8 @@ Example: $ gitlab -o yaml -f id,permissions -g elsewhere -c /tmp/gl.cfg project list +.. _cli_from_files: + Reading values from files ------------------------- diff --git a/docs/gl_objects/ci_lint.rst b/docs/gl_objects/ci_lint.rst new file mode 100644 index 000000000..6533db310 --- /dev/null +++ b/docs/gl_objects/ci_lint.rst @@ -0,0 +1,53 @@ +####### +CI Lint +####### + +Reference +--------- + +* v4 API: + + + :class:`gitlab.v4.objects.CiLint` + + :class:`gitlab.v4.objects.CiLintManager` + + :attr:`gitlab.Gitlab.ci_lint` + + :class:`gitlab.v4.objects.ProjectCiLint` + + :class:`gitlab.v4.objects.ProjectCiLintManager` + + :attr:`gitlab.v4.objects.Project.ci_lint` + +* GitLab API: https://docs.gitlab.com/ee/api/lint.html + +Examples +--------- + +Validate a CI YAML configuration:: + + gitlab_ci_yml = """.api_test: + rules: + - if: $CI_PIPELINE_SOURCE=="merge_request_event" + changes: + - src/api/* + deploy: + extends: + - .api_test + rules: + - when: manual + allow_failure: true + script: + - echo "hello world" + """ + lint_result = gl.ci_lint.create({"content": gitlab_ci_yml}) + + print(lint_result.status) # Print the status of the CI YAML + print(lint_result.merged_yaml) # Print the merged YAML file + +Validate a project's CI configuration:: + + lint_result = project.ci_lint.get() + assert lint_result.valid is True # Test that the .gitlab-ci.yml is valid + print(lint_result.merged_yaml) # Print the merged YAML file + +Validate a CI YAML configuration with a namespace:: + + lint_result = project.ci_lint.create({"content": gitlab_ci_yml}) + assert lint_result.valid is True # Test that the .gitlab-ci.yml is valid + print(lint_result.merged_yaml) # Print the merged YAML file diff --git a/docs/gl_objects/projects.rst b/docs/gl_objects/projects.rst index a6ed0e638..82ec77f52 100644 --- a/docs/gl_objects/projects.rst +++ b/docs/gl_objects/projects.rst @@ -819,49 +819,6 @@ Get total fetches in last 30 days of a project:: total_fetches = project.additionalstatistics.get().fetches['total'] -Project CI Lint -============================= - -Reference ---------- - -* v4 API: - - + :class:`gitlab.v4.objects.ProjectCiLint` - + :class:`gitlab.v4.objects.ProjectCiLintManager` - + :attr:`gitlab.v4.objects.Project.ci_lint` - -* GitLab API: https://docs.gitlab.com/ee/api/lint.html - -Examples ---------- - -Validate a project's CI configuration:: - - lint_result = project.ci_lint.get() - assert lint_result.valid is True # Test that the .gitlab-ci.yml is valid - print(lint_result.merged_yaml) # Print the merged YAML file - -Validate a CI YAML configuration with a namespace:: - - gitlab_ci_yml = """.api_test: - rules: - - if: $CI_PIPELINE_SOURCE=="merge_request_event" - changes: - - src/api/* - deploy: - extends: - - .api_test - rules: - - when: manual - allow_failure: true - script: - - echo "hello world" - """ - lint_result = project.ci_lint.create({"content": gitlab_ci_yml}) - assert lint_result.valid is True # Test that the .gitlab-ci.yml is valid - print(lint_result.merged_yaml) # Print the merged YAML file - Project storage ============================= 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