Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit3b1ede4

Browse files
nejchJohnVillalovos
authored andcommitted
feat: support validating CI lint results
1 parent0daec5f commit3b1ede4

File tree

8 files changed

+184
-12
lines changed

8 files changed

+184
-12
lines changed

‎docs/cli-examples.rst‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ Lint a CI YAML configuration from a string:
1515

1616
To see output, you will need to use the ``-v``/``--verbose`` flag.
1717

18+
To exit with non-zero on YAML lint failures instead, use the ``validate``
19+
subcommand shown below.
20+
1821
..code-block::console
1922
2023
$ gitlab --verbose ci-lint create --content \
@@ -30,12 +33,24 @@ Lint a CI YAML configuration from a file (see :ref:`cli_from_files`):
3033
3134
$ gitlab --verbose ci-lint create --content @.gitlab-ci.yml
3235
36+
Validate a CI YAML configuration from a file (lints and exits with non-zero on failure):
37+
38+
..code-block::console
39+
40+
$ gitlab ci-lint validate --content @.gitlab-ci.yml
41+
3342
Lint a project's CI YAML configuration:
3443

3544
..code-block::console
3645
3746
$ gitlab --verbose project-ci-lint create --project-id group/my-project --content @.gitlab-ci.yml
3847
48+
Validate a project's CI YAML configuration (lints and exits with non-zero on failure):
49+
50+
..code-block::console
51+
52+
$ gitlab project-ci-lint validate --project-id group/my-project --content @.gitlab-ci.yml
53+
3954
Lint a project's current CI YAML configuration:
4055

4156
..code-block::console

‎docs/gl_objects/ci_lint.rst‎

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ Reference
1919
Examples
2020
---------
2121

22-
Validate a CI YAML configuration::
22+
Lint a CI YAML configuration::
2323

