diff --git a/app/cmd/job_history.go b/app/cmd/job_history.go index 539f87b537932a6629bb4c192b1e9a4a688c3196..a5d60f6f83cb4756e42746512e59e4b1c70d0ee2 100644 --- a/app/cmd/job_history.go +++ b/app/cmd/job_history.go @@ -1,18 +1,20 @@ package cmd import ( + "bytes" "fmt" - "log" - "os" - + "github.com/jenkins-zh/jenkins-cli/app/helper" "github.com/jenkins-zh/jenkins-cli/client" "github.com/jenkins-zh/jenkins-cli/util" "github.com/spf13/cobra" + "net/http" ) // JobHistoryOption is the job history option type JobHistoryOption struct { OutputOption + + RoundTripper http.RoundTripper } var jobHistoryOption JobHistoryOption @@ -30,41 +32,39 @@ var jobHistoryCmd = &cobra.Command{ Run: func(cmd *cobra.Command, args []string) { jobName := args[0] - jenkins := getCurrentJenkinsFromOptionsOrDie() - jclient := &client.JobClient{} - jclient.URL = jenkins.URL - jclient.UserName = jenkins.UserName - jclient.Token = jenkins.Token - jclient.Proxy = jenkins.Proxy - jclient.ProxyAuth = jenkins.ProxyAuth + jClient := &client.JobClient{ + JenkinsCore: client.JenkinsCore{ + RoundTripper: jobHistoryOption.RoundTripper, + }, + } + getCurrentJenkinsAndClient(&(jClient.JenkinsCore)) - if builds, err := jclient.GetHistory(jobName); err == nil { - if data, err := jobHistoryOption.Output(builds); err == nil { - if len(data) > 0 { - fmt.Println(string(data)) - } - } else { - log.Fatal(err) + builds, err := jClient.GetHistory(jobName) + if err == nil { + var data []byte + data, err = jobHistoryOption.Output(builds) + if err == nil && len(data) > 0 { + cmd.Print(string(data)) } - } else { - log.Fatal(err) } + helper.CheckErr(cmd, err) }, } // Output print the output func (o *JobHistoryOption) Output(obj interface{}) (data []byte, err error) { if data, err = o.OutputOption.Output(obj); err != nil { - buildList := obj.([]client.JobBuild) - table := util.CreateTable(os.Stdout) + buildList := obj.([]*client.JobBuild) + buf := new(bytes.Buffer) + table := util.CreateTable(buf) table.AddRow("number", "displayname", "building", "result") for i, build := range buildList { table.AddRow(fmt.Sprintf("%d", i), build.DisplayName, fmt.Sprintf("%v", build.Building), build.Result) } table.Render() + data = buf.Bytes() err = nil - data = []byte{} } return } diff --git a/app/cmd/job_history_test.go b/app/cmd/job_history_test.go new file mode 100644 index 0000000000000000000000000000000000000000..1e5666d0a4d4103bb0edcdbe1e992ac9209653c8 --- /dev/null +++ b/app/cmd/job_history_test.go @@ -0,0 +1,76 @@ +package cmd + +import ( + "bytes" + "github.com/jenkins-zh/jenkins-cli/client" + "io/ioutil" + "os" + + "github.com/golang/mock/gomock" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/jenkins-zh/jenkins-cli/mock/mhttp" +) + +var _ = Describe("job history command", func() { + var ( + ctrl *gomock.Controller + roundTripper *mhttp.MockRoundTripper + err error + jenkinsRoot string + username string + token string + ) + + BeforeEach(func() { + ctrl = gomock.NewController(GinkgoT()) + roundTripper = mhttp.NewMockRoundTripper(ctrl) + jobHistoryOption.RoundTripper = roundTripper + rootCmd.SetArgs([]string{}) + rootOptions.Jenkins = "" + rootOptions.ConfigFile = "test.yaml" + + jenkinsRoot = "http://localhost:8080/jenkins" + username = "admin" + token = "111e3a2f0231198855dceaff96f20540a9" + }) + + AfterEach(func() { + rootCmd.SetArgs([]string{}) + err = os.Remove(rootOptions.ConfigFile) + rootOptions.ConfigFile = "" + ctrl.Finish() + }) + + Context("basic cases", func() { + It("should not error", func() { + Expect(err).NotTo(HaveOccurred()) + }) + + It("should success", func() { + data, err := generateSampleConfig() + Expect(err).To(BeNil()) + err = ioutil.WriteFile(rootOptions.ConfigFile, data, 0664) + Expect(err).To(BeNil()) + + jobName := "fakeJob" + + client.PrepareForGetJob(roundTripper, jenkinsRoot, jobName, username, token) + client.PrepareForGetBuild(roundTripper, jenkinsRoot, jobName, 1, username, token) + client.PrepareForGetBuild(roundTripper, jenkinsRoot, jobName, 2, username, token) + + rootCmd.SetArgs([]string{"job", "history", jobName}) + + buf := new(bytes.Buffer) + rootCmd.SetOutput(buf) + _, err = rootCmd.ExecuteC() + Expect(err).To(BeNil()) + + Expect(buf.String()).To(Equal(`number displayname building result +0 fake false +1 fake false +`)) + }) + }) +}) diff --git a/app/cmd/job_param.go b/app/cmd/job_param.go index 6505e076cfef40de4bab0d54e6ad78cf33ff34ba..ab5affee126f74765baa397e13dc73579ab679d2 100644 --- a/app/cmd/job_param.go +++ b/app/cmd/job_param.go @@ -28,12 +28,8 @@ var jobParamCmd = &cobra.Command{ Use: "param ", Short: "Get param of the job of your Jenkins", Long: `Get param of the job of your Jenkins`, + Args: cobra.MinimumNArgs(1), Run: func(cmd *cobra.Command, args []string) { - if len(args) == 0 { - cmd.Help() - return - } - name := args[0] jenkins := getCurrentJenkinsFromOptionsOrDie() jclient := &client.JobClient{} diff --git a/app/cmd/user_delete.go b/app/cmd/user_delete.go index 20b287424ec5395a5aca4a4a4db9862f4f494b7a..bdd51b89b07e81496dafcf81e8a0844d1bc776c2 100644 --- a/app/cmd/user_delete.go +++ b/app/cmd/user_delete.go @@ -2,6 +2,7 @@ package cmd import ( "fmt" + "github.com/jenkins-zh/jenkins-cli/app/helper" "net/http" "github.com/jenkins-zh/jenkins-cli/client" @@ -42,8 +43,7 @@ var userDeleteCmd = &cobra.Command{ } getCurrentJenkinsAndClient(&(jclient.JenkinsCore)) - if err := jclient.Delete(username); err != nil { - cmd.PrintErrln(err) - } + err := jclient.Delete(username) + helper.CheckErr(cmd, err) }, } diff --git a/client/job.go b/client/job.go index ae2b890752e5e13b389c1d58e656d139651b5357..2510ef54a4a55cba4736f13c99031794854e8e62 100644 --- a/client/job.go +++ b/client/job.go @@ -131,38 +131,18 @@ func (q *JobClient) UpdatePipeline(name, script string) (err error) { } // GetHistory returns the build history of a job -func (q *JobClient) GetHistory(name string) (builds []JobBuild, err error) { +func (q *JobClient) GetHistory(name string) (builds []*JobBuild, err error) { var job *Job if job, err = q.GetJob(name); err == nil { - builds = job.Builds - - for i, build := range builds { - api := fmt.Sprintf("%sapi/json", build.URL) - var ( - req *http.Request - response *http.Response - ) - - req, err = http.NewRequest("GET", api, nil) - if err == nil { - q.AuthHandle(req) - } else { - return - } - client := q.GetClient() - if response, err = client.Do(req); err == nil { - code := response.StatusCode - var data []byte - data, err = ioutil.ReadAll(response.Body) - if code == 200 { - err = json.Unmarshal(data, &build) - builds[i] = build - } else { - log.Fatal(string(data)) - } - } else { - log.Fatal(err) + buildList := job.Builds // only contains basic info + + var build *JobBuild + for _, buildItem := range buildList { + build, err = q.GetBuild(name, buildItem.Number) + if err != nil { + break } + builds = append(builds, build) } } return diff --git a/client/job_test.go b/client/job_test.go index ace6d89cb7d78044a48c8f6c43fb20e2f3866e66..0268521870b358d49178b1e7c3e6cffbfda00c8d 100644 --- a/client/job_test.go +++ b/client/job_test.go @@ -158,18 +158,7 @@ var _ = Describe("job test", func() { It("basic case with one build", func() { jobName := "fake" buildID := 2 - - request, _ := http.NewRequest("GET", fmt.Sprintf("%s/job/%s/%d/api/json", jobClient.URL, jobName, buildID), nil) - response := &http.Response{ - StatusCode: 200, - Proto: "HTTP/1.1", - Request: request, - Body: ioutil.NopCloser(bytes.NewBufferString(` - {"displayName":"fake"} - `)), - } - roundTripper.EXPECT(). - RoundTrip(request).Return(response, nil) + PrepareForGetBuild(roundTripper, jobClient.URL, jobName, 2, "", "") result, err := jobClient.GetBuild(jobName, buildID) Expect(err).To(BeNil()) @@ -365,4 +354,19 @@ var _ = Describe("job test", func() { Expect(err).To(BeNil()) }) }) + + Context("GetHistory", func() { + It("simple case, should success", func() { + jobName := "fakeJob" + + PrepareForGetJob(roundTripper, jobClient.URL, jobName, "", "") + PrepareForGetBuild(roundTripper, jobClient.URL, jobName, 1, "", "") + PrepareForGetBuild(roundTripper, jobClient.URL, jobName, 2, "", "") + + builds, err := jobClient.GetHistory(jobName) + Expect(err).To(BeNil()) + Expect(builds).NotTo(BeNil()) + Expect(len(builds)).To(Equal(2)) + }) + }) }) diff --git a/client/job_test_common.go b/client/job_test_common.go index 20ea7d79e20f6b985b97e32144219f75d7d60818..52b297f7d4ec2bdad13f3af9258ff4f6957ab78f 100644 --- a/client/job_test_common.go +++ b/client/job_test_common.go @@ -13,7 +13,7 @@ import ( ) // PrepareForGetJobInputActions only for test -func PrepareForGetJobInputActions(roundTripper *mhttp.MockRoundTripper, rootURL, user, passwd, jobName string, buildID int) ( +func PrepareForGetJobInputActions(roundTripper *mhttp.MockRoundTripper, rootURL, user, password, jobName string, buildID int) ( request *http.Request, response *http.Response) { request, _ = http.NewRequest("GET", fmt.Sprintf("%s/job/%s/%d/wfapi/pendingInputActions", rootURL, jobName, buildID), nil) response = &http.Response{ @@ -27,48 +27,93 @@ func PrepareForGetJobInputActions(roundTripper *mhttp.MockRoundTripper, rootURL, roundTripper.EXPECT(). RoundTrip(request).Return(response, nil) - if user != "" && passwd != "" { - request.SetBasicAuth(user, passwd) + if user != "" && password != "" { + request.SetBasicAuth(user, password) } return } // PrepareForSubmitInput only for test -func PrepareForSubmitInput(roundTripper *mhttp.MockRoundTripper, rootURL, jobPath, user, passwd string) ( +func PrepareForSubmitInput(roundTripper *mhttp.MockRoundTripper, rootURL, jobPath, user, password string) ( request *http.Request, response *http.Response) { request, _ = http.NewRequest("POST", fmt.Sprintf("%s%s/%d/input/%s/abort?json={\"parameter\":[]}", rootURL, jobPath, 1, "Eff7d5dba32b4da32d9a67a519434d3f"), nil) - PrepareCommonPost(request, "", roundTripper, user, passwd, rootURL) + PrepareCommonPost(request, "", roundTripper, user, password, rootURL) return } // PrepareForSubmitProcessInput only for test -func PrepareForSubmitProcessInput(roundTripper *mhttp.MockRoundTripper, rootURL, jobPath, user, passwd string) ( +func PrepareForSubmitProcessInput(roundTripper *mhttp.MockRoundTripper, rootURL, jobPath, user, password string) ( request *http.Request, response *http.Response) { request, _ = http.NewRequest("POST", fmt.Sprintf("%s%s/%d/input/%s/proceed?json={\"parameter\":[]}", rootURL, jobPath, 1, "Eff7d5dba32b4da32d9a67a519434d3f"), nil) - PrepareCommonPost(request, "", roundTripper, user, passwd, rootURL) + PrepareCommonPost(request, "", roundTripper, user, password, rootURL) return } // PrepareForBuildWithNoParams only for test -func PrepareForBuildWithNoParams(roundTripper *mhttp.MockRoundTripper, rootURL, jobName, user, passwd string) ( +func PrepareForBuildWithNoParams(roundTripper *mhttp.MockRoundTripper, rootURL, jobName, user, password string) ( request *http.Request, response *http.Response) { formData := url.Values{"json": {`{"parameter": []}`}} payload := strings.NewReader(formData.Encode()) request, _ = http.NewRequest("POST", fmt.Sprintf("%s/job/%s/build", rootURL, jobName), payload) request.Header.Add(util.ContentType, util.ApplicationForm) - response = PrepareCommonPost(request, "", roundTripper, user, passwd, rootURL) + response = PrepareCommonPost(request, "", roundTripper, user, password, rootURL) response.StatusCode = 201 return } // PrepareForBuildWithParams only for test -func PrepareForBuildWithParams(roundTripper *mhttp.MockRoundTripper, rootURL, jobName, user, passwd string) ( +func PrepareForBuildWithParams(roundTripper *mhttp.MockRoundTripper, rootURL, jobName, user, password string) ( request *http.Request, response *http.Response) { formData := url.Values{"json": {`{"parameter": {"Description":"","name":"name","Type":"","value":"value","DefaultParameterValue":{"Description":"","Value":null}}}`}} payload := strings.NewReader(formData.Encode()) request, _ = http.NewRequest("POST", fmt.Sprintf("%s/job/%s/build", rootURL, jobName), payload) request.Header.Add(util.ContentType, util.ApplicationForm) - response = PrepareCommonPost(request, "", roundTripper, user, passwd, rootURL) + response = PrepareCommonPost(request, "", roundTripper, user, password, rootURL) response.StatusCode = 201 return } + +// PrepareForGetJob only for test +func PrepareForGetJob(roundTripper *mhttp.MockRoundTripper, rootURL, jobName, user, password string) { + request, _ := http.NewRequest("GET", fmt.Sprintf("%s/job/%s/api/json", rootURL, jobName), nil) + response := &http.Response{ + StatusCode: 200, + Proto: "HTTP/1.1", + Request: request, + Body: ioutil.NopCloser(bytes.NewBufferString(fmt.Sprintf(`{ + "name" : "%s", + "builds" : [ + { + "number" : 1, + "url" : "http://localhost:8080/job/we/1/" + }, + { + "number" : 2, + "url" : "http://localhost:8080/job/we/2/" + }] + }`, jobName))), + } + roundTripper.EXPECT(). + RoundTrip(request).Return(response, nil) + if user != "" && password != "" { + request.SetBasicAuth(user, password) + } +} + +// PrepareForGetBuild only for test +func PrepareForGetBuild(roundTripper *mhttp.MockRoundTripper, rootURL, jobName string, buildID int, user, password string) { + request, _ := http.NewRequest("GET", fmt.Sprintf("%s/job/%s/%d/api/json", rootURL, jobName, buildID), nil) + response := &http.Response{ + StatusCode: 200, + Proto: "HTTP/1.1", + Request: request, + Body: ioutil.NopCloser(bytes.NewBufferString(` + {"displayName":"fake"} + `)), + } + roundTripper.EXPECT(). + RoundTrip(request).Return(response, nil) + if user != "" && password != "" { + request.SetBasicAuth(user, password) + } +}