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  }