Skip to content

Commit

Permalink
Add Pipeline obtain API (#27)
Browse files Browse the repository at this point in the history
* Add Pipeline obtain API

Provide Pipeline obtain API

Add comment on GetPipeline method

Signed-off-by: John Niang <[email protected]>

* Refine Pipeline data structure

Move bluocean types into a separated file
  • Loading branch information
JohnNiang authored Sep 29, 2021
1 parent 7a5d1f2 commit d28f47e
Show file tree
Hide file tree
Showing 3 changed files with 251 additions and 78 deletions.
104 changes: 27 additions & 77 deletions pkg/job/blueocean.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,33 @@ func (c *BlueOceanClient) GetPipelines(folders ...string) (pipelines []Pipeline,
return
}

func (c *BlueOceanClient) getPipelineAPI(folders ...string) (api string) {
api = fmt.Sprintf("%s/%s/pipelines", organizationAPIPrefix, c.Organization)
for _, folder := range folders {
api = fmt.Sprintf("%s/%s/pipelines/", api, folder)
}
return
}

// GetPipeline obtains Pipeline metadata with Pipeline name and folders.
func (c *BlueOceanClient) GetPipeline(pipelineName string, folders ...string) (*Pipeline, error) {
api := c.getGetPipelineAPI(pipelineName, folders...)
pipeline := &Pipeline{}
if err := c.RequestWithData(http.MethodGet, api, nil, nil, 200, pipeline); err != nil {
return nil, err
}
return pipeline, nil
}

func (c *BlueOceanClient) getGetPipelineAPI(pipelineName string, folders ...string) string {
api := fmt.Sprintf("%s/%s", organizationAPIPrefix, c.Organization)
folders = append(folders, pipelineName)
for _, folder := range folders {
api = fmt.Sprintf("%s/pipelines/%s", api, folder)
}
return api
}

// Search searches jobs via the BlueOcean API
func (c *BlueOceanClient) Search(name string, start, limit int) (items []JenkinsItem, err error) {
api := fmt.Sprintf("%s/?q=pipeline:*%s*;type:pipeline;organization:%s;excludedFromFlattening=jenkins.branch.MultiBranchProject,com.cloudbees.hudson.plugins.folder.AbstractFolder&filter=no-folders&start=%d&limit=%d",
Expand Down Expand Up @@ -99,14 +126,6 @@ func (c *BlueOceanClient) GetBuild(option GetBuildOption) (*PipelineRun, error)
return &pr, nil
}

func (c *BlueOceanClient) getPipelineAPI(folders ...string) (api string) {
api = fmt.Sprintf("%s/%s/pipelines", organizationAPIPrefix, c.Organization)
for _, folder := range folders {
api = fmt.Sprintf("%s/%s/pipelines/", api, folder)
}
return
}

// GetPipelineRuns returns a PipelineRun which in the possible nest folders
func (c *BlueOceanClient) GetPipelineRuns(pipeline string, folders ...string) (runs []PipelineRun, err error) {
api := c.getPipelineAPI(folders...)
Expand Down Expand Up @@ -190,72 +209,3 @@ func getHeaders() map[string]string {
"Content-Type": "application/json",
}
}

// PipelineRun represents a build detail of Pipeline.
// Reference: https://github.com/jenkinsci/blueocean-plugin/blob/a7cbc946b73d89daf9dfd91cd713cc7ab64a2d95/blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/PipelineRunImpl.java
type PipelineRun struct {
ArtifactsZipFile interface{} `json:"artifactsZipFile,omitempty"`
CauseOfBlockage string `json:"causeOfBlockage,omitempty"`
Causes []interface{} `json:"causes,omitempty"`
ChangeSet []interface{} `json:"changeSet,omitempty"`
Description string `json:"description,omitempty"`
DurationInMillis *int64 `json:"durationInMillis,omitempty"`
EnQueueTime Time `json:"enQueueTime,omitempty"`
EndTime Time `json:"endTime,omitempty"`
EstimatedDurationInMillis *int64 `json:"estimatedDurationInMillis,omitempty"`
ID string `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Organization string `json:"organization,omitempty"`
Pipeline string `json:"pipeline,omitempty"`
Replayable bool `json:"replayable,omitempty"`
Result string `json:"result,omitempty"`
RunSummary string `json:"runSummary,omitempty"`
StartTime Time `json:"startTime,omitempty"`
State string `json:"state,omitempty"`
Type string `json:"type,omitempty"`
QueueID string `json:"queueId,omitempty"`
CommitID string `json:"commitId,omitempty"`
CommitURL string `json:"commitUrl,omitempty"`
PullRequest interface{} `json:"pullRequest,omitempty"`
Branch interface{} `json:"branch,omitempty"`
}

// Node represents a node detail of a PipelineRun.
type Node struct {
DisplayDescription string `json:"displayDescription,omitempty"`
DisplayName string `json:"displayName,omitempty"`
DurationInMillis int `json:"durationInMillis,omitempty"`
ID string `json:"id,omitempty"`
Input *Input `json:"input,omitempty"`
Result string `json:"result,omitempty"`
StartTime Time `json:"startTime,omitempty"`
State string `json:"state,omitempty"`
Type string `json:"type,omitempty"`
CauseOfBlockage string `json:"causeOfBlockage,omitempty"`
Edges []Edge `json:"edges,omitempty"`
FirstParent string `json:"firstParent,omitempty"`
Restartable bool `json:"restartable,omitempty"`
}

// Edge represents edge of SimplePipeline flow graph.
type Edge struct {
ID string `json:"id,omitempty"`
Type string `json:"type,omitempty"`
}

// Input contains input step data.
type Input struct {
ID string `json:"id,omitempty"`
Message string `json:"message,omitempty"`
Ok string `json:"ok,omitempty"`
Parameters []ParameterDefinition `json:"parameters,omitempty"`
Submitter string `json:"submitter,omitempty"`
}

// Pipeline represents a Jenkins BlueOcean Pipeline data
type Pipeline struct {
Name string
Disabled bool
DisplayName string
WeatherScore int
}
104 changes: 103 additions & 1 deletion pkg/job/blueocean_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import (
"github.com/golang/mock/gomock"
"github.com/jenkins-zh/jenkins-client/pkg/core"
"github.com/jenkins-zh/jenkins-client/pkg/mock/mhttp"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
Expand Down Expand Up @@ -508,6 +507,59 @@ var _ = Describe("SimplePipeline test via BlueOcean RESTful API", func() {
})
})

Context("GetPipeline", func() {
It("Without folder", func() {
pipelineName := "pipelineA"
request, _ := http.NewRequest(http.MethodGet, c.getGetPipelineAPI(pipelineName), nil)
response := &http.Response{
StatusCode: http.StatusOK,
Body: io.NopCloser(bytes.NewBufferString(`{"name":"pipelineA"}`)),
}
roundTripper.EXPECT().
RoundTrip(core.NewRequestMatcher(request)).
Return(response, nil)

pipeline, err := c.GetPipeline(pipelineName)
Expect(err).To(Succeed())
Expect(pipeline.Name).To(Equal(pipelineName))
})

It("With one folder", func() {
pipelineName := "pipelineA"
folder1 := "folder1"
request, _ := http.NewRequest(http.MethodGet, c.getGetPipelineAPI(pipelineName, folder1), nil)
response := &http.Response{
StatusCode: http.StatusOK,
Body: io.NopCloser(bytes.NewBufferString(`{"name":"pipelineA"}`)),
}
roundTripper.EXPECT().
RoundTrip(core.NewRequestMatcher(request)).
Return(response, nil)

pipeline, err := c.GetPipeline(pipelineName, folder1)
Expect(err).To(Succeed())
Expect(pipeline.Name).To(Equal(pipelineName))
})

It("With two folders", func() {
pipelineName := "pipelineA"
folder1 := "folder1"
folder2 := "folder2"
request, _ := http.NewRequest(http.MethodGet, c.getGetPipelineAPI(pipelineName, folder1, folder2), nil)
response := &http.Response{
StatusCode: http.StatusOK,
Body: io.NopCloser(bytes.NewBufferString(`{"name":"pipelineA"}`)),
}
roundTripper.EXPECT().
RoundTrip(core.NewRequestMatcher(request)).
Return(response, nil)

pipeline, err := c.GetPipeline(pipelineName, folder1, folder2)
Expect(err).To(Succeed())
Expect(pipeline.Name).To(Equal(pipelineName))
})
})

Context("GetPipelineRun", func() {
It("Without two folders, with one pipeline", func() {
name := "test"
Expand Down Expand Up @@ -840,3 +892,53 @@ func TestBlueOceanClient_getReplayAPI(t *testing.T) {
})
}
}

func TestBlueOceanClient_getGetPipelineAPI(t *testing.T) {
type args struct {
pipelineName string
folders []string
}
tests := []struct {
name string
args args
want string
}{{
name: "Without folder",
args: args{
pipelineName: "pipeline1",
},
want: "/blue/rest/organizations/jenkins/pipelines/pipeline1",
}, {
name: "Single folder",
args: args{
pipelineName: "pipeline1",
folders: []string{"folder1"},
},
want: "/blue/rest/organizations/jenkins/pipelines/folder1/pipelines/pipeline1",
}, {
name: "Tweo folders",
args: args{
pipelineName: "pipeline1",
folders: []string{"folder1", "folder2"},
},
want: "/blue/rest/organizations/jenkins/pipelines/folder1/pipelines/folder2/pipelines/pipeline1",
}, {
name: "Three folders",
args: args{
pipelineName: "pipeline1",
folders: []string{"folder1", "folder2", "folder3"},
},
want: "/blue/rest/organizations/jenkins/pipelines/folder1/pipelines/folder2/pipelines/folder3/pipelines/pipeline1",
}}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
c := &BlueOceanClient{
JenkinsCore: core.JenkinsCore{},
Organization: "jenkins",
}
if got := c.getGetPipelineAPI(tt.args.pipelineName, tt.args.folders...); got != tt.want {
t.Errorf("BlueOceanClient.getGetPipelineAPI() = %v, want %v", got, tt.want)
}
})
}
}
121 changes: 121 additions & 0 deletions pkg/job/blueocean_type.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package job

// PipelineRun represents a build detail of Pipeline.
// Reference: https://github.com/jenkinsci/blueocean-plugin/blob/a7cbc946b73d89daf9dfd91cd713cc7ab64a2d95/blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/PipelineRunImpl.java
type PipelineRun struct {
ArtifactsZipFile interface{} `json:"artifactsZipFile,omitempty"`
CauseOfBlockage string `json:"causeOfBlockage,omitempty"`
Causes []interface{} `json:"causes,omitempty"`
ChangeSet []interface{} `json:"changeSet,omitempty"`
Description string `json:"description,omitempty"`
DurationInMillis *int64 `json:"durationInMillis,omitempty"`
EnQueueTime Time `json:"enQueueTime,omitempty"`
EndTime Time `json:"endTime,omitempty"`
EstimatedDurationInMillis *int64 `json:"estimatedDurationInMillis,omitempty"`
ID string `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Organization string `json:"organization,omitempty"`
Pipeline string `json:"pipeline,omitempty"`
Replayable bool `json:"replayable,omitempty"`
Result string `json:"result,omitempty"`
RunSummary string `json:"runSummary,omitempty"`
StartTime Time `json:"startTime,omitempty"`
State string `json:"state,omitempty"`
Type string `json:"type,omitempty"`
QueueID string `json:"queueId,omitempty"`
CommitID string `json:"commitId,omitempty"`
CommitURL string `json:"commitUrl,omitempty"`
PullRequest interface{} `json:"pullRequest,omitempty"`
Branch interface{} `json:"branch,omitempty"`
}

// Node represents a node detail of a PipelineRun.
type Node struct {
DisplayDescription string `json:"displayDescription,omitempty"`
DisplayName string `json:"displayName,omitempty"`
DurationInMillis int `json:"durationInMillis,omitempty"`
ID string `json:"id,omitempty"`
Input *Input `json:"input,omitempty"`
Result string `json:"result,omitempty"`
StartTime Time `json:"startTime,omitempty"`
State string `json:"state,omitempty"`
Type string `json:"type,omitempty"`
CauseOfBlockage string `json:"causeOfBlockage,omitempty"`
Edges []Edge `json:"edges,omitempty"`
FirstParent string `json:"firstParent,omitempty"`
Restartable bool `json:"restartable,omitempty"`
}

// Edge represents edge of SimplePipeline flow graph.
type Edge struct {
ID string `json:"id,omitempty"`
Type string `json:"type,omitempty"`
}

// Input contains input step data.
type Input struct {
ID string `json:"id,omitempty"`
Message string `json:"message,omitempty"`
Ok string `json:"ok,omitempty"`
Parameters []ParameterDefinition `json:"parameters,omitempty"`
Submitter string `json:"submitter,omitempty"`
}

// Reference: https://github.com/jenkinsci/blueocean-plugin/blob/6b27be3724c892427b732f30575fdcc2977cfaef/blueocean-rest/src/main/java/io/jenkins/blueocean/rest/model/BlueRunnableItem.java
type blueRunnableItem struct {
WeatherScore int `json:"weatherScore,omitempty"`
LatestRun *PipelineRun `json:"latestRun,omitempty"`
EstimatedDurationInMillis int64 `json:"estimatedDurationInMillis,omitempty"`
Permissions map[string]bool `json:"permissions,omitempty"`
Parameters []ParameterDefinition `json:"parameters,omitempty"`
}

// Reference: https://github.com/jenkinsci/blueocean-plugin/blob/6b27be3724c892427b732f30575fdcc2977cfaef/blueocean-rest/src/main/java/io/jenkins/blueocean/rest/model/BluePipelineItem.java
type bluePipelineItem struct {
Organization string `json:"organization,omitempty"`
Name string `json:"name,omitempty"`
Disabled bool `json:"disabled,omitempty"`
DisplayName string `json:"displayName,omitempty"`
FullName string `json:"fullName,omitempty"`
FullDisplayName string `json:"fullDisplayName,omitempty"`
}

// Reference: https://github.com/jenkinsci/blueocean-plugin/blob/6b27be3724c892427b732f30575fdcc2977cfaef/blueocean-rest/src/main/java/io/jenkins/blueocean/rest/model/BlueContainerItem.java
type blueContainerItem struct {
NumberOfPipelines int `json:"numberOfPipelines,omitempty"`
NumberOfFolders int `json:"numberOfFolders,omitempty"`
PipelineFolderNames []string `json:"pipelineFolderNames,omitempty"`
}

// Reference: https://github.com/jenkinsci/blueocean-plugin/blob/6b27be3724c892427b732f30575fdcc2977cfaef/blueocean-rest/src/main/java/io/jenkins/blueocean/rest/model/BlueMultiBranchItem.java
type blueMultiBranchItem struct {
TotalNumberOfBranches int `json:"totalNumberOfBranches,omitempty"`
NumberOfFailingBranches int `json:"numberOfFailingBranches,omitempty"`
NumberOfSuccessfulBranches int `json:"numberOfSuccessfulBranches,omitempty"`
TotalNumberOfPullRequests int `json:"totalNumberOfPullRequests,omitempty"`
NumberOfFailingPullRequests int `json:"numberOfFailingPullRequests,omitempty"`
NumberOfSuccessfulPullRequests int `json:"numberOfSuccessfulPullRequests,omitempty"`
BranchNames []string `json:"branchNames,omitempty"`
}

// Reference: https://github.com/jenkinsci/blueocean-plugin/blob/6b27be3724c892427b732f30575fdcc2977cfaef/blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/MultiBranchPipelineImpl.java
type blueMultiBranchPipeline struct {
blueRunnableItem
bluePipelineItem
blueContainerItem
blueMultiBranchItem
SCMSource *SCMSource `json:"scmSource,omitempty"`
ScriptPath string `json:"scriptPath,omitempty"`
}

// Pipeline represents a Jenkins BlueOcean Pipeline data
type Pipeline struct {
blueMultiBranchPipeline
}

// SCMSource provides metadata about the backing SCM for a BluePipeline.
// Reference: https://github.com/jenkinsci/blueocean-plugin/blob/868c0ea4354f19e8d509deacc94325f97151aec0/blueocean-rest/src/main/java/io/jenkins/blueocean/rest/model/BlueScmSource.java
type SCMSource struct {
ID string `json:"id,omitempty"`
APIUrl string `json:"apiUrl,omitempty"`
}

0 comments on commit d28f47e

Please sign in to comment.