2424
gitlab_ci_yml = """.api_test:
2525
rules:
@@ -40,14 +40,30 @@ Validate a CI YAML configuration::
4040
print(lint_result.status) # Print the status of the CI YAML
4141
print(lint_result.merged_yaml) # Print the merged YAML file
4242

43-
Validate a project's CI configuration::
43+
Lint a project's CI configuration::
4444

4545
lint_result = project.ci_lint.get()
4646
assert lint_result.valid is True # Test that the .gitlab-ci.yml is valid
4747
print(lint_result.merged_yaml) # Print the merged YAML file
4848

49-
Validate a CI YAML configuration with a namespace::
49+
Lint a CI YAML configuration with a namespace::
5050

5151
lint_result = project.ci_lint.create({"content": gitlab_ci_yml})
5252
assert lint_result.valid is True # Test that the .gitlab-ci.yml is valid
5353
print(lint_result.merged_yaml) # Print the merged YAML file
54+
55+
Validate a CI YAML configuration (raises ``GitlabCiLintError`` on failures)::
56+
57+
# returns None
58+
gl.ci_lint.validate({"content": gitlab_ci_yml})
59+
60+
# raises GitlabCiLintError
61+
gl.ci_lint.validate({"content": "invalid"})
62+
63+
Validate a CI YAML configuration with a namespace::
64+
65+
# returns None
66+
project.ci_lint.validate({"content": gitlab_ci_yml})
67+
68+
# raises GitlabCiLintError
69+
project.ci_lint.validate({"content": "invalid"})

‎gitlab/exceptions.py‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ class GitlabParsingError(GitlabError):
6262
pass
6363

6464

65+
classGitlabCiLintError(GitlabError):
66+
pass
67+
68+
6569
classGitlabConnectionError(GitlabError):
6670
pass
6771

‎gitlab/v4/cli.py‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
importgitlab.base
2626
importgitlab.v4.objects
2727
fromgitlabimportcli
28+
fromgitlab.exceptionsimportGitlabCiLintError
2829

2930

3031
classGitlabCLI:
@@ -133,6 +134,16 @@ def do_project_export_download(self) -> None:
133134
exceptExceptionase:# pragma: no cover, cli.die is unit-tested
134135
cli.die("Impossible to download the export",e)
135136

137+
defdo_validate(self)->None:
138+
ifTYPE_CHECKING:
139+
assertisinstance(self.mgr,gitlab.v4.objects.CiLintManager)
140+
try:
141+
self.mgr.validate(self.args)
142+
exceptGitlabCiLintErrorase:# pragma: no cover, cli.die is unit-tested
143+
cli.die("CI YAML Lint failed",e)
144+
exceptExceptionase:# pragma: no cover, cli.die is unit-tested
145+
cli.die("Cannot validate CI YAML",e)
146+
136147
defdo_create(self)->gitlab.base.RESTObject:
137148
ifTYPE_CHECKING:
138149
assertisinstance(self.mgr,gitlab.mixins.CreateMixin)

‎gitlab/v4/objects/ci_lint.py‎

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
fromtypingimportAny,cast
77

88
fromgitlab.baseimportRESTManager,RESTObject
9+
fromgitlab.cliimportregister_custom_action
10+
fromgitlab.exceptionsimportGitlabCiLintError
911
fromgitlab.mixinsimportCreateMixin,GetWithoutIdMixin
1012
fromgitlab.typesimportRequiredOptional
1113

@@ -28,9 +30,24 @@ class CiLintManager(CreateMixin, RESTManager):
2830
required=("content",),optional=("include_merged_yaml","include_jobs")
2931
)
3032

33+
@register_custom_action(
34+
"CiLintManager",
35+
("content",),
36+
optional=("include_merged_yaml","include_jobs"),
37+
)
38+
defvalidate(self,*args:Any,**kwargs:Any)->None:
39+
"""Raise an error if the CI Lint results are not valid.
40+
41+
This is a custom python-gitlab method to wrap lint endpoints."""
42+
result=self.create(*args,**kwargs)
43+
44+
ifresult.status!="valid":
45+
message=",\n".join(result.errors)
46+
raiseGitlabCiLintError(message)
47+
3148

3249
classProjectCiLint(RESTObject):
33-
pass
50+
_id_attr=None
3451

3552

3653
classProjectCiLintManager(GetWithoutIdMixin,CreateMixin,RESTManager):
@@ -43,3 +60,18 @@ class ProjectCiLintManager(GetWithoutIdMixin, CreateMixin, RESTManager):
4360

4461
defget(self,**kwargs:Any)->ProjectCiLint:
4562
returncast(ProjectCiLint,super().get(**kwargs))
63+
64+
@register_custom_action(
65+
"ProjectCiLintManager",
66+
("content",),
67+
optional=("dry_run","include_jobs","ref"),
68+
)
69+
defvalidate(self,*args:Any,**kwargs:Any)->None:
70+
"""Raise an error if the Project CI Lint results are not valid.
71+
72+
This is a custom python-gitlab method to wrap lint endpoints."""
73+
result=self.create(*args,**kwargs)
74+
75+
ifnotresult.valid:
76+
message=",\n".join(result.errors)
77+
raiseGitlabCiLintError(message)

‎tests/conftest.py‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,16 @@
44
@pytest.fixture(scope="session")
55
deftest_dir(pytestconfig):
66
returnpytestconfig.rootdir/"tests"
7+
8+
9+
@pytest.fixture
10+
defvalid_gitlab_ci_yml():
11+
return"""---
12+
:test_job:
13+
:script: echo 1
14+
"""
15+
16+
17+
@pytest.fixture
18+
definvalid_gitlab_ci_yml():
19+
return"invalid"

‎tests/functional/cli/test_cli_v4.py‎

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,59 @@ def test_update_project(gitlab_cli, project):
2222
assertdescriptioninret.stdout
2323

2424

25+
deftest_create_ci_lint(gitlab_cli,valid_gitlab_ci_yml):
26+
cmd= ["ci-lint","create","--content",valid_gitlab_ci_yml]
27+
ret=gitlab_cli(cmd)
28+
29+
assertret.success
30+
31+
32+
deftest_validate_ci_lint(gitlab_cli,valid_gitlab_ci_yml):
33+
cmd= ["ci-lint","validate","--content",valid_gitlab_ci_yml]
34+
ret=gitlab_cli(cmd)
35+
36+
assertret.success
37+
38+
39+
deftest_validate_ci_lint_invalid_exits_non_zero(gitlab_cli,invalid_gitlab_ci_yml):
40+
cmd= ["ci-lint","validate","--content",invalid_gitlab_ci_yml]
41+
ret=gitlab_cli(cmd)
42+
43+
assertnotret.success
44+
assert"CI YAML Lint failed (Invalid configuration format)"inret.stderr
45+
46+
47+
deftest_validate_project_ci_lint(gitlab_cli,project,valid_gitlab_ci_yml):
48+
cmd= [
49+
"project-ci-lint",
50+
"validate",
51+
"--project-id",
52+
project.id,
53+
"--content",
54+
valid_gitlab_ci_yml,
55+
]
56+
ret=gitlab_cli(cmd)
57+
58+
assertret.success
59+
60+
61+
deftest_validate_project_ci_lint_invalid_exits_non_zero(
62+
gitlab_cli,project,invalid_gitlab_ci_yml
63+
):
64+
cmd= [
65+
"project-ci-lint",
66+
"validate",
67+
"--project-id",
68+
project.id,
69+
"--content",
70+
invalid_gitlab_ci_yml,
71+
]
72+
ret=gitlab_cli(cmd)
73+
74+
assertnotret.success
75+
assert"CI YAML Lint failed (Invalid configuration format)"inret.stderr
76+
77+
2578
deftest_create_group(gitlab_cli):
2679
name="test-group1"
2780
path="group1"

‎tests/unit/objects/test_ci_lint.py‎

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
importpytest
22
importresponses
33

4-
gitlab_ci_yml="""---
5-
:test_job:
6-
:script: echo 1
7-
"""
4+
fromgitlabimportexceptions
85

96
ci_lint_create_content= {"status":"valid","errors": [],"warnings": []}
7+
ci_lint_create_invalid_content= {
8+
"status":"invalid",
9+
"errors": ["invalid format"],
10+
"warnings": [],
11+
}
1012

1113

1214
project_ci_lint_content= {
@@ -30,6 +32,19 @@ def resp_create_ci_lint():
3032
yieldrsps
3133

3234

35+
@pytest.fixture
36+
defresp_create_ci_lint_invalid():
37+
withresponses.RequestsMock()asrsps:
38+
rsps.add(
39+
method=responses.POST,
40+
url="http://localhost/api/v4/ci/lint",
41+
json=ci_lint_create_invalid_content,
42+
content_type="application/json",
43+
status=200,
44+
)
45+
yieldrsps
46+
47+
3348
@pytest.fixture
3449
defresp_get_project_ci_lint():
3550
withresponses.RequestsMock()asrsps:
@@ -56,16 +71,29 @@ def resp_create_project_ci_lint():
5671
yieldrsps
5772

5873

59-
deftest_ci_lint_create(gl,resp_create_ci_lint):
60-
lint_result=gl.ci_lint.create({"content":gitlab_ci_yml})
74+
deftest_ci_lint_create(gl,resp_create_ci_lint,valid_gitlab_ci_yml):
75+
lint_result=gl.ci_lint.create({"content":valid_gitlab_ci_yml})
6176
assertlint_result.status=="valid"
6277

6378

79+
deftest_ci_lint_validate(gl,resp_create_ci_lint,valid_gitlab_ci_yml):
80+
gl.ci_lint.validate({"content":valid_gitlab_ci_yml})
81+
82+
83+
deftest_ci_lint_validate_invalid_raises(
84+
gl,resp_create_ci_lint_invalid,invalid_gitlab_ci_yml
85+
):
86+
withpytest.raises(exceptions.GitlabCiLintError,match="invalid format"):
87+
gl.ci_lint.validate({"content":invalid_gitlab_ci_yml})
88+
89+
6490
deftest_project_ci_lint_get(project,resp_get_project_ci_lint):
6591
lint_result=project.ci_lint.get()
6692
assertlint_result.validisTrue
6793

6894

69-
deftest_project_ci_lint_create(project,resp_create_project_ci_lint):
70-
lint_result=project.ci_lint.create({"content":gitlab_ci_yml})
95+
deftest_project_ci_lint_create(
96+
project,resp_create_project_ci_lint,valid_gitlab_ci_yml
97+
):
98+
lint_result=project.ci_lint.create({"content":valid_gitlab_ci_yml})
7199
assertlint_result.validisTrue

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp