From e272e45538312b5d1638fc45684c7ba9813af461 Mon Sep 17 00:00:00 2001 From: Meng JiaFeng Date: Mon, 19 Sep 2022 17:35:49 +0800 Subject: [PATCH 1/3] feat: jenkins repo support private repo Signed-off-by: Meng JiaFeng --- .../gitlab-jenkins-harbor.zh.md | 8 +- docs/plugins/jenkins-pipeline.zh.md | 7 +- internal/pkg/plugininstaller/common/repo.go | 78 +++++++++--------- .../pkg/plugininstaller/common/repo_test.go | 79 ++++++++++++++++++- .../pkg/plugininstaller/jenkins/installer.go | 4 + .../pkg/plugininstaller/jenkins/option.go | 43 +++++++--- .../plugininstaller/jenkins/option_test.go | 13 ++- .../pkg/plugininstaller/jenkins/validate.go | 11 ++- .../plugininstaller/jenkins/validate_test.go | 18 +++-- .../show/config/plugins/jenkins-pipeline.yaml | 8 +- pkg/util/jenkins/auth.go | 38 ++++++++- pkg/util/jenkins/jenkins.go | 1 + pkg/util/jenkins/tpl/seedjob.tpl.groovy | 2 +- pkg/util/scm/client.go | 5 ++ pkg/util/scm/gitlab/gitlab.go | 10 +++ 15 files changed, 252 insertions(+), 73 deletions(-) diff --git a/docs/best-practices/gitlab-jenkins-harbor.zh.md b/docs/best-practices/gitlab-jenkins-harbor.zh.md index a6249156b..778aba17d 100644 --- a/docs/best-practices/gitlab-jenkins-harbor.zh.md +++ b/docs/best-practices/gitlab-jenkins-harbor.zh.md @@ -473,8 +473,8 @@ jenkins-pipeline 插件的配置如下: user: admin enableRestart: true scm: - projectURL: http://gitlab.example.com:30080/root/spring-demo - projectBranch: master + cloneURL: http://gitlab.example.com:30080/root/spring-demo + branch: master pipeline: jobName: test-job jenkinsfilePath: https://raw.githubusercontent.com/devstream-io/dtm-jenkins-pipeline-example/main/springboot/Jenkinsfile @@ -535,8 +535,8 @@ tools: user: admin enableRestart: true scm: - projectURL: http://gitlab.example.com:30080/root/spring-demo - projectBranch: master + cloneURL: http://gitlab.example.com:30080/root/spring-demo + branch: master pipeline: jobName: test-job jenkinsfilePath: https://raw.githubusercontent.com/devstream-io/dtm-jenkins-pipeline-example/main/springboot/Jenkinsfile diff --git a/docs/plugins/jenkins-pipeline.zh.md b/docs/plugins/jenkins-pipeline.zh.md index 334b07efd..75e60ac71 100644 --- a/docs/plugins/jenkins-pipeline.zh.md +++ b/docs/plugins/jenkins-pipeline.zh.md @@ -35,6 +35,7 @@ ```shell export IMAGE_REPO_PASSWORD=YOUR_IMAGE_REPO_PASSWORD export GITLAB_TOKEN=YOUR_GITLAB_TOKEN +export GITLAB_SSHKEY=YOUR_REPO_PRIVATE_KEY ``` 然后准备 DevStream 插件配置: @@ -64,8 +65,9 @@ tools: user: admin enableRestart: true scm: - projectURL: YOUR_JENKINS_ADDR/root/spring-demo - projectBranch: master + cloneURL: git@YOUR_REPO_CLONE_ADDRESS/root/spring-demo + branch: master + apiURL: YOUR_JENKINS_ADDR pipeline: jobName: test-job jenkinsfilePath: https://raw.githubusercontent.com/devstream-io/dtm-jenkins-pipeline-example/main/springboot/Jenkinsfile @@ -77,6 +79,7 @@ tools: 上述配置文件中使用的 GitLab、Jenkins 和 Harbor 访问地址需要替换成你的环境中实际地址。例如: - **YOUR_GITLAB_ADDR**: http://54.71.232.26:30080 +- **YOUR_REPO_CLONE_ADDRESS**: http://54.71.232.26:30022 - **YOUR_JENKINS_ADDR**: http://54.71.232.26:32000 - **YOUR_HARBOR_ADDR**: http://harbor.example.com:80 diff --git a/internal/pkg/plugininstaller/common/repo.go b/internal/pkg/plugininstaller/common/repo.go index c8433b480..5fcbaae41 100644 --- a/internal/pkg/plugininstaller/common/repo.go +++ b/internal/pkg/plugininstaller/common/repo.go @@ -7,6 +7,7 @@ import ( "github.com/devstream-io/devstream/pkg/util/file" "github.com/devstream-io/devstream/pkg/util/log" + "github.com/devstream-io/devstream/pkg/util/scm" "github.com/devstream-io/devstream/pkg/util/scm/git" "github.com/devstream-io/devstream/pkg/util/scm/github" "github.com/devstream-io/devstream/pkg/util/scm/gitlab" @@ -78,52 +79,30 @@ func (d *Repo) BuildRepoInfo() *git.RepoInfo { } } -// BuildURL return url build from repo struct -func (d *Repo) BuildURL() string { - repoInfo := d.BuildRepoInfo() - switch d.RepoType { - case "github": - return fmt.Sprintf("https://github.com/%s/%s.git", repoInfo.GetRepoOwner(), d.Repo) - case "gitlab": - var gitlabURL string - if d.BaseURL != "" { - gitlabURL = d.BaseURL - } else { - gitlabURL = gitlab.DefaultGitlabHost - } - return fmt.Sprintf("%s/%s/%s.git", gitlabURL, repoInfo.GetRepoOwner(), d.Repo) - default: - return "" - } -} - // NewRepoFromURL build repo struct from scm url -func NewRepoFromURL(repoURL, branch string) (*Repo, error) { +func NewRepoFromURL(repoType, apiURL, cloneURL, branch string) (*Repo, error) { repo := &Repo{ Branch: branch, } - u, err := url.ParseRequestURI(repoURL) - if err != nil { - return nil, err - } - //config repo type - if strings.Contains(u.Host, "github") { + + if scm.IsGithubRepo(repoType, cloneURL) { repo.RepoType = "github" - } else if strings.Contains(u.Host, "gitlab.com") { - repo.RepoType = "gitlab" - repo.BaseURL = gitlab.DefaultGitlabHost } else { repo.RepoType = "gitlab" - repo.BaseURL = fmt.Sprintf("%s://%s", u.Scheme, u.Host) + // extract gitlab baseURL from url string + if apiURL == "" { + apiURL = cloneURL + } + gitlabBaseURL, err := gitlab.ExtractBaseURLfromRaw(apiURL) + if err != nil { + return nil, fmt.Errorf("gitlab repo extract baseURL failed: %w", err) + } + repo.BaseURL = gitlabBaseURL } - path := u.Path - // config repo owner org and - pathPart := strings.Split(strings.TrimPrefix(path, "/"), "/") - if len(pathPart) != 2 { - return nil, fmt.Errorf("git repo path is not valid") + + if err := repo.updateRepoPathByCloneURL(cloneURL); err != nil { + return nil, fmt.Errorf("git extract repo info failed: %w", err) } - repo.Owner = pathPart[0] - repo.Repo = pathPart[1] repo.Branch = repo.getBranch() return repo, nil } @@ -150,3 +129,28 @@ func (d *Repo) getRepoDownloadURL() string { log.Debugf("LatestCodeZipfileDownloadUrl: %s.", latestCodeZipfileDownloadURL) return latestCodeZipfileDownloadURL } + +func (d *Repo) updateRepoPathByCloneURL(cloneURL string) error { + var paths string + c, err := url.ParseRequestURI(cloneURL) + if err != nil { + if strings.Contains(cloneURL, "git@") { + gitSSHLastIndex := strings.LastIndex(cloneURL, ":") + if gitSSHLastIndex == -1 { + return fmt.Errorf("git ssh repo not valid") + } + paths = strings.Trim(cloneURL[gitSSHLastIndex:], ":") + } else { + return fmt.Errorf("git repo transport not support for now") + } + } else { + paths = c.Path + } + projectPaths := strings.Split(strings.Trim(paths, "/"), "/") + if len(projectPaths) != 2 { + return fmt.Errorf("git repo path is not valid") + } + d.Owner = projectPaths[0] + d.Repo = strings.TrimSuffix(projectPaths[1], ".git") + return nil +} diff --git a/internal/pkg/plugininstaller/common/repo_test.go b/internal/pkg/plugininstaller/common/repo_test.go index f0a109f01..f6b766e48 100644 --- a/internal/pkg/plugininstaller/common/repo_test.go +++ b/internal/pkg/plugininstaller/common/repo_test.go @@ -29,7 +29,6 @@ var _ = Describe("Repo Struct", func() { Visibility: visibility, } }) - Context("BuildRepoRenderConfig method", func() { It("should return map", func() { config := repo.BuildRepoRenderConfig() @@ -48,3 +47,81 @@ var _ = Describe("Repo Struct", func() { }) }) }) + +var _ = Describe("NewRepoFromURL func", func() { + var ( + repoType, apiURL, cloneURL, branch string + ) + When("is github repo", func() { + BeforeEach(func() { + cloneURL = "git@github.com:test/dtm-test.git" + branch = "test" + }) + It("should return github repo info", func() { + repo, err := NewRepoFromURL(repoType, apiURL, cloneURL, branch) + Expect(err).Error().ShouldNot(HaveOccurred()) + Expect(repo).ShouldNot(BeNil()) + Expect(repo.Repo).Should(Equal("dtm-test")) + Expect(repo.Owner).Should(Equal("test")) + Expect(repo.RepoType).Should(Equal("github")) + Expect(repo.Branch).Should(Equal("test")) + }) + }) + When("clone url is not valid", func() { + BeforeEach(func() { + cloneURL = "git@github.comtest/dtm-test.git" + branch = "test" + }) + It("should return error", func() { + _, err := NewRepoFromURL(repoType, apiURL, cloneURL, branch) + Expect(err).Error().Should(HaveOccurred()) + }) + }) + When("is gitlab repo", func() { + BeforeEach(func() { + repoType = "gitlab" + }) + When("apiURL is not set, cloneURL is ssh format", func() { + BeforeEach(func() { + cloneURL = "git@gitlab.test.com:root/test-demo.git" + apiURL = "" + branch = "test" + }) + It("should return error", func() { + _, err := NewRepoFromURL(repoType, apiURL, cloneURL, branch) + Expect(err).Error().Should(HaveOccurred()) + }) + }) + When("apiURL is not set, cloneURL is http format", func() { + BeforeEach(func() { + cloneURL = "http://gitlab.test.com:3000/root/test-demo.git" + apiURL = "" + branch = "test" + }) + It("should return error", func() { + repo, err := NewRepoFromURL(repoType, apiURL, cloneURL, branch) + Expect(err).Error().ShouldNot(HaveOccurred()) + Expect(repo.BaseURL).Should(Equal("http://gitlab.test.com:3000")) + Expect(repo.Owner).Should(Equal("root")) + Expect(repo.Repo).Should(Equal("test-demo")) + Expect(repo.Branch).Should(Equal("test")) + }) + }) + When("apiURL is set", func() { + BeforeEach(func() { + cloneURL = "git@gitlab.test.com:root/test-demo.git" + apiURL = "http://gitlab.http.com" + branch = "test" + }) + It("should set apiURL as BaseURL", func() { + repo, err := NewRepoFromURL(repoType, apiURL, cloneURL, branch) + Expect(err).Error().ShouldNot(HaveOccurred()) + Expect(repo.BaseURL).Should(Equal("http://gitlab.http.com")) + Expect(repo.Owner).Should(Equal("root")) + Expect(repo.Repo).Should(Equal("test-demo")) + Expect(repo.Branch).Should(Equal("test")) + }) + + }) + }) +}) diff --git a/internal/pkg/plugininstaller/jenkins/installer.go b/internal/pkg/plugininstaller/jenkins/installer.go index b178f9483..7c0ed41c2 100644 --- a/internal/pkg/plugininstaller/jenkins/installer.go +++ b/internal/pkg/plugininstaller/jenkins/installer.go @@ -75,6 +75,10 @@ func PreInstall(plugins []string, cascTemplate string) plugininstaller.BaseOpera switch opts.ProjectRepo.RepoType { case "gitlab": // 3. create gitlab connection for gitlab + err := opts.createGitlabSSHPrivateKey(jenkinsClient) + if err != nil { + return err + } return opts.createGitlabConnection(jenkinsClient, cascTemplate) default: log.Debugf("jenkins preinstall only support gitlab for now") diff --git a/internal/pkg/plugininstaller/jenkins/option.go b/internal/pkg/plugininstaller/jenkins/option.go index 46a8d83e0..3f5e60837 100644 --- a/internal/pkg/plugininstaller/jenkins/option.go +++ b/internal/pkg/plugininstaller/jenkins/option.go @@ -22,6 +22,7 @@ import ( const ( jenkinsGitlabCredentialName = "jenkinsGitlabCredential" jenkinsGitlabConnectionName = "jenkinsGitlabConnection" + jenkinsSSHkeyCredentialName = "jenkinsSSHKeyCredential" ) type JobOptions struct { @@ -44,8 +45,11 @@ type Jenkins struct { } type SCM struct { - ProjectURL string `mapstructure:"projectURL" validate:"required"` - ProjectBranch string `mapstructure:"projectBranch"` + CloneURL string `mapstructure:"cloneURL" validate:"required"` + APIURL string `mapstructure:"apiURL"` + Branch string `mapstructure:"branch"` + Type string `mapstructure:"type"` + SSHprivateKey string `mapstructure:"sshPrivateKey"` } type Pipeline struct { @@ -60,13 +64,14 @@ type ImageRepo struct { } type jobScriptRenderInfo struct { - RepoType string - JobName string - RepositoryURL string - Branch string - SecretToken string - FolderName string - GitlabConnection string + RepoType string + JobName string + RepositoryURL string + Branch string + SecretToken string + FolderName string + GitlabConnection string + RepoCredentialsId string } func newJobOptions(options plugininstaller.RawOptions) (*JobOptions, error) { @@ -91,15 +96,19 @@ func (j *JobOptions) newJenkinsClient() (jenkins.JenkinsAPI, error) { func (j *JobOptions) createOrUpdateJob(jenkinsClient jenkins.JenkinsAPI) error { // 1. render groovy script - jobScript, err := jenkins.BuildRenderedScript(&jobScriptRenderInfo{ + jobRenderInfo := &jobScriptRenderInfo{ RepoType: j.ProjectRepo.RepoType, JobName: j.getJobName(), - RepositoryURL: j.ProjectRepo.BuildURL(), + RepositoryURL: j.SCM.CloneURL, Branch: j.ProjectRepo.Branch, SecretToken: j.SecretToken, FolderName: j.getJobFolder(), GitlabConnection: jenkinsGitlabConnectionName, - }) + } + if j.SCM.SSHprivateKey != "" { + jobRenderInfo.RepoCredentialsId = jenkinsSSHkeyCredentialName + } + jobScript, err := jenkins.BuildRenderedScript(jobRenderInfo) if err != nil { log.Debugf("jenkins redner template failed: %s", err) return err @@ -210,3 +219,13 @@ func (j *JobOptions) buildCIConfig() { } j.CIConfig = ciConfig } + +func (j *JobOptions) createGitlabSSHPrivateKey(jenkinsClient jenkins.JenkinsAPI) error { + if j.SCM.SSHprivateKey == "" { + log.Warnf("jenkins gittlab ssh key not config, private repo can't be clone") + return nil + } + return jenkinsClient.CreateSSHKeyCredential( + jenkinsSSHkeyCredentialName, j.ProjectRepo.Owner, j.SCM.SSHprivateKey, + ) +} diff --git a/internal/pkg/plugininstaller/jenkins/option_test.go b/internal/pkg/plugininstaller/jenkins/option_test.go index e9ff87f3a..1204956b4 100644 --- a/internal/pkg/plugininstaller/jenkins/option_test.go +++ b/internal/pkg/plugininstaller/jenkins/option_test.go @@ -39,6 +39,11 @@ func (m *mockSuccessJenkinsClient) InstallPluginsIfNotExists(plugin []string, en func (m *mockSuccessJenkinsClient) CreateGiltabCredential(id, token string) error { return nil } + +func (m *mockSuccessJenkinsClient) CreateSSHKeyCredential(id, userName, privateKey string) error { + return nil +} + func (m *mockSuccessJenkinsClient) ConfigCasc(cascScript string) error { return nil } @@ -69,6 +74,10 @@ func (m *mockErrorJenkinsClient) ConfigCasc(cascScript string) error { return testError } +func (m *mockErrorJenkinsClient) CreateSSHKeyCredential(id, userName, privateKey string) error { + return testError +} + var _ = Describe("JobOptions struct", func() { var ( jenkinsURL, secretToken, jobName, projectURL, jenkinsFilePath, userName, password, repoOwner, repoName string @@ -110,8 +119,8 @@ var _ = Describe("JobOptions struct", func() { EnableRestart: false, }, SCM: SCM{ - ProjectURL: projectURL, - ProjectBranch: "test", + CloneURL: projectURL, + Branch: "test", }, Pipeline: Pipeline{ JobName: jobName, diff --git a/internal/pkg/plugininstaller/jenkins/validate.go b/internal/pkg/plugininstaller/jenkins/validate.go index d13fb1606..dbf6bce2f 100644 --- a/internal/pkg/plugininstaller/jenkins/validate.go +++ b/internal/pkg/plugininstaller/jenkins/validate.go @@ -33,7 +33,7 @@ func SetJobDefaultConfig(options plugininstaller.RawOptions) (plugininstaller.Ra } // config default values - projectRepo, err := common.NewRepoFromURL(opts.SCM.ProjectURL, opts.SCM.ProjectBranch) + projectRepo, err := common.NewRepoFromURL(opts.SCM.Type, opts.SCM.APIURL, opts.SCM.CloneURL, opts.SCM.Branch) if err != nil { return nil, err } @@ -42,8 +42,12 @@ func SetJobDefaultConfig(options plugininstaller.RawOptions) (plugininstaller.Ra opts.Jenkins.Namespace = "jenkins" } - if opts.SCM.ProjectBranch == "" { - opts.SCM.ProjectBranch = "master" + if opts.SCM.Branch == "" { + opts.SCM.Branch = projectRepo.Branch + } + sshKey := os.Getenv("GITLAB_SSHKEY") + if sshKey != "" && opts.SCM.SSHprivateKey == "" { + opts.SCM.SSHprivateKey = sshKey } opts.ProjectRepo = projectRepo @@ -56,7 +60,6 @@ func SetJobDefaultConfig(options plugininstaller.RawOptions) (plugininstaller.Ra if err != nil { return nil, err } - opts.BasicAuth = basicAuth opts.SecretToken = generateRandomSecretToken() return opts.encode() diff --git a/internal/pkg/plugininstaller/jenkins/validate_test.go b/internal/pkg/plugininstaller/jenkins/validate_test.go index 3ac41883b..093ad1c48 100644 --- a/internal/pkg/plugininstaller/jenkins/validate_test.go +++ b/internal/pkg/plugininstaller/jenkins/validate_test.go @@ -26,7 +26,7 @@ var _ = Describe("SetJobDefaultConfig func", func() { "user": jenkinsUser, }, "scm": map[string]interface{}{ - "projectURL": projectURL, + "cloneURL": projectURL, }, "pipeline": map[string]interface{}{ "jenkinsfilePath": jenkinsFilePath, @@ -36,7 +36,7 @@ var _ = Describe("SetJobDefaultConfig func", func() { When("repo url is not valie", func() { BeforeEach(func() { options["scm"] = map[string]interface{}{ - "projectURL": "not_valid_url/gg", + "cloneURL": "not_valid_url/gg", } }) It("should return err", func() { @@ -45,18 +45,24 @@ var _ = Describe("SetJobDefaultConfig func", func() { }) }) When("all input is valid", func() { + BeforeEach(func() { + options["scm"] = map[string]interface{}{ + "cloneURL": "git@54.71.232.26:30022:root/spring-demo.git", + "apiURL": "http://www.app.com", + } + }) It("should set default value", func() { newOptions, err := SetJobDefaultConfig(options) Expect(err).Error().ShouldNot(HaveOccurred()) opts, err := newJobOptions(newOptions) Expect(err).Error().ShouldNot(HaveOccurred()) Expect(opts.CIConfig).ShouldNot(BeNil()) - Expect(opts.Pipeline.JobName).Should(Equal("test_project")) + Expect(opts.Pipeline.JobName).Should(Equal("spring-demo")) Expect(opts.BasicAuth).ShouldNot(BeNil()) Expect(opts.BasicAuth.Username).Should(Equal(jenkinsUser)) Expect(opts.BasicAuth.Password).Should(Equal(jenkinsPassword)) Expect(opts.ProjectRepo).ShouldNot(BeNil()) - Expect(opts.ProjectRepo.Repo).Should(Equal("test_project")) + Expect(opts.ProjectRepo.Repo).Should(Equal("spring-demo")) }) }) AfterEach(func() { @@ -87,7 +93,7 @@ var _ = Describe("ValidateJobConfig func", func() { "user": jenkinsUser, }, "scm": map[string]interface{}{ - "projectURL": projectURL, + "cloneURL": projectURL, }, "pipeline": map[string]interface{}{ "jenkinsfilePath": jenkinsFilePath, @@ -102,7 +108,7 @@ var _ = Describe("ValidateJobConfig func", func() { "user": jenkinsUser, }, "scm": map[string]interface{}{ - "projectURL": projectURL, + "cloneURL": projectURL, }, } }) diff --git a/internal/pkg/show/config/plugins/jenkins-pipeline.yaml b/internal/pkg/show/config/plugins/jenkins-pipeline.yaml index 6f90679f6..dd580797c 100644 --- a/internal/pkg/show/config/plugins/jenkins-pipeline.yaml +++ b/internal/pkg/show/config/plugins/jenkins-pipeline.yaml @@ -17,10 +17,12 @@ tools: # restart jenkins if true for plugin install enableRestart: true scm: - # projectURL is the project repo location - projectURL: http://gitlab.example.com:30080/root/test-project + # cloneURL is the project repo location, this can be http://test.com/root/test-project or git@test.com:root/test-project + cloneURL: git@gitlab.com/root/test-project.git + # apiURL is the api address of gitlab, if you use github, this field can be empty + apiURL: http://gitlab.com # project branch, master as default - projectBranch: master + branch: master pipeline: # jobName is jenkins's job name; or ; e.g. jobs/test-job, test-job, jobs2/test-job jobName: test-job diff --git a/pkg/util/jenkins/auth.go b/pkg/util/jenkins/auth.go index 881ef9745..997e3f2d8 100644 --- a/pkg/util/jenkins/auth.go +++ b/pkg/util/jenkins/auth.go @@ -10,6 +10,10 @@ import ( "github.com/devstream-io/devstream/pkg/util/log" ) +const ( + credentialDescription = "this credential is created by devstream" +) + type GitlabCredentials struct { XMLName xml.Name `xml:"com.dabsquared.gitlabjenkins.connection.GitLabApiTokenImpl"` ID string `xml:"id"` @@ -23,7 +27,7 @@ func (j *jenkins) CreateGiltabCredential(id, gitlabToken string) error { ID: id, Scope: credentialScope, APIToken: gitlabToken, - Description: "this credential is created by devstream", + Description: credentialDescription, } cm := &gojenkins.CredentialsManager{ @@ -45,3 +49,35 @@ func (j *jenkins) CreateGiltabCredential(id, gitlabToken string) error { } return nil } + +func (j *jenkins) CreateSSHKeyCredential(id, userName, privateKey string) error { + cred := gojenkins.SSHCredentials{ + ID: id, + Scope: credentialScope, + Username: userName, + PrivateKeySource: &gojenkins.PrivateKey{ + Value: privateKey, + Class: gojenkins.KeySourceDirectEntryType, + }, + Description: id, + } + + cm := &gojenkins.CredentialsManager{ + J: &j.Jenkins, + } + err := cm.Add(j.ctx, domain, cred) + if err != nil { + if strings.Contains(err.Error(), "already exists") { + log.Debugf("jenkins credential %s has been created", id) + return nil + } + return fmt.Errorf("could not create credential: %v", err) + } + + // get credential to validate creation + getCred := gojenkins.SSHCredentials{} + if err = cm.GetSingle(j.ctx, domain, cred.ID, &getCred); err != nil { + return fmt.Errorf("could not get credential: %v", err) + } + return nil +} diff --git a/pkg/util/jenkins/jenkins.go b/pkg/util/jenkins/jenkins.go index a5f5574ac..06ac19ae4 100644 --- a/pkg/util/jenkins/jenkins.go +++ b/pkg/util/jenkins/jenkins.go @@ -24,6 +24,7 @@ type JenkinsAPI interface { DeleteJob(ctx context.Context, name string) (bool, error) InstallPluginsIfNotExists(plugin []string, enableRestart bool) error CreateGiltabCredential(id, token string) error + CreateSSHKeyCredential(id, userName, privateKey string) error ConfigCasc(cascScript string) error } diff --git a/pkg/util/jenkins/tpl/seedjob.tpl.groovy b/pkg/util/jenkins/tpl/seedjob.tpl.groovy index 0790f2b59..c56fa458c 100644 --- a/pkg/util/jenkins/tpl/seedjob.tpl.groovy +++ b/pkg/util/jenkins/tpl/seedjob.tpl.groovy @@ -53,7 +53,7 @@ if (jobRef == null) { jobRef.setDisplayName("[[ .JobName ]]") // --> 2. this module is used to init jenkinsfile config -UserRemoteConfig userRemoteConfig = new UserRemoteConfig("[[ .RepositoryURL ]]", "[[ .JobName ]]", null, "") +UserRemoteConfig userRemoteConfig = new UserRemoteConfig("[[ .RepositoryURL ]]", "[[ .JobName ]]", null, "[[ .RepoCredentialsId ]]") branches = newArrayList(new BranchSpec("*/[[ .Branch ]]")) doGenerateSubmoduleConfigurations = false diff --git a/pkg/util/scm/client.go b/pkg/util/scm/client.go index 15496df95..bfc19089a 100644 --- a/pkg/util/scm/client.go +++ b/pkg/util/scm/client.go @@ -2,6 +2,7 @@ package scm import ( "fmt" + "strings" "github.com/devstream-io/devstream/pkg/util/log" "github.com/devstream-io/devstream/pkg/util/scm/git" @@ -56,3 +57,7 @@ func PushInitRepo(client ClientOperation, commitInfo *git.CommitInfo) error { needRollBack, err := client.PushLocalFileToRepo(commitInfo, false) return err } + +func IsGithubRepo(repoType, url string) bool { + return repoType == "github" || strings.Contains(url, "github") +} diff --git a/pkg/util/scm/gitlab/gitlab.go b/pkg/util/scm/gitlab/gitlab.go index 78280055c..6c9b8ad92 100644 --- a/pkg/util/scm/gitlab/gitlab.go +++ b/pkg/util/scm/gitlab/gitlab.go @@ -2,6 +2,8 @@ package gitlab import ( "errors" + "fmt" + "net/url" "os" "github.com/xanzy/go-gitlab" @@ -43,3 +45,11 @@ func NewClient(options *git.RepoInfo) (*Client, error) { return c, nil } + +func ExtractBaseURLfromRaw(repoURL string) (string, error) { + u, err := url.ParseRequestURI(repoURL) + if err != nil { + return "", err + } + return fmt.Sprintf("%s://%s", u.Scheme, u.Host), nil +} From 50af4c6b3919860f030ab97986902bb5db37cea0 Mon Sep 17 00:00:00 2001 From: Meng JiaFeng Date: Mon, 19 Sep 2022 17:49:52 +0800 Subject: [PATCH 2/3] fix: doc error Signed-off-by: Meng JiaFeng --- internal/pkg/show/config/plugins/jenkins-pipeline.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/pkg/show/config/plugins/jenkins-pipeline.yaml b/internal/pkg/show/config/plugins/jenkins-pipeline.yaml index dd580797c..adb810adc 100644 --- a/internal/pkg/show/config/plugins/jenkins-pipeline.yaml +++ b/internal/pkg/show/config/plugins/jenkins-pipeline.yaml @@ -17,7 +17,7 @@ tools: # restart jenkins if true for plugin install enableRestart: true scm: - # cloneURL is the project repo location, this can be http://test.com/root/test-project or git@test.com:root/test-project + # cloneURL is the project repo location, this can be http address or git address cloneURL: git@gitlab.com/root/test-project.git # apiURL is the api address of gitlab, if you use github, this field can be empty apiURL: http://gitlab.com From 358c15d73c20d374760da980821acb24af553f53 Mon Sep 17 00:00:00 2001 From: Meng JiaFeng Date: Tue, 20 Sep 2022 14:46:53 +0800 Subject: [PATCH 3/3] fix: log message error Signed-off-by: Meng JiaFeng --- internal/pkg/plugininstaller/jenkins/option.go | 2 +- internal/pkg/plugininstaller/jenkins/validate.go | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/internal/pkg/plugininstaller/jenkins/option.go b/internal/pkg/plugininstaller/jenkins/option.go index 3f5e60837..860ce0b8a 100644 --- a/internal/pkg/plugininstaller/jenkins/option.go +++ b/internal/pkg/plugininstaller/jenkins/option.go @@ -222,7 +222,7 @@ func (j *JobOptions) buildCIConfig() { func (j *JobOptions) createGitlabSSHPrivateKey(jenkinsClient jenkins.JenkinsAPI) error { if j.SCM.SSHprivateKey == "" { - log.Warnf("jenkins gittlab ssh key not config, private repo can't be clone") + log.Warnf("jenkins gitlab ssh key not config, private repo can't be clone") return nil } return jenkinsClient.CreateSSHKeyCredential( diff --git a/internal/pkg/plugininstaller/jenkins/validate.go b/internal/pkg/plugininstaller/jenkins/validate.go index dbf6bce2f..6d658ae14 100644 --- a/internal/pkg/plugininstaller/jenkins/validate.go +++ b/internal/pkg/plugininstaller/jenkins/validate.go @@ -32,7 +32,7 @@ func SetJobDefaultConfig(options plugininstaller.RawOptions) (plugininstaller.Ra return nil, err } - // config default values + // config scm and projectRepo values projectRepo, err := common.NewRepoFromURL(opts.SCM.Type, opts.SCM.APIURL, opts.SCM.CloneURL, opts.SCM.Branch) if err != nil { return nil, err @@ -54,6 +54,8 @@ func SetJobDefaultConfig(options plugininstaller.RawOptions) (plugininstaller.Ra if opts.Pipeline.JobName == "" { opts.Pipeline.JobName = projectRepo.Repo } + + // config ci related values opts.buildCIConfig() basicAuth, err := buildAdminToken(opts.Jenkins.User) @@ -75,6 +77,7 @@ func ValidateJobConfig(options plugininstaller.RawOptions) (plugininstaller.RawO return nil, err } + // check jenkins job name if strings.Contains(opts.Pipeline.JobName, "/") { strs := strings.Split(opts.Pipeline.JobName, "/") if len(strs) != 2 || len(strs[0]) == 0 || len(strs[1]) == 0 { @@ -82,9 +85,11 @@ func ValidateJobConfig(options plugininstaller.RawOptions) (plugininstaller.RawO } } + // check projectRepo name if opts.ProjectRepo.RepoType == "github" { - return nil, errors.New("jenkins job not support github for now") + return nil, fmt.Errorf("jenkins job not support github for now") } + return options, nil }