devops refactor (#1739)
* add devops client interface Signed-off-by: runzexia <runzexia@yunify.com> * direct return jenkins Signed-off-by: runzexia <runzexia@yunify.com> * add some interface Signed-off-by: runzexia <runzexia@yunify.com> * update Signed-off-by: runzexia <runzexia@yunify.com> * update interface Signed-off-by: runzexia <runzexia@yunify.com> * update Signed-off-by: runzexia <runzexia@yunify.com> * credential op structs Signed-off-by: runzexia <runzexia@yunify.com> * status Signed-off-by: zhuxiaoyang <sunzhu@yunify.com> * update interface Signed-off-by: zhuxiaoyang <sunzhu@yunify.com> * credential handler Signed-off-by: runzexia <runzexia@yunify.com> * update devopsoperator func Signed-off-by: zhuxiaoyang <sunzhu@yunify.com> * get build sonar Signed-off-by: runzexia <runzexia@yunify.com> * sonar handler * mv code to cilent Signed-off-by: runzexia <runzexia@yunify.com> * update Signed-off-by: runzexia <runzexia@yunify.com> * project member handler Signed-off-by: runzexia <runzexia@yunify.com> * update pipeline operator interface Signed-off-by: zhuxiaoyang <sunzhu@yunify.com> * add tenant devops handler Signed-off-by: runzexia <runzexia@yunify.com> * update merge Signed-off-by: runzexia <runzexia@yunify.com> * clean Signed-off-by: runzexia <runzexia@yunify.com> * fmt Signed-off-by: runzexia <runzexia@yunify.com> * update ListPipelineRuns Signed-off-by: zhuxiaoyang <sunzhu@yunify.com> * complate pipelineOperator interface Signed-off-by: zhuxiaoyang <sunzhu@yunify.com> * update HttpParameters Signed-off-by: zhuxiaoyang <sunzhu@yunify.com> * add pipeline steps interface Signed-off-by: zhuxiaoyang <sunzhu@yunify.com> * update pipeline GetNodesDetail Signed-off-by: zhuxiaoyang <sunzhu@yunify.com> * add s2i api Signed-off-by: runzexia <runzexia@yunify.com> * add branch pipeline interface and update handler Signed-off-by: zhuxiaoyang <sunzhu@yunify.com> * add scan branch interface and update handler Signed-off-by: zhuxiaoyang <sunzhu@yunify.com> * add common interface and update handler Signed-off-by: zhuxiaoyang <sunzhu@yunify.com> * add SCM interface and update handler Signed-off-by: zhuxiaoyang <sunzhu@yunify.com> * add handler Signed-off-by: runzexia <runzexia@yunify.com> * add fake s3 Signed-off-by: runzexia <runzexia@yunify.com> * add webhook&check interface and update handler Signed-off-by: zhuxiaoyang <sunzhu@yunify.com> * clean Signed-off-by: zhuxiaoyang <sunzhu@yunify.com> * clean Signed-off-by: zhuxiaoyang <sunzhu@yunify.com> * format Signed-off-by: zhuxiaoyang <sunzhu@yunify.com> * add some func Signed-off-by: runzexia <runzexia@yunify.com> * clean code Signed-off-by: runzexia <runzexia@yunify.com> * implement interface Signed-off-by: zhuxiaoyang <sunzhu@yunify.com> * fix interface GetBranchArtifacts Signed-off-by: zhuxiaoyang <sunzhu@yunify.com> * add s2ibinary upload test Signed-off-by: runzexia <runzexia@yunify.com> * tenant devops Signed-off-by: runzexia <runzexia@yunify.com> * update tenant Signed-off-by: runzexia <runzexia@yunify.com> * fake Signed-off-by: zhuxiaoyang <sunzhu@yunify.com> * add some unit test Signed-off-by: zhuxiaoyang <sunzhu@yunify.com> * add devops tenant handler Signed-off-by: runzexia <runzexia@yunify.com> * status Signed-off-by: zhuxiaoyang <sunzhu@yunify.com> * status Signed-off-by: zhuxiaoyang <sunzhu@yunify.com> * status Signed-off-by: zhuxiaoyang <sunzhu@yunify.com> * update fake test Signed-off-by: zhuxiaoyang <sunzhu@yunify.com> * update unit test and fake data Signed-off-by: zhuxiaoyang <sunzhu@yunify.com> * update Co-authored-by: Xiaoyang Zhu <sunzhu@yunify.com>
This commit is contained in:
2
pkg/simple/client/cache/cache.go
vendored
2
pkg/simple/client/cache/cache.go
vendored
@@ -20,4 +20,4 @@ type Interface interface {
|
||||
|
||||
// Expires updates object's expiration time, return err if key doesn't exist
|
||||
Expire(key string, duration time.Duration) error
|
||||
}
|
||||
}
|
||||
|
||||
20
pkg/simple/client/cache/simple_cache.go
vendored
20
pkg/simple/client/cache/simple_cache.go
vendored
@@ -3,38 +3,38 @@ package cache
|
||||
import "time"
|
||||
|
||||
type simpleObject struct {
|
||||
value string
|
||||
expire time.Time
|
||||
value string
|
||||
expire time.Time
|
||||
}
|
||||
|
||||
type SimpleCache struct {
|
||||
store map[string]simpleObject
|
||||
store map[string]simpleObject
|
||||
}
|
||||
|
||||
func NewSimpleCache() Interface {
|
||||
return &SimpleCache{store: make(map[string]simpleObject)}
|
||||
return &SimpleCache{store: make(map[string]simpleObject)}
|
||||
}
|
||||
|
||||
func (s *SimpleCache) Keys(pattern string) ([]string, error) {
|
||||
panic("implement me")
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (s *SimpleCache) Set(key string, value string, duration time.Duration) error {
|
||||
panic("implement me")
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (s *SimpleCache) Del(key string) error {
|
||||
panic("implement me")
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (s *SimpleCache) Get(key string) (string, error) {
|
||||
return "", nil
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (s *SimpleCache) Exists(key string) (bool, error) {
|
||||
panic("implement me")
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (s *SimpleCache) Expire(key string, duration time.Duration) error {
|
||||
panic("implement me")
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
10
pkg/simple/client/devops/OWNERS
Normal file
10
pkg/simple/client/devops/OWNERS
Normal file
@@ -0,0 +1,10 @@
|
||||
approvers:
|
||||
- runzexia
|
||||
- soulseen
|
||||
|
||||
reviewers:
|
||||
- runzexia
|
||||
- soulseen
|
||||
|
||||
labels:
|
||||
- area/devops
|
||||
115
pkg/simple/client/devops/build.go
Normal file
115
pkg/simple/client/devops/build.go
Normal file
@@ -0,0 +1,115 @@
|
||||
package devops
|
||||
|
||||
const (
|
||||
LastBuild = "lastBuild"
|
||||
LastCompletedBuild = "lastCompletedBuild"
|
||||
LastFailedBuild = "lastFailedBuild"
|
||||
LastStableBuild = "lastStableBuild"
|
||||
LastSuccessfulBuild = "lastSuccessfulBuild"
|
||||
LastUnstableBuild = "lastUnstableBuild"
|
||||
LastUnsuccessfulBuild = "lastUnsuccessfulBuild"
|
||||
FirstBuild = "firstBuild"
|
||||
)
|
||||
|
||||
type GeneralParameter struct {
|
||||
Name string
|
||||
Value string
|
||||
}
|
||||
|
||||
type Branch struct {
|
||||
SHA1 string `json:",omitempty"`
|
||||
Name string `json:",omitempty"`
|
||||
}
|
||||
|
||||
type BuildRevision struct {
|
||||
SHA1 string `json:"SHA1,omitempty"`
|
||||
Branch []Branch `json:"Branch,omitempty"`
|
||||
}
|
||||
|
||||
type Builds struct {
|
||||
BuildNumber int64 `json:"buildNumber"`
|
||||
BuildResult interface{} `json:"buildResult"`
|
||||
Marked BuildRevision `json:"marked"`
|
||||
Revision BuildRevision `json:"revision"`
|
||||
}
|
||||
|
||||
type Culprit struct {
|
||||
AbsoluteUrl string
|
||||
FullName string
|
||||
}
|
||||
|
||||
type GeneralAction struct {
|
||||
Parameters []GeneralParameter `json:"parameters,omitempty"`
|
||||
Causes []map[string]interface{} `json:"causes,omitempty"`
|
||||
BuildsByBranchName map[string]Builds `json:"buildsByBranchName,omitempty"`
|
||||
LastBuiltRevision *BuildRevision `json:"lastBuiltRevision,omitempty"`
|
||||
RemoteUrls []string `json:"remoteUrls,omitempty"`
|
||||
ScmName string `json:"scmName,omitempty"`
|
||||
Subdir interface{} `json:"subdir,omitempty"`
|
||||
ClassName string `json:"_class,omitempty"`
|
||||
SonarTaskId string `json:"ceTaskId,omitempty"`
|
||||
SonarServerUrl string `json:"serverUrl,omitempty"`
|
||||
SonarDashboardUrl string `json:"sonarqubeDashboardUrl,omitempty"`
|
||||
TotalCount int64 `json:",omitempty"`
|
||||
UrlName string `json:",omitempty"`
|
||||
}
|
||||
|
||||
type Build struct {
|
||||
Actions []GeneralAction
|
||||
Artifacts []struct {
|
||||
DisplayPath string `json:"displayPath"`
|
||||
FileName string `json:"fileName"`
|
||||
RelativePath string `json:"relativePath"`
|
||||
} `json:"artifacts"`
|
||||
Building bool `json:"building"`
|
||||
BuiltOn string `json:"builtOn"`
|
||||
ChangeSet struct {
|
||||
Items []struct {
|
||||
AffectedPaths []string `json:"affectedPaths"`
|
||||
Author struct {
|
||||
AbsoluteUrl string `json:"absoluteUrl"`
|
||||
FullName string `json:"fullName"`
|
||||
} `json:"author"`
|
||||
Comment string `json:"comment"`
|
||||
CommitID string `json:"commitId"`
|
||||
Date string `json:"date"`
|
||||
ID string `json:"id"`
|
||||
Msg string `json:"msg"`
|
||||
Paths []struct {
|
||||
EditType string `json:"editType"`
|
||||
File string `json:"file"`
|
||||
} `json:"paths"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
} `json:"items"`
|
||||
Kind string `json:"kind"`
|
||||
Revisions []struct {
|
||||
Module string
|
||||
Revision int
|
||||
} `json:"revision"`
|
||||
} `json:"changeSet"`
|
||||
Culprits []Culprit `json:"culprits"`
|
||||
Description interface{} `json:"description"`
|
||||
Duration int64 `json:"duration"`
|
||||
EstimatedDuration int64 `json:"estimatedDuration"`
|
||||
Executor interface{} `json:"executor"`
|
||||
FullDisplayName string `json:"fullDisplayName"`
|
||||
ID string `json:"id"`
|
||||
KeepLog bool `json:"keepLog"`
|
||||
Number int64 `json:"number"`
|
||||
QueueID int64 `json:"queueId"`
|
||||
Result string `json:"result"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
URL string `json:"url"`
|
||||
Runs []struct {
|
||||
Number int64
|
||||
URL string
|
||||
} `json:"runs"`
|
||||
}
|
||||
|
||||
type BuildGetter interface {
|
||||
// GetProjectPipelineBuildByType get the last build of the pipeline, status can specify the status of the last build.
|
||||
GetProjectPipelineBuildByType(projectId, pipelineId string, status string) (*Build, error)
|
||||
|
||||
// GetMultiBranchPipelineBuildByType get the last build of the pipeline, status can specify the status of the last build.
|
||||
GetMultiBranchPipelineBuildByType(projectId, pipelineId, branch string, status string) (*Build, error)
|
||||
}
|
||||
77
pkg/simple/client/devops/credential.go
Normal file
77
pkg/simple/client/devops/credential.go
Normal file
@@ -0,0 +1,77 @@
|
||||
package devops
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type Credential struct {
|
||||
Id string `json:"id" description:"Id of Credential, e.g. dockerhub-id"`
|
||||
Type string `json:"type" description:"Type of Credential, e.g. ssh/kubeconfig"`
|
||||
DisplayName string `json:"display_name,omitempty" description:"Credential's display name"`
|
||||
Fingerprint *struct {
|
||||
FileName string `json:"file_name,omitempty" description:"Credential's display name and description"`
|
||||
Hash string `json:"hash,omitempty" description:"Credential's hash"`
|
||||
Usage []*struct {
|
||||
Name string `json:"name,omitempty" description:"pipeline full name"`
|
||||
Ranges struct {
|
||||
Ranges []*struct {
|
||||
Start int `json:"start,omitempty" description:"Start build number"`
|
||||
End int `json:"end,omitempty" description:"End build number"`
|
||||
} `json:"ranges,omitempty"`
|
||||
} `json:"ranges,omitempty" description:"The build number of all pipelines that use this credential"`
|
||||
} `json:"usage,omitempty" description:"all usage of Credential"`
|
||||
} `json:"fingerprint,omitempty" description:"usage of the Credential"`
|
||||
Description string `json:"description,omitempty" description:"Credential's description'"`
|
||||
Domain string `json:"domain,omitempty" description:"Credential's domain,In ks we only use the default domain, default '_''"`
|
||||
CreateTime *time.Time `json:"create_time,omitempty" description:"Credential's create_time'"`
|
||||
Creator string `json:"creator,omitempty" description:"Creator's username"`
|
||||
UsernamePasswordCredential *UsernamePasswordCredential `json:"username_password,omitempty" description:"username password Credential struct"`
|
||||
SshCredential *SshCredential `json:"ssh,omitempty" description:"ssh Credential struct"`
|
||||
SecretTextCredential *SecretTextCredential `json:"secret_text,omitempty" description:"secret_text Credential struct"`
|
||||
KubeconfigCredential *KubeconfigCredential `json:"kubeconfig,omitempty" description:"kubeconfig Credential struct"`
|
||||
}
|
||||
|
||||
type UsernamePasswordCredential struct {
|
||||
Username string `json:"username,omitempty" description:"username of username_password credential"`
|
||||
Password string `json:"password,omitempty" description:"password of username_password credential"`
|
||||
}
|
||||
|
||||
type SshCredential struct {
|
||||
Username string `json:"username,omitempty" description:"username of ssh credential"`
|
||||
Passphrase string `json:"passphrase,omitempty" description:"passphrase of ssh credential, password of ssh credential"`
|
||||
PrivateKey string `json:"private_key,omitempty" mapstructure:"private_key" description:"private key of ssh credential"`
|
||||
}
|
||||
|
||||
type SecretTextCredential struct {
|
||||
Secret string `json:"secret,omitempty" description:"secret content of credential"`
|
||||
}
|
||||
|
||||
type KubeconfigCredential struct {
|
||||
Content string `json:"content,omitempty" description:"content of kubeconfig"`
|
||||
}
|
||||
|
||||
const (
|
||||
CredentialTypeUsernamePassword = "username_password"
|
||||
CredentialTypeSsh = "ssh"
|
||||
CredentialTypeSecretText = "secret_text"
|
||||
CredentialTypeKubeConfig = "kubeconfig"
|
||||
)
|
||||
|
||||
var CredentialTypeMap = map[string]string{
|
||||
"SSH Username with private key": CredentialTypeSsh,
|
||||
"Username with password": CredentialTypeUsernamePassword,
|
||||
"Secret text": CredentialTypeSecretText,
|
||||
"Kubernetes configuration (kubeconfig)": CredentialTypeKubeConfig,
|
||||
}
|
||||
|
||||
type CredentialOperator interface {
|
||||
CreateCredentialInProject(projectId string, credential *Credential) (*string, error)
|
||||
|
||||
UpdateCredentialInProject(projectId string, credential *Credential) (*string, error)
|
||||
|
||||
GetCredentialInProject(projectId, id string, content bool) (*Credential, error)
|
||||
|
||||
GetCredentialsInProject(projectId string) ([]*Credential, error)
|
||||
|
||||
DeleteCredentialInProject(projectId, id string) (*string, error)
|
||||
}
|
||||
206
pkg/simple/client/devops/fake/fakedevops.go
Normal file
206
pkg/simple/client/devops/fake/fakedevops.go
Normal file
@@ -0,0 +1,206 @@
|
||||
package fake
|
||||
|
||||
import (
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/devops"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type FakeDevops struct {
|
||||
Data map[string]interface{}
|
||||
}
|
||||
|
||||
func NewFakeDevops(data map[string]interface{}) *FakeDevops {
|
||||
var fakeData FakeDevops
|
||||
fakeData.Data = data
|
||||
return &fakeData
|
||||
}
|
||||
|
||||
// Pipelinne operator interface
|
||||
func (d *FakeDevops) GetPipeline(projectName, pipelineName string, httpParameters *devops.HttpParameters) (*devops.Pipeline, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (d *FakeDevops) ListPipelines(httpParameters *devops.HttpParameters) (*devops.PipelineList, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (d *FakeDevops) GetPipelineRun(projectName, pipelineName, runId string, httpParameters *devops.HttpParameters) (*devops.PipelineRun, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (d *FakeDevops) ListPipelineRuns(projectName, pipelineName string, httpParameters *devops.HttpParameters) (*devops.PipelineRunList, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (d *FakeDevops) StopPipeline(projectName, pipelineName, runId string, httpParameters *devops.HttpParameters) (*devops.StopPipeline, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (d *FakeDevops) ReplayPipeline(projectName, pipelineName, runId string, httpParameters *devops.HttpParameters) (*devops.ReplayPipeline, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (d *FakeDevops) RunPipeline(projectName, pipelineName string, httpParameters *devops.HttpParameters) (*devops.RunPipeline, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (d *FakeDevops) GetArtifacts(projectName, pipelineName, runId string, httpParameters *devops.HttpParameters) ([]devops.Artifacts, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (d *FakeDevops) GetRunLog(projectName, pipelineName, runId string, httpParameters *devops.HttpParameters) ([]byte, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (d *FakeDevops) GetStepLog(projectName, pipelineName, runId, nodeId, stepId string, httpParameters *devops.HttpParameters) ([]byte, http.Header, error) {
|
||||
return nil, nil, nil
|
||||
}
|
||||
func (d *FakeDevops) GetNodeSteps(projectName, pipelineName, runId, nodeId string, httpParameters *devops.HttpParameters) ([]devops.NodeSteps, error) {
|
||||
s := []string{projectName, pipelineName, runId, nodeId}
|
||||
key := strings.Join(s, "-")
|
||||
res := d.Data[key].([]devops.NodeSteps)
|
||||
return res, nil
|
||||
}
|
||||
func (d *FakeDevops) GetPipelineRunNodes(projectName, pipelineName, runId string, httpParameters *devops.HttpParameters) ([]devops.PipelineRunNodes, error) {
|
||||
s := []string{projectName, pipelineName, runId}
|
||||
key := strings.Join(s, "-")
|
||||
res := d.Data[key].([]devops.PipelineRunNodes)
|
||||
return res, nil
|
||||
}
|
||||
func (d *FakeDevops) SubmitInputStep(projectName, pipelineName, runId, nodeId, stepId string, httpParameters *devops.HttpParameters) ([]byte, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
//BranchPipelinne operator interface
|
||||
func (d *FakeDevops) GetBranchPipeline(projectName, pipelineName, branchName string, httpParameters *devops.HttpParameters) (*devops.BranchPipeline, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (d *FakeDevops) GetBranchPipelineRun(projectName, pipelineName, branchName, runId string, httpParameters *devops.HttpParameters) (*devops.PipelineRun, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (d *FakeDevops) StopBranchPipeline(projectName, pipelineName, branchName, runId string, httpParameters *devops.HttpParameters) (*devops.StopPipeline, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (d *FakeDevops) ReplayBranchPipeline(projectName, pipelineName, branchName, runId string, httpParameters *devops.HttpParameters) (*devops.ReplayPipeline, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (d *FakeDevops) RunBranchPipeline(projectName, pipelineName, branchName string, httpParameters *devops.HttpParameters) (*devops.RunPipeline, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (d *FakeDevops) GetBranchArtifacts(projectName, pipelineName, branchName, runId string, httpParameters *devops.HttpParameters) ([]devops.Artifacts, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (d *FakeDevops) GetBranchRunLog(projectName, pipelineName, branchName, runId string, httpParameters *devops.HttpParameters) ([]byte, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (d *FakeDevops) GetBranchStepLog(projectName, pipelineName, branchName, runId, nodeId, stepId string, httpParameters *devops.HttpParameters) ([]byte, http.Header, error) {
|
||||
return nil, nil, nil
|
||||
}
|
||||
func (d *FakeDevops) GetBranchNodeSteps(projectName, pipelineName, branchName, runId, nodeId string, httpParameters *devops.HttpParameters) ([]devops.NodeSteps, error) {
|
||||
s := []string{projectName, pipelineName, branchName, runId, nodeId}
|
||||
key := strings.Join(s, "-")
|
||||
res := d.Data[key].([]devops.NodeSteps)
|
||||
return res, nil
|
||||
}
|
||||
func (d *FakeDevops) GetBranchPipelineRunNodes(projectName, pipelineName, branchName, runId string, httpParameters *devops.HttpParameters) ([]devops.BranchPipelineRunNodes, error) {
|
||||
s := []string{projectName, pipelineName, branchName, runId}
|
||||
key := strings.Join(s, "-")
|
||||
res := d.Data[key].([]devops.BranchPipelineRunNodes)
|
||||
return res, nil
|
||||
}
|
||||
func (d *FakeDevops) SubmitBranchInputStep(projectName, pipelineName, branchName, runId, nodeId, stepId string, httpParameters *devops.HttpParameters) ([]byte, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (d *FakeDevops) GetPipelineBranch(projectName, pipelineName string, httpParameters *devops.HttpParameters) (*devops.PipelineBranch, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (d *FakeDevops) ScanBranch(projectName, pipelineName string, httpParameters *devops.HttpParameters) ([]byte, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Common pipeline operator interface
|
||||
func (d *FakeDevops) GetConsoleLog(projectName, pipelineName string, httpParameters *devops.HttpParameters) ([]byte, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (d *FakeDevops) GetCrumb(httpParameters *devops.HttpParameters) (*devops.Crumb, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// SCM operator interface
|
||||
func (d *FakeDevops) GetSCMServers(scmId string, httpParameters *devops.HttpParameters) ([]devops.SCMServer, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (d *FakeDevops) GetSCMOrg(scmId string, httpParameters *devops.HttpParameters) ([]devops.SCMOrg, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (d *FakeDevops) GetOrgRepo(scmId, organizationId string, httpParameters *devops.HttpParameters) ([]devops.OrgRepo, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (d *FakeDevops) CreateSCMServers(scmId string, httpParameters *devops.HttpParameters) (*devops.SCMServer, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (d *FakeDevops) Validate(scmId string, httpParameters *devops.HttpParameters) (*devops.Validates, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
//Webhook operator interface
|
||||
func (d *FakeDevops) GetNotifyCommit(httpParameters *devops.HttpParameters) ([]byte, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (d *FakeDevops) GithubWebhook(httpParameters *devops.HttpParameters) ([]byte, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (d *FakeDevops) CheckScriptCompile(projectName, pipelineName string, httpParameters *devops.HttpParameters) (*devops.CheckScript, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (d *FakeDevops) CheckCron(projectName string, httpParameters *devops.HttpParameters) (*devops.CheckCronRes, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (d *FakeDevops) ToJenkinsfile(httpParameters *devops.HttpParameters) (*devops.ResJenkinsfile, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (d *FakeDevops) ToJson(httpParameters *devops.HttpParameters) (*devops.ResJson, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// CredentialOperator
|
||||
func (d *FakeDevops) CreateCredentialInProject(projectId string, credential *devops.Credential) (*string, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (d *FakeDevops) UpdateCredentialInProject(projectId string, credential *devops.Credential) (*string, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (d *FakeDevops) GetCredentialInProject(projectId, id string, content bool) (*devops.Credential, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (d *FakeDevops) GetCredentialsInProject(projectId string) ([]*devops.Credential, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (d *FakeDevops) DeleteCredentialInProject(projectId, id string) (*string, error) { return nil, nil }
|
||||
|
||||
// BuildGetter
|
||||
func (d *FakeDevops) GetProjectPipelineBuildByType(projectId, pipelineId string, status string) (*devops.Build, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (d *FakeDevops) GetMultiBranchPipelineBuildByType(projectId, pipelineId, branch string, status string) (*devops.Build, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// ProjectMemberOperator
|
||||
func (d *FakeDevops) AddProjectMember(membership *devops.ProjectMembership) (*devops.ProjectMembership, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (d *FakeDevops) UpdateProjectMember(oldMembership, newMembership *devops.ProjectMembership) (*devops.ProjectMembership, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (d *FakeDevops) DeleteProjectMember(membership *devops.ProjectMembership) (*devops.ProjectMembership, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// ProjectPipelineOperator
|
||||
func (d *FakeDevops) CreateProjectPipeline(projectId string, pipeline *devops.ProjectPipeline) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
func (d *FakeDevops) DeleteProjectPipeline(projectId string, pipelineId string) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
func (d *FakeDevops) UpdateProjectPipeline(projectId string, pipeline *devops.ProjectPipeline) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
func (d *FakeDevops) GetProjectPipelineConfig(projectId, pipelineId string) (*devops.ProjectPipeline, error) {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -1,19 +1,13 @@
|
||||
package devops
|
||||
|
||||
type Job struct {
|
||||
|
||||
}
|
||||
|
||||
type Interface interface {
|
||||
GetJob(projectId, pipelineName string) (*Job, error)
|
||||
CredentialOperator
|
||||
|
||||
DeleteJob(projectId, pipelineId string) (bool, error)
|
||||
BuildGetter
|
||||
|
||||
CreateJobInFolder()
|
||||
PipelineOperator
|
||||
|
||||
GetGlobalRole(roleName string)
|
||||
ProjectMemberOperator
|
||||
|
||||
AddGlobalRole(roleName string, permission string)
|
||||
|
||||
GetProjectRole(roleName string)
|
||||
ProjectPipelineOperator
|
||||
}
|
||||
|
||||
24
pkg/simple/client/devops/jenkins/README.md
Normal file
24
pkg/simple/client/devops/jenkins/README.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# Jenkins API Client for Go
|
||||
|
||||
|
||||
## About
|
||||
|
||||
Jenkins is the most popular Open Source Continuous Integration system. This Library will help you interact with Jenkins in a more developer-friendly way.
|
||||
|
||||
Fork From https://github.com/bndr/gojenkins
|
||||
|
||||
These are some of the features that are currently implemented:
|
||||
|
||||
* Get information on test-results of completed/failed build
|
||||
* Ability to query Nodes, and manipulate them. Start, Stop, set Offline.
|
||||
* Ability to query Jobs, and manipulate them.
|
||||
* Get Plugins, Builds, Artifacts, Fingerprints
|
||||
* Validate Fingerprints of Artifacts
|
||||
* Get Current Queue, Cancel Tasks
|
||||
* etc. For all methods go to GoDoc Reference.
|
||||
|
||||
Add some features:
|
||||
|
||||
* Credentials Management
|
||||
* Pipeline Model Converter
|
||||
* RBAC control
|
||||
414
pkg/simple/client/devops/jenkins/build.go
Normal file
414
pkg/simple/client/devops/jenkins/build.go
Normal file
@@ -0,0 +1,414 @@
|
||||
// Copyright 2015 Vadim Kravcenko
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package jenkins
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"github.com/emicklei/go-restful"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/devops"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
Git = "git"
|
||||
Hg = "hg"
|
||||
Svn = "svc"
|
||||
)
|
||||
|
||||
type Build struct {
|
||||
Raw *devops.Build
|
||||
Job *Job
|
||||
Jenkins *Jenkins
|
||||
Base string
|
||||
Depth int
|
||||
}
|
||||
|
||||
type Parameter struct {
|
||||
Name string
|
||||
Value string
|
||||
}
|
||||
|
||||
type Branch struct {
|
||||
SHA1 string `json:",omitempty"`
|
||||
Name string `json:",omitempty"`
|
||||
}
|
||||
|
||||
type BuildRevision struct {
|
||||
SHA1 string `json:"SHA1,omitempty"`
|
||||
Branch []Branch `json:"Branch,omitempty"`
|
||||
}
|
||||
|
||||
type Builds struct {
|
||||
BuildNumber int64 `json:"buildNumber"`
|
||||
BuildResult interface{} `json:"buildResult"`
|
||||
Marked BuildRevision `json:"marked"`
|
||||
Revision BuildRevision `json:"revision"`
|
||||
}
|
||||
|
||||
type Culprit struct {
|
||||
AbsoluteUrl string
|
||||
FullName string
|
||||
}
|
||||
|
||||
type GeneralObj struct {
|
||||
Parameters []Parameter `json:"parameters,omitempty"`
|
||||
Causes []map[string]interface{} `json:"causes,omitempty"`
|
||||
BuildsByBranchName map[string]Builds `json:"buildsByBranchName,omitempty"`
|
||||
LastBuiltRevision *BuildRevision `json:"lastBuiltRevision,omitempty"`
|
||||
RemoteUrls []string `json:"remoteUrls,omitempty"`
|
||||
ScmName string `json:"scmName,omitempty"`
|
||||
MercurialNodeName string `json:"mercurialNodeName,omitempty"`
|
||||
MercurialRevisionNumber string `json:"mercurialRevisionNumber,omitempty"`
|
||||
Subdir interface{} `json:"subdir,omitempty"`
|
||||
ClassName string `json:"_class,omitempty"`
|
||||
SonarTaskId string `json:"ceTaskId,omitempty"`
|
||||
SonarServerUrl string `json:"serverUrl,omitempty"`
|
||||
SonarDashboardUrl string `json:"sonarqubeDashboardUrl,omitempty"`
|
||||
TotalCount int64 `json:",omitempty"`
|
||||
UrlName string `json:",omitempty"`
|
||||
}
|
||||
|
||||
type TestResult struct {
|
||||
Duration int64 `json:"duration"`
|
||||
Empty bool `json:"empty"`
|
||||
FailCount int64 `json:"failCount"`
|
||||
PassCount int64 `json:"passCount"`
|
||||
SkipCount int64 `json:"skipCount"`
|
||||
Suites []struct {
|
||||
Cases []struct {
|
||||
Age int64 `json:"age"`
|
||||
ClassName string `json:"className"`
|
||||
Duration int64 `json:"duration"`
|
||||
ErrorDetails interface{} `json:"errorDetails"`
|
||||
ErrorStackTrace interface{} `json:"errorStackTrace"`
|
||||
FailedSince int64 `json:"failedSince"`
|
||||
Name string `json:"name"`
|
||||
Skipped bool `json:"skipped"`
|
||||
SkippedMessage interface{} `json:"skippedMessage"`
|
||||
Status string `json:"status"`
|
||||
Stderr interface{} `json:"stderr"`
|
||||
Stdout interface{} `json:"stdout"`
|
||||
} `json:"cases"`
|
||||
Duration int64 `json:"duration"`
|
||||
ID interface{} `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Stderr interface{} `json:"stderr"`
|
||||
Stdout interface{} `json:"stdout"`
|
||||
Timestamp interface{} `json:"timestamp"`
|
||||
} `json:"suites"`
|
||||
}
|
||||
|
||||
type BuildResponse struct {
|
||||
Actions []devops.GeneralAction
|
||||
Artifacts []struct {
|
||||
DisplayPath string `json:"displayPath"`
|
||||
FileName string `json:"fileName"`
|
||||
RelativePath string `json:"relativePath"`
|
||||
} `json:"artifacts"`
|
||||
Building bool `json:"building"`
|
||||
BuiltOn string `json:"builtOn"`
|
||||
ChangeSet struct {
|
||||
Items []struct {
|
||||
AffectedPaths []string `json:"affectedPaths"`
|
||||
Author struct {
|
||||
AbsoluteUrl string `json:"absoluteUrl"`
|
||||
FullName string `json:"fullName"`
|
||||
} `json:"author"`
|
||||
Comment string `json:"comment"`
|
||||
CommitID string `json:"commitId"`
|
||||
Date string `json:"date"`
|
||||
ID string `json:"id"`
|
||||
Msg string `json:"msg"`
|
||||
Paths []struct {
|
||||
EditType string `json:"editType"`
|
||||
File string `json:"file"`
|
||||
} `json:"paths"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
} `json:"items"`
|
||||
Kind string `json:"kind"`
|
||||
Revisions []struct {
|
||||
Module string
|
||||
Revision int
|
||||
} `json:"revision"`
|
||||
} `json:"changeSet"`
|
||||
Culprits []devops.Culprit `json:"culprits"`
|
||||
Description interface{} `json:"description"`
|
||||
Duration int64 `json:"duration"`
|
||||
EstimatedDuration int64 `json:"estimatedDuration"`
|
||||
Executor interface{} `json:"executor"`
|
||||
FullDisplayName string `json:"fullDisplayName"`
|
||||
ID string `json:"id"`
|
||||
KeepLog bool `json:"keepLog"`
|
||||
Number int64 `json:"number"`
|
||||
QueueID int64 `json:"queueId"`
|
||||
Result string `json:"result"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
URL string `json:"url"`
|
||||
MavenArtifacts interface{} `json:"mavenArtifacts"`
|
||||
MavenVersionUsed string `json:"mavenVersionUsed"`
|
||||
Runs []struct {
|
||||
Number int64
|
||||
URL string
|
||||
} `json:"runs"`
|
||||
}
|
||||
|
||||
// Builds
|
||||
func (b *Build) Info() *devops.Build {
|
||||
return b.Raw
|
||||
}
|
||||
|
||||
func (b *Build) GetUrl() string {
|
||||
return b.Raw.URL
|
||||
}
|
||||
|
||||
func (b *Build) GetBuildNumber() int64 {
|
||||
return b.Raw.Number
|
||||
}
|
||||
func (b *Build) GetResult() string {
|
||||
return b.Raw.Result
|
||||
}
|
||||
|
||||
func (b *Build) Stop() (bool, error) {
|
||||
if b.IsRunning() {
|
||||
response, err := b.Jenkins.Requester.Post(b.Base+"/stop", nil, nil, nil)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return false, errors.New(strconv.Itoa(response.StatusCode))
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (b *Build) GetConsoleOutput() string {
|
||||
url := b.Base + "/consoleText"
|
||||
var content string
|
||||
b.Jenkins.Requester.GetXML(url, &content, nil)
|
||||
return content
|
||||
}
|
||||
|
||||
func (b *Build) GetCauses() ([]map[string]interface{}, error) {
|
||||
_, err := b.Poll()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, a := range b.Raw.Actions {
|
||||
if a.Causes != nil {
|
||||
return a.Causes, nil
|
||||
}
|
||||
}
|
||||
return nil, errors.New("No Causes")
|
||||
}
|
||||
|
||||
func (b *Build) GetInjectedEnvVars() (map[string]string, error) {
|
||||
var envVars struct {
|
||||
EnvMap map[string]string `json:"envMap"`
|
||||
}
|
||||
endpoint := b.Base + "/injectedEnvVars"
|
||||
_, err := b.Jenkins.Requester.GetJSON(endpoint, &envVars, nil)
|
||||
if err != nil {
|
||||
return envVars.EnvMap, err
|
||||
}
|
||||
return envVars.EnvMap, nil
|
||||
}
|
||||
|
||||
func (b *Build) GetDownstreamBuilds() ([]*Build, error) {
|
||||
result := make([]*Build, 0)
|
||||
downstreamJobs, err := b.Job.GetDownstreamJobs()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, job := range downstreamJobs {
|
||||
allBuildIDs, err := job.GetAllBuildIds()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, buildID := range allBuildIDs {
|
||||
build, err := job.GetBuild(buildID.Number)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
upstreamBuild, _ := build.GetUpstreamBuild()
|
||||
// cannot compare only id, it can be from different job
|
||||
if b.GetUrl() == upstreamBuild.GetUrl() {
|
||||
result = append(result, build)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (b *Build) GetUpstreamJob() (*Job, error) {
|
||||
causes, err := b.GetCauses()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(causes) > 0 {
|
||||
if job, ok := causes[0]["upstreamProject"]; ok {
|
||||
return b.Jenkins.GetJob(job.(string))
|
||||
}
|
||||
}
|
||||
return nil, errors.New("Unable to get Upstream Job")
|
||||
}
|
||||
|
||||
func (b *Build) GetUpstreamBuildNumber() (int64, error) {
|
||||
causes, err := b.GetCauses()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if len(causes) > 0 {
|
||||
if build, ok := causes[0]["upstreamBuild"]; ok {
|
||||
switch t := build.(type) {
|
||||
default:
|
||||
return t.(int64), nil
|
||||
case float64:
|
||||
return int64(t), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
func (b *Build) GetUpstreamBuild() (*Build, error) {
|
||||
job, err := b.GetUpstreamJob()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if job != nil {
|
||||
buildNumber, err := b.GetUpstreamBuildNumber()
|
||||
if err == nil {
|
||||
return job.GetBuild(buildNumber)
|
||||
}
|
||||
}
|
||||
return nil, errors.New("Build not found")
|
||||
}
|
||||
|
||||
func (b *Build) GetResultSet() (*TestResult, error) {
|
||||
|
||||
url := b.Base + "/testReport"
|
||||
var report TestResult
|
||||
|
||||
_, err := b.Jenkins.Requester.GetJSON(url, &report, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &report, nil
|
||||
|
||||
}
|
||||
|
||||
func (b *Build) GetTimestamp() time.Time {
|
||||
msInt := int64(b.Raw.Timestamp)
|
||||
return time.Unix(0, msInt*int64(time.Millisecond))
|
||||
}
|
||||
|
||||
func (b *Build) GetDuration() int64 {
|
||||
return b.Raw.Duration
|
||||
}
|
||||
|
||||
func (b *Build) GetRevisionBranch() string {
|
||||
vcs := b.Raw.ChangeSet.Kind
|
||||
if vcs == Git {
|
||||
for _, a := range b.Raw.Actions {
|
||||
if len(a.LastBuiltRevision.Branch) > 0 && a.LastBuiltRevision.Branch[0].SHA1 != "" {
|
||||
return a.LastBuiltRevision.Branch[0].SHA1
|
||||
}
|
||||
}
|
||||
} else {
|
||||
panic("Not implemented")
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (b *Build) IsGood() bool {
|
||||
return (!b.IsRunning() && b.Raw.Result == STATUS_SUCCESS)
|
||||
}
|
||||
|
||||
func (b *Build) IsRunning() bool {
|
||||
_, err := b.Poll()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return b.Raw.Building
|
||||
}
|
||||
|
||||
func (b *Build) SetDescription(description string) error {
|
||||
data := url.Values{}
|
||||
data.Set("description", description)
|
||||
_, err := b.Jenkins.Requester.Post(b.Base+"/submitDescription", bytes.NewBufferString(data.Encode()), nil, nil)
|
||||
return err
|
||||
}
|
||||
func (b *Build) PauseToggle() error {
|
||||
response, err := b.Jenkins.Requester.Post(b.Base+"/pause/toggle", nil, nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return errors.New(strconv.Itoa(response.StatusCode))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Poll for current data. Optional Parameter - depth.
|
||||
// More about depth here: https://wiki.jenkins-ci.org/display/JENKINS/Remote+access+API
|
||||
func (b *Build) Poll(options ...interface{}) (int, error) {
|
||||
depth := "-1"
|
||||
|
||||
for _, o := range options {
|
||||
switch v := o.(type) {
|
||||
case string:
|
||||
depth = v
|
||||
case int:
|
||||
depth = strconv.Itoa(v)
|
||||
case int64:
|
||||
depth = strconv.FormatInt(v, 10)
|
||||
}
|
||||
}
|
||||
if depth == "-1" {
|
||||
depth = strconv.Itoa(b.Depth)
|
||||
}
|
||||
|
||||
qr := map[string]string{
|
||||
"depth": depth,
|
||||
}
|
||||
response, err := b.Jenkins.Requester.GetJSON(b.Base, b.Raw, qr)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return response.StatusCode, nil
|
||||
}
|
||||
|
||||
func (j *Jenkins) GetProjectPipelineBuildByType(projectId, pipelineId string, status string) (*devops.Build, error) {
|
||||
job, err := j.GetJob(pipelineId, projectId)
|
||||
if err != nil {
|
||||
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
|
||||
}
|
||||
build, err := job.getBuildByType(status)
|
||||
return build.Raw, nil
|
||||
}
|
||||
func (j *Jenkins) GetMultiBranchPipelineBuildByType(projectId, pipelineId, branch string, status string) (*devops.Build, error) {
|
||||
job, err := j.GetJob(pipelineId, projectId, branch)
|
||||
if err != nil {
|
||||
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
|
||||
}
|
||||
build, err := job.getBuildByType(status)
|
||||
return build.Raw, nil
|
||||
}
|
||||
20
pkg/simple/client/devops/jenkins/constants.go
Normal file
20
pkg/simple/client/devops/jenkins/constants.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package jenkins
|
||||
|
||||
const (
|
||||
STATUS_FAIL = "FAIL"
|
||||
STATUS_ERROR = "ERROR"
|
||||
STATUS_ABORTED = "ABORTED"
|
||||
STATUS_REGRESSION = "REGRESSION"
|
||||
STATUS_SUCCESS = "SUCCESS"
|
||||
STATUS_FIXED = "FIXED"
|
||||
STATUS_PASSED = "PASSED"
|
||||
RESULT_STATUS_FAILURE = "FAILURE"
|
||||
RESULT_STATUS_FAILED = "FAILED"
|
||||
RESULT_STATUS_SKIPPED = "SKIPPED"
|
||||
STR_RE_SPLIT_VIEW = "(.*)/view/([^/]*)/?"
|
||||
)
|
||||
|
||||
const (
|
||||
GLOBAL_ROLE = "globalRoles"
|
||||
PROJECT_ROLE = "projectRoles"
|
||||
)
|
||||
341
pkg/simple/client/devops/jenkins/credential.go
Normal file
341
pkg/simple/client/devops/jenkins/credential.go
Normal file
@@ -0,0 +1,341 @@
|
||||
/*
|
||||
Copyright 2018 The KubeSphere Authors.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package jenkins
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/PuerkitoBio/goquery"
|
||||
"github.com/emicklei/go-restful"
|
||||
"k8s.io/klog"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/devops"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const SSHCrenditalStaplerClass = "com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey"
|
||||
const DirectSSHCrenditalStaplerClass = "com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey$DirectEntryPrivateKeySource"
|
||||
const UsernamePassswordCredentialStaplerClass = "com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl"
|
||||
const SecretTextCredentialStaplerClass = "org.jenkinsci.plugins.plaincredentials.impl.StringCredentialsImpl"
|
||||
const KubeconfigCredentialStaplerClass = "com.microsoft.jenkins.kubernetes.credentials.KubeconfigCredentials"
|
||||
const DirectKubeconfigCredentialStaperClass = "com.microsoft.jenkins.kubernetes.credentials.KubeconfigCredentials$DirectEntryKubeconfigSource"
|
||||
const GLOBALScope = "GLOBAL"
|
||||
|
||||
type UsernamePasswordCredential struct {
|
||||
Scope string `json:"scope"`
|
||||
Id string `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
Description string `json:"description"`
|
||||
StaplerClass string `json:"stapler-class"`
|
||||
}
|
||||
|
||||
type SshCredential struct {
|
||||
Scope string `json:"scope"`
|
||||
Id string `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Passphrase string `json:"passphrase"`
|
||||
KeySource PrivateKeySource `json:"privateKeySource"`
|
||||
Description string `json:"description"`
|
||||
StaplerClass string `json:"stapler-class"`
|
||||
}
|
||||
|
||||
type SecretTextCredential struct {
|
||||
Scope string `json:"scope"`
|
||||
Id string `json:"id"`
|
||||
Secret string `json:"secret"`
|
||||
Description string `json:"description"`
|
||||
StaplerClass string `json:"stapler-class"`
|
||||
}
|
||||
|
||||
type KubeconfigCredential struct {
|
||||
Scope string `json:"scope"`
|
||||
Id string `json:"id"`
|
||||
Description string `json:"description"`
|
||||
KubeconfigSource KubeconfigSource `json:"kubeconfigSource"`
|
||||
StaplerClass string `json:"stapler-class"`
|
||||
}
|
||||
|
||||
type PrivateKeySource struct {
|
||||
StaplerClass string `json:"stapler-class"`
|
||||
PrivateKey string `json:"privateKey"`
|
||||
}
|
||||
|
||||
type KubeconfigSource struct {
|
||||
StaplerClass string `json:"stapler-class"`
|
||||
Content string `json:"content"`
|
||||
}
|
||||
|
||||
type CredentialResponse struct {
|
||||
Id string `json:"id"`
|
||||
TypeName string `json:"typeName"`
|
||||
DisplayName string `json:"displayName"`
|
||||
Fingerprint *struct {
|
||||
FileName string `json:"file_name,omitempty" description:"Credential's display name and description"`
|
||||
Hash string `json:"hash,omitempty" description:"Credential's hash"`
|
||||
Usage []*struct {
|
||||
Name string `json:"name,omitempty" description:"Jenkins pipeline full name"`
|
||||
Ranges struct {
|
||||
Ranges []*struct {
|
||||
Start int `json:"start,omitempty" description:"Start build number"`
|
||||
End int `json:"end,omitempty" description:"End build number"`
|
||||
} `json:"ranges,omitempty"`
|
||||
} `json:"ranges,omitempty" description:"The build number of all pipelines that use this credential"`
|
||||
} `json:"usage,omitempty" description:"all usage of Credential"`
|
||||
} `json:"fingerprint,omitempty" description:"usage of the Credential"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Domain string `json:"domain"`
|
||||
}
|
||||
|
||||
func NewSshCredential(id, username, passphrase, privateKey, description string) *SshCredential {
|
||||
keySource := PrivateKeySource{
|
||||
StaplerClass: DirectSSHCrenditalStaplerClass,
|
||||
PrivateKey: privateKey,
|
||||
}
|
||||
|
||||
return &SshCredential{
|
||||
Scope: GLOBALScope,
|
||||
Id: id,
|
||||
Username: username,
|
||||
Passphrase: passphrase,
|
||||
KeySource: keySource,
|
||||
Description: description,
|
||||
StaplerClass: SSHCrenditalStaplerClass,
|
||||
}
|
||||
}
|
||||
|
||||
func NewUsernamePasswordCredential(id, username, password, description string) *UsernamePasswordCredential {
|
||||
return &UsernamePasswordCredential{
|
||||
Scope: GLOBALScope,
|
||||
Id: id,
|
||||
Username: username,
|
||||
Password: password,
|
||||
Description: description,
|
||||
StaplerClass: UsernamePassswordCredentialStaplerClass,
|
||||
}
|
||||
}
|
||||
|
||||
func NewSecretTextCredential(id, secret, description string) *SecretTextCredential {
|
||||
return &SecretTextCredential{
|
||||
Scope: GLOBALScope,
|
||||
Id: id,
|
||||
Secret: secret,
|
||||
Description: description,
|
||||
StaplerClass: SecretTextCredentialStaplerClass,
|
||||
}
|
||||
}
|
||||
|
||||
func NewKubeconfigCredential(id, content, description string) *KubeconfigCredential {
|
||||
credentialSource := KubeconfigSource{
|
||||
StaplerClass: DirectKubeconfigCredentialStaperClass,
|
||||
Content: content,
|
||||
}
|
||||
|
||||
return &KubeconfigCredential{
|
||||
Scope: GLOBALScope,
|
||||
Id: id,
|
||||
Description: description,
|
||||
KubeconfigSource: credentialSource,
|
||||
StaplerClass: KubeconfigCredentialStaplerClass,
|
||||
}
|
||||
}
|
||||
|
||||
func (j *Jenkins) GetCredentialInProject(projectId, id string, content bool) (*devops.Credential, error) {
|
||||
responseStruct := &devops.Credential{}
|
||||
|
||||
domain := "_"
|
||||
|
||||
response, err := j.Requester.GetJSON(
|
||||
fmt.Sprintf("/job/%s/credentials/store/folder/domain/_/credential/%s", projectId, id),
|
||||
responseStruct, map[string]string{
|
||||
"depth": "2",
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return nil, errors.New(strconv.Itoa(response.StatusCode))
|
||||
}
|
||||
responseStruct.Domain = domain
|
||||
if content {
|
||||
|
||||
}
|
||||
contentString := ""
|
||||
response, err = j.Requester.GetHtml(
|
||||
fmt.Sprintf("/job/%s/credentials/store/folder/domain/%s/credential/%s/update", projectId, domain, id),
|
||||
&contentString, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return nil, errors.New(strconv.Itoa(response.StatusCode))
|
||||
}
|
||||
stringReader := strings.NewReader(contentString)
|
||||
doc, err := goquery.NewDocumentFromReader(stringReader)
|
||||
if err != nil {
|
||||
klog.Errorf("%+v", err)
|
||||
return nil, restful.NewError(http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
switch responseStruct.Type {
|
||||
case devops.CredentialTypeKubeConfig:
|
||||
content := &devops.KubeconfigCredential{}
|
||||
doc.Find("textarea[name*=content]").Each(func(i int, selection *goquery.Selection) {
|
||||
value := selection.Text()
|
||||
content.Content = value
|
||||
})
|
||||
responseStruct.KubeconfigCredential = content
|
||||
case devops.CredentialTypeUsernamePassword:
|
||||
content := &devops.UsernamePasswordCredential{}
|
||||
doc.Find("input[name*=username]").Each(func(i int, selection *goquery.Selection) {
|
||||
value, _ := selection.Attr("value")
|
||||
content.Username = value
|
||||
})
|
||||
|
||||
responseStruct.UsernamePasswordCredential = content
|
||||
case devops.CredentialTypeSsh:
|
||||
content := &devops.SshCredential{}
|
||||
doc.Find("input[name*=username]").Each(func(i int, selection *goquery.Selection) {
|
||||
value, _ := selection.Attr("value")
|
||||
content.Username = value
|
||||
})
|
||||
|
||||
doc.Find("textarea[name*=privateKey]").Each(func(i int, selection *goquery.Selection) {
|
||||
value := selection.Text()
|
||||
content.PrivateKey = value
|
||||
})
|
||||
responseStruct.SshCredential = content
|
||||
}
|
||||
return responseStruct, nil
|
||||
}
|
||||
|
||||
func (j *Jenkins) GetCredentialsInProject(projectId string) ([]*devops.Credential, error) {
|
||||
domain := "_"
|
||||
var responseStruct = &struct {
|
||||
Credentials []*devops.Credential `json:"credentials"`
|
||||
}{}
|
||||
response, err := j.Requester.GetJSON(
|
||||
fmt.Sprintf("/job/%s/credentials/store/folder/domain/_", projectId),
|
||||
responseStruct, map[string]string{
|
||||
"depth": "2",
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return nil, errors.New(strconv.Itoa(response.StatusCode))
|
||||
}
|
||||
for _, credential := range responseStruct.Credentials {
|
||||
credential.Domain = domain
|
||||
}
|
||||
return responseStruct.Credentials, nil
|
||||
|
||||
}
|
||||
|
||||
func (j *Jenkins) CreateCredentialInProject(projectId string, credential *devops.Credential) (*string, error) {
|
||||
|
||||
var request interface{}
|
||||
responseString := ""
|
||||
switch credential.Type {
|
||||
case devops.CredentialTypeUsernamePassword:
|
||||
request = NewUsernamePasswordCredential(credential.Id,
|
||||
credential.UsernamePasswordCredential.Username, credential.UsernamePasswordCredential.Password,
|
||||
credential.Description)
|
||||
|
||||
case devops.CredentialTypeSsh:
|
||||
request = NewSshCredential(credential.Id,
|
||||
credential.SshCredential.Username, credential.SshCredential.Passphrase,
|
||||
credential.SshCredential.PrivateKey, credential.Description)
|
||||
case devops.CredentialTypeSecretText:
|
||||
request = NewSecretTextCredential(credential.Id,
|
||||
credential.SecretTextCredential.Secret, credential.Description)
|
||||
case devops.CredentialTypeKubeConfig:
|
||||
request = NewKubeconfigCredential(credential.Id,
|
||||
credential.KubeconfigCredential.Content, credential.Description)
|
||||
default:
|
||||
err := fmt.Errorf("error unsupport credential type")
|
||||
klog.Errorf("%+v", err)
|
||||
return nil, restful.NewError(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
|
||||
response, err := j.Requester.Post(
|
||||
fmt.Sprintf("/job/%s/credentials/store/folder/domain/_/createCredentials", projectId),
|
||||
nil, &responseString, map[string]string{
|
||||
"json": makeJson(map[string]interface{}{
|
||||
"credentials": request,
|
||||
}),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return nil, errors.New(strconv.Itoa(response.StatusCode))
|
||||
}
|
||||
return &credential.Id, nil
|
||||
}
|
||||
|
||||
func (j *Jenkins) UpdateCredentialInProject(projectId string, credential *devops.Credential) (*string, error) {
|
||||
|
||||
requestContent := ""
|
||||
switch credential.Type {
|
||||
case devops.CredentialTypeUsernamePassword:
|
||||
requestStruct := NewUsernamePasswordCredential(credential.Id,
|
||||
credential.UsernamePasswordCredential.Username, credential.UsernamePasswordCredential.Password,
|
||||
credential.Description)
|
||||
requestContent = makeJson(requestStruct)
|
||||
|
||||
case devops.CredentialTypeSsh:
|
||||
requestStruct := NewSshCredential(credential.Id,
|
||||
credential.SshCredential.Username, credential.SshCredential.Passphrase,
|
||||
credential.SshCredential.PrivateKey, credential.Description)
|
||||
requestContent = makeJson(requestStruct)
|
||||
case devops.CredentialTypeSecretText:
|
||||
requestStruct := NewSecretTextCredential(credential.Id,
|
||||
credential.SecretTextCredential.Secret, credential.Description)
|
||||
requestContent = makeJson(requestStruct)
|
||||
case devops.CredentialTypeKubeConfig:
|
||||
requestStruct := NewKubeconfigCredential(credential.Id,
|
||||
credential.KubeconfigCredential.Content, credential.Description)
|
||||
requestContent = makeJson(requestStruct)
|
||||
default:
|
||||
err := fmt.Errorf("error unsupport credential type")
|
||||
klog.Errorf("%+v", err)
|
||||
return nil, restful.NewError(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
response, err := j.Requester.Post(
|
||||
fmt.Sprintf("/job/%s/credentials/store/folder/domain/_/credential/%s/updateSubmit", projectId, credential.Id),
|
||||
nil, nil, map[string]string{
|
||||
"json": requestContent,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return nil, errors.New(strconv.Itoa(response.StatusCode))
|
||||
}
|
||||
return &credential.Id, nil
|
||||
}
|
||||
|
||||
func (j *Jenkins) DeleteCredentialInProject(projectId, id string) (*string, error) {
|
||||
response, err := j.Requester.Post(
|
||||
fmt.Sprintf("/job/%s/credentials/store/folder/domain/_/credential/%s/doDelete", projectId, id),
|
||||
nil, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return nil, errors.New(strconv.Itoa(response.StatusCode))
|
||||
}
|
||||
return &id, nil
|
||||
}
|
||||
@@ -11,12 +11,11 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package devops
|
||||
package jenkins
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"k8s.io/klog"
|
||||
"kubesphere.io/kubesphere/pkg/gojenkins"
|
||||
"sync"
|
||||
)
|
||||
|
||||
@@ -25,13 +24,13 @@ const (
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
jenkinsClient *gojenkins.Jenkins
|
||||
jenkinsClient *Jenkins
|
||||
}
|
||||
|
||||
func NewDevopsClient(options *Options) (*Client, error) {
|
||||
var d Client
|
||||
|
||||
jenkins := gojenkins.CreateJenkins(nil, options.Host, options.MaxConnections, options.Username, options.Password)
|
||||
jenkins := CreateJenkins(nil, options.Host, options.MaxConnections, options.Username, options.Password)
|
||||
jenkins, err := jenkins.Init()
|
||||
if err != nil {
|
||||
klog.Errorf("failed to connecto to jenkins role, %+v", err)
|
||||
@@ -49,7 +48,7 @@ func NewDevopsClient(options *Options) (*Client, error) {
|
||||
return &d, nil
|
||||
}
|
||||
|
||||
func (c *Client) Jenkins() *gojenkins.Jenkins {
|
||||
func (c *Client) Jenkins() *Jenkins {
|
||||
return c.jenkinsClient
|
||||
}
|
||||
|
||||
@@ -71,14 +70,14 @@ func (c *Client) initializeJenkins() error {
|
||||
|
||||
// Jenkins uninitialized, create global role
|
||||
if globalRole == nil {
|
||||
_, err := c.jenkinsClient.AddGlobalRole(jenkinsAllUserRoleName, gojenkins.GlobalPermissionIds{GlobalRead: true}, true)
|
||||
_, err := c.jenkinsClient.AddGlobalRole(jenkinsAllUserRoleName, GlobalPermissionIds{GlobalRead: true}, true)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
_, err = c.jenkinsClient.AddProjectRole(jenkinsAllUserRoleName, "\\n\\s*\\r", gojenkins.ProjectPermissionIds{SCMTag: true}, true)
|
||||
_, err = c.jenkinsClient.AddProjectRole(jenkinsAllUserRoleName, "\\n\\s*\\r", ProjectPermissionIds{SCMTag: true}, true)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
40
pkg/simple/client/devops/jenkins/devops_test.go
Normal file
40
pkg/simple/client/devops/jenkins/devops_test.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package jenkins
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_parseCronJobTime(t *testing.T) {
|
||||
type Except struct {
|
||||
Last string
|
||||
Next string
|
||||
}
|
||||
|
||||
Items := []struct {
|
||||
Input string
|
||||
Expected Except
|
||||
}{
|
||||
{"上次运行的时间 Tuesday, September 10, 2019 8:59:09 AM UTC; 下次运行的时间 Tuesday, September 10, 2019 9:14:09 AM UTC.", Except{Last: "2019-09-10T08:59:09Z", Next: "2019-09-10T09:14:09Z"}},
|
||||
{"上次运行的时间 Thursday, January 3, 2019 11:56:30 PM UTC; 下次运行的时间 Friday, January 3, 2020 12:11:30 AM UTC.", Except{Last: "2019-01-03T23:56:30Z", Next: "2020-01-03T00:11:30Z"}},
|
||||
{"上次运行的时间 Tuesday, September 10, 2019 8:41:34 AM UTC; 下次运行的时间 Tuesday, September 10, 2019 9:41:34 AM UTC.", Except{Last: "2019-09-10T08:41:34Z", Next: "2019-09-10T09:41:34Z"}},
|
||||
{"上次运行的时间 Tuesday, September 10, 2019 9:15:26 AM UTC; 下次运行的时间 Tuesday, September 10, 2019 10:03:26 AM UTC.", Except{Last: "2019-09-10T09:15:26Z", Next: "2019-09-10T10:03:26Z"}},
|
||||
{"Would last have run at Tuesday, September 10, 2019 9:15:26 AM UTC; would next run at Tuesday, September 10, 2019 10:03:26 AM UTC.", Except{Last: "2019-09-10T09:15:26Z", Next: "2019-09-10T10:03:26Z"}},
|
||||
{"Would last have run at Tuesday, September 10, 2019 8:41:34 AM UTC; would next run at Tuesday, September 10, 2019 9:41:34 AM UTC.", Except{Last: "2019-09-10T08:41:34Z", Next: "2019-09-10T09:41:34Z"}},
|
||||
}
|
||||
|
||||
for _, item := range Items {
|
||||
last, next, err := parseCronJobTime(item.Input)
|
||||
if err != nil {
|
||||
t.Fatalf("should not get error %+v", err)
|
||||
}
|
||||
|
||||
if last != item.Expected.Last {
|
||||
t.Errorf("got %#v, expected %#v", last, item.Expected.Last)
|
||||
}
|
||||
|
||||
if next != item.Expected.Next {
|
||||
t.Errorf("got %#v, expected %#v", next, item.Expected.Next)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
75
pkg/simple/client/devops/jenkins/folder.go
Normal file
75
pkg/simple/client/devops/jenkins/folder.go
Normal file
@@ -0,0 +1,75 @@
|
||||
// Copyright 2015 Vadim Kravcenko
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package jenkins
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Folder struct {
|
||||
Raw *FolderResponse
|
||||
Jenkins *Jenkins
|
||||
Base string
|
||||
}
|
||||
|
||||
type FolderResponse struct {
|
||||
Actions []GeneralObj
|
||||
Description string `json:"description"`
|
||||
DisplayName string `json:"displayName"`
|
||||
Name string `json:"name"`
|
||||
URL string `json:"url"`
|
||||
Jobs []InnerJob `json:"jobs"`
|
||||
}
|
||||
|
||||
func (f *Folder) parentBase() string {
|
||||
return f.Base[:strings.LastIndex(f.Base, "/job")]
|
||||
}
|
||||
|
||||
func (f *Folder) GetName() string {
|
||||
return f.Raw.Name
|
||||
}
|
||||
|
||||
func (f *Folder) Create(name, description string) (*Folder, error) {
|
||||
mode := "com.cloudbees.hudson.plugins.folder.Folder"
|
||||
data := map[string]string{
|
||||
"name": name,
|
||||
"mode": mode,
|
||||
"Submit": "OK",
|
||||
"json": makeJson(map[string]string{
|
||||
"name": name,
|
||||
"mode": mode,
|
||||
"description": description,
|
||||
}),
|
||||
}
|
||||
r, err := f.Jenkins.Requester.Post(f.parentBase()+"/createItem", nil, f.Raw, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.StatusCode == 200 {
|
||||
f.Poll()
|
||||
return f, nil
|
||||
}
|
||||
return nil, errors.New(strconv.Itoa(r.StatusCode))
|
||||
}
|
||||
|
||||
func (f *Folder) Poll() (int, error) {
|
||||
response, err := f.Jenkins.Requester.GetJSON(f.Base, f.Raw, nil)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return response.StatusCode, nil
|
||||
}
|
||||
803
pkg/simple/client/devops/jenkins/jenkins.go
Normal file
803
pkg/simple/client/devops/jenkins/jenkins.go
Normal file
@@ -0,0 +1,803 @@
|
||||
// Copyright 2015 Vadim Kravcenko
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
// Gojenkins is a Jenkins Client in Go, that exposes the jenkins REST api in a more developer friendly way.
|
||||
package jenkins
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"k8s.io/klog"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/devops"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Basic Authentication
|
||||
type BasicAuth struct {
|
||||
Username string
|
||||
Password string
|
||||
}
|
||||
|
||||
type Jenkins struct {
|
||||
Server string
|
||||
Version string
|
||||
Requester *Requester
|
||||
}
|
||||
|
||||
// Loggers
|
||||
var (
|
||||
Info *log.Logger
|
||||
Warning *log.Logger
|
||||
Error *log.Logger
|
||||
)
|
||||
|
||||
// Init Method. Should be called after creating a Jenkins Instance.
|
||||
// e.g jenkins := CreateJenkins("url").Init()
|
||||
// HTTP Client is set here, Connection to jenkins is tested here.
|
||||
func (j *Jenkins) Init() (*Jenkins, error) {
|
||||
j.initLoggers()
|
||||
|
||||
rsp, err := j.Requester.GetJSON("/", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
j.Version = rsp.Header.Get("X-Jenkins")
|
||||
//if j.Raw == nil {
|
||||
// return nil, errors.New("Connection Failed, Please verify that the host and credentials are correct.")
|
||||
//}
|
||||
|
||||
return j, nil
|
||||
}
|
||||
|
||||
func (j *Jenkins) initLoggers() {
|
||||
Info = log.New(os.Stdout,
|
||||
"INFO: ",
|
||||
log.Ldate|log.Ltime|log.Lshortfile)
|
||||
|
||||
Warning = log.New(os.Stdout,
|
||||
"WARNING: ",
|
||||
log.Ldate|log.Ltime|log.Lshortfile)
|
||||
|
||||
Error = log.New(os.Stderr,
|
||||
"ERROR: ",
|
||||
log.Ldate|log.Ltime|log.Lshortfile)
|
||||
}
|
||||
|
||||
// Create a new folder
|
||||
// This folder can be nested in other parent folders
|
||||
// Example: jenkins.CreateFolder("newFolder", "grandparentFolder", "parentFolder")
|
||||
func (j *Jenkins) CreateFolder(name, description string, parents ...string) (*Folder, error) {
|
||||
folderObj := &Folder{Jenkins: j, Raw: new(FolderResponse), Base: "/job/" + strings.Join(append(parents, name), "/job/")}
|
||||
folder, err := folderObj.Create(name, description)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return folder, nil
|
||||
}
|
||||
|
||||
// Create a new job in the folder
|
||||
// Example: jenkins.CreateJobInFolder("<config></config>", "newJobName", "myFolder", "parentFolder")
|
||||
func (j *Jenkins) CreateJobInFolder(config string, jobName string, parentIDs ...string) (*Job, error) {
|
||||
jobObj := Job{Jenkins: j, Raw: new(JobResponse), Base: "/job/" + strings.Join(append(parentIDs, jobName), "/job/")}
|
||||
qr := map[string]string{
|
||||
"name": jobName,
|
||||
}
|
||||
job, err := jobObj.Create(config, qr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return job, nil
|
||||
}
|
||||
|
||||
// Create a new job from config File
|
||||
// Method takes XML string as first Parameter, and if the name is not specified in the config file
|
||||
// takes name as string as second Parameter
|
||||
// e.g jenkins.CreateJob("<config></config>","newJobName")
|
||||
func (j *Jenkins) CreateJob(config string, options ...interface{}) (*Job, error) {
|
||||
qr := make(map[string]string)
|
||||
if len(options) > 0 {
|
||||
qr["name"] = options[0].(string)
|
||||
} else {
|
||||
return nil, errors.New("Error Creating Job, job name is missing")
|
||||
}
|
||||
jobObj := Job{Jenkins: j, Raw: new(JobResponse), Base: "/job/" + qr["name"]}
|
||||
job, err := jobObj.Create(config, qr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return job, nil
|
||||
}
|
||||
|
||||
// Rename a job.
|
||||
// First Parameter job old name, Second Parameter job new name.
|
||||
func (j *Jenkins) RenameJob(job string, name string) *Job {
|
||||
jobObj := Job{Jenkins: j, Raw: new(JobResponse), Base: "/job/" + job}
|
||||
jobObj.Rename(name)
|
||||
return &jobObj
|
||||
}
|
||||
|
||||
// Create a copy of a job.
|
||||
// First Parameter Name of the job to copy from, Second Parameter new job name.
|
||||
func (j *Jenkins) CopyJob(copyFrom string, newName string) (*Job, error) {
|
||||
job := Job{Jenkins: j, Raw: new(JobResponse), Base: "/job/" + copyFrom}
|
||||
_, err := job.Poll()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return job.Copy(newName)
|
||||
}
|
||||
|
||||
// Delete a job.
|
||||
func (j *Jenkins) DeleteJob(name string, parentIDs ...string) (bool, error) {
|
||||
job := Job{Jenkins: j, Raw: new(JobResponse), Base: "/job/" + strings.Join(append(parentIDs, name), "/job/")}
|
||||
return job.Delete()
|
||||
}
|
||||
|
||||
// Invoke a job.
|
||||
// First Parameter job name, second Parameter is optional Build parameters.
|
||||
func (j *Jenkins) BuildJob(name string, options ...interface{}) (int64, error) {
|
||||
job := Job{Jenkins: j, Raw: new(JobResponse), Base: "/job/" + name}
|
||||
var params map[string]string
|
||||
if len(options) > 0 {
|
||||
params, _ = options[0].(map[string]string)
|
||||
}
|
||||
return job.InvokeSimple(params)
|
||||
}
|
||||
|
||||
func (j *Jenkins) GetBuild(jobName string, number int64) (*Build, error) {
|
||||
job, err := j.GetJob(jobName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
build, err := job.GetBuild(number)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return build, nil
|
||||
}
|
||||
|
||||
func (j *Jenkins) GetJob(id string, parentIDs ...string) (*Job, error) {
|
||||
job := Job{Jenkins: j, Raw: new(JobResponse), Base: "/job/" + strings.Join(append(parentIDs, id), "/job/")}
|
||||
status, err := job.Poll()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if status == 200 {
|
||||
return &job, nil
|
||||
}
|
||||
return nil, errors.New(strconv.Itoa(status))
|
||||
}
|
||||
|
||||
func (j *Jenkins) GetFolder(id string, parents ...string) (*Folder, error) {
|
||||
folder := Folder{Jenkins: j, Raw: new(FolderResponse), Base: "/job/" + strings.Join(append(parents, id), "/job/")}
|
||||
status, err := folder.Poll()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("trouble polling folder: %v", err)
|
||||
}
|
||||
if status == 200 {
|
||||
return &folder, nil
|
||||
}
|
||||
return nil, errors.New(strconv.Itoa(status))
|
||||
}
|
||||
|
||||
// Get all builds Numbers and URLS for a specific job.
|
||||
// There are only build IDs here,
|
||||
// To get all the other info of the build use jenkins.GetBuild(job,buildNumber)
|
||||
// or job.GetBuild(buildNumber)
|
||||
|
||||
func (j *Jenkins) Poll() (int, error) {
|
||||
resp, err := j.Requester.GetJSON("/", nil, nil)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return resp.StatusCode, nil
|
||||
}
|
||||
|
||||
func (j *Jenkins) GetGlobalRole(roleName string) (*GlobalRole, error) {
|
||||
roleResponse := &GlobalRoleResponse{
|
||||
RoleName: roleName,
|
||||
}
|
||||
stringResponse := ""
|
||||
response, err := j.Requester.Get("/role-strategy/strategy/getRole",
|
||||
&stringResponse,
|
||||
map[string]string{
|
||||
"roleName": roleName,
|
||||
"type": GLOBAL_ROLE,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return nil, errors.New(strconv.Itoa(response.StatusCode))
|
||||
}
|
||||
if stringResponse == "{}" {
|
||||
return nil, nil
|
||||
}
|
||||
err = json.Unmarshal([]byte(stringResponse), roleResponse)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &GlobalRole{
|
||||
Jenkins: j,
|
||||
Raw: *roleResponse,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (j *Jenkins) GetProjectRole(roleName string) (*ProjectRole, error) {
|
||||
roleResponse := &ProjectRoleResponse{
|
||||
RoleName: roleName,
|
||||
}
|
||||
stringResponse := ""
|
||||
response, err := j.Requester.Get("/role-strategy/strategy/getRole",
|
||||
&stringResponse,
|
||||
map[string]string{
|
||||
"roleName": roleName,
|
||||
"type": PROJECT_ROLE,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return nil, errors.New(strconv.Itoa(response.StatusCode))
|
||||
}
|
||||
if stringResponse == "{}" {
|
||||
return nil, nil
|
||||
}
|
||||
err = json.Unmarshal([]byte(stringResponse), roleResponse)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ProjectRole{
|
||||
Jenkins: j,
|
||||
Raw: *roleResponse,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (j *Jenkins) AddGlobalRole(roleName string, ids GlobalPermissionIds, overwrite bool) (*GlobalRole, error) {
|
||||
responseRole := &GlobalRole{
|
||||
Jenkins: j,
|
||||
Raw: GlobalRoleResponse{
|
||||
RoleName: roleName,
|
||||
PermissionIds: ids,
|
||||
}}
|
||||
var idArray []string
|
||||
values := reflect.ValueOf(ids)
|
||||
for i := 0; i < values.NumField(); i++ {
|
||||
field := values.Field(i)
|
||||
if field.Bool() {
|
||||
idArray = append(idArray, values.Type().Field(i).Tag.Get("json"))
|
||||
}
|
||||
}
|
||||
param := map[string]string{
|
||||
"roleName": roleName,
|
||||
"type": GLOBAL_ROLE,
|
||||
"permissionIds": strings.Join(idArray, ","),
|
||||
"overwrite": strconv.FormatBool(overwrite),
|
||||
}
|
||||
responseString := ""
|
||||
response, err := j.Requester.Post("/role-strategy/strategy/addRole", nil, &responseString, param)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return nil, errors.New(strconv.Itoa(response.StatusCode))
|
||||
}
|
||||
return responseRole, nil
|
||||
}
|
||||
|
||||
func (j *Jenkins) DeleteProjectRoles(roleName ...string) error {
|
||||
responseString := ""
|
||||
|
||||
response, err := j.Requester.Post("/role-strategy/strategy/removeRoles", nil, &responseString, map[string]string{
|
||||
"type": PROJECT_ROLE,
|
||||
"roleNames": strings.Join(roleName, ","),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if response.StatusCode != http.StatusOK {
|
||||
fmt.Println(responseString)
|
||||
return errors.New(strconv.Itoa(response.StatusCode))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (j *Jenkins) AddProjectRole(roleName string, pattern string, ids ProjectPermissionIds, overwrite bool) (*ProjectRole, error) {
|
||||
responseRole := &ProjectRole{
|
||||
Jenkins: j,
|
||||
Raw: ProjectRoleResponse{
|
||||
RoleName: roleName,
|
||||
PermissionIds: ids,
|
||||
Pattern: pattern,
|
||||
}}
|
||||
var idArray []string
|
||||
values := reflect.ValueOf(ids)
|
||||
for i := 0; i < values.NumField(); i++ {
|
||||
field := values.Field(i)
|
||||
if field.Bool() {
|
||||
idArray = append(idArray, values.Type().Field(i).Tag.Get("json"))
|
||||
}
|
||||
}
|
||||
param := map[string]string{
|
||||
"roleName": roleName,
|
||||
"type": PROJECT_ROLE,
|
||||
"permissionIds": strings.Join(idArray, ","),
|
||||
"overwrite": strconv.FormatBool(overwrite),
|
||||
"pattern": pattern,
|
||||
}
|
||||
responseString := ""
|
||||
response, err := j.Requester.Post("/role-strategy/strategy/addRole", nil, &responseString, param)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return nil, errors.New(strconv.Itoa(response.StatusCode))
|
||||
}
|
||||
return responseRole, nil
|
||||
}
|
||||
|
||||
func (j *Jenkins) DeleteUserInProject(username string) error {
|
||||
param := map[string]string{
|
||||
"type": PROJECT_ROLE,
|
||||
"sid": username,
|
||||
}
|
||||
responseString := ""
|
||||
response, err := j.Requester.Post("/role-strategy/strategy/deleteSid", nil, &responseString, param)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return errors.New(strconv.Itoa(response.StatusCode))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (j *Jenkins) GetPipeline(projectName, pipelineName string, httpParameters *devops.HttpParameters) (*devops.Pipeline, error) {
|
||||
PipelineOjb := &Pipeline{
|
||||
HttpParameters: httpParameters,
|
||||
Jenkins: j,
|
||||
Path: fmt.Sprintf(GetPipelineUrl, projectName, pipelineName),
|
||||
}
|
||||
res, err := PipelineOjb.GetPipeline()
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (j *Jenkins) ListPipelines(httpParameters *devops.HttpParameters) (*devops.PipelineList, error) {
|
||||
PipelineOjb := &Pipeline{
|
||||
HttpParameters: httpParameters,
|
||||
Jenkins: j,
|
||||
Path: ListPipelinesUrl + httpParameters.Url.RawQuery,
|
||||
}
|
||||
res, err := PipelineOjb.ListPipelines()
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (j *Jenkins) GetPipelineRun(projectName, pipelineName, runId string, httpParameters *devops.HttpParameters) (*devops.PipelineRun, error) {
|
||||
PipelineOjb := &Pipeline{
|
||||
HttpParameters: httpParameters,
|
||||
Jenkins: j,
|
||||
Path: fmt.Sprintf(GetPipelineRunUrl, projectName, pipelineName, runId),
|
||||
}
|
||||
res, err := PipelineOjb.GetPipelineRun()
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (j *Jenkins) ListPipelineRuns(projectName, pipelineName string, httpParameters *devops.HttpParameters) (*devops.PipelineRunList, error) {
|
||||
PipelineOjb := &Pipeline{
|
||||
HttpParameters: httpParameters,
|
||||
Jenkins: j,
|
||||
Path: ListPipelineRunUrl + httpParameters.Url.RawQuery,
|
||||
}
|
||||
res, err := PipelineOjb.ListPipelineRuns()
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (j *Jenkins) StopPipeline(projectName, pipelineName, runId string, httpParameters *devops.HttpParameters) (*devops.StopPipeline, error) {
|
||||
PipelineOjb := &Pipeline{
|
||||
HttpParameters: httpParameters,
|
||||
Jenkins: j,
|
||||
Path: fmt.Sprintf(StopPipelineUrl, projectName, pipelineName, runId),
|
||||
}
|
||||
res, err := PipelineOjb.StopPipeline()
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (j *Jenkins) ReplayPipeline(projectName, pipelineName, runId string, httpParameters *devops.HttpParameters) (*devops.ReplayPipeline, error) {
|
||||
PipelineOjb := &Pipeline{
|
||||
HttpParameters: httpParameters,
|
||||
Jenkins: j,
|
||||
Path: fmt.Sprintf(ReplayPipelineUrl+httpParameters.Url.RawQuery, projectName, pipelineName, runId),
|
||||
}
|
||||
res, err := PipelineOjb.ReplayPipeline()
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (j *Jenkins) RunPipeline(projectName, pipelineName string, httpParameters *devops.HttpParameters) (*devops.RunPipeline, error) {
|
||||
PipelineOjb := &Pipeline{
|
||||
HttpParameters: httpParameters,
|
||||
Jenkins: j,
|
||||
Path: fmt.Sprintf(RunPipelineUrl+httpParameters.Url.RawQuery, projectName, pipelineName),
|
||||
}
|
||||
res, err := PipelineOjb.RunPipeline()
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (j *Jenkins) GetArtifacts(projectName, pipelineName, runId string, httpParameters *devops.HttpParameters) ([]devops.Artifacts, error) {
|
||||
PipelineOjb := &Pipeline{
|
||||
HttpParameters: httpParameters,
|
||||
Jenkins: j,
|
||||
Path: fmt.Sprintf(GetArtifactsUrl+httpParameters.Url.RawQuery, projectName, pipelineName, runId),
|
||||
}
|
||||
res, err := PipelineOjb.GetArtifacts()
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (j *Jenkins) GetRunLog(projectName, pipelineName, runId string, httpParameters *devops.HttpParameters) ([]byte, error) {
|
||||
PipelineOjb := &Pipeline{
|
||||
HttpParameters: httpParameters,
|
||||
Jenkins: j,
|
||||
Path: fmt.Sprintf(GetRunLogUrl+httpParameters.Url.RawQuery, projectName, pipelineName, runId),
|
||||
}
|
||||
res, err := PipelineOjb.GetRunLog()
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (j *Jenkins) GetStepLog(projectName, pipelineName, runId, nodeId, stepId string, httpParameters *devops.HttpParameters) ([]byte, http.Header, error) {
|
||||
PipelineOjb := &Pipeline{
|
||||
HttpParameters: httpParameters,
|
||||
Jenkins: j,
|
||||
Path: fmt.Sprintf(GetStepLogUrl+httpParameters.Url.RawQuery, projectName, pipelineName, runId, nodeId, stepId),
|
||||
}
|
||||
res, header, err := PipelineOjb.GetStepLog()
|
||||
return res, header, err
|
||||
}
|
||||
|
||||
func (j *Jenkins) GetNodeSteps(projectName, pipelineName, runId, nodeId string, httpParameters *devops.HttpParameters) ([]devops.NodeSteps, error) {
|
||||
PipelineOjb := &Pipeline{
|
||||
HttpParameters: httpParameters,
|
||||
Jenkins: j,
|
||||
Path: fmt.Sprintf(GetNodeStepsUrl+httpParameters.Url.RawQuery, projectName, pipelineName, runId, nodeId),
|
||||
}
|
||||
res, err := PipelineOjb.GetNodeSteps()
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (j *Jenkins) GetPipelineRunNodes(projectName, pipelineName, runId string, httpParameters *devops.HttpParameters) ([]devops.PipelineRunNodes, error) {
|
||||
PipelineOjb := &Pipeline{
|
||||
HttpParameters: httpParameters,
|
||||
Jenkins: j,
|
||||
Path: fmt.Sprintf(GetPipelineRunNodesUrl+httpParameters.Url.RawQuery, projectName, pipelineName, runId),
|
||||
}
|
||||
res, err := PipelineOjb.GetPipelineRunNodes()
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (j *Jenkins) SubmitInputStep(projectName, pipelineName, runId, nodeId, stepId string, httpParameters *devops.HttpParameters) ([]byte, error) {
|
||||
PipelineOjb := &Pipeline{
|
||||
HttpParameters: httpParameters,
|
||||
Jenkins: j,
|
||||
Path: fmt.Sprintf(SubmitInputStepUrl+httpParameters.Url.RawQuery, projectName, pipelineName, runId, nodeId, stepId),
|
||||
}
|
||||
res, err := PipelineOjb.SubmitInputStep()
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (j *Jenkins) GetBranchPipeline(projectName, pipelineName, branchName string, httpParameters *devops.HttpParameters) (*devops.BranchPipeline, error) {
|
||||
PipelineOjb := &Pipeline{
|
||||
HttpParameters: httpParameters,
|
||||
Jenkins: j,
|
||||
Path: fmt.Sprintf(GetBranchPipelineUrl, projectName, pipelineName, branchName),
|
||||
}
|
||||
res, err := PipelineOjb.GetBranchPipeline()
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (j *Jenkins) GetBranchPipelineRun(projectName, pipelineName, branchName, runId string, httpParameters *devops.HttpParameters) (*devops.PipelineRun, error) {
|
||||
PipelineOjb := &Pipeline{
|
||||
HttpParameters: httpParameters,
|
||||
Jenkins: j,
|
||||
Path: fmt.Sprintf(GetBranchPipelineRunUrl, projectName, pipelineName, branchName, runId),
|
||||
}
|
||||
res, err := PipelineOjb.GetBranchPipelineRun()
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (j *Jenkins) StopBranchPipeline(projectName, pipelineName, branchName, runId string, httpParameters *devops.HttpParameters) (*devops.StopPipeline, error) {
|
||||
PipelineOjb := &Pipeline{
|
||||
HttpParameters: httpParameters,
|
||||
Jenkins: j,
|
||||
Path: fmt.Sprintf(StopBranchPipelineUrl+httpParameters.Url.RawQuery, projectName, pipelineName, branchName, runId),
|
||||
}
|
||||
res, err := PipelineOjb.StopBranchPipeline()
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (j *Jenkins) ReplayBranchPipeline(projectName, pipelineName, branchName, runId string, httpParameters *devops.HttpParameters) (*devops.ReplayPipeline, error) {
|
||||
PipelineOjb := &Pipeline{
|
||||
HttpParameters: httpParameters,
|
||||
Jenkins: j,
|
||||
Path: fmt.Sprintf(ReplayBranchPipelineUrl+httpParameters.Url.RawQuery, projectName, pipelineName, branchName, runId),
|
||||
}
|
||||
res, err := PipelineOjb.ReplayBranchPipeline()
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (j *Jenkins) RunBranchPipeline(projectName, pipelineName, branchName string, httpParameters *devops.HttpParameters) (*devops.RunPipeline, error) {
|
||||
PipelineOjb := &Pipeline{
|
||||
HttpParameters: httpParameters,
|
||||
Jenkins: j,
|
||||
Path: fmt.Sprintf(RunBranchPipelineUrl+httpParameters.Url.RawQuery, projectName, pipelineName, branchName),
|
||||
}
|
||||
res, err := PipelineOjb.RunBranchPipeline()
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (j *Jenkins) GetBranchArtifacts(projectName, pipelineName, branchName, runId string, httpParameters *devops.HttpParameters) ([]devops.Artifacts, error) {
|
||||
PipelineOjb := &Pipeline{
|
||||
HttpParameters: httpParameters,
|
||||
Jenkins: j,
|
||||
Path: fmt.Sprintf(GetBranchArtifactsUrl+httpParameters.Url.RawQuery, projectName, pipelineName, branchName, runId),
|
||||
}
|
||||
res, err := PipelineOjb.GetBranchArtifacts()
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (j *Jenkins) GetBranchRunLog(projectName, pipelineName, branchName, runId string, httpParameters *devops.HttpParameters) ([]byte, error) {
|
||||
PipelineOjb := &Pipeline{
|
||||
HttpParameters: httpParameters,
|
||||
Jenkins: j,
|
||||
Path: fmt.Sprintf(GetBranchRunLogUrl+httpParameters.Url.RawQuery, projectName, pipelineName, branchName, runId),
|
||||
}
|
||||
res, err := PipelineOjb.GetBranchRunLog()
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (j *Jenkins) GetBranchStepLog(projectName, pipelineName, branchName, runId, nodeId, stepId string, httpParameters *devops.HttpParameters) ([]byte, http.Header, error) {
|
||||
PipelineOjb := &Pipeline{
|
||||
HttpParameters: httpParameters,
|
||||
Jenkins: j,
|
||||
Path: fmt.Sprintf(GetBranchStepLogUrl+httpParameters.Url.RawQuery, projectName, pipelineName, branchName, runId, nodeId, stepId),
|
||||
}
|
||||
res, header, err := PipelineOjb.GetBranchStepLog()
|
||||
return res, header, err
|
||||
}
|
||||
|
||||
func (j *Jenkins) GetBranchNodeSteps(projectName, pipelineName, branchName, runId, nodeId string, httpParameters *devops.HttpParameters) ([]devops.NodeSteps, error) {
|
||||
PipelineOjb := &Pipeline{
|
||||
HttpParameters: httpParameters,
|
||||
Jenkins: j,
|
||||
Path: fmt.Sprintf(GetBranchNodeStepsUrl+httpParameters.Url.RawQuery, projectName, pipelineName, branchName, runId, nodeId),
|
||||
}
|
||||
res, err := PipelineOjb.GetBranchNodeSteps()
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (j *Jenkins) GetBranchPipelineRunNodes(projectName, pipelineName, branchName, runId string, httpParameters *devops.HttpParameters) ([]devops.BranchPipelineRunNodes, error) {
|
||||
PipelineOjb := &Pipeline{
|
||||
HttpParameters: httpParameters,
|
||||
Jenkins: j,
|
||||
Path: fmt.Sprintf(GetBranchPipeRunNodesUrl+httpParameters.Url.RawQuery, projectName, pipelineName, branchName, runId),
|
||||
}
|
||||
res, err := PipelineOjb.GetBranchPipelineRunNodes()
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (j *Jenkins) SubmitBranchInputStep(projectName, pipelineName, branchName, runId, nodeId, stepId string, httpParameters *devops.HttpParameters) ([]byte, error) {
|
||||
PipelineOjb := &Pipeline{
|
||||
HttpParameters: httpParameters,
|
||||
Jenkins: j,
|
||||
Path: fmt.Sprintf(CheckBranchPipelineUrl+httpParameters.Url.RawQuery, projectName, pipelineName, branchName, runId, nodeId, stepId),
|
||||
}
|
||||
res, err := PipelineOjb.SubmitBranchInputStep()
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (j *Jenkins) GetPipelineBranch(projectName, pipelineName string, httpParameters *devops.HttpParameters) (*devops.PipelineBranch, error) {
|
||||
path := fmt.Sprintf(GetPipeBranchUrl, projectName, pipelineName) + httpParameters.Url.RawQuery
|
||||
PipelineOjb := &Pipeline{
|
||||
HttpParameters: httpParameters,
|
||||
Jenkins: j,
|
||||
Path: path,
|
||||
}
|
||||
res, err := PipelineOjb.GetPipelineBranch()
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (j *Jenkins) ScanBranch(projectName, pipelineName string, httpParameters *devops.HttpParameters) ([]byte, error) {
|
||||
PipelineOjb := &Pipeline{
|
||||
HttpParameters: httpParameters,
|
||||
Jenkins: j,
|
||||
Path: fmt.Sprintf(ScanBranchUrl+httpParameters.Url.RawQuery, projectName, pipelineName),
|
||||
}
|
||||
res, err := PipelineOjb.ScanBranch()
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (j *Jenkins) GetConsoleLog(projectName, pipelineName string, httpParameters *devops.HttpParameters) ([]byte, error) {
|
||||
PipelineOjb := &Pipeline{
|
||||
HttpParameters: httpParameters,
|
||||
Jenkins: j,
|
||||
Path: fmt.Sprintf(GetConsoleLogUrl+httpParameters.Url.RawQuery, projectName, pipelineName),
|
||||
}
|
||||
res, err := PipelineOjb.GetConsoleLog()
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (j *Jenkins) GetCrumb(httpParameters *devops.HttpParameters) (*devops.Crumb, error) {
|
||||
PipelineOjb := &Pipeline{
|
||||
HttpParameters: httpParameters,
|
||||
Jenkins: j,
|
||||
Path: GetCrumbUrl,
|
||||
}
|
||||
res, err := PipelineOjb.GetCrumb()
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (j *Jenkins) GetSCMServers(scmId string, httpParameters *devops.HttpParameters) ([]devops.SCMServer, error) {
|
||||
PipelineOjb := &Pipeline{
|
||||
HttpParameters: httpParameters,
|
||||
Jenkins: j,
|
||||
Path: GetSCMServersUrl,
|
||||
}
|
||||
res, err := PipelineOjb.GetSCMServers()
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (j *Jenkins) GetSCMOrg(scmId string, httpParameters *devops.HttpParameters) ([]devops.SCMOrg, error) {
|
||||
PipelineOjb := &Pipeline{
|
||||
HttpParameters: httpParameters,
|
||||
Jenkins: j,
|
||||
Path: fmt.Sprintf(GetSCMOrgUrl+httpParameters.Url.RawQuery, scmId),
|
||||
}
|
||||
res, err := PipelineOjb.GetSCMOrg()
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (j *Jenkins) GetOrgRepo(scmId, organizationId string, httpParameters *devops.HttpParameters) ([]devops.OrgRepo, error) {
|
||||
PipelineOjb := &Pipeline{
|
||||
HttpParameters: httpParameters,
|
||||
Jenkins: j,
|
||||
Path: fmt.Sprintf(GetOrgRepoUrl+httpParameters.Url.RawQuery, scmId, organizationId),
|
||||
}
|
||||
res, err := PipelineOjb.GetOrgRepo()
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (j *Jenkins) CreateSCMServers(scmId string, httpParameters *devops.HttpParameters) (*devops.SCMServer, error) {
|
||||
PipelineOjb := &Pipeline{
|
||||
HttpParameters: httpParameters,
|
||||
Jenkins: j,
|
||||
Path: fmt.Sprintf(CreateSCMServersUrl, scmId),
|
||||
}
|
||||
res, err := PipelineOjb.CreateSCMServers()
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (j *Jenkins) GetNotifyCommit(httpParameters *devops.HttpParameters) ([]byte, error) {
|
||||
PipelineOjb := &Pipeline{
|
||||
HttpParameters: httpParameters,
|
||||
Jenkins: j,
|
||||
Path: GetNotifyCommitUrl + httpParameters.Url.RawQuery,
|
||||
}
|
||||
res, err := PipelineOjb.GetNotifyCommit()
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (j *Jenkins) GithubWebhook(httpParameters *devops.HttpParameters) ([]byte, error) {
|
||||
PipelineOjb := &Pipeline{
|
||||
HttpParameters: httpParameters,
|
||||
Jenkins: j,
|
||||
Path: GithubWebhookUrl + httpParameters.Url.RawQuery,
|
||||
}
|
||||
res, err := PipelineOjb.GithubWebhook()
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (j *Jenkins) Validate(scmId string, httpParameters *devops.HttpParameters) (*devops.Validates, error) {
|
||||
PipelineOjb := &Pipeline{
|
||||
HttpParameters: httpParameters,
|
||||
Jenkins: j,
|
||||
Path: fmt.Sprintf(ValidateUrl, scmId),
|
||||
}
|
||||
res, err := PipelineOjb.Validate()
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (j *Jenkins) CheckScriptCompile(projectName, pipelineName string, httpParameters *devops.HttpParameters) (*devops.CheckScript, error) {
|
||||
PipelineOjb := &Pipeline{
|
||||
HttpParameters: httpParameters,
|
||||
Jenkins: j,
|
||||
Path: fmt.Sprintf(CheckScriptCompileUrl, projectName, pipelineName),
|
||||
}
|
||||
res, err := PipelineOjb.CheckScriptCompile()
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (j *Jenkins) CheckCron(projectName string, httpParameters *devops.HttpParameters) (*devops.CheckCronRes, error) {
|
||||
var cron = new(devops.CronData)
|
||||
var reader io.ReadCloser
|
||||
var path string
|
||||
|
||||
reader = httpParameters.Body
|
||||
cronData, err := ioutil.ReadAll(reader)
|
||||
err = json.Unmarshal(cronData, cron)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if cron.PipelineName != "" {
|
||||
path = fmt.Sprintf(CheckPipelienCronUrl, projectName, cron.PipelineName, cron.Cron)
|
||||
} else {
|
||||
path = fmt.Sprintf(CheckCronUrl, projectName, cron.Cron)
|
||||
}
|
||||
|
||||
PipelineOjb := &Pipeline{
|
||||
HttpParameters: httpParameters,
|
||||
Jenkins: j,
|
||||
Path: path,
|
||||
}
|
||||
|
||||
res, err := PipelineOjb.CheckCron()
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (j *Jenkins) ToJenkinsfile(httpParameters *devops.HttpParameters) (*devops.ResJenkinsfile, error) {
|
||||
PipelineOjb := &Pipeline{
|
||||
HttpParameters: httpParameters,
|
||||
Jenkins: j,
|
||||
Path: ToJenkinsfileUrl,
|
||||
}
|
||||
res, err := PipelineOjb.ToJenkinsfile()
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (j *Jenkins) ToJson(httpParameters *devops.HttpParameters) (*devops.ResJson, error) {
|
||||
PipelineOjb := &Pipeline{
|
||||
HttpParameters: httpParameters,
|
||||
Jenkins: j,
|
||||
Path: ToJsonUrl,
|
||||
}
|
||||
res, err := PipelineOjb.ToJson()
|
||||
return res, err
|
||||
}
|
||||
|
||||
// Creates a new Jenkins Instance
|
||||
// Optional parameters are: client, username, password
|
||||
// After creating an instance call init method.
|
||||
func CreateJenkins(client *http.Client, base string, maxConnection int, auth ...interface{}) *Jenkins {
|
||||
j := &Jenkins{}
|
||||
if strings.HasSuffix(base, "/") {
|
||||
base = base[:len(base)-1]
|
||||
}
|
||||
j.Server = base
|
||||
j.Requester = &Requester{Base: base, SslVerify: true, Client: client, connControl: make(chan struct{}, maxConnection)}
|
||||
if j.Requester.Client == nil {
|
||||
j.Requester.Client = http.DefaultClient
|
||||
}
|
||||
if len(auth) == 2 {
|
||||
j.Requester.BasicAuth = &BasicAuth{Username: auth[0].(string), Password: auth[1].(string)}
|
||||
}
|
||||
return j
|
||||
}
|
||||
504
pkg/simple/client/devops/jenkins/job.go
Normal file
504
pkg/simple/client/devops/jenkins/job.go
Normal file
@@ -0,0 +1,504 @@
|
||||
// Copyright 2015 Vadim Kravcenko
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package jenkins
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/devops"
|
||||
"net/url"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Job struct {
|
||||
Raw *JobResponse
|
||||
Jenkins *Jenkins
|
||||
Base string
|
||||
}
|
||||
|
||||
type JobBuild struct {
|
||||
Number int64
|
||||
URL string
|
||||
}
|
||||
|
||||
type JobBuildStatus struct {
|
||||
Number int64
|
||||
Building bool
|
||||
Result string
|
||||
}
|
||||
|
||||
type InnerJob struct {
|
||||
Name string `json:"name"`
|
||||
Url string `json:"url"`
|
||||
Color string `json:"color"`
|
||||
}
|
||||
|
||||
type ParameterDefinition struct {
|
||||
DefaultParameterValue struct {
|
||||
Name string `json:"name"`
|
||||
Value interface{} `json:"value"`
|
||||
} `json:"defaultParameterValue"`
|
||||
Description string `json:"description"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
type JobResponse struct {
|
||||
Class string `json:"_class"`
|
||||
Actions []devops.GeneralAction
|
||||
Buildable bool `json:"buildable"`
|
||||
Builds []JobBuild
|
||||
Color string `json:"color"`
|
||||
ConcurrentBuild bool `json:"concurrentBuild"`
|
||||
Description string `json:"description"`
|
||||
DisplayName string `json:"displayName"`
|
||||
DisplayNameOrNull interface{} `json:"displayNameOrNull"`
|
||||
DownstreamProjects []InnerJob `json:"downstreamProjects"`
|
||||
FirstBuild JobBuild
|
||||
HealthReport []struct {
|
||||
Description string `json:"description"`
|
||||
IconClassName string `json:"iconClassName"`
|
||||
IconUrl string `json:"iconUrl"`
|
||||
Score int64 `json:"score"`
|
||||
} `json:"healthReport"`
|
||||
InQueue bool `json:"inQueue"`
|
||||
KeepDependencies bool `json:"keepDependencies"`
|
||||
LastBuild JobBuild `json:"lastBuild"`
|
||||
LastCompletedBuild JobBuild `json:"lastCompletedBuild"`
|
||||
LastFailedBuild JobBuild `json:"lastFailedBuild"`
|
||||
LastStableBuild JobBuild `json:"lastStableBuild"`
|
||||
LastSuccessfulBuild JobBuild `json:"lastSuccessfulBuild"`
|
||||
LastUnstableBuild JobBuild `json:"lastUnstableBuild"`
|
||||
LastUnsuccessfulBuild JobBuild `json:"lastUnsuccessfulBuild"`
|
||||
Name string `json:"name"`
|
||||
SubJobs []InnerJob `json:"subJobs"`
|
||||
NextBuildNumber int64 `json:"nextBuildNumber"`
|
||||
Property []struct {
|
||||
ParameterDefinitions []ParameterDefinition `json:"parameterDefinitions"`
|
||||
} `json:"property"`
|
||||
QueueItem interface{} `json:"queueItem"`
|
||||
Scm struct{} `json:"scm"`
|
||||
UpstreamProjects []InnerJob `json:"upstreamProjects"`
|
||||
URL string `json:"url"`
|
||||
Jobs []InnerJob `json:"jobs"`
|
||||
}
|
||||
|
||||
func (j *Job) parentBase() string {
|
||||
return j.Base[:strings.LastIndex(j.Base, "/job/")]
|
||||
}
|
||||
|
||||
type History struct {
|
||||
BuildNumber int
|
||||
BuildStatus string
|
||||
BuildTimestamp int64
|
||||
}
|
||||
|
||||
func (j *Job) GetName() string {
|
||||
return j.Raw.Name
|
||||
}
|
||||
|
||||
func (j *Job) GetDescription() string {
|
||||
return j.Raw.Description
|
||||
}
|
||||
|
||||
func (j *Job) GetDetails() *JobResponse {
|
||||
return j.Raw
|
||||
}
|
||||
|
||||
func (j *Job) GetBuild(id int64) (*Build, error) {
|
||||
build := Build{Jenkins: j.Jenkins, Job: j, Raw: new(devops.Build), Depth: 1, Base: "/job/" + j.GetName() + "/" + strconv.FormatInt(id, 10)}
|
||||
status, err := build.Poll()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if status == 200 {
|
||||
return &build, nil
|
||||
}
|
||||
return nil, errors.New(strconv.Itoa(status))
|
||||
}
|
||||
|
||||
func (j *Job) getBuildByType(buildType string) (*Build, error) {
|
||||
allowed := map[string]JobBuild{
|
||||
"lastStableBuild": j.Raw.LastStableBuild,
|
||||
"lastSuccessfulBuild": j.Raw.LastSuccessfulBuild,
|
||||
"lastBuild": j.Raw.LastBuild,
|
||||
"lastCompletedBuild": j.Raw.LastCompletedBuild,
|
||||
"firstBuild": j.Raw.FirstBuild,
|
||||
"lastFailedBuild": j.Raw.LastFailedBuild,
|
||||
}
|
||||
number := ""
|
||||
if val, ok := allowed[buildType]; ok {
|
||||
number = strconv.FormatInt(val.Number, 10)
|
||||
} else {
|
||||
panic("No Such Build")
|
||||
}
|
||||
build := Build{
|
||||
Jenkins: j.Jenkins,
|
||||
Depth: 1,
|
||||
Job: j,
|
||||
Raw: new(devops.Build),
|
||||
Base: j.Base + "/" + number}
|
||||
status, err := build.Poll()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if status == 200 {
|
||||
return &build, nil
|
||||
}
|
||||
return nil, errors.New(strconv.Itoa(status))
|
||||
}
|
||||
|
||||
func (j *Job) GetLastSuccessfulBuild() (*Build, error) {
|
||||
return j.getBuildByType("lastSuccessfulBuild")
|
||||
}
|
||||
|
||||
func (j *Job) GetFirstBuild() (*Build, error) {
|
||||
return j.getBuildByType("firstBuild")
|
||||
}
|
||||
|
||||
func (j *Job) GetLastBuild() (*Build, error) {
|
||||
return j.getBuildByType("lastBuild")
|
||||
}
|
||||
|
||||
func (j *Job) GetLastStableBuild() (*Build, error) {
|
||||
return j.getBuildByType("lastStableBuild")
|
||||
}
|
||||
|
||||
func (j *Job) GetLastFailedBuild() (*Build, error) {
|
||||
return j.getBuildByType("lastFailedBuild")
|
||||
}
|
||||
|
||||
func (j *Job) GetLastCompletedBuild() (*Build, error) {
|
||||
return j.getBuildByType("lastCompletedBuild")
|
||||
}
|
||||
|
||||
// Returns All Builds with Number and URL
|
||||
func (j *Job) GetAllBuildIds() ([]JobBuild, error) {
|
||||
var buildsResp struct {
|
||||
Builds []JobBuild `json:"allBuilds"`
|
||||
}
|
||||
_, err := j.Jenkins.Requester.GetJSON(j.Base, &buildsResp, map[string]string{"tree": "allBuilds[number,url]"})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buildsResp.Builds, nil
|
||||
}
|
||||
|
||||
func (j *Job) GetAllBuildStatus() ([]JobBuildStatus, error) {
|
||||
var buildsResp struct {
|
||||
Builds []JobBuildStatus `json:"allBuilds"`
|
||||
}
|
||||
_, err := j.Jenkins.Requester.GetJSON(j.Base, &buildsResp, map[string]string{"tree": "allBuilds[number,building,result]"})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buildsResp.Builds, nil
|
||||
}
|
||||
|
||||
func (j *Job) GetUpstreamJobsMetadata() []InnerJob {
|
||||
return j.Raw.UpstreamProjects
|
||||
}
|
||||
|
||||
func (j *Job) GetDownstreamJobsMetadata() []InnerJob {
|
||||
return j.Raw.DownstreamProjects
|
||||
}
|
||||
|
||||
func (j *Job) GetInnerJobsMetadata() []InnerJob {
|
||||
return j.Raw.Jobs
|
||||
}
|
||||
|
||||
func (j *Job) GetUpstreamJobs() ([]*Job, error) {
|
||||
jobs := make([]*Job, len(j.Raw.UpstreamProjects))
|
||||
for i, job := range j.Raw.UpstreamProjects {
|
||||
ji, err := j.Jenkins.GetJob(job.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
jobs[i] = ji
|
||||
}
|
||||
return jobs, nil
|
||||
}
|
||||
|
||||
func (j *Job) GetDownstreamJobs() ([]*Job, error) {
|
||||
jobs := make([]*Job, len(j.Raw.DownstreamProjects))
|
||||
for i, job := range j.Raw.DownstreamProjects {
|
||||
ji, err := j.Jenkins.GetJob(job.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
jobs[i] = ji
|
||||
}
|
||||
return jobs, nil
|
||||
}
|
||||
|
||||
func (j *Job) GetInnerJob(id string) (*Job, error) {
|
||||
job := Job{Jenkins: j.Jenkins, Raw: new(JobResponse), Base: j.Base + "/job/" + id}
|
||||
status, err := job.Poll()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if status == 200 {
|
||||
return &job, nil
|
||||
}
|
||||
return nil, errors.New(strconv.Itoa(status))
|
||||
}
|
||||
|
||||
func (j *Job) GetInnerJobs() ([]*Job, error) {
|
||||
jobs := make([]*Job, len(j.Raw.Jobs))
|
||||
for i, job := range j.Raw.Jobs {
|
||||
ji, err := j.GetInnerJob(job.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
jobs[i] = ji
|
||||
}
|
||||
return jobs, nil
|
||||
}
|
||||
|
||||
func (j *Job) Enable() (bool, error) {
|
||||
resp, err := j.Jenkins.Requester.Post(j.Base+"/enable", nil, nil, nil)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if resp.StatusCode != 200 {
|
||||
return false, errors.New(strconv.Itoa(resp.StatusCode))
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (j *Job) Disable() (bool, error) {
|
||||
resp, err := j.Jenkins.Requester.Post(j.Base+"/disable", nil, nil, nil)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if resp.StatusCode != 200 {
|
||||
return false, errors.New(strconv.Itoa(resp.StatusCode))
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (j *Job) Delete() (bool, error) {
|
||||
resp, err := j.Jenkins.Requester.Post(j.Base+"/doDelete", nil, nil, nil)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if resp.StatusCode != 200 {
|
||||
return false, errors.New(strconv.Itoa(resp.StatusCode))
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (j *Job) Rename(name string) (bool, error) {
|
||||
data := url.Values{}
|
||||
data.Set("newName", name)
|
||||
_, err := j.Jenkins.Requester.Post(j.Base+"/doRename", bytes.NewBufferString(data.Encode()), nil, nil)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
j.Base = "/job/" + name
|
||||
j.Poll()
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (j *Job) Create(config string, qr ...interface{}) (*Job, error) {
|
||||
var querystring map[string]string
|
||||
if len(qr) > 0 {
|
||||
querystring = qr[0].(map[string]string)
|
||||
}
|
||||
resp, err := j.Jenkins.Requester.PostXML(j.parentBase()+"/createItem", config, j.Raw, querystring)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.StatusCode == 200 {
|
||||
j.Poll()
|
||||
return j, nil
|
||||
}
|
||||
return nil, errors.New(strconv.Itoa(resp.StatusCode))
|
||||
}
|
||||
|
||||
func (j *Job) Copy(destinationName string) (*Job, error) {
|
||||
qr := map[string]string{"name": destinationName, "from": j.GetName(), "mode": "copy"}
|
||||
resp, err := j.Jenkins.Requester.Post(j.parentBase()+"/createItem", nil, nil, qr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.StatusCode == 200 {
|
||||
newJob := &Job{Jenkins: j.Jenkins, Raw: new(JobResponse), Base: "/job/" + destinationName}
|
||||
_, err := newJob.Poll()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newJob, nil
|
||||
}
|
||||
return nil, errors.New(strconv.Itoa(resp.StatusCode))
|
||||
}
|
||||
|
||||
func (j *Job) UpdateConfig(config string) error {
|
||||
|
||||
var querystring map[string]string
|
||||
|
||||
resp, err := j.Jenkins.Requester.PostXML(j.Base+"/config.xml", config, nil, querystring)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.StatusCode == 200 {
|
||||
j.Poll()
|
||||
return nil
|
||||
}
|
||||
return errors.New(strconv.Itoa(resp.StatusCode))
|
||||
|
||||
}
|
||||
|
||||
func (j *Job) GetConfig() (string, error) {
|
||||
var data string
|
||||
_, err := j.Jenkins.Requester.GetXML(j.Base+"/config.xml", &data, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (j *Job) GetParameters() ([]ParameterDefinition, error) {
|
||||
_, err := j.Poll()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var parameters []ParameterDefinition
|
||||
for _, property := range j.Raw.Property {
|
||||
parameters = append(parameters, property.ParameterDefinitions...)
|
||||
}
|
||||
return parameters, nil
|
||||
}
|
||||
|
||||
func (j *Job) IsQueued() (bool, error) {
|
||||
if _, err := j.Poll(); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return j.Raw.InQueue, nil
|
||||
}
|
||||
|
||||
func (j *Job) IsRunning() (bool, error) {
|
||||
if _, err := j.Poll(); err != nil {
|
||||
return false, err
|
||||
}
|
||||
lastBuild, err := j.GetLastBuild()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return lastBuild.IsRunning(), nil
|
||||
}
|
||||
|
||||
func (j *Job) IsEnabled() (bool, error) {
|
||||
if _, err := j.Poll(); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return j.Raw.Color != "disabled", nil
|
||||
}
|
||||
|
||||
func (j *Job) HasQueuedBuild() {
|
||||
panic("Not Implemented yet")
|
||||
}
|
||||
|
||||
func (j *Job) InvokeSimple(params map[string]string) (int64, error) {
|
||||
endpoint := "/build"
|
||||
parameters, err := j.GetParameters()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if len(parameters) > 0 {
|
||||
endpoint = "/buildWithParameters"
|
||||
}
|
||||
data := url.Values{}
|
||||
for k, v := range params {
|
||||
data.Set(k, v)
|
||||
}
|
||||
resp, err := j.Jenkins.Requester.Post(j.Base+endpoint, bytes.NewBufferString(data.Encode()), nil, nil)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if resp.StatusCode != 200 && resp.StatusCode != 201 {
|
||||
return 0, errors.New("Could not invoke job " + j.GetName())
|
||||
}
|
||||
|
||||
location := resp.Header.Get("Location")
|
||||
if location == "" {
|
||||
return 0, errors.New("Don't have key \"Location\" in response of header")
|
||||
}
|
||||
|
||||
u, err := url.Parse(location)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
number, err := strconv.ParseInt(path.Base(u.Path), 10, 64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return number, nil
|
||||
}
|
||||
|
||||
func (j *Job) Invoke(files []string, skipIfRunning bool, params map[string]string, cause string, securityToken string) (bool, error) {
|
||||
isRunning, err := j.IsRunning()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if isRunning && skipIfRunning {
|
||||
return false, fmt.Errorf("Will not request new build because %s is already running", j.GetName())
|
||||
}
|
||||
|
||||
base := "/build"
|
||||
|
||||
// If parameters are specified - url is /builWithParameters
|
||||
if params != nil {
|
||||
base = "/buildWithParameters"
|
||||
} else {
|
||||
params = make(map[string]string)
|
||||
}
|
||||
|
||||
// If files are specified - url is /build
|
||||
if files != nil {
|
||||
base = "/build"
|
||||
}
|
||||
reqParams := map[string]string{}
|
||||
buildParams := map[string]string{}
|
||||
if securityToken != "" {
|
||||
reqParams["token"] = securityToken
|
||||
}
|
||||
|
||||
buildParams["json"] = string(makeJson(params))
|
||||
b, _ := json.Marshal(buildParams)
|
||||
resp, err := j.Jenkins.Requester.PostFiles(j.Base+base, bytes.NewBuffer(b), nil, reqParams, files)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if resp.StatusCode == 200 || resp.StatusCode == 201 {
|
||||
return true, nil
|
||||
}
|
||||
return false, errors.New(strconv.Itoa(resp.StatusCode))
|
||||
}
|
||||
|
||||
func (j *Job) Poll() (int, error) {
|
||||
response, err := j.Jenkins.Requester.GetJSON(j.Base, j.Raw, nil)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return response.StatusCode, nil
|
||||
}
|
||||
322
pkg/simple/client/devops/jenkins/member.go
Normal file
322
pkg/simple/client/devops/jenkins/member.go
Normal file
@@ -0,0 +1,322 @@
|
||||
package jenkins
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/emicklei/go-restful"
|
||||
"k8s.io/klog"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/devops"
|
||||
)
|
||||
|
||||
const (
|
||||
JenkinsAllUserRoleName = "kubesphere-user"
|
||||
)
|
||||
|
||||
func GetProjectRoleName(projectId, role string) string {
|
||||
return fmt.Sprintf("%s-%s-project", projectId, role)
|
||||
}
|
||||
|
||||
func GetPipelineRoleName(projectId, role string) string {
|
||||
return fmt.Sprintf("%s-%s-pipeline", projectId, role)
|
||||
}
|
||||
|
||||
func GetProjectRolePattern(projectId string) string {
|
||||
return fmt.Sprintf("^%s$", projectId)
|
||||
}
|
||||
|
||||
func GetPipelineRolePattern(projectId string) string {
|
||||
return fmt.Sprintf("^%s/.*", projectId)
|
||||
}
|
||||
|
||||
var JenkinsOwnerProjectPermissionIds = &ProjectPermissionIds{
|
||||
CredentialCreate: true,
|
||||
CredentialDelete: true,
|
||||
CredentialManageDomains: true,
|
||||
CredentialUpdate: true,
|
||||
CredentialView: true,
|
||||
ItemBuild: true,
|
||||
ItemCancel: true,
|
||||
ItemConfigure: true,
|
||||
ItemCreate: true,
|
||||
ItemDelete: true,
|
||||
ItemDiscover: true,
|
||||
ItemMove: true,
|
||||
ItemRead: true,
|
||||
ItemWorkspace: true,
|
||||
RunDelete: true,
|
||||
RunReplay: true,
|
||||
RunUpdate: true,
|
||||
SCMTag: true,
|
||||
}
|
||||
|
||||
var JenkinsProjectPermissionMap = map[string]ProjectPermissionIds{
|
||||
devops.ProjectOwner: {
|
||||
CredentialCreate: true,
|
||||
CredentialDelete: true,
|
||||
CredentialManageDomains: true,
|
||||
CredentialUpdate: true,
|
||||
CredentialView: true,
|
||||
ItemBuild: true,
|
||||
ItemCancel: true,
|
||||
ItemConfigure: true,
|
||||
ItemCreate: true,
|
||||
ItemDelete: true,
|
||||
ItemDiscover: true,
|
||||
ItemMove: true,
|
||||
ItemRead: true,
|
||||
ItemWorkspace: true,
|
||||
RunDelete: true,
|
||||
RunReplay: true,
|
||||
RunUpdate: true,
|
||||
SCMTag: true,
|
||||
},
|
||||
devops.ProjectMaintainer: {
|
||||
CredentialCreate: true,
|
||||
CredentialDelete: true,
|
||||
CredentialManageDomains: true,
|
||||
CredentialUpdate: true,
|
||||
CredentialView: true,
|
||||
ItemBuild: true,
|
||||
ItemCancel: true,
|
||||
ItemConfigure: false,
|
||||
ItemCreate: true,
|
||||
ItemDelete: false,
|
||||
ItemDiscover: true,
|
||||
ItemMove: false,
|
||||
ItemRead: true,
|
||||
ItemWorkspace: true,
|
||||
RunDelete: true,
|
||||
RunReplay: true,
|
||||
RunUpdate: true,
|
||||
SCMTag: true,
|
||||
},
|
||||
devops.ProjectDeveloper: {
|
||||
CredentialCreate: false,
|
||||
CredentialDelete: false,
|
||||
CredentialManageDomains: false,
|
||||
CredentialUpdate: false,
|
||||
CredentialView: false,
|
||||
ItemBuild: true,
|
||||
ItemCancel: true,
|
||||
ItemConfigure: false,
|
||||
ItemCreate: false,
|
||||
ItemDelete: false,
|
||||
ItemDiscover: true,
|
||||
ItemMove: false,
|
||||
ItemRead: true,
|
||||
ItemWorkspace: true,
|
||||
RunDelete: true,
|
||||
RunReplay: true,
|
||||
RunUpdate: true,
|
||||
SCMTag: false,
|
||||
},
|
||||
devops.ProjectReporter: {
|
||||
CredentialCreate: false,
|
||||
CredentialDelete: false,
|
||||
CredentialManageDomains: false,
|
||||
CredentialUpdate: false,
|
||||
CredentialView: false,
|
||||
ItemBuild: false,
|
||||
ItemCancel: false,
|
||||
ItemConfigure: false,
|
||||
ItemCreate: false,
|
||||
ItemDelete: false,
|
||||
ItemDiscover: true,
|
||||
ItemMove: false,
|
||||
ItemRead: true,
|
||||
ItemWorkspace: false,
|
||||
RunDelete: false,
|
||||
RunReplay: false,
|
||||
RunUpdate: false,
|
||||
SCMTag: false,
|
||||
},
|
||||
}
|
||||
|
||||
var JenkinsPipelinePermissionMap = map[string]ProjectPermissionIds{
|
||||
devops.ProjectOwner: {
|
||||
CredentialCreate: true,
|
||||
CredentialDelete: true,
|
||||
CredentialManageDomains: true,
|
||||
CredentialUpdate: true,
|
||||
CredentialView: true,
|
||||
ItemBuild: true,
|
||||
ItemCancel: true,
|
||||
ItemConfigure: true,
|
||||
ItemCreate: true,
|
||||
ItemDelete: true,
|
||||
ItemDiscover: true,
|
||||
ItemMove: true,
|
||||
ItemRead: true,
|
||||
ItemWorkspace: true,
|
||||
RunDelete: true,
|
||||
RunReplay: true,
|
||||
RunUpdate: true,
|
||||
SCMTag: true,
|
||||
},
|
||||
devops.ProjectMaintainer: {
|
||||
CredentialCreate: true,
|
||||
CredentialDelete: true,
|
||||
CredentialManageDomains: true,
|
||||
CredentialUpdate: true,
|
||||
CredentialView: true,
|
||||
ItemBuild: true,
|
||||
ItemCancel: true,
|
||||
ItemConfigure: true,
|
||||
ItemCreate: true,
|
||||
ItemDelete: true,
|
||||
ItemDiscover: true,
|
||||
ItemMove: true,
|
||||
ItemRead: true,
|
||||
ItemWorkspace: true,
|
||||
RunDelete: true,
|
||||
RunReplay: true,
|
||||
RunUpdate: true,
|
||||
SCMTag: true,
|
||||
},
|
||||
devops.ProjectDeveloper: {
|
||||
CredentialCreate: false,
|
||||
CredentialDelete: false,
|
||||
CredentialManageDomains: false,
|
||||
CredentialUpdate: false,
|
||||
CredentialView: false,
|
||||
ItemBuild: true,
|
||||
ItemCancel: true,
|
||||
ItemConfigure: false,
|
||||
ItemCreate: false,
|
||||
ItemDelete: false,
|
||||
ItemDiscover: true,
|
||||
ItemMove: false,
|
||||
ItemRead: true,
|
||||
ItemWorkspace: true,
|
||||
RunDelete: true,
|
||||
RunReplay: true,
|
||||
RunUpdate: true,
|
||||
SCMTag: false,
|
||||
},
|
||||
devops.ProjectReporter: {
|
||||
CredentialCreate: false,
|
||||
CredentialDelete: false,
|
||||
CredentialManageDomains: false,
|
||||
CredentialUpdate: false,
|
||||
CredentialView: false,
|
||||
ItemBuild: false,
|
||||
ItemCancel: false,
|
||||
ItemConfigure: false,
|
||||
ItemCreate: false,
|
||||
ItemDelete: false,
|
||||
ItemDiscover: true,
|
||||
ItemMove: false,
|
||||
ItemRead: true,
|
||||
ItemWorkspace: false,
|
||||
RunDelete: false,
|
||||
RunReplay: false,
|
||||
RunUpdate: false,
|
||||
SCMTag: false,
|
||||
},
|
||||
}
|
||||
|
||||
func (j *Jenkins) AddProjectMember(membership *devops.ProjectMembership) (*devops.ProjectMembership, error) {
|
||||
globalRole, err := j.GetGlobalRole(JenkinsAllUserRoleName)
|
||||
if err != nil {
|
||||
klog.Errorf("%+v", err)
|
||||
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
|
||||
}
|
||||
if globalRole == nil {
|
||||
_, err := j.AddGlobalRole(JenkinsAllUserRoleName, GlobalPermissionIds{
|
||||
GlobalRead: true,
|
||||
}, true)
|
||||
if err != nil {
|
||||
klog.Errorf("failed to create jenkins global role %+v", err)
|
||||
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
|
||||
}
|
||||
}
|
||||
err = globalRole.AssignRole(membership.Username)
|
||||
if err != nil {
|
||||
klog.Errorf("%+v", err)
|
||||
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
|
||||
}
|
||||
projectRole, err := j.GetProjectRole(GetProjectRoleName(membership.ProjectId, membership.Role))
|
||||
if err != nil {
|
||||
klog.Errorf("%+v", err)
|
||||
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
|
||||
}
|
||||
err = projectRole.AssignRole(membership.Username)
|
||||
if err != nil {
|
||||
klog.Errorf("%+v", err)
|
||||
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
|
||||
}
|
||||
pipelineRole, err := j.GetProjectRole(GetPipelineRoleName(membership.ProjectId, membership.Role))
|
||||
if err != nil {
|
||||
klog.Errorf("%+v", err)
|
||||
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
|
||||
}
|
||||
err = pipelineRole.AssignRole(membership.Username)
|
||||
if err != nil {
|
||||
klog.Errorf("%+v", err)
|
||||
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
|
||||
}
|
||||
return membership, nil
|
||||
}
|
||||
|
||||
func (j *Jenkins) UpdateProjectMember(oldMembership, newMembership *devops.ProjectMembership) (*devops.ProjectMembership, error) {
|
||||
oldProjectRole, err := j.GetProjectRole(GetProjectRoleName(oldMembership.ProjectId, oldMembership.Role))
|
||||
if err != nil {
|
||||
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
|
||||
}
|
||||
|
||||
err = oldProjectRole.UnAssignRole(newMembership.Username)
|
||||
if err != nil {
|
||||
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
|
||||
}
|
||||
|
||||
oldPipelineRole, err := j.GetProjectRole(GetPipelineRoleName(oldMembership.ProjectId, oldMembership.Role))
|
||||
if err != nil {
|
||||
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
|
||||
}
|
||||
|
||||
err = oldPipelineRole.UnAssignRole(newMembership.Username)
|
||||
if err != nil {
|
||||
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
|
||||
}
|
||||
|
||||
projectRole, err := j.GetProjectRole(GetProjectRoleName(oldMembership.ProjectId, newMembership.Role))
|
||||
if err != nil {
|
||||
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
|
||||
}
|
||||
|
||||
err = projectRole.AssignRole(newMembership.Username)
|
||||
if err != nil {
|
||||
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
|
||||
}
|
||||
|
||||
pipelineRole, err := j.GetProjectRole(GetPipelineRoleName(oldMembership.ProjectId, newMembership.Role))
|
||||
if err != nil {
|
||||
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
|
||||
}
|
||||
|
||||
err = pipelineRole.AssignRole(newMembership.Username)
|
||||
if err != nil {
|
||||
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
|
||||
}
|
||||
return newMembership, nil
|
||||
}
|
||||
|
||||
func (j *Jenkins) DeleteProjectMember(membership *devops.ProjectMembership) (*devops.ProjectMembership, error) {
|
||||
oldProjectRole, err := j.GetProjectRole(GetProjectRoleName(membership.ProjectId, membership.Role))
|
||||
if err != nil {
|
||||
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
|
||||
}
|
||||
err = oldProjectRole.UnAssignRole(membership.Username)
|
||||
if err != nil {
|
||||
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
|
||||
}
|
||||
|
||||
oldPipelineRole, err := j.GetProjectRole(GetPipelineRoleName(membership.ProjectId, membership.Role))
|
||||
if err != nil {
|
||||
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
|
||||
}
|
||||
err = oldPipelineRole.UnAssignRole(membership.Username)
|
||||
if err != nil {
|
||||
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
|
||||
}
|
||||
return membership, nil
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package devops
|
||||
package jenkins
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
722
pkg/simple/client/devops/jenkins/pipeline.go
Normal file
722
pkg/simple/client/devops/jenkins/pipeline.go
Normal file
@@ -0,0 +1,722 @@
|
||||
package jenkins
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/PuerkitoBio/goquery"
|
||||
"k8s.io/klog"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/devops"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Pipeline struct {
|
||||
HttpParameters *devops.HttpParameters
|
||||
Jenkins *Jenkins
|
||||
Path string
|
||||
}
|
||||
|
||||
const (
|
||||
GetPipelineUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/"
|
||||
ListPipelinesUrl = "/blue/rest/search/?"
|
||||
GetPipelineRunUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/runs/%s/"
|
||||
ListPipelineRunUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/runs/?"
|
||||
StopPipelineUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/runs/%s/stop/?"
|
||||
ReplayPipelineUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/runs/%s/replay/"
|
||||
RunPipelineUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/runs/"
|
||||
GetArtifactsUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/runs/%s/artifacts/?"
|
||||
GetRunLogUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/runs/%s/log/?"
|
||||
GetStepLogUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/runs/%s/nodes/%s/steps/%s/log/?"
|
||||
GetPipelineRunNodesUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/runs/%s/nodes/?"
|
||||
SubmitInputStepUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/runs/%s/nodes/%s/steps/%s/"
|
||||
GetNodeStepsUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/runs/%s/nodes/%s/steps/?"
|
||||
|
||||
GetBranchPipelineUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/branches/%s/"
|
||||
GetBranchPipelineRunUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/branches/%s/runs/%s/"
|
||||
StopBranchPipelineUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/branches/%s/runs/%s/stop/?"
|
||||
ReplayBranchPipelineUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/branches/%s/runs/%s/replay/"
|
||||
RunBranchPipelineUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/branches/%s/runs/"
|
||||
GetBranchArtifactsUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/branches/%s/runs/%s/artifacts/?"
|
||||
GetBranchRunLogUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/branches/%s/runs/%s/log/?"
|
||||
GetBranchStepLogUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/branches/%s/runs/%s/nodes/%s/steps/%s/log/?"
|
||||
GetBranchNodeStepsUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/branches/%s/runs/%s/nodes/%s/steps/?"
|
||||
GetBranchPipeRunNodesUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/branches/%s/runs/%s/nodes/?"
|
||||
CheckBranchPipelineUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/branches/%s/runs/%s/nodes/%s/steps/%s/"
|
||||
GetPipeBranchUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/branches/?"
|
||||
ScanBranchUrl = "/job/%s/job/%s/build?"
|
||||
GetConsoleLogUrl = "/job/%s/job/%s/indexing/consoleText"
|
||||
GetCrumbUrl = "/crumbIssuer/api/json/"
|
||||
GetSCMServersUrl = "/blue/rest/organizations/jenkins/scm/%s/servers/"
|
||||
GetSCMOrgUrl = "/blue/rest/organizations/jenkins/scm/%s/organizations/?"
|
||||
GetOrgRepoUrl = "/blue/rest/organizations/jenkins/scm/%s/organizations/%s/repositories/?"
|
||||
CreateSCMServersUrl = "/blue/rest/organizations/jenkins/scm/%s/servers/"
|
||||
ValidateUrl = "/blue/rest/organizations/jenkins/scm/%s/validate"
|
||||
|
||||
GetNotifyCommitUrl = "/git/notifyCommit/?"
|
||||
GithubWebhookUrl = "/github-webhook/"
|
||||
CheckScriptCompileUrl = "/job/%s/job/%s/descriptorByName/org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition/checkScriptCompile"
|
||||
|
||||
CheckPipelienCronUrl = "/job/%s/job/%s/descriptorByName/hudson.triggers.TimerTrigger/checkSpec?value=%s"
|
||||
CheckCronUrl = "/job/%s/descriptorByName/hudson.triggers.TimerTrigger/checkSpec?value=%s"
|
||||
ToJenkinsfileUrl = "/pipeline-model-converter/toJenkinsfile"
|
||||
ToJsonUrl = "/pipeline-model-converter/toJson"
|
||||
|
||||
cronJobLayout = "Monday, January 2, 2006 15:04:05 PM"
|
||||
)
|
||||
|
||||
func (p *Pipeline) GetPipeline() (*devops.Pipeline, error) {
|
||||
res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
}
|
||||
var pipeline devops.Pipeline
|
||||
|
||||
err = json.Unmarshal(res, &pipeline)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
return &pipeline, err
|
||||
}
|
||||
|
||||
func (p *Pipeline) ListPipelines() (*devops.PipelineList, error) {
|
||||
res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
count, err := p.searchPipelineCount()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pipelienList := devops.PipelineList{Total: count}
|
||||
err = json.Unmarshal(res, &pipelienList.Items)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
return &pipelienList, err
|
||||
}
|
||||
|
||||
func (p *Pipeline) searchPipelineCount() (int, error) {
|
||||
query, _ := parseJenkinsQuery(p.HttpParameters.Url.RawQuery)
|
||||
query.Set("start", "0")
|
||||
query.Set("limit", "1000")
|
||||
query.Set("depth", "-1")
|
||||
|
||||
formatUrl := ListPipelinesUrl + query.Encode()
|
||||
|
||||
res, err := p.Jenkins.SendPureRequest(formatUrl, p.HttpParameters)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return 0, err
|
||||
}
|
||||
var pipelines []devops.Pipeline
|
||||
err = json.Unmarshal(res, &pipelines)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return 0, err
|
||||
}
|
||||
return len(pipelines), nil
|
||||
}
|
||||
|
||||
func (p *Pipeline) GetPipelineRun() (*devops.PipelineRun, error) {
|
||||
res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
}
|
||||
|
||||
var pipelineRun devops.PipelineRun
|
||||
err = json.Unmarshal(res, &pipelineRun)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
return &pipelineRun, err
|
||||
}
|
||||
|
||||
func (p *Pipeline) ListPipelineRuns() (*devops.PipelineRunList, error) {
|
||||
res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
}
|
||||
|
||||
var pipelineRunList devops.PipelineRunList
|
||||
err = json.Unmarshal(res, &pipelineRunList)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
return &pipelineRunList, err
|
||||
}
|
||||
|
||||
func (p *Pipeline) searchPipelineRunsCount() (int, error) {
|
||||
query, _ := parseJenkinsQuery(p.HttpParameters.Url.RawQuery)
|
||||
query.Set("start", "0")
|
||||
query.Set("limit", "1000")
|
||||
query.Set("depth", "-1")
|
||||
//formatUrl := fmt.Sprintf(SearchPipelineRunUrl, projectName, pipelineName)
|
||||
|
||||
res, err := p.Jenkins.SendPureRequest(ListPipelineRunUrl+query.Encode(), p.HttpParameters)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return 0, err
|
||||
}
|
||||
var runs []devops.PipelineRun
|
||||
err = json.Unmarshal(res, &runs)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return 0, err
|
||||
}
|
||||
return len(runs), nil
|
||||
}
|
||||
|
||||
func (p *Pipeline) StopPipeline() (*devops.StopPipeline, error) {
|
||||
res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
}
|
||||
|
||||
var stopPipeline devops.StopPipeline
|
||||
err = json.Unmarshal(res, &stopPipeline)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &stopPipeline, err
|
||||
}
|
||||
|
||||
func (p *Pipeline) ReplayPipeline() (*devops.ReplayPipeline, error) {
|
||||
res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
}
|
||||
|
||||
var replayPipeline devops.ReplayPipeline
|
||||
err = json.Unmarshal(res, &replayPipeline)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &replayPipeline, err
|
||||
}
|
||||
|
||||
func (p *Pipeline) RunPipeline() (*devops.RunPipeline, error) {
|
||||
res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
}
|
||||
|
||||
var runPipeline devops.RunPipeline
|
||||
err = json.Unmarshal(res, &runPipeline)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &runPipeline, err
|
||||
}
|
||||
|
||||
func (p *Pipeline) GetArtifacts() ([]devops.Artifacts, error) {
|
||||
res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
}
|
||||
|
||||
var artifacts []devops.Artifacts
|
||||
err = json.Unmarshal(res, &artifacts)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return artifacts, err
|
||||
}
|
||||
|
||||
func (p *Pipeline) GetRunLog() ([]byte, error) {
|
||||
res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
}
|
||||
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (p *Pipeline) GetStepLog() ([]byte, http.Header, error) {
|
||||
res, header, err := p.Jenkins.SendPureRequestWithHeaderResp(p.Path, p.HttpParameters)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
}
|
||||
|
||||
return res, header, err
|
||||
}
|
||||
|
||||
func (p *Pipeline) GetNodeSteps() ([]devops.NodeSteps, error) {
|
||||
res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
}
|
||||
|
||||
var nodeSteps []devops.NodeSteps
|
||||
err = json.Unmarshal(res, &nodeSteps)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nodeSteps, err
|
||||
}
|
||||
|
||||
func (p *Pipeline) GetPipelineRunNodes() ([]devops.PipelineRunNodes, error) {
|
||||
res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
}
|
||||
|
||||
var pipelineRunNodes []devops.PipelineRunNodes
|
||||
err = json.Unmarshal(res, &pipelineRunNodes)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return pipelineRunNodes, err
|
||||
}
|
||||
|
||||
func (p *Pipeline) SubmitInputStep() ([]byte, error) {
|
||||
res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
}
|
||||
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (p *Pipeline) GetBranchPipeline() (*devops.BranchPipeline, error) {
|
||||
res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
}
|
||||
var branchPipeline devops.BranchPipeline
|
||||
err = json.Unmarshal(res, &branchPipeline)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &branchPipeline, err
|
||||
}
|
||||
|
||||
func (p *Pipeline) GetBranchPipelineRun() (*devops.PipelineRun, error) {
|
||||
res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
}
|
||||
var branchPipelineRun devops.PipelineRun
|
||||
err = json.Unmarshal(res, &branchPipelineRun)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &branchPipelineRun, err
|
||||
}
|
||||
|
||||
func (p *Pipeline) StopBranchPipeline() (*devops.StopPipeline, error) {
|
||||
res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
}
|
||||
var branchStopPipeline devops.StopPipeline
|
||||
err = json.Unmarshal(res, &branchStopPipeline)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &branchStopPipeline, err
|
||||
}
|
||||
|
||||
func (p *Pipeline) ReplayBranchPipeline() (*devops.ReplayPipeline, error) {
|
||||
res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
}
|
||||
var branchReplayPipeline devops.ReplayPipeline
|
||||
err = json.Unmarshal(res, &branchReplayPipeline)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &branchReplayPipeline, err
|
||||
}
|
||||
|
||||
func (p *Pipeline) RunBranchPipeline() (*devops.RunPipeline, error) {
|
||||
res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
}
|
||||
var branchRunPipeline devops.RunPipeline
|
||||
err = json.Unmarshal(res, &branchRunPipeline)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &branchRunPipeline, err
|
||||
}
|
||||
|
||||
func (p *Pipeline) GetBranchArtifacts() ([]devops.Artifacts, error) {
|
||||
res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
}
|
||||
|
||||
var artifacts []devops.Artifacts
|
||||
err = json.Unmarshal(res, &artifacts)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return artifacts, err
|
||||
}
|
||||
|
||||
func (p *Pipeline) GetBranchRunLog() ([]byte, error) {
|
||||
res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
}
|
||||
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (p *Pipeline) GetBranchStepLog() ([]byte, http.Header, error) {
|
||||
res, header, err := p.Jenkins.SendPureRequestWithHeaderResp(p.Path, p.HttpParameters)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
}
|
||||
|
||||
return res, header, err
|
||||
}
|
||||
|
||||
func (p *Pipeline) GetBranchNodeSteps() ([]devops.NodeSteps, error) {
|
||||
res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
}
|
||||
var branchNodeSteps []devops.NodeSteps
|
||||
err = json.Unmarshal(res, &branchNodeSteps)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return branchNodeSteps, err
|
||||
}
|
||||
|
||||
func (p *Pipeline) GetBranchPipelineRunNodes() ([]devops.BranchPipelineRunNodes, error) {
|
||||
res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
}
|
||||
var branchPipelineRunNodes []devops.BranchPipelineRunNodes
|
||||
err = json.Unmarshal(res, &branchPipelineRunNodes)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return branchPipelineRunNodes, err
|
||||
}
|
||||
|
||||
func (p *Pipeline) SubmitBranchInputStep() ([]byte, error) {
|
||||
res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
}
|
||||
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (p *Pipeline) GetPipelineBranch() (*devops.PipelineBranch, error) {
|
||||
res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
}
|
||||
var pipelineBranch devops.PipelineBranch
|
||||
err = json.Unmarshal(res, &pipelineBranch)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &pipelineBranch, err
|
||||
}
|
||||
|
||||
func (p *Pipeline) ScanBranch() ([]byte, error) {
|
||||
res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
}
|
||||
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (p *Pipeline) GetConsoleLog() ([]byte, error) {
|
||||
res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
}
|
||||
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (p *Pipeline) GetCrumb() (*devops.Crumb, error) {
|
||||
res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
}
|
||||
var crumb devops.Crumb
|
||||
err = json.Unmarshal(res, &crumb)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &crumb, err
|
||||
}
|
||||
|
||||
func (p *Pipeline) GetSCMServers() ([]devops.SCMServer, error) {
|
||||
res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
}
|
||||
var SCMServer []devops.SCMServer
|
||||
err = json.Unmarshal(res, &SCMServer)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return SCMServer, err
|
||||
}
|
||||
|
||||
func (p *Pipeline) GetSCMOrg() ([]devops.SCMOrg, error) {
|
||||
res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
}
|
||||
var SCMOrg []devops.SCMOrg
|
||||
err = json.Unmarshal(res, &SCMOrg)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return SCMOrg, err
|
||||
}
|
||||
|
||||
func (p *Pipeline) GetOrgRepo() ([]devops.OrgRepo, error) {
|
||||
res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
}
|
||||
var OrgRepo []devops.OrgRepo
|
||||
err = json.Unmarshal(res, &OrgRepo)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return OrgRepo, err
|
||||
}
|
||||
|
||||
func (p *Pipeline) CreateSCMServers() (*devops.SCMServer, error) {
|
||||
res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
}
|
||||
var SCMServer devops.SCMServer
|
||||
err = json.Unmarshal(res, &SCMServer)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &SCMServer, err
|
||||
}
|
||||
|
||||
func (p *Pipeline) GetNotifyCommit() ([]byte, error) {
|
||||
res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
}
|
||||
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (p *Pipeline) GithubWebhook() ([]byte, error) {
|
||||
res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
}
|
||||
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (p *Pipeline) Validate() (*devops.Validates, error) {
|
||||
res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
}
|
||||
|
||||
var validates devops.Validates
|
||||
err = json.Unmarshal(res, &validates)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &validates, err
|
||||
}
|
||||
|
||||
func (p *Pipeline) CheckScriptCompile() (*devops.CheckScript, error) {
|
||||
res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
}
|
||||
|
||||
// Jenkins will return different struct according to different results.
|
||||
var checkScript devops.CheckScript
|
||||
ok := json.Unmarshal(res, &checkScript)
|
||||
if ok != nil {
|
||||
var resJson []*devops.CheckScript
|
||||
err := json.Unmarshal(res, &resJson)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return resJson[0], nil
|
||||
}
|
||||
|
||||
return &checkScript, err
|
||||
|
||||
}
|
||||
|
||||
func (p *Pipeline) CheckCron() (*devops.CheckCronRes, error) {
|
||||
|
||||
var res = new(devops.CheckCronRes)
|
||||
|
||||
Url, err := url.Parse(p.Jenkins.Server + p.Path)
|
||||
|
||||
reqJenkins := &http.Request{
|
||||
Method: http.MethodGet,
|
||||
URL: Url,
|
||||
Header: p.HttpParameters.Header,
|
||||
}
|
||||
|
||||
client := &http.Client{Timeout: 30 * time.Second}
|
||||
|
||||
resp, err := client.Do(reqJenkins)
|
||||
|
||||
if resp != nil && resp.StatusCode != http.StatusOK {
|
||||
resBody, _ := getRespBody(resp)
|
||||
return &devops.CheckCronRes{
|
||||
Result: "error",
|
||||
Message: string(resBody),
|
||||
}, err
|
||||
}
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
doc, err := goquery.NewDocumentFromReader(resp.Body)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
doc.Find("div").Each(func(i int, selection *goquery.Selection) {
|
||||
res.Message = selection.Text()
|
||||
res.Result, _ = selection.Attr("class")
|
||||
})
|
||||
if res.Result == "ok" {
|
||||
res.LastTime, res.NextTime, err = parseCronJobTime(res.Message)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return res, err
|
||||
}
|
||||
|
||||
func parseCronJobTime(msg string) (string, string, error) {
|
||||
|
||||
times := strings.Split(msg, ";")
|
||||
|
||||
lastTmp := strings.Split(times[0], " ")
|
||||
lastCount := len(lastTmp)
|
||||
lastTmp = lastTmp[lastCount-7 : lastCount-1]
|
||||
lastTime := strings.Join(lastTmp, " ")
|
||||
lastUinx, err := time.Parse(cronJobLayout, lastTime)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return "", "", err
|
||||
}
|
||||
last := lastUinx.Format(time.RFC3339)
|
||||
|
||||
nextTmp := strings.Split(times[1], " ")
|
||||
nextCount := len(nextTmp)
|
||||
nextTmp = nextTmp[nextCount-7 : nextCount-1]
|
||||
nextTime := strings.Join(nextTmp, " ")
|
||||
nextUinx, err := time.Parse(cronJobLayout, nextTime)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return "", "", err
|
||||
}
|
||||
next := nextUinx.Format(time.RFC3339)
|
||||
|
||||
return last, next, nil
|
||||
}
|
||||
|
||||
func (p *Pipeline) ToJenkinsfile() (*devops.ResJenkinsfile, error) {
|
||||
res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
}
|
||||
|
||||
var jenkinsfile devops.ResJenkinsfile
|
||||
err = json.Unmarshal(res, &jenkinsfile)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &jenkinsfile, err
|
||||
}
|
||||
|
||||
func (p *Pipeline) ToJson() (*devops.ResJson, error) {
|
||||
res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
}
|
||||
|
||||
var toJson devops.ResJson
|
||||
err = json.Unmarshal(res, &toJson)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &toJson, err
|
||||
}
|
||||
893
pkg/simple/client/devops/jenkins/pipeline_internal.go
Normal file
893
pkg/simple/client/devops/jenkins/pipeline_internal.go
Normal file
@@ -0,0 +1,893 @@
|
||||
package jenkins
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/beevik/etree"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/devops"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func replaceXmlVersion(config, oldVersion, targetVersion string) string {
|
||||
lines := strings.Split(config, "\n")
|
||||
lines[0] = strings.Replace(lines[0], oldVersion, targetVersion, -1)
|
||||
output := strings.Join(lines, "\n")
|
||||
return output
|
||||
}
|
||||
|
||||
func createPipelineConfigXml(pipeline *devops.NoScmPipeline) (string, error) {
|
||||
doc := etree.NewDocument()
|
||||
xmlString := `<?xml version='1.0' encoding='UTF-8'?>
|
||||
<flow-definition plugin="workflow-job">
|
||||
<actions>
|
||||
<org.jenkinsci.plugins.pipeline.modeldefinition.actions.DeclarativeJobAction plugin="pipeline-model-definition"/>
|
||||
<org.jenkinsci.plugins.pipeline.modeldefinition.actions.DeclarativeJobPropertyTrackerAction plugin="pipeline-model-definition">
|
||||
<jobProperties/>
|
||||
<triggers/>
|
||||
<parameters/>
|
||||
<options/>
|
||||
</org.jenkinsci.plugins.pipeline.modeldefinition.actions.DeclarativeJobPropertyTrackerAction>
|
||||
</actions>
|
||||
</flow-definition>
|
||||
`
|
||||
doc.ReadFromString(xmlString)
|
||||
flow := doc.SelectElement("flow-definition")
|
||||
flow.CreateElement("description").SetText(pipeline.Description)
|
||||
properties := flow.CreateElement("properties")
|
||||
|
||||
if pipeline.DisableConcurrent {
|
||||
properties.CreateElement("org.jenkinsci.plugins.workflow.job.properties.DisableConcurrentBuildsJobProperty")
|
||||
}
|
||||
|
||||
if pipeline.Discarder != nil {
|
||||
discarder := properties.CreateElement("jenkins.model.BuildDiscarderProperty")
|
||||
strategy := discarder.CreateElement("strategy")
|
||||
strategy.CreateAttr("class", "hudson.tasks.LogRotator")
|
||||
strategy.CreateElement("daysToKeep").SetText(pipeline.Discarder.DaysToKeep)
|
||||
strategy.CreateElement("numToKeep").SetText(pipeline.Discarder.NumToKeep)
|
||||
strategy.CreateElement("artifactDaysToKeep").SetText("-1")
|
||||
strategy.CreateElement("artifactNumToKeep").SetText("-1")
|
||||
}
|
||||
if pipeline.Parameters != nil {
|
||||
appendParametersToEtree(properties, pipeline.Parameters)
|
||||
}
|
||||
|
||||
if pipeline.TimerTrigger != nil {
|
||||
triggers := properties.
|
||||
CreateElement("org.jenkinsci.plugins.workflow.job.properties.PipelineTriggersJobProperty").
|
||||
CreateElement("triggers")
|
||||
triggers.CreateElement("hudson.triggers.TimerTrigger").CreateElement("spec").SetText(pipeline.TimerTrigger.Cron)
|
||||
}
|
||||
|
||||
pipelineDefine := flow.CreateElement("definition")
|
||||
pipelineDefine.CreateAttr("class", "org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition")
|
||||
pipelineDefine.CreateAttr("plugin", "workflow-cps")
|
||||
pipelineDefine.CreateElement("script").SetText(pipeline.Jenkinsfile)
|
||||
|
||||
pipelineDefine.CreateElement("sandbox").SetText("true")
|
||||
|
||||
flow.CreateElement("triggers")
|
||||
|
||||
if pipeline.RemoteTrigger != nil {
|
||||
flow.CreateElement("authToken").SetText(pipeline.RemoteTrigger.Token)
|
||||
}
|
||||
flow.CreateElement("disabled").SetText("false")
|
||||
|
||||
doc.Indent(2)
|
||||
stringXml, err := doc.WriteToString()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return replaceXmlVersion(stringXml, "1.0", "1.1"), err
|
||||
}
|
||||
|
||||
func parsePipelineConfigXml(config string) (*devops.NoScmPipeline, error) {
|
||||
pipeline := &devops.NoScmPipeline{}
|
||||
config = replaceXmlVersion(config, "1.1", "1.0")
|
||||
doc := etree.NewDocument()
|
||||
err := doc.ReadFromString(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
flow := doc.SelectElement("flow-definition")
|
||||
if flow == nil {
|
||||
return nil, fmt.Errorf("can not find pipeline definition")
|
||||
}
|
||||
pipeline.Description = flow.SelectElement("description").Text()
|
||||
|
||||
properties := flow.SelectElement("properties")
|
||||
if properties.
|
||||
SelectElement(
|
||||
"org.jenkinsci.plugins.workflow.job.properties.DisableConcurrentBuildsJobProperty") != nil {
|
||||
pipeline.DisableConcurrent = true
|
||||
}
|
||||
if properties.SelectElement("jenkins.model.BuildDiscarderProperty") != nil {
|
||||
strategy := properties.
|
||||
SelectElement("jenkins.model.BuildDiscarderProperty").
|
||||
SelectElement("strategy")
|
||||
pipeline.Discarder = &devops.DiscarderProperty{
|
||||
DaysToKeep: strategy.SelectElement("daysToKeep").Text(),
|
||||
NumToKeep: strategy.SelectElement("numToKeep").Text(),
|
||||
}
|
||||
}
|
||||
pipeline.Parameters = &devops.Parameters{}
|
||||
pipeline.Parameters = getParametersfromEtree(properties)
|
||||
if len(*pipeline.Parameters) == 0 {
|
||||
pipeline.Parameters = nil
|
||||
}
|
||||
|
||||
if triggerProperty := properties.
|
||||
SelectElement(
|
||||
"org.jenkinsci.plugins.workflow.job.properties.PipelineTriggersJobProperty"); triggerProperty != nil {
|
||||
triggers := triggerProperty.SelectElement("triggers")
|
||||
if timerTrigger := triggers.SelectElement("hudson.triggers.TimerTrigger"); timerTrigger != nil {
|
||||
pipeline.TimerTrigger = &devops.TimerTrigger{
|
||||
Cron: timerTrigger.SelectElement("spec").Text(),
|
||||
}
|
||||
}
|
||||
}
|
||||
if authToken := flow.SelectElement("authToken"); authToken != nil {
|
||||
pipeline.RemoteTrigger = &devops.RemoteTrigger{
|
||||
Token: authToken.Text(),
|
||||
}
|
||||
}
|
||||
if definition := flow.SelectElement("definition"); definition != nil {
|
||||
if script := definition.SelectElement("script"); script != nil {
|
||||
pipeline.Jenkinsfile = script.Text()
|
||||
}
|
||||
}
|
||||
return pipeline, nil
|
||||
}
|
||||
|
||||
func appendParametersToEtree(properties *etree.Element, parameters *devops.Parameters) {
|
||||
parameterDefinitions := properties.CreateElement("hudson.model.ParametersDefinitionProperty").
|
||||
CreateElement("parameterDefinitions")
|
||||
for _, parameter := range *parameters {
|
||||
for className, typeName := range devops.ParameterTypeMap {
|
||||
if typeName == parameter.Type {
|
||||
paramDefine := parameterDefinitions.CreateElement(className)
|
||||
paramDefine.CreateElement("name").SetText(parameter.Name)
|
||||
paramDefine.CreateElement("description").SetText(parameter.Description)
|
||||
switch parameter.Type {
|
||||
case "choice":
|
||||
choices := paramDefine.CreateElement("choices")
|
||||
choices.CreateAttr("class", "java.util.Arrays$ArrayList")
|
||||
a := choices.CreateElement("a")
|
||||
a.CreateAttr("class", "string-array")
|
||||
choiceValues := strings.Split(parameter.DefaultValue, "\n")
|
||||
for _, choiceValue := range choiceValues {
|
||||
a.CreateElement("string").SetText(choiceValue)
|
||||
}
|
||||
case "file":
|
||||
break
|
||||
default:
|
||||
paramDefine.CreateElement("defaultValue").SetText(parameter.DefaultValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getParametersfromEtree(properties *etree.Element) *devops.Parameters {
|
||||
var parameters devops.Parameters
|
||||
if parametersProperty := properties.SelectElement("hudson.model.ParametersDefinitionProperty"); parametersProperty != nil {
|
||||
params := parametersProperty.SelectElement("parameterDefinitions").ChildElements()
|
||||
for _, param := range params {
|
||||
switch param.Tag {
|
||||
case "hudson.model.StringParameterDefinition":
|
||||
parameters = append(parameters, &devops.Parameter{
|
||||
Name: param.SelectElement("name").Text(),
|
||||
Description: param.SelectElement("description").Text(),
|
||||
DefaultValue: param.SelectElement("defaultValue").Text(),
|
||||
Type: devops.ParameterTypeMap["hudson.model.StringParameterDefinition"],
|
||||
})
|
||||
case "hudson.model.BooleanParameterDefinition":
|
||||
parameters = append(parameters, &devops.Parameter{
|
||||
Name: param.SelectElement("name").Text(),
|
||||
Description: param.SelectElement("description").Text(),
|
||||
DefaultValue: param.SelectElement("defaultValue").Text(),
|
||||
Type: devops.ParameterTypeMap["hudson.model.BooleanParameterDefinition"],
|
||||
})
|
||||
case "hudson.model.TextParameterDefinition":
|
||||
parameters = append(parameters, &devops.Parameter{
|
||||
Name: param.SelectElement("name").Text(),
|
||||
Description: param.SelectElement("description").Text(),
|
||||
DefaultValue: param.SelectElement("defaultValue").Text(),
|
||||
Type: devops.ParameterTypeMap["hudson.model.TextParameterDefinition"],
|
||||
})
|
||||
case "hudson.model.FileParameterDefinition":
|
||||
parameters = append(parameters, &devops.Parameter{
|
||||
Name: param.SelectElement("name").Text(),
|
||||
Description: param.SelectElement("description").Text(),
|
||||
Type: devops.ParameterTypeMap["hudson.model.FileParameterDefinition"],
|
||||
})
|
||||
case "hudson.model.PasswordParameterDefinition":
|
||||
parameters = append(parameters, &devops.Parameter{
|
||||
Name: param.SelectElement("name").Text(),
|
||||
Description: param.SelectElement("description").Text(),
|
||||
DefaultValue: param.SelectElement("name").Text(),
|
||||
Type: devops.ParameterTypeMap["hudson.model.PasswordParameterDefinition"],
|
||||
})
|
||||
case "hudson.model.ChoiceParameterDefinition":
|
||||
choiceParameter := &devops.Parameter{
|
||||
Name: param.SelectElement("name").Text(),
|
||||
Description: param.SelectElement("description").Text(),
|
||||
Type: devops.ParameterTypeMap["hudson.model.ChoiceParameterDefinition"],
|
||||
}
|
||||
choices := param.SelectElement("choices").SelectElement("a").SelectElements("string")
|
||||
for _, choice := range choices {
|
||||
choiceParameter.DefaultValue += fmt.Sprintf("%s\n", choice.Text())
|
||||
}
|
||||
choiceParameter.DefaultValue = strings.TrimSpace(choiceParameter.DefaultValue)
|
||||
parameters = append(parameters, choiceParameter)
|
||||
default:
|
||||
parameters = append(parameters, &devops.Parameter{
|
||||
Name: param.SelectElement("name").Text(),
|
||||
Description: param.SelectElement("description").Text(),
|
||||
DefaultValue: "unknown",
|
||||
Type: param.Tag,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
return ¶meters
|
||||
}
|
||||
|
||||
func appendGitSourceToEtree(source *etree.Element, gitSource *devops.GitSource) {
|
||||
source.CreateAttr("class", "jenkins.plugins.git.GitSCMSource")
|
||||
source.CreateAttr("plugin", "git")
|
||||
source.CreateElement("id").SetText(gitSource.ScmId)
|
||||
source.CreateElement("remote").SetText(gitSource.Url)
|
||||
if gitSource.CredentialId != "" {
|
||||
source.CreateElement("credentialsId").SetText(gitSource.CredentialId)
|
||||
}
|
||||
traits := source.CreateElement("traits")
|
||||
if gitSource.DiscoverBranches {
|
||||
traits.CreateElement("jenkins.plugins.git.traits.BranchDiscoveryTrait")
|
||||
}
|
||||
if gitSource.CloneOption != nil {
|
||||
cloneExtension := traits.CreateElement("jenkins.plugins.git.traits.CloneOptionTrait").CreateElement("extension")
|
||||
cloneExtension.CreateAttr("class", "hudson.plugins.git.extensions.impl.CloneOption")
|
||||
cloneExtension.CreateElement("shallow").SetText(strconv.FormatBool(gitSource.CloneOption.Shallow))
|
||||
cloneExtension.CreateElement("noTags").SetText(strconv.FormatBool(false))
|
||||
cloneExtension.CreateElement("honorRefspec").SetText(strconv.FormatBool(true))
|
||||
cloneExtension.CreateElement("reference")
|
||||
if gitSource.CloneOption.Timeout >= 0 {
|
||||
cloneExtension.CreateElement("timeout").SetText(strconv.Itoa(gitSource.CloneOption.Timeout))
|
||||
} else {
|
||||
cloneExtension.CreateElement("timeout").SetText(strconv.Itoa(10))
|
||||
}
|
||||
|
||||
if gitSource.CloneOption.Depth >= 0 {
|
||||
cloneExtension.CreateElement("depth").SetText(strconv.Itoa(gitSource.CloneOption.Depth))
|
||||
} else {
|
||||
cloneExtension.CreateElement("depth").SetText(strconv.Itoa(1))
|
||||
}
|
||||
}
|
||||
|
||||
if gitSource.RegexFilter != "" {
|
||||
regexTraits := traits.CreateElement("jenkins.scm.impl.trait.RegexSCMHeadFilterTrait")
|
||||
regexTraits.CreateAttr("plugin", "scm-api@2.4.0")
|
||||
regexTraits.CreateElement("regex").SetText(gitSource.RegexFilter)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getGitSourcefromEtree(source *etree.Element) *devops.GitSource {
|
||||
var gitSource devops.GitSource
|
||||
if credential := source.SelectElement("credentialsId"); credential != nil {
|
||||
gitSource.CredentialId = credential.Text()
|
||||
}
|
||||
if remote := source.SelectElement("remote"); remote != nil {
|
||||
gitSource.Url = remote.Text()
|
||||
}
|
||||
|
||||
traits := source.SelectElement("traits")
|
||||
if branchDiscoverTrait := traits.SelectElement(
|
||||
"jenkins.plugins.git.traits.BranchDiscoveryTrait"); branchDiscoverTrait != nil {
|
||||
gitSource.DiscoverBranches = true
|
||||
}
|
||||
if cloneTrait := traits.SelectElement(
|
||||
"jenkins.plugins.git.traits.CloneOptionTrait"); cloneTrait != nil {
|
||||
if cloneExtension := cloneTrait.SelectElement(
|
||||
"extension"); cloneExtension != nil {
|
||||
gitSource.CloneOption = &devops.GitCloneOption{}
|
||||
if value, err := strconv.ParseBool(cloneExtension.SelectElement("shallow").Text()); err == nil {
|
||||
gitSource.CloneOption.Shallow = value
|
||||
}
|
||||
if value, err := strconv.ParseInt(cloneExtension.SelectElement("timeout").Text(), 10, 32); err == nil {
|
||||
gitSource.CloneOption.Timeout = int(value)
|
||||
}
|
||||
if value, err := strconv.ParseInt(cloneExtension.SelectElement("depth").Text(), 10, 32); err == nil {
|
||||
gitSource.CloneOption.Depth = int(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
if regexTrait := traits.SelectElement(
|
||||
"jenkins.scm.impl.trait.RegexSCMHeadFilterTrait"); regexTrait != nil {
|
||||
if regex := regexTrait.SelectElement("regex"); regex != nil {
|
||||
gitSource.RegexFilter = regex.Text()
|
||||
}
|
||||
}
|
||||
return &gitSource
|
||||
}
|
||||
|
||||
func getGithubSourcefromEtree(source *etree.Element) *devops.GithubSource {
|
||||
var githubSource devops.GithubSource
|
||||
if credential := source.SelectElement("credentialsId"); credential != nil {
|
||||
githubSource.CredentialId = credential.Text()
|
||||
}
|
||||
if repoOwner := source.SelectElement("repoOwner"); repoOwner != nil {
|
||||
githubSource.Owner = repoOwner.Text()
|
||||
}
|
||||
if repository := source.SelectElement("repository"); repository != nil {
|
||||
githubSource.Repo = repository.Text()
|
||||
}
|
||||
if apiUri := source.SelectElement("apiUri"); apiUri != nil {
|
||||
githubSource.ApiUri = apiUri.Text()
|
||||
}
|
||||
traits := source.SelectElement("traits")
|
||||
if branchDiscoverTrait := traits.SelectElement(
|
||||
"org.jenkinsci.plugins.github__branch__source.BranchDiscoveryTrait"); branchDiscoverTrait != nil {
|
||||
strategyId, _ := strconv.Atoi(branchDiscoverTrait.SelectElement("strategyId").Text())
|
||||
githubSource.DiscoverBranches = strategyId
|
||||
}
|
||||
if originPRDiscoverTrait := traits.SelectElement(
|
||||
"org.jenkinsci.plugins.github__branch__source.OriginPullRequestDiscoveryTrait"); originPRDiscoverTrait != nil {
|
||||
strategyId, _ := strconv.Atoi(originPRDiscoverTrait.SelectElement("strategyId").Text())
|
||||
githubSource.DiscoverPRFromOrigin = strategyId
|
||||
}
|
||||
if forkPRDiscoverTrait := traits.SelectElement(
|
||||
"org.jenkinsci.plugins.github__branch__source.ForkPullRequestDiscoveryTrait"); forkPRDiscoverTrait != nil {
|
||||
strategyId, _ := strconv.Atoi(forkPRDiscoverTrait.SelectElement("strategyId").Text())
|
||||
trustClass := forkPRDiscoverTrait.SelectElement("trust").SelectAttr("class").Value
|
||||
trust := strings.Split(trustClass, "$")
|
||||
switch trust[1] {
|
||||
case "TrustContributors":
|
||||
githubSource.DiscoverPRFromForks = &devops.DiscoverPRFromForks{
|
||||
Strategy: strategyId,
|
||||
Trust: 1,
|
||||
}
|
||||
case "TrustEveryone":
|
||||
githubSource.DiscoverPRFromForks = &devops.DiscoverPRFromForks{
|
||||
Strategy: strategyId,
|
||||
Trust: 2,
|
||||
}
|
||||
case "TrustPermission":
|
||||
githubSource.DiscoverPRFromForks = &devops.DiscoverPRFromForks{
|
||||
Strategy: strategyId,
|
||||
Trust: 3,
|
||||
}
|
||||
case "TrustNobody":
|
||||
githubSource.DiscoverPRFromForks = &devops.DiscoverPRFromForks{
|
||||
Strategy: strategyId,
|
||||
Trust: 4,
|
||||
}
|
||||
}
|
||||
if cloneTrait := traits.SelectElement(
|
||||
"jenkins.plugins.git.traits.CloneOptionTrait"); cloneTrait != nil {
|
||||
if cloneExtension := cloneTrait.SelectElement(
|
||||
"extension"); cloneExtension != nil {
|
||||
githubSource.CloneOption = &devops.GitCloneOption{}
|
||||
if value, err := strconv.ParseBool(cloneExtension.SelectElement("shallow").Text()); err == nil {
|
||||
githubSource.CloneOption.Shallow = value
|
||||
}
|
||||
if value, err := strconv.ParseInt(cloneExtension.SelectElement("timeout").Text(), 10, 32); err == nil {
|
||||
githubSource.CloneOption.Timeout = int(value)
|
||||
}
|
||||
if value, err := strconv.ParseInt(cloneExtension.SelectElement("depth").Text(), 10, 32); err == nil {
|
||||
githubSource.CloneOption.Depth = int(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if regexTrait := traits.SelectElement(
|
||||
"jenkins.scm.impl.trait.RegexSCMHeadFilterTrait"); regexTrait != nil {
|
||||
if regex := regexTrait.SelectElement("regex"); regex != nil {
|
||||
githubSource.RegexFilter = regex.Text()
|
||||
}
|
||||
}
|
||||
}
|
||||
return &githubSource
|
||||
}
|
||||
|
||||
func appendGithubSourceToEtree(source *etree.Element, githubSource *devops.GithubSource) {
|
||||
source.CreateAttr("class", "org.jenkinsci.plugins.github_branch_source.GitHubSCMSource")
|
||||
source.CreateAttr("plugin", "github-branch-source")
|
||||
source.CreateElement("id").SetText(githubSource.ScmId)
|
||||
source.CreateElement("credentialsId").SetText(githubSource.CredentialId)
|
||||
source.CreateElement("repoOwner").SetText(githubSource.Owner)
|
||||
source.CreateElement("repository").SetText(githubSource.Repo)
|
||||
if githubSource.ApiUri != "" {
|
||||
source.CreateElement("apiUri").SetText(githubSource.ApiUri)
|
||||
}
|
||||
traits := source.CreateElement("traits")
|
||||
if githubSource.DiscoverBranches != 0 {
|
||||
traits.CreateElement("org.jenkinsci.plugins.github__branch__source.BranchDiscoveryTrait").
|
||||
CreateElement("strategyId").SetText(strconv.Itoa(githubSource.DiscoverBranches))
|
||||
}
|
||||
if githubSource.DiscoverPRFromOrigin != 0 {
|
||||
traits.CreateElement("org.jenkinsci.plugins.github__branch__source.OriginPullRequestDiscoveryTrait").
|
||||
CreateElement("strategyId").SetText(strconv.Itoa(githubSource.DiscoverPRFromOrigin))
|
||||
}
|
||||
if githubSource.DiscoverPRFromForks != nil {
|
||||
forkTrait := traits.CreateElement("org.jenkinsci.plugins.github__branch__source.ForkPullRequestDiscoveryTrait")
|
||||
forkTrait.CreateElement("strategyId").SetText(strconv.Itoa(githubSource.DiscoverPRFromForks.Strategy))
|
||||
trustClass := "org.jenkinsci.plugins.github_branch_source.ForkPullRequestDiscoveryTrait$"
|
||||
switch githubSource.DiscoverPRFromForks.Trust {
|
||||
case 1:
|
||||
trustClass += "TrustContributors"
|
||||
case 2:
|
||||
trustClass += "TrustEveryone"
|
||||
case 3:
|
||||
trustClass += "TrustPermission"
|
||||
case 4:
|
||||
trustClass += "TrustNobody"
|
||||
default:
|
||||
}
|
||||
forkTrait.CreateElement("trust").CreateAttr("class", trustClass)
|
||||
}
|
||||
if githubSource.CloneOption != nil {
|
||||
cloneExtension := traits.CreateElement("jenkins.plugins.git.traits.CloneOptionTrait").CreateElement("extension")
|
||||
cloneExtension.CreateAttr("class", "hudson.plugins.git.extensions.impl.CloneOption")
|
||||
cloneExtension.CreateElement("shallow").SetText(strconv.FormatBool(githubSource.CloneOption.Shallow))
|
||||
cloneExtension.CreateElement("noTags").SetText(strconv.FormatBool(false))
|
||||
cloneExtension.CreateElement("honorRefspec").SetText(strconv.FormatBool(true))
|
||||
cloneExtension.CreateElement("reference")
|
||||
if githubSource.CloneOption.Timeout >= 0 {
|
||||
cloneExtension.CreateElement("timeout").SetText(strconv.Itoa(githubSource.CloneOption.Timeout))
|
||||
} else {
|
||||
cloneExtension.CreateElement("timeout").SetText(strconv.Itoa(10))
|
||||
}
|
||||
|
||||
if githubSource.CloneOption.Depth >= 0 {
|
||||
cloneExtension.CreateElement("depth").SetText(strconv.Itoa(githubSource.CloneOption.Depth))
|
||||
} else {
|
||||
cloneExtension.CreateElement("depth").SetText(strconv.Itoa(1))
|
||||
}
|
||||
}
|
||||
if githubSource.RegexFilter != "" {
|
||||
regexTraits := traits.CreateElement("jenkins.scm.impl.trait.RegexSCMHeadFilterTrait")
|
||||
regexTraits.CreateAttr("plugin", "scm-api@2.4.0")
|
||||
regexTraits.CreateElement("regex").SetText(githubSource.RegexFilter)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getBitbucketServerSourceFromEtree(source *etree.Element) *devops.BitbucketServerSource {
|
||||
var s devops.BitbucketServerSource
|
||||
if credential := source.SelectElement("credentialsId"); credential != nil {
|
||||
s.CredentialId = credential.Text()
|
||||
}
|
||||
if repoOwner := source.SelectElement("repoOwner"); repoOwner != nil {
|
||||
s.Owner = repoOwner.Text()
|
||||
}
|
||||
if repository := source.SelectElement("repository"); repository != nil {
|
||||
s.Repo = repository.Text()
|
||||
}
|
||||
if apiUri := source.SelectElement("serverUrl"); apiUri != nil {
|
||||
s.ApiUri = apiUri.Text()
|
||||
}
|
||||
traits := source.SelectElement("traits")
|
||||
if branchDiscoverTrait := traits.SelectElement(
|
||||
"com.cloudbees.jenkins.plugins.bitbucket.BranchDiscoveryTrait"); branchDiscoverTrait != nil {
|
||||
strategyId, _ := strconv.Atoi(branchDiscoverTrait.SelectElement("strategyId").Text())
|
||||
s.DiscoverBranches = strategyId
|
||||
}
|
||||
if originPRDiscoverTrait := traits.SelectElement(
|
||||
"com.cloudbees.jenkins.plugins.bitbucket.OriginPullRequestDiscoveryTrait"); originPRDiscoverTrait != nil {
|
||||
strategyId, _ := strconv.Atoi(originPRDiscoverTrait.SelectElement("strategyId").Text())
|
||||
s.DiscoverPRFromOrigin = strategyId
|
||||
}
|
||||
if forkPRDiscoverTrait := traits.SelectElement(
|
||||
"com.cloudbees.jenkins.plugins.bitbucket.ForkPullRequestDiscoveryTrait"); forkPRDiscoverTrait != nil {
|
||||
strategyId, _ := strconv.Atoi(forkPRDiscoverTrait.SelectElement("strategyId").Text())
|
||||
trustClass := forkPRDiscoverTrait.SelectElement("trust").SelectAttr("class").Value
|
||||
trust := strings.Split(trustClass, "$")
|
||||
switch trust[1] {
|
||||
case "TrustEveryone":
|
||||
s.DiscoverPRFromForks = &devops.DiscoverPRFromForks{
|
||||
Strategy: strategyId,
|
||||
Trust: 1,
|
||||
}
|
||||
case "TrustTeamForks":
|
||||
s.DiscoverPRFromForks = &devops.DiscoverPRFromForks{
|
||||
Strategy: strategyId,
|
||||
Trust: 2,
|
||||
}
|
||||
case "TrustNobody":
|
||||
s.DiscoverPRFromForks = &devops.DiscoverPRFromForks{
|
||||
Strategy: strategyId,
|
||||
Trust: 3,
|
||||
}
|
||||
}
|
||||
if cloneTrait := traits.SelectElement(
|
||||
"jenkins.plugins.git.traits.CloneOptionTrait"); cloneTrait != nil {
|
||||
if cloneExtension := cloneTrait.SelectElement(
|
||||
"extension"); cloneExtension != nil {
|
||||
s.CloneOption = &devops.GitCloneOption{}
|
||||
if value, err := strconv.ParseBool(cloneExtension.SelectElement("shallow").Text()); err == nil {
|
||||
s.CloneOption.Shallow = value
|
||||
}
|
||||
if value, err := strconv.ParseInt(cloneExtension.SelectElement("timeout").Text(), 10, 32); err == nil {
|
||||
s.CloneOption.Timeout = int(value)
|
||||
}
|
||||
if value, err := strconv.ParseInt(cloneExtension.SelectElement("depth").Text(), 10, 32); err == nil {
|
||||
s.CloneOption.Depth = int(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if regexTrait := traits.SelectElement(
|
||||
"jenkins.scm.impl.trait.RegexSCMHeadFilterTrait"); regexTrait != nil {
|
||||
if regex := regexTrait.SelectElement("regex"); regex != nil {
|
||||
s.RegexFilter = regex.Text()
|
||||
}
|
||||
}
|
||||
}
|
||||
return &s
|
||||
}
|
||||
|
||||
func appendBitbucketServerSourceToEtree(source *etree.Element, s *devops.BitbucketServerSource) {
|
||||
source.CreateAttr("class", "com.cloudbees.jenkins.plugins.bitbucket.BitbucketSCMSource")
|
||||
source.CreateAttr("plugin", "cloudbees-bitbucket-branch-source")
|
||||
source.CreateElement("id").SetText(s.ScmId)
|
||||
source.CreateElement("credentialsId").SetText(s.CredentialId)
|
||||
source.CreateElement("repoOwner").SetText(s.Owner)
|
||||
source.CreateElement("repository").SetText(s.Repo)
|
||||
source.CreateElement("serverUrl").SetText(s.ApiUri)
|
||||
|
||||
traits := source.CreateElement("traits")
|
||||
if s.DiscoverBranches != 0 {
|
||||
traits.CreateElement("com.cloudbees.jenkins.plugins.bitbucket.BranchDiscoveryTrait>").
|
||||
CreateElement("strategyId").SetText(strconv.Itoa(s.DiscoverBranches))
|
||||
}
|
||||
if s.DiscoverPRFromOrigin != 0 {
|
||||
traits.CreateElement("com.cloudbees.jenkins.plugins.bitbucket.OriginPullRequestDiscoveryTrait").
|
||||
CreateElement("strategyId").SetText(strconv.Itoa(s.DiscoverPRFromOrigin))
|
||||
}
|
||||
if s.DiscoverPRFromForks != nil {
|
||||
forkTrait := traits.CreateElement("com.cloudbees.jenkins.plugins.bitbucket.ForkPullRequestDiscoveryTrait")
|
||||
forkTrait.CreateElement("strategyId").SetText(strconv.Itoa(s.DiscoverPRFromForks.Strategy))
|
||||
trustClass := "com.cloudbees.jenkins.plugins.bitbucket.ForkPullRequestDiscoveryTrait$"
|
||||
switch s.DiscoverPRFromForks.Trust {
|
||||
case 1:
|
||||
trustClass += "TrustEveryone"
|
||||
case 2:
|
||||
trustClass += "TrustTeamForks"
|
||||
case 3:
|
||||
trustClass += "TrustNobody"
|
||||
default:
|
||||
trustClass += "TrustEveryone"
|
||||
}
|
||||
forkTrait.CreateElement("trust").CreateAttr("class", trustClass)
|
||||
}
|
||||
if s.CloneOption != nil {
|
||||
cloneExtension := traits.CreateElement("jenkins.plugins.git.traits.CloneOptionTrait").CreateElement("extension")
|
||||
cloneExtension.CreateAttr("class", "hudson.plugins.git.extensions.impl.CloneOption")
|
||||
cloneExtension.CreateElement("shallow").SetText(strconv.FormatBool(s.CloneOption.Shallow))
|
||||
cloneExtension.CreateElement("noTags").SetText(strconv.FormatBool(false))
|
||||
cloneExtension.CreateElement("honorRefspec").SetText(strconv.FormatBool(true))
|
||||
cloneExtension.CreateElement("reference")
|
||||
if s.CloneOption.Timeout >= 0 {
|
||||
cloneExtension.CreateElement("timeout").SetText(strconv.Itoa(s.CloneOption.Timeout))
|
||||
} else {
|
||||
cloneExtension.CreateElement("timeout").SetText(strconv.Itoa(10))
|
||||
}
|
||||
|
||||
if s.CloneOption.Depth >= 0 {
|
||||
cloneExtension.CreateElement("depth").SetText(strconv.Itoa(s.CloneOption.Depth))
|
||||
} else {
|
||||
cloneExtension.CreateElement("depth").SetText(strconv.Itoa(1))
|
||||
}
|
||||
}
|
||||
if s.RegexFilter != "" {
|
||||
regexTraits := traits.CreateElement("jenkins.scm.impl.trait.RegexSCMHeadFilterTrait")
|
||||
regexTraits.CreateAttr("plugin", "scm-api@2.4.0")
|
||||
regexTraits.CreateElement("regex").SetText(s.RegexFilter)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getSvnSourcefromEtree(source *etree.Element) *devops.SvnSource {
|
||||
var s devops.SvnSource
|
||||
if remote := source.SelectElement("remoteBase"); remote != nil {
|
||||
s.Remote = remote.Text()
|
||||
}
|
||||
|
||||
if credentialsId := source.SelectElement("credentialsId"); credentialsId != nil {
|
||||
s.CredentialId = credentialsId.Text()
|
||||
}
|
||||
|
||||
if includes := source.SelectElement("includes"); includes != nil {
|
||||
s.Includes = includes.Text()
|
||||
}
|
||||
|
||||
if excludes := source.SelectElement("excludes"); excludes != nil {
|
||||
s.Excludes = excludes.Text()
|
||||
}
|
||||
return &s
|
||||
}
|
||||
|
||||
func appendSvnSourceToEtree(source *etree.Element, s *devops.SvnSource) {
|
||||
source.CreateAttr("class", "jenkins.scm.impl.subversion.SubversionSCMSource")
|
||||
source.CreateAttr("plugin", "subversion")
|
||||
source.CreateElement("id").SetText(s.ScmId)
|
||||
if s.CredentialId != "" {
|
||||
source.CreateElement("credentialsId").SetText(s.CredentialId)
|
||||
}
|
||||
if s.Remote != "" {
|
||||
source.CreateElement("remoteBase").SetText(s.Remote)
|
||||
}
|
||||
if s.Includes != "" {
|
||||
source.CreateElement("includes").SetText(s.Includes)
|
||||
}
|
||||
if s.Excludes != "" {
|
||||
source.CreateElement("excludes").SetText(s.Excludes)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getSingleSvnSourceFromEtree(source *etree.Element) *devops.SingleSvnSource {
|
||||
var s devops.SingleSvnSource
|
||||
if scm := source.SelectElement("scm"); scm != nil {
|
||||
if locations := scm.SelectElement("locations"); locations != nil {
|
||||
if moduleLocations := locations.SelectElement("hudson.scm.SubversionSCM_-ModuleLocation"); moduleLocations != nil {
|
||||
if remote := moduleLocations.SelectElement("remote"); remote != nil {
|
||||
s.Remote = remote.Text()
|
||||
}
|
||||
if credentialId := moduleLocations.SelectElement("credentialsId"); credentialId != nil {
|
||||
s.CredentialId = credentialId.Text()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return &s
|
||||
}
|
||||
|
||||
func appendSingleSvnSourceToEtree(source *etree.Element, s *devops.SingleSvnSource) {
|
||||
|
||||
source.CreateAttr("class", "jenkins.scm.impl.SingleSCMSource")
|
||||
source.CreateAttr("plugin", "scm-api")
|
||||
source.CreateElement("id").SetText(s.ScmId)
|
||||
source.CreateElement("name").SetText("master")
|
||||
|
||||
scm := source.CreateElement("scm")
|
||||
scm.CreateAttr("class", "hudson.scm.SubversionSCM")
|
||||
scm.CreateAttr("plugin", "subversion")
|
||||
|
||||
location := scm.CreateElement("locations").CreateElement("hudson.scm.SubversionSCM_-ModuleLocation")
|
||||
if s.Remote != "" {
|
||||
location.CreateElement("remote").SetText(s.Remote)
|
||||
}
|
||||
if s.CredentialId != "" {
|
||||
location.CreateElement("credentialsId").SetText(s.CredentialId)
|
||||
}
|
||||
location.CreateElement("local").SetText(".")
|
||||
location.CreateElement("depthOption").SetText("infinity")
|
||||
location.CreateElement("ignoreExternalsOption").SetText("true")
|
||||
location.CreateElement("cancelProcessOnExternalsFail").SetText("true")
|
||||
|
||||
source.CreateElement("excludedRegions")
|
||||
source.CreateElement("includedRegions")
|
||||
source.CreateElement("excludedUsers")
|
||||
source.CreateElement("excludedRevprop")
|
||||
source.CreateElement("excludedCommitMessages")
|
||||
source.CreateElement("workspaceUpdater").CreateAttr("class", "hudson.scm.subversion.UpdateUpdater")
|
||||
source.CreateElement("ignoreDirPropChanges").SetText("false")
|
||||
source.CreateElement("filterChangelog").SetText("false")
|
||||
source.CreateElement("quietOperation").SetText("true")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func appendMultiBranchJobTriggerToEtree(properties *etree.Element, s *devops.MultiBranchJobTrigger) {
|
||||
triggerProperty := properties.CreateElement("org.jenkinsci.plugins.workflow.multibranch.PipelineTriggerProperty")
|
||||
triggerProperty.CreateAttr("plugin", "multibranch-action-triggers")
|
||||
triggerProperty.CreateElement("createActionJobsToTrigger").SetText(s.CreateActionJobsToTrigger)
|
||||
triggerProperty.CreateElement("deleteActionJobsToTrigger").SetText(s.DeleteActionJobsToTrigger)
|
||||
return
|
||||
}
|
||||
|
||||
func getMultiBranchJobTriggerfromEtree(properties *etree.Element) *devops.MultiBranchJobTrigger {
|
||||
var s devops.MultiBranchJobTrigger
|
||||
triggerProperty := properties.SelectElement("org.jenkinsci.plugins.workflow.multibranch.PipelineTriggerProperty")
|
||||
if triggerProperty != nil {
|
||||
s.CreateActionJobsToTrigger = triggerProperty.SelectElement("createActionJobsToTrigger").Text()
|
||||
s.DeleteActionJobsToTrigger = triggerProperty.SelectElement("deleteActionJobsToTrigger").Text()
|
||||
}
|
||||
return &s
|
||||
}
|
||||
func createMultiBranchPipelineConfigXml(projectName string, pipeline *devops.MultiBranchPipeline) (string, error) {
|
||||
doc := etree.NewDocument()
|
||||
xmlString := `
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject plugin="workflow-multibranch">
|
||||
<actions/>
|
||||
<properties>
|
||||
<org.jenkinsci.plugins.pipeline.modeldefinition.config.FolderConfig plugin="pipeline-model-definition">
|
||||
<dockerLabel></dockerLabel>
|
||||
<registry plugin="docker-commons"/>
|
||||
</org.jenkinsci.plugins.pipeline.modeldefinition.config.FolderConfig>
|
||||
</properties>
|
||||
<folderViews class="jenkins.branch.MultiBranchProjectViewHolder" plugin="branch-api">
|
||||
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
|
||||
</folderViews>
|
||||
<healthMetrics>
|
||||
<com.cloudbees.hudson.plugins.folder.health.WorstChildHealthMetric plugin="cloudbees-folder">
|
||||
<nonRecursive>false</nonRecursive>
|
||||
</com.cloudbees.hudson.plugins.folder.health.WorstChildHealthMetric>
|
||||
</healthMetrics>
|
||||
<icon class="jenkins.branch.MetadataActionFolderIcon" plugin="branch-api">
|
||||
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
|
||||
</icon>
|
||||
</org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject>`
|
||||
err := doc.ReadFromString(xmlString)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
project := doc.SelectElement("org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject")
|
||||
project.CreateElement("description").SetText(pipeline.Description)
|
||||
|
||||
if pipeline.MultiBranchJobTrigger != nil {
|
||||
properties := project.SelectElement("properties")
|
||||
appendMultiBranchJobTriggerToEtree(properties, pipeline.MultiBranchJobTrigger)
|
||||
}
|
||||
|
||||
if pipeline.Discarder != nil {
|
||||
discarder := project.CreateElement("orphanedItemStrategy")
|
||||
discarder.CreateAttr("class", "com.cloudbees.hudson.plugins.folder.computed.DefaultOrphanedItemStrategy")
|
||||
discarder.CreateAttr("plugin", "cloudbees-folder")
|
||||
discarder.CreateElement("pruneDeadBranches").SetText("true")
|
||||
discarder.CreateElement("daysToKeep").SetText(pipeline.Discarder.DaysToKeep)
|
||||
discarder.CreateElement("numToKeep").SetText(pipeline.Discarder.NumToKeep)
|
||||
}
|
||||
|
||||
triggers := project.CreateElement("triggers")
|
||||
if pipeline.TimerTrigger != nil {
|
||||
timeTrigger := triggers.CreateElement(
|
||||
"com.cloudbees.hudson.plugins.folder.computed.PeriodicFolderTrigger")
|
||||
timeTrigger.CreateAttr("plugin", "cloudbees-folder")
|
||||
millis, err := strconv.ParseInt(pipeline.TimerTrigger.Interval, 10, 64)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
timeTrigger.CreateElement("spec").SetText(toCrontab(millis))
|
||||
timeTrigger.CreateElement("interval").SetText(pipeline.TimerTrigger.Interval)
|
||||
|
||||
triggers.CreateElement("disabled").SetText("false")
|
||||
}
|
||||
|
||||
sources := project.CreateElement("sources")
|
||||
sources.CreateAttr("class", "jenkins.branch.MultiBranchProject$BranchSourceList")
|
||||
sources.CreateAttr("plugin", "branch-api")
|
||||
sourcesOwner := sources.CreateElement("owner")
|
||||
sourcesOwner.CreateAttr("class", "org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject")
|
||||
sourcesOwner.CreateAttr("reference", "../..")
|
||||
|
||||
branchSource := sources.CreateElement("data").CreateElement("jenkins.branch.BranchSource")
|
||||
branchSourceStrategy := branchSource.CreateElement("strategy")
|
||||
branchSourceStrategy.CreateAttr("class", "jenkins.branch.NamedExceptionsBranchPropertyStrategy")
|
||||
branchSourceStrategy.CreateElement("defaultProperties").CreateAttr("class", "empty-list")
|
||||
branchSourceStrategy.CreateElement("namedExceptions").CreateAttr("class", "empty-list")
|
||||
source := branchSource.CreateElement("source")
|
||||
|
||||
switch pipeline.SourceType {
|
||||
case "git":
|
||||
appendGitSourceToEtree(source, pipeline.GitSource)
|
||||
case "github":
|
||||
appendGithubSourceToEtree(source, pipeline.GitHubSource)
|
||||
case "svn":
|
||||
appendSvnSourceToEtree(source, pipeline.SvnSource)
|
||||
case "single_svn":
|
||||
appendSingleSvnSourceToEtree(source, pipeline.SingleSvnSource)
|
||||
case "bitbucket_server":
|
||||
appendBitbucketServerSourceToEtree(source, pipeline.BitbucketServerSource)
|
||||
|
||||
default:
|
||||
return "", fmt.Errorf("unsupport source type")
|
||||
}
|
||||
|
||||
factory := project.CreateElement("factory")
|
||||
factory.CreateAttr("class", "org.jenkinsci.plugins.workflow.multibranch.WorkflowBranchProjectFactory")
|
||||
factoryOwner := factory.CreateElement("owner")
|
||||
factoryOwner.CreateAttr("class", "org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject")
|
||||
factoryOwner.CreateAttr("reference", "../..")
|
||||
factory.CreateElement("scriptPath").SetText(pipeline.ScriptPath)
|
||||
|
||||
doc.Indent(2)
|
||||
stringXml, err := doc.WriteToString()
|
||||
return replaceXmlVersion(stringXml, "1.0", "1.1"), err
|
||||
}
|
||||
|
||||
func parseMultiBranchPipelineConfigXml(config string) (*devops.MultiBranchPipeline, error) {
|
||||
pipeline := &devops.MultiBranchPipeline{}
|
||||
config = replaceXmlVersion(config, "1.1", "1.0")
|
||||
doc := etree.NewDocument()
|
||||
err := doc.ReadFromString(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
project := doc.SelectElement("org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject")
|
||||
if project == nil {
|
||||
return nil, fmt.Errorf("can not parse mutibranch pipeline config")
|
||||
}
|
||||
if properties := project.SelectElement("properties"); properties != nil {
|
||||
if multibranchTrigger := properties.SelectElement(
|
||||
"org.jenkinsci.plugins.workflow.multibranch.PipelineTriggerProperty"); multibranchTrigger != nil {
|
||||
pipeline.MultiBranchJobTrigger = getMultiBranchJobTriggerfromEtree(properties)
|
||||
}
|
||||
}
|
||||
pipeline.Description = project.SelectElement("description").Text()
|
||||
|
||||
if discarder := project.SelectElement("orphanedItemStrategy"); discarder != nil {
|
||||
pipeline.Discarder = &devops.DiscarderProperty{
|
||||
DaysToKeep: discarder.SelectElement("daysToKeep").Text(),
|
||||
NumToKeep: discarder.SelectElement("numToKeep").Text(),
|
||||
}
|
||||
}
|
||||
if triggers := project.SelectElement("triggers"); triggers != nil {
|
||||
if timerTrigger := triggers.SelectElement(
|
||||
"com.cloudbees.hudson.plugins.folder.computed.PeriodicFolderTrigger"); timerTrigger != nil {
|
||||
pipeline.TimerTrigger = &devops.TimerTrigger{
|
||||
Interval: timerTrigger.SelectElement("interval").Text(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if sources := project.SelectElement("sources"); sources != nil {
|
||||
if sourcesData := sources.SelectElement("data"); sourcesData != nil {
|
||||
if branchSource := sourcesData.SelectElement("jenkins.branch.BranchSource"); branchSource != nil {
|
||||
source := branchSource.SelectElement("source")
|
||||
switch source.SelectAttr("class").Value {
|
||||
case "org.jenkinsci.plugins.github_branch_source.GitHubSCMSource":
|
||||
pipeline.GitHubSource = getGithubSourcefromEtree(source)
|
||||
pipeline.SourceType = "github"
|
||||
case "com.cloudbees.jenkins.plugins.bitbucket.BitbucketSCMSource":
|
||||
pipeline.BitbucketServerSource = getBitbucketServerSourceFromEtree(source)
|
||||
pipeline.SourceType = "bitbucket_server"
|
||||
|
||||
case "jenkins.plugins.git.GitSCMSource":
|
||||
pipeline.SourceType = "git"
|
||||
pipeline.GitSource = getGitSourcefromEtree(source)
|
||||
|
||||
case "jenkins.scm.impl.SingleSCMSource":
|
||||
pipeline.SourceType = "single_svn"
|
||||
pipeline.SingleSvnSource = getSingleSvnSourceFromEtree(source)
|
||||
|
||||
case "jenkins.scm.impl.subversion.SubversionSCMSource":
|
||||
pipeline.SourceType = "svn"
|
||||
pipeline.SvnSource = getSvnSourcefromEtree(source)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pipeline.ScriptPath = project.SelectElement("factory").SelectElement("scriptPath").Text()
|
||||
return pipeline, nil
|
||||
}
|
||||
|
||||
func toCrontab(millis int64) string {
|
||||
if millis*time.Millisecond.Nanoseconds() <= 5*time.Minute.Nanoseconds() {
|
||||
return "* * * * *"
|
||||
}
|
||||
if millis*time.Millisecond.Nanoseconds() <= 30*time.Minute.Nanoseconds() {
|
||||
return "H/5 * * * *"
|
||||
}
|
||||
if millis*time.Millisecond.Nanoseconds() <= 1*time.Hour.Nanoseconds() {
|
||||
return "H/15 * * * *"
|
||||
}
|
||||
if millis*time.Millisecond.Nanoseconds() <= 8*time.Hour.Nanoseconds() {
|
||||
return "H/30 * * * *"
|
||||
}
|
||||
if millis*time.Millisecond.Nanoseconds() <= 24*time.Hour.Nanoseconds() {
|
||||
return "H H/4 * * *"
|
||||
}
|
||||
if millis*time.Millisecond.Nanoseconds() <= 48*time.Hour.Nanoseconds() {
|
||||
return "H H/12 * * *"
|
||||
}
|
||||
return "H H * * *"
|
||||
|
||||
}
|
||||
621
pkg/simple/client/devops/jenkins/pipeline_internal_test.go
Normal file
621
pkg/simple/client/devops/jenkins/pipeline_internal_test.go
Normal file
@@ -0,0 +1,621 @@
|
||||
package jenkins
|
||||
|
||||
import (
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/devops"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_NoScmPipelineConfig(t *testing.T) {
|
||||
inputs := []*devops.NoScmPipeline{
|
||||
{
|
||||
Name: "",
|
||||
Description: "for test",
|
||||
Jenkinsfile: "node{echo 'hello'}",
|
||||
},
|
||||
{
|
||||
Name: "",
|
||||
Description: "",
|
||||
Jenkinsfile: "node{echo 'hello'}",
|
||||
},
|
||||
{
|
||||
Name: "",
|
||||
Description: "",
|
||||
Jenkinsfile: "node{echo 'hello'}",
|
||||
DisableConcurrent: true,
|
||||
},
|
||||
}
|
||||
for _, input := range inputs {
|
||||
outputString, err := createPipelineConfigXml(input)
|
||||
if err != nil {
|
||||
t.Fatalf("should not get error %+v", err)
|
||||
}
|
||||
output, err := parsePipelineConfigXml(outputString)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("should not get error %+v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(input, output) {
|
||||
t.Fatalf("input [%+v] output [%+v] should equal ", input, output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Test_NoScmPipelineConfig_Discarder(t *testing.T) {
|
||||
inputs := []*devops.NoScmPipeline{
|
||||
{
|
||||
Name: "",
|
||||
Description: "for test",
|
||||
Jenkinsfile: "node{echo 'hello'}",
|
||||
Discarder: &devops.DiscarderProperty{
|
||||
"3", "5",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "",
|
||||
Description: "for test",
|
||||
Jenkinsfile: "node{echo 'hello'}",
|
||||
Discarder: &devops.DiscarderProperty{
|
||||
"3", "",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "",
|
||||
Description: "for test",
|
||||
Jenkinsfile: "node{echo 'hello'}",
|
||||
Discarder: &devops.DiscarderProperty{
|
||||
"", "21321",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "",
|
||||
Description: "for test",
|
||||
Jenkinsfile: "node{echo 'hello'}",
|
||||
Discarder: &devops.DiscarderProperty{
|
||||
"", "",
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, input := range inputs {
|
||||
outputString, err := createPipelineConfigXml(input)
|
||||
if err != nil {
|
||||
t.Fatalf("should not get error %+v", err)
|
||||
}
|
||||
output, err := parsePipelineConfigXml(outputString)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("should not get error %+v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(input, output) {
|
||||
t.Fatalf("input [%+v] output [%+v] should equal ", input, output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Test_NoScmPipelineConfig_Param(t *testing.T) {
|
||||
inputs := []*devops.NoScmPipeline{
|
||||
{
|
||||
Name: "",
|
||||
Description: "for test",
|
||||
Jenkinsfile: "node{echo 'hello'}",
|
||||
Parameters: &devops.Parameters{
|
||||
&devops.Parameter{
|
||||
Name: "d",
|
||||
DefaultValue: "a\nb",
|
||||
Type: "choice",
|
||||
Description: "fortest",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "",
|
||||
Description: "for test",
|
||||
Jenkinsfile: "node{echo 'hello'}",
|
||||
Parameters: &devops.Parameters{
|
||||
&devops.Parameter{
|
||||
Name: "a",
|
||||
DefaultValue: "abc",
|
||||
Type: "string",
|
||||
Description: "fortest",
|
||||
},
|
||||
&devops.Parameter{
|
||||
Name: "b",
|
||||
DefaultValue: "false",
|
||||
Type: "boolean",
|
||||
Description: "fortest",
|
||||
},
|
||||
&devops.Parameter{
|
||||
Name: "c",
|
||||
DefaultValue: "password \n aaa",
|
||||
Type: "text",
|
||||
Description: "fortest",
|
||||
},
|
||||
&devops.Parameter{
|
||||
Name: "d",
|
||||
DefaultValue: "a\nb",
|
||||
Type: "choice",
|
||||
Description: "fortest",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, input := range inputs {
|
||||
outputString, err := createPipelineConfigXml(input)
|
||||
if err != nil {
|
||||
t.Fatalf("should not get error %+v", err)
|
||||
}
|
||||
output, err := parsePipelineConfigXml(outputString)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("should not get error %+v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(input, output) {
|
||||
t.Fatalf("input [%+v] output [%+v] should equal ", input, output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Test_NoScmPipelineConfig_Trigger(t *testing.T) {
|
||||
inputs := []*devops.NoScmPipeline{
|
||||
{
|
||||
Name: "",
|
||||
Description: "for test",
|
||||
Jenkinsfile: "node{echo 'hello'}",
|
||||
TimerTrigger: &devops.TimerTrigger{
|
||||
Cron: "1 1 1 * * *",
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
Name: "",
|
||||
Description: "for test",
|
||||
Jenkinsfile: "node{echo 'hello'}",
|
||||
RemoteTrigger: &devops.RemoteTrigger{
|
||||
Token: "abc",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "",
|
||||
Description: "for test",
|
||||
Jenkinsfile: "node{echo 'hello'}",
|
||||
TimerTrigger: &devops.TimerTrigger{
|
||||
Cron: "1 1 1 * * *",
|
||||
},
|
||||
RemoteTrigger: &devops.RemoteTrigger{
|
||||
Token: "abc",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, input := range inputs {
|
||||
outputString, err := createPipelineConfigXml(input)
|
||||
if err != nil {
|
||||
t.Fatalf("should not get error %+v", err)
|
||||
}
|
||||
output, err := parsePipelineConfigXml(outputString)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("should not get error %+v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(input, output) {
|
||||
t.Fatalf("input [%+v] output [%+v] should equal ", input, output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Test_MultiBranchPipelineConfig(t *testing.T) {
|
||||
|
||||
inputs := []*devops.MultiBranchPipeline{
|
||||
{
|
||||
Name: "",
|
||||
Description: "for test",
|
||||
ScriptPath: "Jenkinsfile",
|
||||
SourceType: "git",
|
||||
GitSource: &devops.GitSource{},
|
||||
},
|
||||
{
|
||||
Name: "",
|
||||
Description: "for test",
|
||||
ScriptPath: "Jenkinsfile",
|
||||
SourceType: "github",
|
||||
GitHubSource: &devops.GithubSource{},
|
||||
},
|
||||
{
|
||||
Name: "",
|
||||
Description: "for test",
|
||||
ScriptPath: "Jenkinsfile",
|
||||
SourceType: "single_svn",
|
||||
SingleSvnSource: &devops.SingleSvnSource{},
|
||||
},
|
||||
{
|
||||
Name: "",
|
||||
Description: "for test",
|
||||
ScriptPath: "Jenkinsfile",
|
||||
SourceType: "svn",
|
||||
SvnSource: &devops.SvnSource{},
|
||||
},
|
||||
}
|
||||
for _, input := range inputs {
|
||||
outputString, err := createMultiBranchPipelineConfigXml("", input)
|
||||
if err != nil {
|
||||
t.Fatalf("should not get error %+v", err)
|
||||
}
|
||||
output, err := parseMultiBranchPipelineConfigXml(outputString)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("should not get error %+v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(input, output) {
|
||||
t.Fatalf("input [%+v] output [%+v] should equal ", input, output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Test_MultiBranchPipelineConfig_Discarder(t *testing.T) {
|
||||
|
||||
inputs := []*devops.MultiBranchPipeline{
|
||||
{
|
||||
Name: "",
|
||||
Description: "for test",
|
||||
ScriptPath: "Jenkinsfile",
|
||||
SourceType: "git",
|
||||
Discarder: &devops.DiscarderProperty{
|
||||
DaysToKeep: "1",
|
||||
NumToKeep: "2",
|
||||
},
|
||||
GitSource: &devops.GitSource{},
|
||||
},
|
||||
}
|
||||
for _, input := range inputs {
|
||||
outputString, err := createMultiBranchPipelineConfigXml("", input)
|
||||
if err != nil {
|
||||
t.Fatalf("should not get error %+v", err)
|
||||
}
|
||||
output, err := parseMultiBranchPipelineConfigXml(outputString)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("should not get error %+v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(input, output) {
|
||||
t.Fatalf("input [%+v] output [%+v] should equal ", input, output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Test_MultiBranchPipelineConfig_TimerTrigger(t *testing.T) {
|
||||
inputs := []*devops.MultiBranchPipeline{
|
||||
{
|
||||
Name: "",
|
||||
Description: "for test",
|
||||
ScriptPath: "Jenkinsfile",
|
||||
SourceType: "git",
|
||||
TimerTrigger: &devops.TimerTrigger{
|
||||
Interval: "12345566",
|
||||
},
|
||||
GitSource: &devops.GitSource{},
|
||||
},
|
||||
}
|
||||
for _, input := range inputs {
|
||||
outputString, err := createMultiBranchPipelineConfigXml("", input)
|
||||
if err != nil {
|
||||
t.Fatalf("should not get error %+v", err)
|
||||
}
|
||||
output, err := parseMultiBranchPipelineConfigXml(outputString)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("should not get error %+v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(input, output) {
|
||||
t.Fatalf("input [%+v] output [%+v] should equal ", input, output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Test_MultiBranchPipelineConfig_Source(t *testing.T) {
|
||||
|
||||
inputs := []*devops.MultiBranchPipeline{
|
||||
{
|
||||
Name: "",
|
||||
Description: "for test",
|
||||
ScriptPath: "Jenkinsfile",
|
||||
SourceType: "git",
|
||||
TimerTrigger: &devops.TimerTrigger{
|
||||
Interval: "12345566",
|
||||
},
|
||||
GitSource: &devops.GitSource{
|
||||
Url: "https://github.com/kubesphere/devops",
|
||||
CredentialId: "git",
|
||||
DiscoverBranches: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "",
|
||||
Description: "for test",
|
||||
ScriptPath: "Jenkinsfile",
|
||||
SourceType: "github",
|
||||
TimerTrigger: &devops.TimerTrigger{
|
||||
Interval: "12345566",
|
||||
},
|
||||
GitHubSource: &devops.GithubSource{
|
||||
Owner: "kubesphere",
|
||||
Repo: "devops",
|
||||
CredentialId: "github",
|
||||
ApiUri: "https://api.github.com",
|
||||
DiscoverBranches: 1,
|
||||
DiscoverPRFromOrigin: 2,
|
||||
DiscoverPRFromForks: &devops.DiscoverPRFromForks{
|
||||
Strategy: 1,
|
||||
Trust: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "",
|
||||
Description: "for test",
|
||||
ScriptPath: "Jenkinsfile",
|
||||
SourceType: "bitbucket_server",
|
||||
TimerTrigger: &devops.TimerTrigger{
|
||||
Interval: "12345566",
|
||||
},
|
||||
BitbucketServerSource: &devops.BitbucketServerSource{
|
||||
Owner: "kubesphere",
|
||||
Repo: "devops",
|
||||
CredentialId: "github",
|
||||
ApiUri: "https://api.github.com",
|
||||
DiscoverBranches: 1,
|
||||
DiscoverPRFromOrigin: 2,
|
||||
DiscoverPRFromForks: &devops.DiscoverPRFromForks{
|
||||
Strategy: 1,
|
||||
Trust: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
Name: "",
|
||||
Description: "for test",
|
||||
ScriptPath: "Jenkinsfile",
|
||||
SourceType: "svn",
|
||||
TimerTrigger: &devops.TimerTrigger{
|
||||
Interval: "12345566",
|
||||
},
|
||||
SvnSource: &devops.SvnSource{
|
||||
Remote: "https://api.svn.com/bcd",
|
||||
CredentialId: "svn",
|
||||
Excludes: "truck",
|
||||
Includes: "tag/*",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "",
|
||||
Description: "for test",
|
||||
ScriptPath: "Jenkinsfile",
|
||||
SourceType: "single_svn",
|
||||
TimerTrigger: &devops.TimerTrigger{
|
||||
Interval: "12345566",
|
||||
},
|
||||
SingleSvnSource: &devops.SingleSvnSource{
|
||||
Remote: "https://api.svn.com/bcd",
|
||||
CredentialId: "svn",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, input := range inputs {
|
||||
outputString, err := createMultiBranchPipelineConfigXml("", input)
|
||||
if err != nil {
|
||||
t.Fatalf("should not get error %+v", err)
|
||||
}
|
||||
output, err := parseMultiBranchPipelineConfigXml(outputString)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("should not get error %+v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(input, output) {
|
||||
t.Fatalf("input [%+v] output [%+v] should equal ", input, output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Test_MultiBranchPipelineCloneConfig(t *testing.T) {
|
||||
|
||||
inputs := []*devops.MultiBranchPipeline{
|
||||
{
|
||||
Name: "",
|
||||
Description: "for test",
|
||||
ScriptPath: "Jenkinsfile",
|
||||
SourceType: "git",
|
||||
GitSource: &devops.GitSource{
|
||||
Url: "https://github.com/kubesphere/devops",
|
||||
CredentialId: "git",
|
||||
DiscoverBranches: true,
|
||||
CloneOption: &devops.GitCloneOption{
|
||||
Shallow: false,
|
||||
Depth: 3,
|
||||
Timeout: 20,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "",
|
||||
Description: "for test",
|
||||
ScriptPath: "Jenkinsfile",
|
||||
SourceType: "github",
|
||||
GitHubSource: &devops.GithubSource{
|
||||
Owner: "kubesphere",
|
||||
Repo: "devops",
|
||||
CredentialId: "github",
|
||||
ApiUri: "https://api.github.com",
|
||||
DiscoverBranches: 1,
|
||||
DiscoverPRFromOrigin: 2,
|
||||
DiscoverPRFromForks: &devops.DiscoverPRFromForks{
|
||||
Strategy: 1,
|
||||
Trust: 1,
|
||||
},
|
||||
CloneOption: &devops.GitCloneOption{
|
||||
Shallow: false,
|
||||
Depth: 3,
|
||||
Timeout: 20,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, input := range inputs {
|
||||
outputString, err := createMultiBranchPipelineConfigXml("", input)
|
||||
if err != nil {
|
||||
t.Fatalf("should not get error %+v", err)
|
||||
}
|
||||
output, err := parseMultiBranchPipelineConfigXml(outputString)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("should not get error %+v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(input, output) {
|
||||
t.Fatalf("input [%+v] output [%+v] should equal ", input, output)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func Test_MultiBranchPipelineRegexFilter(t *testing.T) {
|
||||
|
||||
inputs := []*devops.MultiBranchPipeline{
|
||||
{
|
||||
Name: "",
|
||||
Description: "for test",
|
||||
ScriptPath: "Jenkinsfile",
|
||||
SourceType: "git",
|
||||
GitSource: &devops.GitSource{
|
||||
Url: "https://github.com/kubesphere/devops",
|
||||
CredentialId: "git",
|
||||
DiscoverBranches: true,
|
||||
RegexFilter: ".*",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "",
|
||||
Description: "for test",
|
||||
ScriptPath: "Jenkinsfile",
|
||||
SourceType: "github",
|
||||
GitHubSource: &devops.GithubSource{
|
||||
Owner: "kubesphere",
|
||||
Repo: "devops",
|
||||
CredentialId: "github",
|
||||
ApiUri: "https://api.github.com",
|
||||
DiscoverBranches: 1,
|
||||
DiscoverPRFromOrigin: 2,
|
||||
DiscoverPRFromForks: &devops.DiscoverPRFromForks{
|
||||
Strategy: 1,
|
||||
Trust: 1,
|
||||
},
|
||||
RegexFilter: ".*",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, input := range inputs {
|
||||
outputString, err := createMultiBranchPipelineConfigXml("", input)
|
||||
if err != nil {
|
||||
t.Fatalf("should not get error %+v", err)
|
||||
}
|
||||
output, err := parseMultiBranchPipelineConfigXml(outputString)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("should not get error %+v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(input, output) {
|
||||
t.Fatalf("input [%+v] output [%+v] should equal ", input, output)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func Test_MultiBranchPipelineMultibranchTrigger(t *testing.T) {
|
||||
|
||||
inputs := []*devops.MultiBranchPipeline{
|
||||
{
|
||||
Name: "",
|
||||
Description: "for test",
|
||||
ScriptPath: "Jenkinsfile",
|
||||
SourceType: "github",
|
||||
GitHubSource: &devops.GithubSource{
|
||||
Owner: "kubesphere",
|
||||
Repo: "devops",
|
||||
CredentialId: "github",
|
||||
ApiUri: "https://api.github.com",
|
||||
DiscoverBranches: 1,
|
||||
DiscoverPRFromOrigin: 2,
|
||||
DiscoverPRFromForks: &devops.DiscoverPRFromForks{
|
||||
Strategy: 1,
|
||||
Trust: 1,
|
||||
},
|
||||
RegexFilter: ".*",
|
||||
},
|
||||
MultiBranchJobTrigger: &devops.MultiBranchJobTrigger{
|
||||
CreateActionJobsToTrigger: "abc",
|
||||
DeleteActionJobsToTrigger: "ddd",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "",
|
||||
Description: "for test",
|
||||
ScriptPath: "Jenkinsfile",
|
||||
SourceType: "github",
|
||||
GitHubSource: &devops.GithubSource{
|
||||
Owner: "kubesphere",
|
||||
Repo: "devops",
|
||||
CredentialId: "github",
|
||||
ApiUri: "https://api.github.com",
|
||||
DiscoverBranches: 1,
|
||||
DiscoverPRFromOrigin: 2,
|
||||
DiscoverPRFromForks: &devops.DiscoverPRFromForks{
|
||||
Strategy: 1,
|
||||
Trust: 1,
|
||||
},
|
||||
RegexFilter: ".*",
|
||||
},
|
||||
MultiBranchJobTrigger: &devops.MultiBranchJobTrigger{
|
||||
CreateActionJobsToTrigger: "abc",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "",
|
||||
Description: "for test",
|
||||
ScriptPath: "Jenkinsfile",
|
||||
SourceType: "github",
|
||||
GitHubSource: &devops.GithubSource{
|
||||
Owner: "kubesphere",
|
||||
Repo: "devops",
|
||||
CredentialId: "github",
|
||||
ApiUri: "https://api.github.com",
|
||||
DiscoverBranches: 1,
|
||||
DiscoverPRFromOrigin: 2,
|
||||
DiscoverPRFromForks: &devops.DiscoverPRFromForks{
|
||||
Strategy: 1,
|
||||
Trust: 1,
|
||||
},
|
||||
RegexFilter: ".*",
|
||||
},
|
||||
MultiBranchJobTrigger: &devops.MultiBranchJobTrigger{
|
||||
DeleteActionJobsToTrigger: "ddd",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, input := range inputs {
|
||||
outputString, err := createMultiBranchPipelineConfigXml("", input)
|
||||
if err != nil {
|
||||
t.Fatalf("should not get error %+v", err)
|
||||
}
|
||||
output, err := parseMultiBranchPipelineConfigXml(outputString)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("should not get error %+v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(input, output) {
|
||||
t.Fatalf("input [%+v] output [%+v] should equal ", input, output)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
162
pkg/simple/client/devops/jenkins/pipeline_model_converter.go
Normal file
162
pkg/simple/client/devops/jenkins/pipeline_model_converter.go
Normal file
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
Copyright 2018 The KubeSphere Authors.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package jenkins
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type ValidateJenkinsfileResponse struct {
|
||||
Status string `json:"status"`
|
||||
Data struct {
|
||||
Result string `json:"result"`
|
||||
Errors []map[string]interface{} `json:"errors"`
|
||||
} `json:"data"`
|
||||
}
|
||||
type ValidatePipelineJsonResponse struct {
|
||||
Status string `json:"status"`
|
||||
Data struct {
|
||||
Result string `json:"result"`
|
||||
Errors []map[string]interface{} `json:"errors"`
|
||||
}
|
||||
}
|
||||
|
||||
type PipelineJsonToJenkinsfileResponse struct {
|
||||
Status string `json:"status"`
|
||||
Data struct {
|
||||
Result string `json:"result"`
|
||||
Errors []map[string]interface{} `json:"errors"`
|
||||
Jenkinsfile string `json:"jenkinsfile"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
type JenkinsfileToPipelineJsonResponse struct {
|
||||
Status string `json:"status"`
|
||||
Data struct {
|
||||
Result string `json:"result"`
|
||||
Errors []map[string]interface{} `json:"errors"`
|
||||
Json map[string]interface{} `json:"json"`
|
||||
} `json:"data"`
|
||||
}
|
||||
type StepJsonToJenkinsfileResponse struct {
|
||||
Status string `json:"status"`
|
||||
Data struct {
|
||||
Result string `json:"result"`
|
||||
Errors []map[string]interface{} `json:"errors"`
|
||||
Jenkinsfile string `json:"jenkinsfile"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
type StepsJenkinsfileToJsonResponse struct {
|
||||
Status string `json:"status"`
|
||||
Data struct {
|
||||
Result string `json:"result"`
|
||||
Errors []map[string]interface{} `json:"errors"`
|
||||
Json []map[string]interface{} `json:"json"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
func (j *Jenkins) ValidateJenkinsfile(jenkinsfile string) (*ValidateJenkinsfileResponse, error) {
|
||||
responseStrut := &ValidateJenkinsfileResponse{}
|
||||
query := map[string]string{
|
||||
"jenkinsfile": jenkinsfile,
|
||||
}
|
||||
response, err := j.Requester.PostForm("/pipeline-model-converter/validateJenkinsfile", nil, responseStrut, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return nil, errors.New(strconv.Itoa(response.StatusCode))
|
||||
}
|
||||
return responseStrut, nil
|
||||
|
||||
}
|
||||
|
||||
func (j *Jenkins) ValidatePipelineJson(json string) (*ValidatePipelineJsonResponse, error) {
|
||||
|
||||
responseStruct := &ValidatePipelineJsonResponse{}
|
||||
query := map[string]string{
|
||||
"json": json,
|
||||
}
|
||||
response, err := j.Requester.PostForm("/pipeline-model-converter/validateJson", nil, responseStruct, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return nil, errors.New(strconv.Itoa(response.StatusCode))
|
||||
}
|
||||
return responseStruct, nil
|
||||
}
|
||||
|
||||
func (j *Jenkins) PipelineJsonToJenkinsfile(json string) (*PipelineJsonToJenkinsfileResponse, error) {
|
||||
responseStrut := &PipelineJsonToJenkinsfileResponse{}
|
||||
query := map[string]string{
|
||||
"json": json,
|
||||
}
|
||||
response, err := j.Requester.PostForm("/pipeline-model-converter/toJenkinsfile", nil, responseStrut, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return nil, errors.New(strconv.Itoa(response.StatusCode))
|
||||
}
|
||||
return responseStrut, nil
|
||||
}
|
||||
|
||||
func (j *Jenkins) JenkinsfileToPipelineJson(jenkinsfile string) (*JenkinsfileToPipelineJsonResponse, error) {
|
||||
responseStrut := &JenkinsfileToPipelineJsonResponse{}
|
||||
query := map[string]string{
|
||||
"jenkinsfile": jenkinsfile,
|
||||
}
|
||||
response, err := j.Requester.PostForm("/pipeline-model-converter/toJson", nil, responseStrut, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return nil, errors.New(strconv.Itoa(response.StatusCode))
|
||||
}
|
||||
return responseStrut, nil
|
||||
}
|
||||
|
||||
func (j *Jenkins) StepsJsonToJenkinsfile(json string) (*StepJsonToJenkinsfileResponse, error) {
|
||||
responseStrut := &StepJsonToJenkinsfileResponse{}
|
||||
query := map[string]string{
|
||||
"json": json,
|
||||
}
|
||||
response, err := j.Requester.PostForm("/pipeline-model-converter/stepsToJenkinsfile", nil, responseStrut, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return nil, errors.New(strconv.Itoa(response.StatusCode))
|
||||
}
|
||||
return responseStrut, nil
|
||||
}
|
||||
|
||||
func (j *Jenkins) StepsJenkinsfileToJson(jenkinsfile string) (*StepsJenkinsfileToJsonResponse, error) {
|
||||
responseStrut := &StepsJenkinsfileToJsonResponse{}
|
||||
query := map[string]string{
|
||||
"jenkinsfile": jenkinsfile,
|
||||
}
|
||||
response, err := j.Requester.PostForm("/pipeline-model-converter/stepsToJson", nil, responseStrut, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return nil, errors.New(strconv.Itoa(response.StatusCode))
|
||||
}
|
||||
return responseStrut, nil
|
||||
}
|
||||
109
pkg/simple/client/devops/jenkins/project.go
Normal file
109
pkg/simple/client/devops/jenkins/project.go
Normal file
@@ -0,0 +1,109 @@
|
||||
package jenkins
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"k8s.io/klog"
|
||||
"kubesphere.io/kubesphere/pkg/api/devops/v1alpha2"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/devops"
|
||||
"net/http"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type DevOpsProjectRoleResponse struct {
|
||||
ProjectRole *ProjectRole
|
||||
Err error
|
||||
}
|
||||
|
||||
func (j *Jenkins) CreateDevOpsProject(username string, project *v1alpha2.DevOpsProject) (*v1alpha2.DevOpsProject, error) {
|
||||
_, err := j.CreateFolder(project.ProjectId, project.Description)
|
||||
if err != nil {
|
||||
klog.Errorf("%+v", err)
|
||||
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
|
||||
}
|
||||
|
||||
var addRoleCh = make(chan *DevOpsProjectRoleResponse, 8)
|
||||
var addRoleWg sync.WaitGroup
|
||||
for role, permission := range JenkinsProjectPermissionMap {
|
||||
addRoleWg.Add(1)
|
||||
go func(role string, permission ProjectPermissionIds) {
|
||||
_, err := j.AddProjectRole(GetProjectRoleName(project.ProjectId, role),
|
||||
GetProjectRolePattern(project.ProjectId), permission, true)
|
||||
addRoleCh <- &DevOpsProjectRoleResponse{nil, err}
|
||||
addRoleWg.Done()
|
||||
}(role, permission)
|
||||
}
|
||||
for role, permission := range JenkinsPipelinePermissionMap {
|
||||
addRoleWg.Add(1)
|
||||
go func(role string, permission ProjectPermissionIds) {
|
||||
_, err := j.AddProjectRole(GetPipelineRoleName(project.ProjectId, role),
|
||||
GetPipelineRolePattern(project.ProjectId), permission, true)
|
||||
addRoleCh <- &DevOpsProjectRoleResponse{nil, err}
|
||||
addRoleWg.Done()
|
||||
}(role, permission)
|
||||
}
|
||||
addRoleWg.Wait()
|
||||
close(addRoleCh)
|
||||
for addRoleResponse := range addRoleCh {
|
||||
if addRoleResponse.Err != nil {
|
||||
klog.Errorf("%+v", addRoleResponse.Err)
|
||||
return nil, restful.NewError(GetJenkinsStatusCode(addRoleResponse.Err), addRoleResponse.Err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
globalRole, err := j.GetGlobalRole(JenkinsAllUserRoleName)
|
||||
if err != nil {
|
||||
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
|
||||
}
|
||||
if globalRole == nil {
|
||||
_, err := j.AddGlobalRole(JenkinsAllUserRoleName, GlobalPermissionIds{
|
||||
GlobalRead: true,
|
||||
}, true)
|
||||
if err != nil {
|
||||
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
|
||||
}
|
||||
}
|
||||
err = globalRole.AssignRole(username)
|
||||
if err != nil {
|
||||
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
|
||||
}
|
||||
|
||||
projectRole, err := j.GetProjectRole(GetProjectRoleName(project.ProjectId, devops.ProjectOwner))
|
||||
if err != nil {
|
||||
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
|
||||
}
|
||||
err = projectRole.AssignRole(username)
|
||||
if err != nil {
|
||||
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
|
||||
}
|
||||
|
||||
pipelineRole, err := j.GetProjectRole(GetPipelineRoleName(project.ProjectId, devops.ProjectOwner))
|
||||
if err != nil {
|
||||
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
|
||||
}
|
||||
err = pipelineRole.AssignRole(username)
|
||||
if err != nil {
|
||||
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
|
||||
}
|
||||
return project, nil
|
||||
}
|
||||
|
||||
func (j *Jenkins) DeleteDevOpsProject(projectId string) error {
|
||||
_, err := j.DeleteJob(projectId)
|
||||
|
||||
if err != nil && GetJenkinsStatusCode(err) != http.StatusNotFound {
|
||||
klog.Errorf("%+v", err)
|
||||
return restful.NewError(GetJenkinsStatusCode(err), err.Error())
|
||||
}
|
||||
|
||||
roleNames := make([]string, 0)
|
||||
for role := range JenkinsProjectPermissionMap {
|
||||
roleNames = append(roleNames, GetProjectRoleName(projectId, role))
|
||||
roleNames = append(roleNames, GetPipelineRoleName(projectId, role))
|
||||
}
|
||||
err = j.DeleteProjectRoles(roleNames...)
|
||||
if err != nil {
|
||||
klog.Errorf("%+v", err)
|
||||
return restful.NewError(GetJenkinsStatusCode(err), err.Error())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
165
pkg/simple/client/devops/jenkins/project_pipeline.go
Normal file
165
pkg/simple/client/devops/jenkins/project_pipeline.go
Normal file
@@ -0,0 +1,165 @@
|
||||
package jenkins
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/emicklei/go-restful"
|
||||
"k8s.io/klog"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/devops"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func (j *Jenkins) CreateProjectPipeline(projectId string, pipeline *devops.ProjectPipeline) (string, error) {
|
||||
switch pipeline.Type {
|
||||
case devops.NoScmPipelineType:
|
||||
|
||||
config, err := createPipelineConfigXml(pipeline.Pipeline)
|
||||
if err != nil {
|
||||
return "", restful.NewError(http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
job, err := j.GetJob(pipeline.Pipeline.Name, projectId)
|
||||
if job != nil {
|
||||
err := fmt.Errorf("job name [%s] has been used", job.GetName())
|
||||
return "", restful.NewError(http.StatusConflict, err.Error())
|
||||
}
|
||||
|
||||
if err != nil && GetJenkinsStatusCode(err) != http.StatusNotFound {
|
||||
return "", restful.NewError(GetJenkinsStatusCode(err), err.Error())
|
||||
}
|
||||
|
||||
_, err = j.CreateJobInFolder(config, pipeline.Pipeline.Name, projectId)
|
||||
if err != nil {
|
||||
return "", restful.NewError(GetJenkinsStatusCode(err), err.Error())
|
||||
}
|
||||
|
||||
return pipeline.Pipeline.Name, nil
|
||||
case devops.MultiBranchPipelineType:
|
||||
config, err := createMultiBranchPipelineConfigXml(projectId, pipeline.MultiBranchPipeline)
|
||||
if err != nil {
|
||||
return "", restful.NewError(http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
job, err := j.GetJob(pipeline.MultiBranchPipeline.Name, projectId)
|
||||
if job != nil {
|
||||
err := fmt.Errorf("job name [%s] has been used", job.GetName())
|
||||
return "", restful.NewError(http.StatusConflict, err.Error())
|
||||
}
|
||||
|
||||
if err != nil && GetJenkinsStatusCode(err) != http.StatusNotFound {
|
||||
return "", restful.NewError(GetJenkinsStatusCode(err), err.Error())
|
||||
}
|
||||
|
||||
_, err = j.CreateJobInFolder(config, pipeline.MultiBranchPipeline.Name, projectId)
|
||||
if err != nil {
|
||||
return "", restful.NewError(GetJenkinsStatusCode(err), err.Error())
|
||||
}
|
||||
|
||||
return pipeline.MultiBranchPipeline.Name, nil
|
||||
|
||||
default:
|
||||
err := fmt.Errorf("error unsupport job type")
|
||||
klog.Errorf("%+v", err)
|
||||
return "", restful.NewError(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func (j *Jenkins) DeleteProjectPipeline(projectId string, pipelineId string) (string, error) {
|
||||
_, err := j.DeleteJob(pipelineId, projectId)
|
||||
if err != nil {
|
||||
return "", restful.NewError(GetJenkinsStatusCode(err), err.Error())
|
||||
}
|
||||
return pipelineId, nil
|
||||
|
||||
}
|
||||
func (j *Jenkins) UpdateProjectPipeline(projectId string, pipeline *devops.ProjectPipeline) (string, error) {
|
||||
switch pipeline.Type {
|
||||
case devops.NoScmPipelineType:
|
||||
|
||||
config, err := createPipelineConfigXml(pipeline.Pipeline)
|
||||
if err != nil {
|
||||
return "", restful.NewError(http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
job, err := j.GetJob(pipeline.Pipeline.Name, projectId)
|
||||
|
||||
if err != nil {
|
||||
return "", restful.NewError(GetJenkinsStatusCode(err), err.Error())
|
||||
}
|
||||
|
||||
err = job.UpdateConfig(config)
|
||||
if err != nil {
|
||||
return "", restful.NewError(GetJenkinsStatusCode(err), err.Error())
|
||||
}
|
||||
|
||||
return pipeline.Pipeline.Name, nil
|
||||
case devops.MultiBranchPipelineType:
|
||||
|
||||
config, err := createMultiBranchPipelineConfigXml(projectId, pipeline.MultiBranchPipeline)
|
||||
if err != nil {
|
||||
klog.Errorf("%+v", err)
|
||||
|
||||
return "", restful.NewError(http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
job, err := j.GetJob(pipeline.MultiBranchPipeline.Name, projectId)
|
||||
|
||||
if err != nil {
|
||||
return "", restful.NewError(GetJenkinsStatusCode(err), err.Error())
|
||||
}
|
||||
|
||||
err = job.UpdateConfig(config)
|
||||
if err != nil {
|
||||
klog.Errorf("%+v", err)
|
||||
return "", restful.NewError(GetJenkinsStatusCode(err), err.Error())
|
||||
}
|
||||
|
||||
return pipeline.MultiBranchPipeline.Name, nil
|
||||
|
||||
default:
|
||||
err := fmt.Errorf("error unsupport job type")
|
||||
klog.Errorf("%+v", err)
|
||||
return "", restful.NewError(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func (j *Jenkins) GetProjectPipelineConfig(projectId, pipelineId string) (*devops.ProjectPipeline, error) {
|
||||
job, err := j.GetJob(pipelineId, projectId)
|
||||
if err != nil {
|
||||
klog.Errorf("%+v", err)
|
||||
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
|
||||
}
|
||||
switch job.Raw.Class {
|
||||
case "org.jenkinsci.plugins.workflow.job.WorkflowJob":
|
||||
config, err := job.GetConfig()
|
||||
if err != nil {
|
||||
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
|
||||
}
|
||||
pipeline, err := parsePipelineConfigXml(config)
|
||||
if err != nil {
|
||||
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
|
||||
}
|
||||
pipeline.Name = pipelineId
|
||||
return &devops.ProjectPipeline{
|
||||
Type: devops.NoScmPipelineType,
|
||||
Pipeline: pipeline,
|
||||
}, nil
|
||||
|
||||
case "org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject":
|
||||
config, err := job.GetConfig()
|
||||
if err != nil {
|
||||
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
|
||||
}
|
||||
pipeline, err := parseMultiBranchPipelineConfigXml(config)
|
||||
if err != nil {
|
||||
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
|
||||
}
|
||||
pipeline.Name = pipelineId
|
||||
return &devops.ProjectPipeline{
|
||||
Type: devops.MultiBranchPipelineType,
|
||||
MultiBranchPipeline: pipeline,
|
||||
}, nil
|
||||
default:
|
||||
klog.Errorf("%+v", err)
|
||||
return nil, restful.NewError(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
}
|
||||
54
pkg/simple/client/devops/jenkins/pure_request.go
Normal file
54
pkg/simple/client/devops/jenkins/pure_request.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package jenkins
|
||||
|
||||
import (
|
||||
"k8s.io/klog"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/devops"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
)
|
||||
|
||||
// TODO: deprecated, use SendJenkinsRequestWithHeaderResp() instead
|
||||
func (j *Jenkins) SendPureRequest(path string, httpParameters *devops.HttpParameters) ([]byte, error) {
|
||||
resBody, _, err := j.SendPureRequestWithHeaderResp(path, httpParameters)
|
||||
|
||||
return resBody, err
|
||||
}
|
||||
|
||||
func (j *Jenkins) SendPureRequestWithHeaderResp(path string, httpParameters *devops.HttpParameters) ([]byte, http.Header, error) {
|
||||
Url, err := url.Parse(j.Server + path)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
client := &http.Client{Timeout: 30 * time.Second}
|
||||
|
||||
newRequest := &http.Request{
|
||||
Method: httpParameters.Method,
|
||||
URL: Url,
|
||||
Header: httpParameters.Header,
|
||||
Body: httpParameters.Body,
|
||||
Form: httpParameters.Form,
|
||||
PostForm: httpParameters.PostForm,
|
||||
}
|
||||
|
||||
resp, err := client.Do(newRequest)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
resBody, _ := getRespBody(resp)
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode >= http.StatusBadRequest {
|
||||
klog.Errorf("%+v", string(resBody))
|
||||
jkerr := new(JkError)
|
||||
jkerr.Code = resp.StatusCode
|
||||
jkerr.Message = string(resBody)
|
||||
return nil, nil, jkerr
|
||||
}
|
||||
|
||||
return resBody, resp.Header, nil
|
||||
}
|
||||
468
pkg/simple/client/devops/jenkins/request.go
Normal file
468
pkg/simple/client/devops/jenkins/request.go
Normal file
@@ -0,0 +1,468 @@
|
||||
// Copyright 2015 Vadim Kravcenko
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package jenkins
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Request Methods
|
||||
|
||||
type APIRequest struct {
|
||||
Method string
|
||||
Endpoint string
|
||||
Payload io.Reader
|
||||
Headers http.Header
|
||||
Suffix string
|
||||
}
|
||||
|
||||
func (ar *APIRequest) SetHeader(key string, value string) *APIRequest {
|
||||
ar.Headers.Set(key, value)
|
||||
return ar
|
||||
}
|
||||
|
||||
func NewAPIRequest(method string, endpoint string, payload io.Reader) *APIRequest {
|
||||
var headers = http.Header{}
|
||||
var suffix string
|
||||
ar := &APIRequest{method, endpoint, payload, headers, suffix}
|
||||
return ar
|
||||
}
|
||||
|
||||
type Requester struct {
|
||||
Base string
|
||||
BasicAuth *BasicAuth
|
||||
Client *http.Client
|
||||
CACert []byte
|
||||
SslVerify bool
|
||||
connControl chan struct{}
|
||||
}
|
||||
|
||||
func (r *Requester) SetCrumb(ar *APIRequest) error {
|
||||
crumbData := map[string]string{}
|
||||
response, err := r.GetJSON("/crumbIssuer/api/json", &crumbData, nil)
|
||||
if err != nil {
|
||||
jenkinsError, ok := err.(*ErrorResponse)
|
||||
if ok && jenkinsError.Response.StatusCode == http.StatusNotFound {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
if response.StatusCode == 200 && crumbData["crumbRequestField"] != "" {
|
||||
ar.SetHeader(crumbData["crumbRequestField"], crumbData["crumb"])
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Requester) PostJSON(endpoint string, payload io.Reader, responseStruct interface{}, querystring map[string]string) (*http.Response, error) {
|
||||
ar := NewAPIRequest("POST", endpoint, payload)
|
||||
if err := r.SetCrumb(ar); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ar.SetHeader("Content-Type", "application/x-www-form-urlencoded")
|
||||
ar.Suffix = "api/json"
|
||||
return r.Do(ar, responseStruct, querystring)
|
||||
}
|
||||
|
||||
func (r *Requester) Post(endpoint string, payload io.Reader, responseStruct interface{}, querystring map[string]string) (*http.Response, error) {
|
||||
ar := NewAPIRequest("POST", endpoint, payload)
|
||||
if err := r.SetCrumb(ar); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ar.SetHeader("Content-Type", "application/x-www-form-urlencoded")
|
||||
ar.Suffix = ""
|
||||
return r.Do(ar, responseStruct, querystring)
|
||||
}
|
||||
func (r *Requester) PostForm(endpoint string, payload io.Reader, responseStruct interface{}, formString map[string]string) (*http.Response, error) {
|
||||
ar := NewAPIRequest("POST", endpoint, payload)
|
||||
if err := r.SetCrumb(ar); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ar.SetHeader("Content-Type", "application/x-www-form-urlencoded")
|
||||
ar.Suffix = ""
|
||||
return r.DoPostForm(ar, responseStruct, formString)
|
||||
}
|
||||
|
||||
func (r *Requester) PostFiles(endpoint string, payload io.Reader, responseStruct interface{}, querystring map[string]string, files []string) (*http.Response, error) {
|
||||
ar := NewAPIRequest("POST", endpoint, payload)
|
||||
if err := r.SetCrumb(ar); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return r.Do(ar, responseStruct, querystring, files)
|
||||
}
|
||||
|
||||
func (r *Requester) PostXML(endpoint string, xml string, responseStruct interface{}, querystring map[string]string) (*http.Response, error) {
|
||||
payload := bytes.NewBuffer([]byte(xml))
|
||||
ar := NewAPIRequest("POST", endpoint, payload)
|
||||
if err := r.SetCrumb(ar); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ar.SetHeader("Content-Type", "application/xml;charset=utf-8")
|
||||
ar.Suffix = ""
|
||||
return r.Do(ar, responseStruct, querystring)
|
||||
}
|
||||
|
||||
func (r *Requester) GetJSON(endpoint string, responseStruct interface{}, query map[string]string) (*http.Response, error) {
|
||||
ar := NewAPIRequest("GET", endpoint, nil)
|
||||
ar.SetHeader("Content-Type", "application/json")
|
||||
ar.Suffix = "api/json"
|
||||
return r.Do(ar, responseStruct, query)
|
||||
}
|
||||
|
||||
func (r *Requester) GetXML(endpoint string, responseStruct interface{}, query map[string]string) (*http.Response, error) {
|
||||
ar := NewAPIRequest("GET", endpoint, nil)
|
||||
ar.SetHeader("Content-Type", "application/xml")
|
||||
ar.Suffix = ""
|
||||
return r.Do(ar, responseStruct, query)
|
||||
}
|
||||
|
||||
func (r *Requester) Get(endpoint string, responseStruct interface{}, querystring map[string]string) (*http.Response, error) {
|
||||
ar := NewAPIRequest("GET", endpoint, nil)
|
||||
ar.Suffix = ""
|
||||
return r.Do(ar, responseStruct, querystring)
|
||||
}
|
||||
|
||||
func (r *Requester) GetHtml(endpoint string, responseStruct interface{}, querystring map[string]string) (*http.Response, error) {
|
||||
ar := NewAPIRequest("GET", endpoint, nil)
|
||||
ar.Suffix = ""
|
||||
return r.DoGet(ar, responseStruct, querystring)
|
||||
}
|
||||
|
||||
func (r *Requester) SetClient(client *http.Client) *Requester {
|
||||
r.Client = client
|
||||
return r
|
||||
}
|
||||
|
||||
//Add auth on redirect if required.
|
||||
func (r *Requester) redirectPolicyFunc(req *http.Request, via []*http.Request) error {
|
||||
if r.BasicAuth != nil {
|
||||
req.SetBasicAuth(r.BasicAuth.Username, r.BasicAuth.Password)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Requester) DoGet(ar *APIRequest, responseStruct interface{}, options ...interface{}) (*http.Response, error) {
|
||||
fileUpload := false
|
||||
var files []string
|
||||
URL, err := url.Parse(r.Base + ar.Endpoint + ar.Suffix)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, o := range options {
|
||||
switch v := o.(type) {
|
||||
case map[string]string:
|
||||
|
||||
querystring := make(url.Values)
|
||||
for key, val := range v {
|
||||
querystring.Set(key, val)
|
||||
}
|
||||
|
||||
URL.RawQuery = querystring.Encode()
|
||||
case []string:
|
||||
fileUpload = true
|
||||
files = v
|
||||
}
|
||||
}
|
||||
var req *http.Request
|
||||
if fileUpload {
|
||||
body := &bytes.Buffer{}
|
||||
writer := multipart.NewWriter(body)
|
||||
for _, file := range files {
|
||||
fileData, err := os.Open(file)
|
||||
if err != nil {
|
||||
Error.Println(err.Error())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
part, err := writer.CreateFormFile("file", filepath.Base(file))
|
||||
if err != nil {
|
||||
Error.Println(err.Error())
|
||||
return nil, err
|
||||
}
|
||||
if _, err = io.Copy(part, fileData); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer fileData.Close()
|
||||
}
|
||||
var params map[string]string
|
||||
json.NewDecoder(ar.Payload).Decode(¶ms)
|
||||
for key, val := range params {
|
||||
if err = writer.WriteField(key, val); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if err = writer.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req, err = http.NewRequest(ar.Method, URL.String(), body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Content-Type", writer.FormDataContentType())
|
||||
} else {
|
||||
req, err = http.NewRequest(ar.Method, URL.String(), ar.Payload)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if r.BasicAuth != nil {
|
||||
req.SetBasicAuth(r.BasicAuth.Username, r.BasicAuth.Password)
|
||||
}
|
||||
req.Close = true
|
||||
req.Header.Add("Accept", "*/*")
|
||||
for k := range ar.Headers {
|
||||
req.Header.Add(k, ar.Headers.Get(k))
|
||||
}
|
||||
r.connControl <- struct{}{}
|
||||
if response, err := r.Client.Do(req); err != nil {
|
||||
<-r.connControl
|
||||
return nil, err
|
||||
} else {
|
||||
<-r.connControl
|
||||
errorText := response.Header.Get("X-Error")
|
||||
if errorText != "" {
|
||||
return nil, errors.New(errorText)
|
||||
}
|
||||
err := CheckResponse(response)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch responseStruct.(type) {
|
||||
case *string:
|
||||
return r.ReadRawResponse(response, responseStruct)
|
||||
default:
|
||||
return r.ReadJSONResponse(response, responseStruct)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (r *Requester) Do(ar *APIRequest, responseStruct interface{}, options ...interface{}) (*http.Response, error) {
|
||||
if !strings.HasSuffix(ar.Endpoint, "/") && ar.Method != "POST" {
|
||||
ar.Endpoint += "/"
|
||||
}
|
||||
|
||||
fileUpload := false
|
||||
var files []string
|
||||
URL, err := url.Parse(r.Base + ar.Endpoint + ar.Suffix)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, o := range options {
|
||||
switch v := o.(type) {
|
||||
case map[string]string:
|
||||
|
||||
querystring := make(url.Values)
|
||||
for key, val := range v {
|
||||
querystring.Set(key, val)
|
||||
}
|
||||
|
||||
URL.RawQuery = querystring.Encode()
|
||||
case []string:
|
||||
fileUpload = true
|
||||
files = v
|
||||
}
|
||||
}
|
||||
var req *http.Request
|
||||
if fileUpload {
|
||||
body := &bytes.Buffer{}
|
||||
writer := multipart.NewWriter(body)
|
||||
for _, file := range files {
|
||||
fileData, err := os.Open(file)
|
||||
if err != nil {
|
||||
Error.Println(err.Error())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
part, err := writer.CreateFormFile("file", filepath.Base(file))
|
||||
if err != nil {
|
||||
Error.Println(err.Error())
|
||||
return nil, err
|
||||
}
|
||||
if _, err = io.Copy(part, fileData); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer fileData.Close()
|
||||
}
|
||||
var params map[string]string
|
||||
json.NewDecoder(ar.Payload).Decode(¶ms)
|
||||
for key, val := range params {
|
||||
if err = writer.WriteField(key, val); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if err = writer.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req, err = http.NewRequest(ar.Method, URL.String(), body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Content-Type", writer.FormDataContentType())
|
||||
} else {
|
||||
req, err = http.NewRequest(ar.Method, URL.String(), ar.Payload)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if r.BasicAuth != nil {
|
||||
req.SetBasicAuth(r.BasicAuth.Username, r.BasicAuth.Password)
|
||||
}
|
||||
req.Close = true
|
||||
req.Header.Add("Accept", "*/*")
|
||||
for k := range ar.Headers {
|
||||
req.Header.Add(k, ar.Headers.Get(k))
|
||||
}
|
||||
r.connControl <- struct{}{}
|
||||
if response, err := r.Client.Do(req); err != nil {
|
||||
<-r.connControl
|
||||
return nil, err
|
||||
} else {
|
||||
<-r.connControl
|
||||
errorText := response.Header.Get("X-Error")
|
||||
if errorText != "" {
|
||||
return nil, errors.New(errorText)
|
||||
}
|
||||
err := CheckResponse(response)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch responseStruct.(type) {
|
||||
case *string:
|
||||
return r.ReadRawResponse(response, responseStruct)
|
||||
default:
|
||||
return r.ReadJSONResponse(response, responseStruct)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (r *Requester) DoPostForm(ar *APIRequest, responseStruct interface{}, form map[string]string) (*http.Response, error) {
|
||||
|
||||
if !strings.HasSuffix(ar.Endpoint, "/") && ar.Method != "POST" {
|
||||
ar.Endpoint += "/"
|
||||
}
|
||||
URL, err := url.Parse(r.Base + ar.Endpoint + ar.Suffix)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
formValue := make(url.Values)
|
||||
for k, v := range form {
|
||||
formValue.Set(k, v)
|
||||
}
|
||||
req, err := http.NewRequest("POST", URL.String(), strings.NewReader(formValue.Encode()))
|
||||
if r.BasicAuth != nil {
|
||||
req.SetBasicAuth(r.BasicAuth.Username, r.BasicAuth.Password)
|
||||
}
|
||||
req.Close = true
|
||||
req.Header.Add("Accept", "*/*")
|
||||
for k := range ar.Headers {
|
||||
req.Header.Add(k, ar.Headers.Get(k))
|
||||
}
|
||||
r.connControl <- struct{}{}
|
||||
if response, err := r.Client.Do(req); err != nil {
|
||||
<-r.connControl
|
||||
return nil, err
|
||||
} else {
|
||||
<-r.connControl
|
||||
errorText := response.Header.Get("X-Error")
|
||||
if errorText != "" {
|
||||
return nil, errors.New(errorText)
|
||||
}
|
||||
err := CheckResponse(response)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch responseStruct.(type) {
|
||||
case *string:
|
||||
return r.ReadRawResponse(response, responseStruct)
|
||||
default:
|
||||
return r.ReadJSONResponse(response, responseStruct)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Requester) ReadRawResponse(response *http.Response, responseStruct interface{}) (*http.Response, error) {
|
||||
defer response.Body.Close()
|
||||
|
||||
content, err := ioutil.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if str, ok := responseStruct.(*string); ok {
|
||||
*str = string(content)
|
||||
} else {
|
||||
return nil, fmt.Errorf("Could not cast responseStruct to *string")
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (r *Requester) ReadJSONResponse(response *http.Response, responseStruct interface{}) (*http.Response, error) {
|
||||
defer response.Body.Close()
|
||||
err := json.NewDecoder(response.Body).Decode(responseStruct)
|
||||
if err != nil && err.Error() == "EOF" {
|
||||
return response, nil
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
type ErrorResponse struct {
|
||||
Body []byte
|
||||
Response *http.Response
|
||||
Message string
|
||||
}
|
||||
|
||||
func (e *ErrorResponse) Error() string {
|
||||
u := fmt.Sprintf("%s://%s%s", e.Response.Request.URL.Scheme, e.Response.Request.URL.Host, e.Response.Request.URL.RequestURI())
|
||||
return fmt.Sprintf("%s %s: %d %s", e.Response.Request.Method, u, e.Response.StatusCode, e.Message)
|
||||
}
|
||||
func CheckResponse(r *http.Response) error {
|
||||
|
||||
switch r.StatusCode {
|
||||
case http.StatusOK, http.StatusCreated, http.StatusAccepted, http.StatusNoContent, http.StatusFound, http.StatusNotModified:
|
||||
return nil
|
||||
}
|
||||
defer r.Body.Close()
|
||||
errorResponse := &ErrorResponse{Response: r}
|
||||
data, err := ioutil.ReadAll(r.Body)
|
||||
if err == nil && data != nil {
|
||||
errorResponse.Body = data
|
||||
errorResponse.Message = string(data)
|
||||
}
|
||||
|
||||
return errorResponse
|
||||
}
|
||||
204
pkg/simple/client/devops/jenkins/role.go
Normal file
204
pkg/simple/client/devops/jenkins/role.go
Normal file
@@ -0,0 +1,204 @@
|
||||
package jenkins
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type GlobalRoleResponse struct {
|
||||
RoleName string `json:"roleName"`
|
||||
PermissionIds GlobalPermissionIds `json:"permissionIds"`
|
||||
}
|
||||
|
||||
type GlobalRole struct {
|
||||
Jenkins *Jenkins
|
||||
Raw GlobalRoleResponse
|
||||
}
|
||||
|
||||
type GlobalPermissionIds struct {
|
||||
Administer bool `json:"hudson.model.Hudson.Administer"`
|
||||
GlobalRead bool `json:"hudson.model.Hudson.Read"`
|
||||
CredentialCreate bool `json:"com.cloudbees.plugins.credentials.CredentialsProvider.Create"`
|
||||
CredentialUpdate bool `json:"com.cloudbees.plugins.credentials.CredentialsProvider.Update"`
|
||||
CredentialView bool `json:"com.cloudbees.plugins.credentials.CredentialsProvider.View"`
|
||||
CredentialDelete bool `json:"com.cloudbees.plugins.credentials.CredentialsProvider.Delete"`
|
||||
CredentialManageDomains bool `json:"com.cloudbees.plugins.credentials.CredentialsProvider.ManageDomains"`
|
||||
SlaveCreate bool `json:"hudson.model.Computer.Create"`
|
||||
SlaveConfigure bool `json:"hudson.model.Computer.Configure"`
|
||||
SlaveDelete bool `json:"hudson.model.Computer.Delete"`
|
||||
SlaveBuild bool `json:"hudson.model.Computer.Build"`
|
||||
SlaveConnect bool `json:"hudson.model.Computer.Connect"`
|
||||
SlaveDisconnect bool `json:"hudson.model.Computer.Disconnect"`
|
||||
ItemBuild bool `json:"hudson.model.Item.Build"`
|
||||
ItemCreate bool `json:"hudson.model.Item.Create"`
|
||||
ItemRead bool `json:"hudson.model.Item.Read"`
|
||||
ItemConfigure bool `json:"hudson.model.Item.Configure"`
|
||||
ItemCancel bool `json:"hudson.model.Item.Cancel"`
|
||||
ItemMove bool `json:"hudson.model.Item.Move"`
|
||||
ItemDiscover bool `json:"hudson.model.Item.Discover"`
|
||||
ItemWorkspace bool `json:"hudson.model.Item.Workspace"`
|
||||
ItemDelete bool `json:"hudson.model.Item.Delete"`
|
||||
RunUpdate bool `json:"hudson.model.Run.Update"`
|
||||
RunDelete bool `json:"hudson.model.Run.Delete"`
|
||||
ViewCreate bool `json:"hudson.model.View.Create"`
|
||||
ViewConfigure bool `json:"hudson.model.View.Configure"`
|
||||
ViewRead bool `json:"hudson.model.View.Read"`
|
||||
ViewDelete bool `json:"hudson.model.View.Delete"`
|
||||
SCMTag bool `json:"hudson.scm.SCM.Tag"`
|
||||
}
|
||||
|
||||
type ProjectRole struct {
|
||||
Jenkins *Jenkins
|
||||
Raw ProjectRoleResponse
|
||||
}
|
||||
|
||||
type ProjectRoleResponse struct {
|
||||
RoleName string `json:"roleName"`
|
||||
PermissionIds ProjectPermissionIds `json:"permissionIds"`
|
||||
Pattern string `json:"pattern"`
|
||||
}
|
||||
|
||||
type ProjectPermissionIds struct {
|
||||
CredentialCreate bool `json:"com.cloudbees.plugins.credentials.CredentialsProvider.Create"`
|
||||
CredentialUpdate bool `json:"com.cloudbees.plugins.credentials.CredentialsProvider.Update"`
|
||||
CredentialView bool `json:"com.cloudbees.plugins.credentials.CredentialsProvider.View"`
|
||||
CredentialDelete bool `json:"com.cloudbees.plugins.credentials.CredentialsProvider.Delete"`
|
||||
CredentialManageDomains bool `json:"com.cloudbees.plugins.credentials.CredentialsProvider.ManageDomains"`
|
||||
ItemBuild bool `json:"hudson.model.Item.Build"`
|
||||
ItemCreate bool `json:"hudson.model.Item.Create"`
|
||||
ItemRead bool `json:"hudson.model.Item.Read"`
|
||||
ItemConfigure bool `json:"hudson.model.Item.Configure"`
|
||||
ItemCancel bool `json:"hudson.model.Item.Cancel"`
|
||||
ItemMove bool `json:"hudson.model.Item.Move"`
|
||||
ItemDiscover bool `json:"hudson.model.Item.Discover"`
|
||||
ItemWorkspace bool `json:"hudson.model.Item.Workspace"`
|
||||
ItemDelete bool `json:"hudson.model.Item.Delete"`
|
||||
RunUpdate bool `json:"hudson.model.Run.Update"`
|
||||
RunDelete bool `json:"hudson.model.Run.Delete"`
|
||||
RunReplay bool `json:"hudson.model.Run.Replay"`
|
||||
SCMTag bool `json:"hudson.scm.SCM.Tag"`
|
||||
}
|
||||
|
||||
func (j *GlobalRole) Update(ids GlobalPermissionIds) error {
|
||||
var idArray []string
|
||||
values := reflect.ValueOf(ids)
|
||||
for i := 0; i < values.NumField(); i++ {
|
||||
field := values.Field(i)
|
||||
if field.Bool() {
|
||||
idArray = append(idArray, values.Type().Field(i).Tag.Get("json"))
|
||||
}
|
||||
}
|
||||
param := map[string]string{
|
||||
"roleName": j.Raw.RoleName,
|
||||
"type": GLOBAL_ROLE,
|
||||
"permissionIds": strings.Join(idArray, ","),
|
||||
"overwrite": strconv.FormatBool(true),
|
||||
}
|
||||
responseString := ""
|
||||
response, err := j.Jenkins.Requester.Post("/role-strategy/strategy/addRole", nil, &responseString, param)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return errors.New(strconv.Itoa(response.StatusCode))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (j *GlobalRole) AssignRole(sid string) error {
|
||||
param := map[string]string{
|
||||
"type": GLOBAL_ROLE,
|
||||
"roleName": j.Raw.RoleName,
|
||||
"sid": sid,
|
||||
}
|
||||
responseString := ""
|
||||
response, err := j.Jenkins.Requester.Post("/role-strategy/strategy/assignRole", nil, &responseString, param)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return errors.New(strconv.Itoa(response.StatusCode))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (j *GlobalRole) UnAssignRole(sid string) error {
|
||||
param := map[string]string{
|
||||
"type": GLOBAL_ROLE,
|
||||
"roleName": j.Raw.RoleName,
|
||||
"sid": sid,
|
||||
}
|
||||
responseString := ""
|
||||
response, err := j.Jenkins.Requester.Post("/role-strategy/strategy/unassignRole", nil, &responseString, param)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return errors.New(strconv.Itoa(response.StatusCode))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (j *ProjectRole) Update(pattern string, ids ProjectPermissionIds) error {
|
||||
var idArray []string
|
||||
values := reflect.ValueOf(ids)
|
||||
for i := 0; i < values.NumField(); i++ {
|
||||
field := values.Field(i)
|
||||
if field.Bool() {
|
||||
idArray = append(idArray, values.Type().Field(i).Tag.Get("json"))
|
||||
}
|
||||
}
|
||||
param := map[string]string{
|
||||
"roleName": j.Raw.RoleName,
|
||||
"type": PROJECT_ROLE,
|
||||
"permissionIds": strings.Join(idArray, ","),
|
||||
"overwrite": strconv.FormatBool(true),
|
||||
"pattern": pattern,
|
||||
}
|
||||
responseString := ""
|
||||
response, err := j.Jenkins.Requester.Post("/role-strategy/strategy/addRole", nil, &responseString, param)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return errors.New(strconv.Itoa(response.StatusCode))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (j *ProjectRole) AssignRole(sid string) error {
|
||||
param := map[string]string{
|
||||
"type": PROJECT_ROLE,
|
||||
"roleName": j.Raw.RoleName,
|
||||
"sid": sid,
|
||||
}
|
||||
responseString := ""
|
||||
response, err := j.Jenkins.Requester.Post("/role-strategy/strategy/assignRole", nil, &responseString, param)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return errors.New(strconv.Itoa(response.StatusCode))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (j *ProjectRole) UnAssignRole(sid string) error {
|
||||
param := map[string]string{
|
||||
"type": PROJECT_ROLE,
|
||||
"roleName": j.Raw.RoleName,
|
||||
"sid": sid,
|
||||
}
|
||||
responseString := ""
|
||||
response, err := j.Jenkins.Requester.Post("/role-strategy/strategy/unassignRole", nil, &responseString, param)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return errors.New(strconv.Itoa(response.StatusCode))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
146
pkg/simple/client/devops/jenkins/utils.go
Normal file
146
pkg/simple/client/devops/jenkins/utils.go
Normal file
@@ -0,0 +1,146 @@
|
||||
// Copyright 2015 Vadim Kravcenko
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package jenkins
|
||||
|
||||
import (
|
||||
"compress/gzip"
|
||||
"encoding/json"
|
||||
"github.com/asaskevich/govalidator"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"k8s.io/klog"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
func makeJson(data interface{}) string {
|
||||
str, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return string(json.RawMessage(str))
|
||||
}
|
||||
|
||||
func Reverse(s string) string {
|
||||
size := len(s)
|
||||
buf := make([]byte, size)
|
||||
for start := 0; start < size; {
|
||||
r, n := utf8.DecodeRuneInString(s[start:])
|
||||
start += n
|
||||
utf8.EncodeRune(buf[size-start:], r)
|
||||
}
|
||||
return string(buf)
|
||||
}
|
||||
|
||||
type JkError struct {
|
||||
Message string `json:"message"`
|
||||
Code int `json:"code"`
|
||||
}
|
||||
|
||||
func (err *JkError) Error() string {
|
||||
return err.Message
|
||||
}
|
||||
|
||||
// Decompress response.body of JenkinsAPIResponse
|
||||
func getRespBody(resp *http.Response) ([]byte, error) {
|
||||
var reader io.ReadCloser
|
||||
if resp.Header.Get("Content-Encoding") == "gzip" {
|
||||
reader, _ = gzip.NewReader(resp.Body)
|
||||
} else {
|
||||
reader = resp.Body
|
||||
}
|
||||
resBody, err := ioutil.ReadAll(reader)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
return resBody, err
|
||||
|
||||
}
|
||||
|
||||
// parseJenkinsQuery Parse the special query of jenkins.
|
||||
// ParseQuery in the standard library makes the query not re-encode
|
||||
func parseJenkinsQuery(query string) (url.Values, error) {
|
||||
m := make(url.Values)
|
||||
err := error(nil)
|
||||
for query != "" {
|
||||
key := query
|
||||
if i := strings.IndexAny(key, "&"); i >= 0 {
|
||||
key, query = key[:i], key[i+1:]
|
||||
} else {
|
||||
query = ""
|
||||
}
|
||||
if key == "" {
|
||||
continue
|
||||
}
|
||||
value := ""
|
||||
if i := strings.Index(key, "="); i >= 0 {
|
||||
key, value = key[:i], key[i+1:]
|
||||
}
|
||||
key, err1 := url.QueryUnescape(key)
|
||||
if err1 != nil {
|
||||
if err == nil {
|
||||
err = err1
|
||||
}
|
||||
continue
|
||||
}
|
||||
value, err1 = url.QueryUnescape(value)
|
||||
if err1 != nil {
|
||||
if err == nil {
|
||||
err = err1
|
||||
}
|
||||
continue
|
||||
}
|
||||
m[key] = append(m[key], value)
|
||||
}
|
||||
return m, err
|
||||
}
|
||||
|
||||
type JenkinsBlueTime time.Time
|
||||
|
||||
func (t *JenkinsBlueTime) UnmarshalJSON(b []byte) error {
|
||||
if b == nil || strings.Trim(string(b), "\"") == "null" {
|
||||
*t = JenkinsBlueTime(time.Time{})
|
||||
return nil
|
||||
}
|
||||
j, err := time.Parse("2006-01-02T15:04:05.000-0700", strings.Trim(string(b), "\""))
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*t = JenkinsBlueTime(j)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t JenkinsBlueTime) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(time.Time(t))
|
||||
}
|
||||
|
||||
func GetJenkinsStatusCode(jenkinsErr error) int {
|
||||
if code, err := strconv.Atoi(jenkinsErr.Error()); err == nil {
|
||||
message := http.StatusText(code)
|
||||
if !govalidator.IsNull(message) {
|
||||
return code
|
||||
}
|
||||
}
|
||||
if jErr, ok := jenkinsErr.(*ErrorResponse); ok {
|
||||
return jErr.Response.StatusCode
|
||||
}
|
||||
return http.StatusInternalServerError
|
||||
}
|
||||
48
pkg/simple/client/devops/member.go
Normal file
48
pkg/simple/client/devops/member.go
Normal file
@@ -0,0 +1,48 @@
|
||||
package devops
|
||||
|
||||
type ProjectMembership struct {
|
||||
Username string `json:"username" description:"Member's username,username can uniquely identify a user"`
|
||||
ProjectId string `json:"project_id" db:"project_id" description:"the DevOps Projects which project membership belongs to"`
|
||||
Role string `json:"role" description:"DevOps Project membership's role type. e.g. owner '"`
|
||||
Status string `json:"status" description:"Deprecated, Status of project membership. e.g. active "`
|
||||
GrantBy string `json:"grand_by,omitempty" description:"Username of the user who assigned the role"`
|
||||
}
|
||||
|
||||
type ProjectMemberOperator interface {
|
||||
AddProjectMember(membership *ProjectMembership) (*ProjectMembership, error)
|
||||
UpdateProjectMember(oldMembership, newMembership *ProjectMembership) (*ProjectMembership, error)
|
||||
DeleteProjectMember(membership *ProjectMembership) (*ProjectMembership, error)
|
||||
}
|
||||
|
||||
var DefaultRoles = []*Role{
|
||||
{
|
||||
Name: ProjectOwner,
|
||||
Description: "Owner have access to do all the operations of a DevOps project and own the highest permissions as well.",
|
||||
},
|
||||
{
|
||||
Name: ProjectMaintainer,
|
||||
Description: "Maintainer have access to manage pipeline and credential configuration in a DevOps project.",
|
||||
},
|
||||
{
|
||||
Name: ProjectDeveloper,
|
||||
Description: "Developer is able to view and trigger the pipeline.",
|
||||
},
|
||||
{
|
||||
Name: ProjectReporter,
|
||||
Description: "Reporter is only allowed to view the status of the pipeline.",
|
||||
},
|
||||
}
|
||||
|
||||
var AllRoleSlice = []string{ProjectDeveloper, ProjectReporter, ProjectMaintainer, ProjectOwner}
|
||||
|
||||
const (
|
||||
ProjectOwner = "owner"
|
||||
ProjectMaintainer = "maintainer"
|
||||
ProjectDeveloper = "developer"
|
||||
ProjectReporter = "reporter"
|
||||
)
|
||||
|
||||
type Role struct {
|
||||
Name string `json:"name" description:"role's name e.g. owner'"`
|
||||
Description string `json:"description" description:"role 's description'"`
|
||||
}
|
||||
1199
pkg/simple/client/devops/pipeline.go
Normal file
1199
pkg/simple/client/devops/pipeline.go
Normal file
File diff suppressed because it is too large
Load Diff
8
pkg/simple/client/devops/project.go
Normal file
8
pkg/simple/client/devops/project.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package devops
|
||||
|
||||
import "kubesphere.io/kubesphere/pkg/api/devops/v1alpha2"
|
||||
|
||||
type ProjectOperator interface {
|
||||
CreateDevOpsProject(username string, project *v1alpha2.DevOpsProject) (*v1alpha2.DevOpsProject, error)
|
||||
DeleteDevOpsProject(projectId string) error
|
||||
}
|
||||
144
pkg/simple/client/devops/project_pipeline.go
Normal file
144
pkg/simple/client/devops/project_pipeline.go
Normal file
@@ -0,0 +1,144 @@
|
||||
package devops
|
||||
|
||||
const (
|
||||
NoScmPipelineType = "pipeline"
|
||||
MultiBranchPipelineType = "multi-branch-pipeline"
|
||||
)
|
||||
|
||||
type Parameters []*Parameter
|
||||
|
||||
var ParameterTypeMap = map[string]string{
|
||||
"hudson.model.StringParameterDefinition": "string",
|
||||
"hudson.model.ChoiceParameterDefinition": "choice",
|
||||
"hudson.model.TextParameterDefinition": "text",
|
||||
"hudson.model.BooleanParameterDefinition": "boolean",
|
||||
"hudson.model.FileParameterDefinition": "file",
|
||||
"hudson.model.PasswordParameterDefinition": "password",
|
||||
}
|
||||
|
||||
type ProjectPipeline struct {
|
||||
Type string `json:"type" description:"type of devops pipeline, in scm or no scm"`
|
||||
Pipeline *NoScmPipeline `json:"pipeline,omitempty" description:"no scm pipeline structs"`
|
||||
MultiBranchPipeline *MultiBranchPipeline `json:"multi_branch_pipeline,omitempty" description:"in scm pipeline structs"`
|
||||
}
|
||||
|
||||
type NoScmPipeline struct {
|
||||
Name string `json:"name" description:"name of pipeline"`
|
||||
Description string `json:"descriptio,omitempty" description:"description of pipeline"`
|
||||
Discarder *DiscarderProperty `json:"discarder,omitempty" description:"Discarder of pipeline, managing when to drop a pipeline"`
|
||||
Parameters *Parameters `json:"parameters,omitempty" description:"Parameters define of pipeline,user could pass param when run pipeline"`
|
||||
DisableConcurrent bool `json:"disable_concurrent,omitempty" mapstructure:"disable_concurrent" description:"Whether to prohibit the pipeline from running in parallel"`
|
||||
TimerTrigger *TimerTrigger `json:"timer_trigger,omitempty" mapstructure:"timer_trigger" description:"Timer to trigger pipeline run"`
|
||||
RemoteTrigger *RemoteTrigger `json:"remote_trigger,omitempty" mapstructure:"remote_trigger" description:"Remote api define to trigger pipeline run"`
|
||||
Jenkinsfile string `json:"jenkinsfile,omitempty" description:"Jenkinsfile's content'"`
|
||||
}
|
||||
|
||||
type MultiBranchPipeline struct {
|
||||
Name string `json:"name" description:"name of pipeline"`
|
||||
Description string `json:"descriptio,omitempty" description:"description of pipeline"`
|
||||
Discarder *DiscarderProperty `json:"discarder,omitempty" description:"Discarder of pipeline, managing when to drop a pipeline"`
|
||||
TimerTrigger *TimerTrigger `json:"timer_trigger,omitempty" mapstructure:"timer_trigger" description:"Timer to trigger pipeline run"`
|
||||
SourceType string `json:"source_type" description:"type of scm, such as github/git/svn"`
|
||||
GitSource *GitSource `json:"git_source,omitempty" description:"git scm define"`
|
||||
GitHubSource *GithubSource `json:"github_source,omitempty" description:"github scm define"`
|
||||
SvnSource *SvnSource `json:"svn_source,omitempty" description:"multi branch svn scm define"`
|
||||
SingleSvnSource *SingleSvnSource `json:"single_svn_source,omitempty" description:"single branch svn scm define"`
|
||||
BitbucketServerSource *BitbucketServerSource `json:"bitbucket_server_source,omitempty" description:"bitbucket server scm defile"`
|
||||
ScriptPath string `json:"script_path" mapstructure:"script_path" description:"script path in scm"`
|
||||
MultiBranchJobTrigger *MultiBranchJobTrigger `json:"multibranch_job_trigger,omitempty" mapstructure:"multibranch_job_trigger" description:"Pipeline tasks that need to be triggered when branch creation/deletion"`
|
||||
}
|
||||
|
||||
type GitSource struct {
|
||||
ScmId string `json:"scm_id,omitempty" description:"uid of scm"`
|
||||
Url string `json:"url,omitempty" mapstructure:"url" description:"url of git source"`
|
||||
CredentialId string `json:"credential_id,omitempty" mapstructure:"credential_id" description:"credential id to access git source"`
|
||||
DiscoverBranches bool `json:"discover_branches,omitempty" mapstructure:"discover_branches" description:"Whether to discover a branch"`
|
||||
CloneOption *GitCloneOption `json:"git_clone_option,omitempty" mapstructure:"git_clone_option" description:"advavced git clone options"`
|
||||
RegexFilter string `json:"regex_filter,omitempty" mapstructure:"regex_filter" description:"Regex used to match the name of the branch that needs to be run"`
|
||||
}
|
||||
|
||||
type GithubSource struct {
|
||||
ScmId string `json:"scm_id,omitempty" description:"uid of scm"`
|
||||
Owner string `json:"owner,omitempty" mapstructure:"owner" description:"owner of github repo"`
|
||||
Repo string `json:"repo,omitempty" mapstructure:"repo" description:"repo name of github repo"`
|
||||
CredentialId string `json:"credential_id,omitempty" mapstructure:"credential_id" description:"credential id to access github source"`
|
||||
ApiUri string `json:"api_uri,omitempty" mapstructure:"api_uri" description:"The api url can specify the location of the github apiserver.For private cloud configuration"`
|
||||
DiscoverBranches int `json:"discover_branches,omitempty" mapstructure:"discover_branches" description:"Discover branch configuration"`
|
||||
DiscoverPRFromOrigin int `json:"discover_pr_from_origin,omitempty" mapstructure:"discover_pr_from_origin" description:"Discover origin PR configuration"`
|
||||
DiscoverPRFromForks *DiscoverPRFromForks `json:"discover_pr_from_forks,omitempty" mapstructure:"discover_pr_from_forks" description:"Discover fork PR configuration"`
|
||||
CloneOption *GitCloneOption `json:"git_clone_option,omitempty" mapstructure:"git_clone_option" description:"advavced git clone options"`
|
||||
RegexFilter string `json:"regex_filter,omitempty" mapstructure:"regex_filter" description:"Regex used to match the name of the branch that needs to be run"`
|
||||
}
|
||||
|
||||
type MultiBranchJobTrigger struct {
|
||||
CreateActionJobsToTrigger string `json:"create_action_job_to_trigger,omitempty" description:"pipeline name to trigger"`
|
||||
DeleteActionJobsToTrigger string `json:"delete_action_job_to_trigger,omitempty" description:"pipeline name to trigger"`
|
||||
}
|
||||
|
||||
type BitbucketServerSource struct {
|
||||
ScmId string `json:"scm_id,omitempty" description:"uid of scm"`
|
||||
Owner string `json:"owner,omitempty" mapstructure:"owner" description:"owner of github repo"`
|
||||
Repo string `json:"repo,omitempty" mapstructure:"repo" description:"repo name of github repo"`
|
||||
CredentialId string `json:"credential_id,omitempty" mapstructure:"credential_id" description:"credential id to access github source"`
|
||||
ApiUri string `json:"api_uri,omitempty" mapstructure:"api_uri" description:"The api url can specify the location of the github apiserver.For private cloud configuration"`
|
||||
DiscoverBranches int `json:"discover_branches,omitempty" mapstructure:"discover_branches" description:"Discover branch configuration"`
|
||||
DiscoverPRFromOrigin int `json:"discover_pr_from_origin,omitempty" mapstructure:"discover_pr_from_origin" description:"Discover origin PR configuration"`
|
||||
DiscoverPRFromForks *DiscoverPRFromForks `json:"discover_pr_from_forks,omitempty" mapstructure:"discover_pr_from_forks" description:"Discover fork PR configuration"`
|
||||
CloneOption *GitCloneOption `json:"git_clone_option,omitempty" mapstructure:"git_clone_option" description:"advavced git clone options"`
|
||||
RegexFilter string `json:"regex_filter,omitempty" mapstructure:"regex_filter" description:"Regex used to match the name of the branch that needs to be run"`
|
||||
}
|
||||
|
||||
type GitCloneOption struct {
|
||||
Shallow bool `json:"shallow,omitempty" mapstructure:"shallow" description:"Whether to use git shallow clone"`
|
||||
Timeout int `json:"timeout,omitempty" mapstructure:"timeout" description:"git clone timeout mins"`
|
||||
Depth int `json:"depth,omitempty" mapstructure:"depth" description:"git clone depth"`
|
||||
}
|
||||
|
||||
type SvnSource struct {
|
||||
ScmId string `json:"scm_id,omitempty" description:"uid of scm"`
|
||||
Remote string `json:"remote,omitempty" description:"remote address url"`
|
||||
CredentialId string `json:"credential_id,omitempty" mapstructure:"credential_id" description:"credential id to access svn source"`
|
||||
Includes string `json:"includes,omitempty" description:"branches to run pipeline"`
|
||||
Excludes string `json:"excludes,omitempty" description:"branches do not run pipeline"`
|
||||
}
|
||||
type SingleSvnSource struct {
|
||||
ScmId string `json:"scm_id,omitempty" description:"uid of scm"`
|
||||
Remote string `json:"remote,omitempty" description:"remote address url"`
|
||||
CredentialId string `json:"credential_id,omitempty" mapstructure:"credential_id" description:"credential id to access svn source"`
|
||||
}
|
||||
|
||||
type DiscoverPRFromForks struct {
|
||||
Strategy int `json:"strategy,omitempty" mapstructure:"strategy" description:"github discover strategy"`
|
||||
Trust int `json:"trust,omitempty" mapstructure:"trust" description:"trust user type"`
|
||||
}
|
||||
|
||||
type DiscarderProperty struct {
|
||||
DaysToKeep string `json:"days_to_keep,omitempty" mapstructure:"days_to_keep" description:"days to keep pipeline"`
|
||||
NumToKeep string `json:"num_to_keep,omitempty" mapstructure:"num_to_keep" description:"nums to keep pipeline"`
|
||||
}
|
||||
|
||||
type Parameter struct {
|
||||
Name string `json:"name" description:"name of param"`
|
||||
DefaultValue string `json:"default_value,omitempty" mapstructure:"default_value" description:"default value of param"`
|
||||
Type string `json:"type" description:"type of param"`
|
||||
Description string `json:"description,omitempty" description:"description of pipeline"`
|
||||
}
|
||||
|
||||
type TimerTrigger struct {
|
||||
// user in no scm job
|
||||
Cron string `json:"cron,omitempty" description:"jenkins cron script"`
|
||||
|
||||
// use in multi-branch job
|
||||
Interval string `json:"interval,omitempty" description:"interval ms"`
|
||||
}
|
||||
|
||||
type RemoteTrigger struct {
|
||||
Token string `json:"token,omitempty" description:"remote trigger token"`
|
||||
}
|
||||
|
||||
type ProjectPipelineOperator interface {
|
||||
CreateProjectPipeline(projectId string, pipeline *ProjectPipeline) (string, error)
|
||||
DeleteProjectPipeline(projectId string, pipelineId string) (string, error)
|
||||
UpdateProjectPipeline(projectId string, pipeline *ProjectPipeline) (string, error)
|
||||
GetProjectPipelineConfig(projectId, pipelineId string) (*ProjectPipeline, error)
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"errors"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/cache"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/devops"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/devops/jenkins"
|
||||
esclient "kubesphere.io/kubesphere/pkg/simple/client/elasticsearch"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/kubesphere"
|
||||
@@ -22,7 +23,7 @@ type ClientSetOptions struct {
|
||||
mySQLOptions *mysql.Options
|
||||
redisOptions *cache.Options
|
||||
kubernetesOptions *k8s.KubernetesOptions
|
||||
devopsOptions *devops.Options
|
||||
devopsOptions *jenkins.Options
|
||||
sonarqubeOptions *sonarqube.Options
|
||||
ldapOptions *ldap.Options
|
||||
s3Options *s3.Options
|
||||
@@ -38,7 +39,7 @@ func NewClientSetOptions() *ClientSetOptions {
|
||||
redisOptions: cache.NewRedisOptions(),
|
||||
kubernetesOptions: k8s.NewKubernetesOptions(),
|
||||
ldapOptions: ldap.NewLdapOptions(),
|
||||
devopsOptions: devops.NewDevopsOptions(),
|
||||
devopsOptions: jenkins.NewDevopsOptions(),
|
||||
sonarqubeOptions: sonarqube.NewSonarQubeOptions(),
|
||||
s3Options: s3.NewS3Options(),
|
||||
openPitrixOptions: openpitrix.NewOpenPitrixOptions(),
|
||||
@@ -63,7 +64,7 @@ func (c *ClientSetOptions) SetKubernetesOptions(options *k8s.KubernetesOptions)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *ClientSetOptions) SetDevopsOptions(options *devops.Options) *ClientSetOptions {
|
||||
func (c *ClientSetOptions) SetDevopsOptions(options *jenkins.Options) *ClientSetOptions {
|
||||
c.devopsOptions = options
|
||||
return c
|
||||
}
|
||||
@@ -114,7 +115,7 @@ type ClientSet struct {
|
||||
|
||||
k8sClient k8s.Client
|
||||
ldapClient *ldap.Client
|
||||
devopsClient *devops.Client
|
||||
devopsClient *jenkins.Client
|
||||
sonarQubeClient *sonarqube.Client
|
||||
redisClient cache.Interface
|
||||
s3Client s3.Interface
|
||||
@@ -194,27 +195,28 @@ func (cs *ClientSet) Cache() (cache.Interface, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func (cs *ClientSet) Devops() (*devops.Client, error) {
|
||||
var err error
|
||||
|
||||
if cs.csoptions.devopsOptions == nil || cs.csoptions.devopsOptions.Host == "" {
|
||||
return nil, ErrClientSetNotEnabled
|
||||
}
|
||||
|
||||
if cs.devopsClient != nil {
|
||||
return cs.devopsClient, nil
|
||||
} else {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
|
||||
if cs.devopsClient == nil {
|
||||
cs.devopsClient, err = devops.NewDevopsClient(cs.csoptions.devopsOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return cs.devopsClient, nil
|
||||
}
|
||||
func (cs *ClientSet) Devops() (devops.Interface, error) {
|
||||
//var err error
|
||||
//
|
||||
//if cs.csoptions.devopsOptions == nil || cs.csoptions.devopsOptions.Host == "" {
|
||||
// return nil, ErrClientSetNotEnabled
|
||||
//}
|
||||
//
|
||||
//if cs.devopsClient != nil {
|
||||
// return cs.devopsClient, nil
|
||||
//} else {
|
||||
// mutex.Lock()
|
||||
// defer mutex.Unlock()
|
||||
//
|
||||
// if cs.devopsClient == nil {
|
||||
// cs.devopsClient, err = jenkins.NewDevopsClient(cs.csoptions.devopsOptions)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// }
|
||||
// return cs.devopsClient, nil
|
||||
//}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (cs *ClientSet) SonarQube() (*sonarqube.Client, error) {
|
||||
|
||||
@@ -1,39 +1,32 @@
|
||||
package monitoring
|
||||
|
||||
|
||||
type ClusterQuery struct {
|
||||
|
||||
}
|
||||
|
||||
type ClusterMetrics struct {
|
||||
|
||||
}
|
||||
|
||||
type WorkspaceQuery struct {
|
||||
|
||||
}
|
||||
|
||||
type WorkspaceMetrics struct {
|
||||
|
||||
}
|
||||
|
||||
type NamespaceQuery struct {
|
||||
|
||||
}
|
||||
|
||||
type NamespaceMetrics struct {
|
||||
|
||||
}
|
||||
|
||||
// Interface defines all the abstract behaviors of monitoring
|
||||
type Interface interface {
|
||||
|
||||
// Get
|
||||
GetClusterMetrics(query ClusterQuery) ClusterMetrics
|
||||
// Get
|
||||
GetClusterMetrics(query ClusterQuery) ClusterMetrics
|
||||
|
||||
//
|
||||
GetWorkspaceMetrics(query WorkspaceQuery) WorkspaceMetrics
|
||||
//
|
||||
GetWorkspaceMetrics(query WorkspaceQuery) WorkspaceMetrics
|
||||
|
||||
//
|
||||
GetNamespaceMetrics(query NamespaceQuery) NamespaceMetrics
|
||||
//
|
||||
GetNamespaceMetrics(query NamespaceQuery) NamespaceMetrics
|
||||
}
|
||||
|
||||
@@ -1,31 +1,31 @@
|
||||
package monitoring
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
// prometheus implements monitoring interface backed by Prometheus
|
||||
type prometheus struct {
|
||||
options *Options
|
||||
client *http.Client
|
||||
options *Options
|
||||
client *http.Client
|
||||
}
|
||||
|
||||
func NewPrometheus(options *Options) Interface {
|
||||
return &prometheus{
|
||||
options:options,
|
||||
client: &http.Client{ Timeout: 10 * time.Second },
|
||||
}
|
||||
return &prometheus{
|
||||
options: options,
|
||||
client: &http.Client{Timeout: 10 * time.Second},
|
||||
}
|
||||
}
|
||||
|
||||
func (p prometheus) GetClusterMetrics(query ClusterQuery) ClusterMetrics {
|
||||
panic("implement me")
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (p prometheus) GetWorkspaceMetrics(query WorkspaceQuery) WorkspaceMetrics {
|
||||
panic("implement me")
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (p prometheus) GetNamespaceMetrics(query NamespaceQuery) NamespaceMetrics {
|
||||
panic("implement me")
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
@@ -1,41 +1,41 @@
|
||||
package monitoring
|
||||
|
||||
import (
|
||||
"github.com/spf13/pflag"
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
Endpoint string `json:"endpoint,omitempty" yaml:"endpoint"`
|
||||
SecondaryEndpoint string `json:"secondaryEndpoint,omitempty" yaml:"secondaryEndpoint"`
|
||||
Endpoint string `json:"endpoint,omitempty" yaml:"endpoint"`
|
||||
SecondaryEndpoint string `json:"secondaryEndpoint,omitempty" yaml:"secondaryEndpoint"`
|
||||
}
|
||||
|
||||
func NewPrometheusOptions() *Options {
|
||||
return &Options{
|
||||
Endpoint: "",
|
||||
SecondaryEndpoint: "",
|
||||
}
|
||||
return &Options{
|
||||
Endpoint: "",
|
||||
SecondaryEndpoint: "",
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Options) Validate() []error {
|
||||
var errs []error
|
||||
return errs
|
||||
var errs []error
|
||||
return errs
|
||||
}
|
||||
|
||||
func (s *Options) ApplyTo(options *Options) {
|
||||
if s.Endpoint != "" {
|
||||
options.Endpoint = s.Endpoint
|
||||
}
|
||||
if s.Endpoint != "" {
|
||||
options.Endpoint = s.Endpoint
|
||||
}
|
||||
|
||||
if s.SecondaryEndpoint != "" {
|
||||
options.SecondaryEndpoint = s.SecondaryEndpoint
|
||||
}
|
||||
if s.SecondaryEndpoint != "" {
|
||||
options.SecondaryEndpoint = s.SecondaryEndpoint
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Options) AddFlags(fs *pflag.FlagSet, c *Options) {
|
||||
fs.StringVar(&s.Endpoint, "prometheus-endpoint", c.Endpoint, ""+
|
||||
"Prometheus service endpoint which stores KubeSphere monitoring data, if left "+
|
||||
"blank, will use builtin metrics-server as data source.")
|
||||
fs.StringVar(&s.Endpoint, "prometheus-endpoint", c.Endpoint, ""+
|
||||
"Prometheus service endpoint which stores KubeSphere monitoring data, if left "+
|
||||
"blank, will use builtin metrics-server as data source.")
|
||||
|
||||
fs.StringVar(&s.SecondaryEndpoint, "prometheus-secondary-endpoint", c.SecondaryEndpoint, ""+
|
||||
"Prometheus secondary service endpoint, if left empty and endpoint is set, will use endpoint instead.")
|
||||
fs.StringVar(&s.SecondaryEndpoint, "prometheus-secondary-endpoint", c.SecondaryEndpoint, ""+
|
||||
"Prometheus secondary service endpoint, if left empty and endpoint is set, will use endpoint instead.")
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
|
||||
type Client struct {
|
||||
client *http.Client
|
||||
endpoint string
|
||||
|
||||
43
pkg/simple/client/s3/fake/fakes3.go
Normal file
43
pkg/simple/client/s3/fake/fakes3.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package fake
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
"io"
|
||||
)
|
||||
|
||||
type FakeS3 struct {
|
||||
Storage map[string]*object
|
||||
}
|
||||
|
||||
func NewFakeS3() *FakeS3 {
|
||||
return &FakeS3{Storage: map[string]*object{}}
|
||||
}
|
||||
|
||||
type object struct {
|
||||
key string
|
||||
fileName string
|
||||
body io.Reader
|
||||
}
|
||||
|
||||
func (s *FakeS3) Upload(key, fileName string, body io.Reader) error {
|
||||
s.Storage[key] = &object{
|
||||
key: key,
|
||||
fileName: fileName,
|
||||
body: body,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *FakeS3) GetDownloadURL(key string, fileName string) (string, error) {
|
||||
if o, ok := s.Storage[key]; ok {
|
||||
return fmt.Sprintf("http://%s/%s", o.key, fileName), nil
|
||||
}
|
||||
return "", awserr.New(s3.ErrCodeNoSuchKey, "no such object", nil)
|
||||
}
|
||||
|
||||
func (s *FakeS3) Delete(key string) error {
|
||||
delete(s.Storage, key)
|
||||
return nil
|
||||
}
|
||||
52
pkg/simple/client/s3/fake/fakes3_test.go
Normal file
52
pkg/simple/client/s3/fake/fakes3_test.go
Normal file
@@ -0,0 +1,52 @@
|
||||
package fake
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestFakeS3(t *testing.T) {
|
||||
s3 := NewFakeS3()
|
||||
key := "hello"
|
||||
fileName := "world"
|
||||
err := s3.Upload(key, fileName, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
o, ok := s3.storage["hello"]
|
||||
if !ok {
|
||||
t.Fatal("should have hello object")
|
||||
}
|
||||
if o.key != key || o.fileName != fileName {
|
||||
t.Fatalf("key should be %s, fileName should be %s", key, fileName)
|
||||
}
|
||||
|
||||
url, err := s3.GetDownloadURL(key, fileName+"1")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if url != fmt.Sprintf("http://%s/%s", key, fileName+"1") {
|
||||
t.Fatalf("url should be %s", fmt.Sprintf("http://%s/%s", key, fileName+"1"))
|
||||
}
|
||||
|
||||
url, err = s3.GetDownloadURL(key, fileName+"2")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if url != fmt.Sprintf("http://%s/%s", key, fileName+"2") {
|
||||
t.Fatalf("url should be %s", fmt.Sprintf("http://%s/%s", key, fileName+"2"))
|
||||
}
|
||||
|
||||
err = s3.Delete(key)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, ok = s3.storage["hello"]
|
||||
if ok {
|
||||
t.Fatal("should not have hello object")
|
||||
}
|
||||
err = s3.Delete(key)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -2,15 +2,13 @@ package s3
|
||||
|
||||
import (
|
||||
"io"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Interface interface {
|
||||
// Upload uploads a object to storage and returns object location if succeeded
|
||||
Upload(key string, body io.Reader) (string, error)
|
||||
Upload(key, fileName string, body io.Reader) error
|
||||
|
||||
// Get retrieves and object's downloadable location if succeeded
|
||||
Get(key string, fileName string, expire time.Duration) (string, error)
|
||||
GetDownloadURL(key string, fileName string) (string, error)
|
||||
|
||||
// Delete deletes an object by its key
|
||||
Delete(key string) error
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
package s3
|
||||
|
||||
import (
|
||||
"code.cloudfoundry.org/bytefmt"
|
||||
"fmt"
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
"github.com/aws/aws-sdk-go/service/s3/s3manager"
|
||||
"io"
|
||||
"k8s.io/klog"
|
||||
"time"
|
||||
@@ -16,16 +19,38 @@ type Client struct {
|
||||
bucket string
|
||||
}
|
||||
|
||||
func (s *Client) Upload(key string, body io.Reader) (string, error) {
|
||||
panic("implement me")
|
||||
func (s *Client) Upload(key, fileName string, body io.Reader) error {
|
||||
uploader := s3manager.NewUploader(s.s3Session, func(uploader *s3manager.Uploader) {
|
||||
uploader.PartSize = 5 * bytefmt.MEGABYTE
|
||||
uploader.LeavePartsOnError = true
|
||||
})
|
||||
_, err := uploader.Upload(&s3manager.UploadInput{
|
||||
Bucket: aws.String(s.bucket),
|
||||
Key: aws.String(key),
|
||||
Body: body,
|
||||
ContentDisposition: aws.String(fmt.Sprintf("attachment; filename=\"%s\"", fileName)),
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *Client) Get(key string, fileName string, expire time.Duration) (string, error) {
|
||||
panic("implement me")
|
||||
func (s *Client) GetDownloadURL(key string, fileName string) (string, error) {
|
||||
req, _ := s.s3Client.GetObjectRequest(&s3.GetObjectInput{
|
||||
Bucket: aws.String(s.bucket),
|
||||
Key: aws.String(key),
|
||||
ResponseContentDisposition: aws.String(fmt.Sprintf("attachment; filename=\"%s\"", fileName)),
|
||||
})
|
||||
return req.Presign(5 * time.Minute)
|
||||
}
|
||||
|
||||
func (s *Client) Delete(key string) error {
|
||||
panic("implement me")
|
||||
_, err := s.s3Client.DeleteObject(
|
||||
&s3.DeleteObjectInput{Bucket: aws.String(s.bucket),
|
||||
Key: aws.String(key),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewS3Client(options *Options) (Interface, error) {
|
||||
@@ -55,7 +80,6 @@ func NewS3Client(options *Options) (Interface, error) {
|
||||
}
|
||||
|
||||
func (s *Client) Client() *s3.S3 {
|
||||
|
||||
return s.s3Client
|
||||
}
|
||||
func (s *Client) Session() *session.Session {
|
||||
|
||||
@@ -1,8 +1,68 @@
|
||||
package sonarqube
|
||||
|
||||
type Interface interface {
|
||||
//
|
||||
GetIssues()
|
||||
import (
|
||||
sonargo "github.com/kubesphere/sonargo/sonar"
|
||||
"k8s.io/klog"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/devops"
|
||||
)
|
||||
|
||||
//
|
||||
type SonarInterface interface {
|
||||
GetSonarResultsByTaskIds(taskId ...string) ([]*SonarStatus, error)
|
||||
}
|
||||
|
||||
type sonarQube struct {
|
||||
client *sonargo.Client
|
||||
}
|
||||
|
||||
const (
|
||||
SonarAnalysisActionClass = "hudson.plugins.sonar.action.SonarAnalysisAction"
|
||||
SonarMetricKeys = "alert_status,quality_gate_details,bugs,new_bugs,reliability_rating,new_reliability_rating,vulnerabilities,new_vulnerabilities,security_rating,new_security_rating,code_smells,new_code_smells,sqale_rating,new_maintainability_rating,sqale_index,new_technical_debt,coverage,new_coverage,new_lines_to_cover,tests,duplicated_lines_density,new_duplicated_lines_density,duplicated_blocks,ncloc,ncloc_language_distribution,projects,new_lines"
|
||||
SonarAdditionalFields = "metrics,periods"
|
||||
)
|
||||
|
||||
type SonarStatus struct {
|
||||
Measures *sonargo.MeasuresComponentObject `json:"measures,omitempty"`
|
||||
Issues *sonargo.IssuesSearchObject `json:"issues,omitempty"`
|
||||
GeneralAction *devops.GeneralAction `json:"generalAction,omitempty"`
|
||||
Task *sonargo.CeTaskObject `json:"task,omitempty"`
|
||||
}
|
||||
|
||||
func (s *sonarQube) GetSonarResultsByTaskIds(taskIds ...string) ([]*SonarStatus, error) {
|
||||
sonarStatuses := make([]*SonarStatus, 0)
|
||||
for _, taskId := range taskIds {
|
||||
sonarStatus := &SonarStatus{}
|
||||
taskOptions := &sonargo.CeTaskOption{
|
||||
Id: taskId,
|
||||
}
|
||||
ceTask, _, err := s.client.Ce.Task(taskOptions)
|
||||
if err != nil {
|
||||
klog.Errorf("get sonar task error [%+v]", err)
|
||||
continue
|
||||
}
|
||||
sonarStatus.Task = ceTask
|
||||
measuresComponentOption := &sonargo.MeasuresComponentOption{
|
||||
Component: ceTask.Task.ComponentKey,
|
||||
AdditionalFields: SonarAdditionalFields,
|
||||
MetricKeys: SonarMetricKeys,
|
||||
}
|
||||
measures, _, err := s.client.Measures.Component(measuresComponentOption)
|
||||
if err != nil {
|
||||
klog.Errorf("get sonar task error [%+v]", err)
|
||||
continue
|
||||
}
|
||||
sonarStatus.Measures = measures
|
||||
|
||||
issuesSearchOption := &sonargo.IssuesSearchOption{
|
||||
AdditionalFields: "_all",
|
||||
ComponentKeys: ceTask.Task.ComponentKey,
|
||||
Resolved: "false",
|
||||
Ps: "10",
|
||||
S: "FILE_LINE",
|
||||
Facets: "severities,types",
|
||||
}
|
||||
issuesSearch, _, err := s.client.Issues.Search(issuesSearchOption)
|
||||
sonarStatus.Issues = issuesSearch
|
||||
sonarStatuses = append(sonarStatuses, sonarStatus)
|
||||
}
|
||||
return sonarStatuses, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user