From b213dd379a4108ab32181b9d3700d2526d950916 Mon Sep 17 00:00:00 2001 From: "John L. Villalovos" Date: Mon, 4 Jul 2022 23:21:31 -0700 Subject: [PATCH] feat(objects): add Project CI Lint support Add support for validating a project's CI configuration [1] [1] https://docs.gitlab.com/ee/api/lint.html --- docs/gl_objects/projects.rst | 43 +++++++++++++++++++++++++++ gitlab/v4/objects/projects.py | 23 +++++++++++++++ tests/unit/objects/test_projects.py | 46 +++++++++++++++++++++++++++++ 3 files changed, 112 insertions(+) diff --git a/docs/gl_objects/projects.rst b/docs/gl_objects/projects.rst index b5a5d66ab..4c67e41c6 100644 --- a/docs/gl_objects/projects.rst +++ b/docs/gl_objects/projects.rst @@ -819,6 +819,49 @@ 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 ============================= diff --git a/gitlab/v4/objects/projects.py b/gitlab/v4/objects/projects.py index e912a280f..367ab6892 100644 --- a/gitlab/v4/objects/projects.py +++ b/gitlab/v4/objects/projects.py @@ -1,3 +1,8 @@ +""" +GitLab API: +https://docs.gitlab.com/ee/api/projects.html +https://docs.gitlab.com/ee/api/lint.html +""" from typing import ( Any, Callable, @@ -97,6 +102,8 @@ "ProjectRemoteMirrorManager", "ProjectStorage", "ProjectStorageManager", + "ProjectCiLint", + "ProjectCiLintManager", ] @@ -158,6 +165,7 @@ class Project(RefreshMixin, SaveMixin, ObjectDeleteMixin, RepositoryMixin, RESTO badges: ProjectBadgeManager boards: ProjectBoardManager branches: ProjectBranchManager + ci_lint: "ProjectCiLintManager" clusters: ProjectClusterManager commits: ProjectCommitManager customattributes: ProjectCustomAttributeManager @@ -1055,3 +1063,18 @@ 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_projects.py b/tests/unit/objects/test_projects.py index 85bae8600..4db88356a 100644 --- a/tests/unit/objects/test_projects.py +++ b/tests/unit/objects/test_projects.py @@ -82,6 +82,12 @@ "status": "created", "source": "trigger", } +ci_lint_get_content = { + "valid": True, + "merged_yaml": "---\n:test_job:\n :script: echo 1\n", + "errors": [], + "warnings": [], +} @pytest.fixture @@ -541,6 +547,32 @@ 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) @@ -756,3 +788,17 @@ 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 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