github.com/zaquestion/lab@v0.25.1/cmd/ci_status.go (about) 1 package cmd 2 3 import ( 4 "fmt" 5 "os" 6 "text/tabwriter" 7 "time" 8 9 "github.com/MakeNowJust/heredoc/v2" 10 "github.com/pkg/errors" 11 "github.com/rsteube/carapace" 12 "github.com/spf13/cobra" 13 gitlab "github.com/xanzy/go-gitlab" 14 "github.com/zaquestion/lab/internal/action" 15 lab "github.com/zaquestion/lab/internal/gitlab" 16 ) 17 18 // ciStatusCmd represents the run command 19 var ciStatusCmd = &cobra.Command{ 20 Use: "status [branch]", 21 Aliases: []string{"run"}, 22 Short: "Textual representation of a CI pipeline", 23 Example: heredoc.Doc(` 24 lab ci status 25 lab ci status upstream 608 --merge-request 26 lab ci status 600 --wait 27 lab ci status upstream 125 --merge-request --bridge 'security-tests'`), 28 RunE: nil, 29 PersistentPreRun: labPersistentPreRun, 30 Run: func(cmd *cobra.Command, args []string) { 31 var ( 32 rn string 33 err error 34 ) 35 36 forMR, err := cmd.Flags().GetBool("merge-request") 37 if err != nil { 38 log.Fatal(err) 39 } 40 41 bridgeName, err = cmd.Flags().GetString("bridge") 42 if err != nil { 43 log.Fatal(err) 44 } else if bridgeName != "" { 45 followBridge = true 46 } else { 47 followBridge, err = cmd.Flags().GetBool("follow") 48 if err != nil { 49 log.Fatal(err) 50 } 51 } 52 53 rn, pipelineID, err := getPipelineFromArgs(args, forMR) 54 if err != nil { 55 log.Fatal(err) 56 } 57 58 pid := rn 59 60 pager := newPager(cmd.Flags()) 61 defer pager.Close() 62 63 w := tabwriter.NewWriter(os.Stdout, 2, 4, 1, byte(' '), 0) 64 65 wait, err := cmd.Flags().GetBool("wait") 66 if err != nil { 67 log.Fatal(err) 68 } 69 70 var jobStructList []lab.JobStruct 71 jobs := make([]*gitlab.Job, 0) 72 73 fmt.Fprintln(w, "Stage:\tName\t-\tStatus") 74 for { 75 // fetch all of the CI Jobs from the API 76 jobStructList, err = lab.CIJobs(pid, pipelineID, followBridge, bridgeName) 77 if err != nil { 78 log.Fatal(errors.Wrap(err, "failed to find ci jobs")) 79 } 80 81 for _, jobStruct := range jobStructList { 82 jobs = append(jobs, jobStruct.Job) 83 } 84 85 // filter out old jobs 86 jobs = latestJobs(jobs) 87 if len(jobs) == 0 { 88 log.Fatal("no CI jobs found in pipeline ", pipelineID, " on remote ", rn) 89 return 90 } 91 92 // print the status of all current jobs 93 for _, job := range jobs { 94 fmt.Fprintf(w, "%s:\t%s\t-\t%s\n", job.Stage, job.Name, job.Status) 95 } 96 97 dontWaitForJobsToFinish := !wait || 98 (jobs[0].Pipeline.Status != "pending" && 99 jobs[0].Pipeline.Status != "running") 100 if dontWaitForJobsToFinish { 101 break 102 } 103 104 fmt.Fprintln(w) 105 106 // don't spam the api TOO much 107 time.Sleep(10 * time.Second) 108 } 109 110 fmt.Fprintf(w, "\nPipeline Status: %s\n", jobs[0].Pipeline.Status) 111 // exit w/ status code 1 to indicate a job failure 112 if wait && jobs[0].Pipeline.Status != "success" { 113 os.Exit(1) 114 } 115 w.Flush() 116 }, 117 } 118 119 func init() { 120 ciStatusCmd.Flags().Bool("wait", false, "continuously print the status and wait to exit until the pipeline finishes. Exit code indicates pipeline status") 121 ciStatusCmd.Flags().Bool("merge-request", false, "use merge request pipeline if enabled") 122 ciCmd.AddCommand(ciStatusCmd) 123 124 carapace.Gen(ciStatusCmd).PositionalCompletion( 125 action.Remotes(), 126 action.RemoteBranches(0), 127 ) 128 }