Repository: xanzy/go-gitlab
Pull request #1017 (2020-12-25 17:14:24)

Validate the CI YAML configuration with a namespace


Patch:
diff --git a/validate.go b/validate.go
index b32dd29..17ffb15 100644
--- a/validate.go
+++ b/validate.go
@@ -20,7 +20,8 @@ type LintResult struct {
 
 // ProjectLintResult represents the linting results by project.
 //
-// GitLab API docs: https://docs.gitlab.com/ee/api/lint.html#validate-a-projects-ci-configuration
+// GitLab API docs:
+// https://docs.gitlab.com/ee/api/lint.html#validate-a-projects-ci-configuration
 type ProjectLintResult struct {
 	Valid      bool     `json:"valid"`
 	Errors     []string `json:"errors"`
@@ -51,16 +52,52 @@ func (s *ValidateService) Lint(content string, options ...RequestOptionFunc) (*L
 	return l, resp, nil
 }
 
+// ProjectNamespaceLintOptions represents the available ProjectNamespaceLint() options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ee/api/lint.html#validate-a-ci-yaml-configuration-with-a-namespace
+type ProjectNamespaceLintOptions struct {
+	Content *string `url:"content,omitempty" json:"content,omitempty"`
+	DryRun  *bool   `url:"dry_run,omitempty" json:"dry_run,omitempty"`
+}
+
+// ProjectNamespaceLint validates .gitlab-ci.yml content by project.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ee/api/lint.html#validate-a-ci-yaml-configuration-with-a-namespace
+func (s *ValidateService) ProjectNamespaceLint(pid interface{}, opt *ProjectNamespaceLintOptions, options ...RequestOptionFunc) (*ProjectLintResult, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/ci/lint", pathEscape(project))
+
+	req, err := s.client.NewRequest("POST", u, &opt, options)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	l := new(ProjectLintResult)
+	resp, err := s.client.Do(req, l)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return l, resp, nil
+}
+
 // ProjectLintOptions represents the available ProjectLint() options.
 //
-// GitLab API docs: https://docs.gitlab.com/ee/api/lint.html#validate-a-projects-ci-configuration
+// GitLab API docs:
+// https://docs.gitlab.com/ee/api/lint.html#validate-a-projects-ci-configuration
 type ProjectLintOptions struct {
 	DryRun *bool `url:"dry_run,omitempty" json:"dry_run,omitempty"`
 }
 
 // ProjectLint validates .gitlab-ci.yml content by project.
 //
-// GitLab API docs: https://docs.gitlab.com/ee/api/lint.html#validate-a-projects-ci-configuration
+// GitLab API docs:
+// https://docs.gitlab.com/ee/api/lint.html#validate-a-projects-ci-configuration
 func (s *ValidateService) ProjectLint(pid interface{}, opt *ProjectLintOptions, options ...RequestOptionFunc) (*ProjectLintResult, *Response, error) {
 	project, err := parseID(pid)
 	if err != nil {


Test patch:
diff --git a/validate_test.go b/validate_test.go
index c8e92c1..4c0ba00 100644
--- a/validate_test.go
+++ b/validate_test.go
@@ -132,3 +132,74 @@ func TestValidateProject(t *testing.T) {
 		})
 	}
 }
+
+func TestValidateProjectNamespace(t *testing.T) {
+	testCases := []struct {
+		description string
+		request     *ProjectNamespaceLintOptions
+		response    string
+		want        *ProjectLintResult
+	}{
+		{
+			description: "valid",
+			request: &ProjectNamespaceLintOptions{
+				Content: String("{'build': {'script': 'echo build'}}"),
+				DryRun:  Bool(false),
+			},
+			response: `{
+				"valid": true,
+				"errors": [],
+				"warnings": [],
+				"merged_yaml": 	"---\n:build:\n  :script:\n  - echo build"
+			}`,
+			want: &ProjectLintResult{
+				Valid:      true,
+				Warnings:   []string{},
+				Errors:     []string{},
+				MergedYaml: "---\n:build:\n  :script:\n  - echo build",
+			},
+		},
+		{
+			description: "invalid",
+			request: &ProjectNamespaceLintOptions{
+				Content: String("{'build': {'script': 'echo build', 'bad_key': 'value'}}"),
+				DryRun:  Bool(false),
+			},
+			response: `{
+				"valid": false,
+				"errors": ["jobs:build config contains unknown keys: bad_key"],
+				"warnings": [],
+				"merged_yaml": 	"---\n:build:\n  :script:\n  - echo build\n  :bad_key: value"
+			}`,
+			want: &ProjectLintResult{
+				Valid:      false,
+				Warnings:   []string{},
+				Errors:     []string{"jobs:build config contains unknown keys: bad_key"},
+				MergedYaml: "---\n:build:\n  :script:\n  - echo build\n  :bad_key: value",
+			},
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.description, func(t *testing.T) {
+			mux, server, client := setup(t)
+			defer teardown(server)
+
+			mux.HandleFunc("/api/v4/projects/1/ci/lint", func(w http.ResponseWriter, r *http.Request) {
+				testMethod(t, r, "POST")
+				fmt.Fprint(w, tc.response)
+			})
+
+			got, _, err := client.Validate.ProjectNamespaceLint(1, tc.request)
+
+			if err != nil {
+				t.Errorf("Validate returned error: %v", err)
+			}
+
+			want := tc.want
+			if !reflect.DeepEqual(got, want) {
+				t.Errorf("Validate returned \ngot:\n%v\nwant:\n%v", Stringify(got), Stringify(want))
+			}
+		})
+	}
+}