Skip to content

Commit

Permalink
Bugfix 971 add check job name api (#958)
Browse files Browse the repository at this point in the history
* add check pipeline is exist interface

* add check devops name if exist interface
  • Loading branch information
drzhangg authored Jun 9, 2023
1 parent c7f1667 commit db5561b
Show file tree
Hide file tree
Showing 12 changed files with 202 additions and 0 deletions.
4 changes: 4 additions & 0 deletions pkg/client/devops/fake/fakedevops.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,10 @@ func (d *Devops) GetPipeline(projectName, pipelineName string, httpParameters *d
return nil, nil
}

func (d *Devops) CheckPipelineName(projectName string, httpParameters *devops.HttpParameters) (map[string]interface{}, error) {
return nil, nil
}

func (d *Devops) ListPipelines(httpParameters *devops.HttpParameters) (*devops.PipelineList, error) {
return nil, nil
}
Expand Down
4 changes: 4 additions & 0 deletions pkg/client/devops/jclient/pipeline.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,3 +225,7 @@ func (j *JenkinsClient) CheckScriptCompile(projectName, pipelineName string, htt
func (j *JenkinsClient) CheckCron(projectName string, httpParameters *devops.HttpParameters) (*devops.CheckCronRes, error) {
return j.jenkins.CheckCron(projectName, httpParameters)
}

func (j *JenkinsClient) CheckPipelineName(projectName string, httpParameters *devops.HttpParameters) (map[string]interface{}, error) {
return j.jenkins.CheckPipelineName(projectName, httpParameters)
}
10 changes: 10 additions & 0 deletions pkg/client/devops/jenkins/jenkins.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,16 @@ func (j *Jenkins) Poll() (int, error) {
return resp.StatusCode, nil
}

func (j *Jenkins) CheckPipelineName(projectName string, httpParameters *devops.HttpParameters) (map[string]interface{}, error) {
PipelineOjb := &Pipeline{
HttpParameters: httpParameters,
Jenkins: j,
Path: fmt.Sprintf(CheckPipelineName+httpParameters.Url.RawQuery, projectName),
}
res, err := PipelineOjb.CheckPipelineName()
return res, err
}

func (j *Jenkins) GetPipeline(projectName, pipelineName string, httpParameters *devops.HttpParameters) (*devops.Pipeline, error) {
PipelineOjb := &Pipeline{
HttpParameters: httpParameters,
Expand Down
29 changes: 29 additions & 0 deletions pkg/client/devops/jenkins/pipeline.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"fmt"
"net/http"
"net/url"
"regexp"
"strconv"
"strings"
"time"
Expand Down Expand Up @@ -84,8 +85,36 @@ const (
CheckCronUrl = "/job/%s/descriptorByName/hudson.triggers.TimerTrigger/checkSpec?%s"

cronJobLayout = "Monday, January 2, 2006 15:04:05 PM"

CheckPipelineName = "/job/%s/checkJobName?"
)

func (p *Pipeline) CheckPipelineName() (map[string]interface{}, error) {
res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters)
if err != nil {
return nil, err
}

/*
if the name exist , the res will be
<div class=error><img src='/static/7abb227e/images/none.gif' height=16 width=1>A job already exists with the name ‘devopsd6b97’</div>
*/
pattern := `>[^<]+<`

reg := regexp.MustCompile(pattern)

result := make(map[string]interface{})

match := reg.FindString(string(res))
if match != "" {
result["exist"] = true
} else {
result["exist"] = false
}

return result, nil
}

func (p *Pipeline) GetPipeline() (*devops.Pipeline, error) {
res, err := p.Jenkins.SendPureRequest(p.Path, p.HttpParameters)
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions pkg/client/devops/pipeline.go
Original file line number Diff line number Diff line change
Expand Up @@ -1127,6 +1127,7 @@ type HttpParameters struct {

type PipelineOperator interface {
// Pipelinne operator interface
CheckPipelineName(projectName string, httpParameters *HttpParameters) (map[string]interface{}, error)
GetPipeline(projectName, pipelineName string, httpParameters *HttpParameters) (*Pipeline, error)
ListPipelines(httpParameters *HttpParameters) (*PipelineList, error)
GetPipelineRun(projectName, pipelineName, runId string, httpParameters *HttpParameters) (*PipelineRun, error)
Expand Down
12 changes: 12 additions & 0 deletions pkg/kapis/devops/v1alpha2/devops.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,18 @@ import (

const jenkinsHeaderPre = "X-"

func (h *ProjectPipelineHandler) CheckPipelineName(req *restful.Request, resp *restful.Response) {
jobName := req.PathParameter("devops")
res, err := h.devopsOperator.CheckPipelineName(jobName, req.Request)
if err != nil {
parseErr(err, resp)
return
}

resp.Header().Set(restful.HEADER_ContentType, restful.MIME_JSON)
resp.WriteAsJson(res)
}

func (h *ProjectPipelineHandler) GetPipeline(req *restful.Request, resp *restful.Response) {
projectName := req.PathParameter("devops")
pipelineName := req.PathParameter("pipeline")
Expand Down
7 changes: 7 additions & 0 deletions pkg/kapis/devops/v1alpha2/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,13 @@ func AddPipelineToWebService(webservice *restful.WebService, devopsClient devops
if projectPipelineEnable {
projectPipelineHandler := NewProjectPipelineHandler(devopsClient, k8sClient)

// match Jenkins api "/job/{devops}/checkJobName?value="
webservice.Route(webservice.GET("/devops/{devops}/checkPipelineName").
To(projectPipelineHandler.CheckPipelineName).
Doc("check the job name does it exist").
Param(webservice.PathParameter("value", "the name of the new job")).
Returns(http.StatusOK, api.StatusOK, nil))

webservice.Route(webservice.GET("/devops/{devops}/credentials/{credential}/usage").
To(projectPipelineHandler.GetProjectCredentialUsage).
Doc("Get the specified credential usage of the DevOps project").
Expand Down
6 changes: 6 additions & 0 deletions pkg/kapis/devops/v1alpha2/register_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,12 @@ func TestAPIsExist(t *testing.T) {
method: http.MethodGet,
uri: "/devops/fake/pipelines/fake",
},
}, {
name: "check pipeline name if exist",
args: args{
method: http.MethodGet,
uri: "/devops/fake/checkPipelineName?value=fake1",
},
}, {
name: "search API",
args: args{
Expand Down
24 changes: 24 additions & 0 deletions pkg/kapis/devops/v1alpha3/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package v1alpha3

import (
"fmt"
"github.com/emicklei/go-restful"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
Expand Down Expand Up @@ -393,3 +394,26 @@ func (h *devopsHandler) getDevOps(request *restful.Request) (operator devops.Dev
}
return
}

func (h *devopsHandler) CheckDevopsName(request *restful.Request, response *restful.Response) {
workspace := request.PathParameter("workspace")
devopsName := request.QueryParameter("devopsName")
generateNameFlag := request.QueryParameter("generateName")

var result map[string]interface{}
if client, err := h.getDevOps(request); err == nil {

switch generateNameFlag {
case "true":
result, err = client.CheckDevopsProject(workspace, devopsName)
if err != nil {
errorHandle(request, response, result, err)
}
errorHandle(request, response, result, nil)
default:
errorHandle(request, response, nil, fmt.Errorf("generateNameFlag can not be false"))
}
} else {
kapis.HandleBadRequest(response, request, err)
}
}
6 changes: 6 additions & 0 deletions pkg/kapis/devops/v1alpha3/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,12 @@ func registerRoutersForWorkspace(handler *devopsHandler, ws *restful.WebService)
Doc("Get the devopsproject of the specified workspace for the current user").
Returns(http.StatusOK, api.StatusOK, v1alpha3.DevOpsProject{}).
Metadata(restfulspec.KeyOpenAPITags, []string{constants.DevOpsProjectTag}))

// /workspaces/{workspace}/devops/checkDevopsName?devopsName=xxx&generateName=true
ws.Route(ws.GET("/workspaces/{workspace}/devops/checkDevopsName").
To(handler.CheckDevopsName).
Doc("check the devops project name does it exist").
Returns(http.StatusOK, api.StatusOK, nil))
}

func registerRoutersForCI(handler *devopsHandler, ws *restful.WebService) {
Expand Down
30 changes: 30 additions & 0 deletions pkg/models/devops/devops.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ type DevopsOperator interface {
DeleteDevOpsProject(workspace string, projectName string) error
UpdateDevOpsProject(workspace string, project *v1alpha3.DevOpsProject) (*v1alpha3.DevOpsProject, error)
ListDevOpsProject(workspace string, limit, offset int) (api.ListResult, error)
CheckDevopsProject(workspace, projectName string) (map[string]interface{}, error)

CreatePipelineObj(projectName string, pipeline *v1alpha3.Pipeline) (*v1alpha3.Pipeline, error)
GetPipelineObj(projectName string, pipelineName string) (*v1alpha3.Pipeline, error)
Expand All @@ -73,6 +74,7 @@ type DevopsOperator interface {
UpdateCredentialObj(projectName string, secret *v1.Secret) (*v1.Secret, error)
ListCredentialObj(projectName string, query *query.Query) (api.ListResult, error)

CheckPipelineName(projectName string, req *http.Request) (map[string]interface{}, error)
GetPipeline(projectName, pipelineName string, req *http.Request) (*devops.Pipeline, error)
ListPipelines(req *http.Request) (*devops.PipelineList, error)
GetPipelineRun(projectName, pipelineName, runId string, req *http.Request) (*devops.PipelineRun, error)
Expand Down Expand Up @@ -191,6 +193,30 @@ func (d devopsOperator) CreateDevOpsProject(workspace string, project *v1alpha3.
return d.ksclient.DevopsV1alpha3().DevOpsProjects().Create(d.context, project, metav1.CreateOptions{})
}

// CheckDevopsProject check the devops is not exist
func (d devopsOperator) CheckDevopsProject(workspace, projectName string) (map[string]interface{}, error) {
var list *v1alpha3.DevOpsProjectList
var err error

result := make(map[string]interface{})
result["exist"] = false

if list, err = d.ksclient.DevopsV1alpha3().DevOpsProjects().List(d.context, metav1.ListOptions{
LabelSelector: fmt.Sprintf("%s=%s", constants.WorkspaceLabelKey, workspace),
}); err == nil {
for i := range list.Items {
item := list.Items[i]
if item.GenerateName == projectName {
result["exist"] = true
break
}
}
return result, nil
} else {
return result, err
}
}

// GetDevOpsProjectByGenerateName finds the DevOps project by workspace and project name
// the projectName is the generateName instead of the real resource name
func (d devopsOperator) GetDevOpsProjectByGenerateName(workspace string, projectName string) (project *v1alpha3.DevOpsProject, err error) {
Expand Down Expand Up @@ -443,6 +469,10 @@ func (d devopsOperator) ListCredentialObj(projectName string, query *query.Query
return *resourcesV1alpha3.DefaultList(result, query, resourcesV1alpha3.DefaultCompare(), resourcesV1alpha3.DefaultFilter()), nil
}

func (d devopsOperator) CheckPipelineName(projectName string, req *http.Request) (map[string]interface{}, error) {
return d.devopsClient.CheckPipelineName(projectName, convertToHttpParameters(req))
}

// others
func (d devopsOperator) GetPipeline(projectName, pipelineName string, req *http.Request) (*devops.Pipeline, error) {
return d.devopsClient.GetPipeline(projectName, pipelineName, convertToHttpParameters(req))
Expand Down
69 changes: 69 additions & 0 deletions pkg/models/devops/devops_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -604,3 +604,72 @@ func Test_devopsOperator_GetJenkinsAgentLabels(t *testing.T) {
})
}
}

func Test_devopsOperator_CheckDevopsName(t *testing.T) {
type fields struct {
ksclient versioned.Interface
}
type args struct {
workspace string
projectName string
}
tests := []struct {
name string
fields fields
args args
verify func(result map[string]interface{}, resultErr error, t *testing.T)
}{{
name: "normal case",
fields: fields{
ksclient: fakeclientset.NewSimpleClientset(&v1alpha3.DevOpsProject{
ObjectMeta: metav1.ObjectMeta{
GenerateName: "fake",
Name: "generated-name",
Labels: map[string]string{
constants.WorkspaceLabelKey: "ws",
},
},
}),
},
args: args{
workspace: "ws",
projectName: "fake",
},
verify: func(result map[string]interface{}, resultErr error, t *testing.T) {
assert.Nil(t, resultErr)
assert.NotNil(t, result)
assert.Equal(t, true, result["exist"])
},
}, {
name: "cannot find by the same generateName in the different workspaces",
fields: fields{
ksclient: fakeclientset.NewSimpleClientset(&v1alpha3.DevOpsProject{
ObjectMeta: metav1.ObjectMeta{
GenerateName: "fake",
Name: "generated-name",
Labels: map[string]string{
constants.WorkspaceLabelKey: "ws",
},
},
}),
},
args: args{
workspace: "ws",
projectName: "fake1",
},
verify: func(result map[string]interface{}, resultErr error, t *testing.T) {
assert.Nil(t, resultErr)
assert.NotNil(t, result)
assert.Equal(t, false, result["exist"])
},
}}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
d := devopsOperator{
ksclient: tt.fields.ksclient,
}
got, err := d.CheckDevopsProject(tt.args.workspace, tt.args.projectName)
tt.verify(got, err, t)
})
}
}

0 comments on commit db5561b

Please sign in to comment.