cli/commands/ci/ciutils/utils.go

125 lines
3.3 KiB
Go

package ciutils
import (
"context"
"fmt"
"io"
"sync"
"time"
"gitlab.com/gitlab-org/cli/pkg/iostreams"
"gitlab.com/gitlab-org/cli/api"
"gitlab.com/gitlab-org/cli/pkg/tableprinter"
"gitlab.com/gitlab-org/cli/pkg/utils"
"github.com/pkg/errors"
"github.com/xanzy/go-gitlab"
)
var (
once sync.Once
offset int64
)
func makeHyperlink(s *iostreams.IOStreams, pipeline *gitlab.PipelineInfo) string {
return s.Hyperlink(fmt.Sprintf("%d", pipeline.ID), pipeline.WebURL)
}
func DisplaySchedules(i *iostreams.IOStreams, s []*gitlab.PipelineSchedule, projectID string) string {
if len(s) > 0 {
table := tableprinter.NewTablePrinter()
table.AddRow("ID", "Description", "Cron", "Owner", "Active")
for _, schedule := range s {
table.AddRow(schedule.ID, schedule.Description, schedule.Cron, schedule.Owner.Username, schedule.Active)
}
return table.Render()
}
// return empty string, since when there is no schedule, the title will already display it accordingly
return ""
}
func DisplayMultiplePipelines(s *iostreams.IOStreams, p []*gitlab.PipelineInfo, projectID string) string {
c := s.Color()
table := tableprinter.NewTablePrinter()
if len(p) > 0 {
for _, pipeline := range p {
duration := ""
if pipeline.CreatedAt != nil {
duration = c.Magenta("(" + utils.TimeToPrettyTimeAgo(*pipeline.CreatedAt) + ")")
}
var pipeState string
if pipeline.Status == "success" {
pipeState = c.Green(fmt.Sprintf("(%s) • #%s", pipeline.Status, makeHyperlink(s, pipeline)))
} else if pipeline.Status == "failed" {
pipeState = c.Red(fmt.Sprintf("(%s) • #%s", pipeline.Status, makeHyperlink(s, pipeline)))
} else {
pipeState = c.Gray(fmt.Sprintf("(%s) • #%s", pipeline.Status, makeHyperlink(s, pipeline)))
}
table.AddRow(pipeState, pipeline.Ref, duration)
}
return table.Render()
}
return "No Pipelines available on " + projectID
}
func RunTraceSha(ctx context.Context, apiClient *gitlab.Client, w io.Writer, pid interface{}, sha, name string) error {
job, err := api.PipelineJobWithSha(apiClient, pid, sha, name)
if err != nil || job == nil {
return errors.Wrap(err, "failed to find job")
}
return RunTrace(ctx, apiClient, w, pid, job, name)
}
func RunTrace(ctx context.Context, apiClient *gitlab.Client, w io.Writer, pid interface{}, job *gitlab.Job, name string) error {
fmt.Fprintln(w, "Getting job trace...")
for range time.NewTicker(time.Second * 3).C {
if ctx.Err() == context.Canceled {
break
}
trace, _, err := apiClient.Jobs.GetTraceFile(pid, job.ID)
if err != nil || trace == nil {
return errors.Wrap(err, "failed to find job")
}
switch job.Status {
case "pending":
fmt.Fprintf(w, "%s is pending... waiting for job to start\n", job.Name)
continue
case "manual":
fmt.Fprintf(w, "Manual job %s not started, waiting for job to start\n", job.Name)
continue
case "skipped":
fmt.Fprintf(w, "%s has been skipped\n", job.Name)
}
once.Do(func() {
if name == "" {
name = job.Name
}
fmt.Fprintf(w, "Showing logs for %s job #%d\n", job.Name, job.ID)
})
_, _ = io.CopyN(io.Discard, trace, offset)
lenT, err := io.Copy(w, trace)
if err != nil {
return err
}
offset += lenT
if job.Status == "success" ||
job.Status == "failed" ||
job.Status == "cancelled" {
return nil
}
}
return nil
}