diff --git a/app/cmd/common.go b/app/cmd/common.go index 296754934eeb02f49b0a8825c85736087fb2b4ff..7eb843e5f72e603e1b780741e4cb7ac0bfa03090 100644 --- a/app/cmd/common.go +++ b/app/cmd/common.go @@ -67,5 +67,6 @@ func (b *BatchOption) Confirm(message string) bool { // WatchOption for the resources which can be watched type WatchOption struct { - Watch bool + Watch bool + Interval int } diff --git a/app/cmd/job_log.go b/app/cmd/job_log.go index dec66b05ff648c75a1244d363382adf9e3585c6e..65ce2141f9ec0004a6bd7b62976d9d6ab3d66c2b 100644 --- a/app/cmd/job_log.go +++ b/app/cmd/job_log.go @@ -3,20 +3,28 @@ package cmd import ( "fmt" "log" + "time" "github.com/linuxsuren/jenkins-cli/client" "github.com/spf13/cobra" ) type JobLogOption struct { + WatchOption History int + + LogText string + LastBuildID int + LastBuildURL string } var jobLogOption JobLogOption func init() { jobCmd.AddCommand(jobLogCmd) - jobLogCmd.PersistentFlags().IntVarP(&jobLogOption.History, "history", "s", -1, "Specific build history of log") + jobLogCmd.Flags().IntVarP(&jobLogOption.History, "history", "s", -1, "Specific build history of log") + jobLogCmd.Flags().BoolVarP(&jobLogOption.Watch, "watch", "w", false, "Watch the job logs") + jobLogCmd.Flags().IntVarP(&jobLogOption.Interval, "interval", "i", 1, "Interval of watch") } var jobLogCmd = &cobra.Command{ @@ -37,13 +45,48 @@ var jobLogCmd = &cobra.Command{ jclient.Proxy = jenkins.Proxy jclient.ProxyAuth = jenkins.ProxyAuth - printLog(jclient, jobOption.Name, jobLogOption.History, 0) + lastBuildID := -1 + for { + if build, err := jclient.GetBuild(jobOption.Name, -1); err == nil { + jobLogOption.LastBuildID = build.Number + jobLogOption.LastBuildURL = build.URL + } + if lastBuildID != jobLogOption.LastBuildID { + lastBuildID = jobLogOption.LastBuildID + fmt.Println("Current build number:", jobLogOption.LastBuildID) + fmt.Println("Current build url:", jobLogOption.LastBuildURL) + + printLog(jclient, jobOption.Name, jobLogOption.History, 0) + } + + if !jobLogOption.Watch { + break + } + + time.Sleep(time.Duration(jobLogOption.Interval) * time.Second) + } }, } func printLog(jclient *client.JobClient, jobName string, history int, start int64) { if status, err := jclient.Log(jobName, history, start); err == nil { - fmt.Print(status.Text) + isNew := false + + if jobLogOption.LogText != status.Text { + jobLogOption.LogText = status.Text + isNew = true + } else if history == -1 { + if build, err := jclient.GetBuild(jobName, -1); err == nil && jobLogOption.LastBuildID != build.Number { + jobLogOption.LastBuildID = build.Number + jobLogOption.LastBuildURL = build.URL + isNew = true + } + } + + if isNew { + fmt.Print(status.Text) + } + if status.HasMore { printLog(jclient, jobName, history, status.NextStart) } diff --git a/client/job.go b/client/job.go index 696940c9b2d552025788f4d1e1500f4531316404..7db6b205aa87782ac9b18cc4e7ad92ea2eacd791 100644 --- a/client/job.go +++ b/client/job.go @@ -89,6 +89,48 @@ func (q *JobClient) Build(jobName string) (err error) { return } +func (q *JobClient) GetBuild(jobName string, id int) (job *JobBuild, err error) { + jobItems := strings.Split(jobName, " ") + path := "" + for _, item := range jobItems { + path = fmt.Sprintf("%s/job/%s", path, item) + } + + var api string + if id == -1 { + api = fmt.Sprintf("%s/%s/lastBuild/api/json", q.URL, path) + } else { + api = fmt.Sprintf("%s/%s/%d/api/json", q.URL, path, id) + } + 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 { + job = &JobBuild{} + err = json.Unmarshal(data, job) + } else { + log.Fatal(string(data)) + } + } else { + log.Fatal(err) + } + return +} + func (q *JobClient) GetJob(name string) (job *Job, err error) { jobItems := strings.Split(name, " ") path := "" @@ -299,11 +341,28 @@ type Job struct { Buildable bool } -type JobBuild struct { +type SimpleJobBuild struct { Number int URL string } +type JobBuild struct { + SimpleJobBuild + Building bool + Description string + DisplayName string + Duration int64 + EstimatedDuration int64 + FullDisplayName string + ID string + KeepLog bool + QueueID int + Result string + Timestamp int64 + PreviousBuild SimpleJobBuild + NextBuild SimpleJobBuild +} + type Pipeline struct { Script string Sandbox bool