Skip to content

Commit

Permalink
(ci_trace,tests) test selecting and stream job logs
Browse files Browse the repository at this point in the history
  • Loading branch information
zaquestion committed Apr 15, 2018
1 parent 8323f0f commit 381b503
Show file tree
Hide file tree
Showing 6 changed files with 157 additions and 48 deletions.
2 changes: 1 addition & 1 deletion Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 3 additions & 8 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
install:
go install -ldflags "-X \"main.version=$$(git rev-parse --short=10 HEAD)\"" github.com/zaquestion/lab

dep:
go get -u -d github.com/zaquestion/lab
cd $GOPATH/src/github.com/zaquestion/lab
dep ensure
go install -ldflags "-X \"main.version=$$(git rev-parse --short=10 HEAD)\"" github.com/zaquestion/lab

test:
bash -c "trap 'trap - SIGINT SIGTERM ERR; mv testdata/.git testdata/test.git; rm coverage-* 2>&1 > /dev/null; exit 1' SIGINT SIGTERM ERR; $(MAKE) internal-test"
Expand All @@ -13,10 +9,9 @@ internal-test:
dep ensure
rm coverage-* 2>&1 > /dev/null || true
mv testdata/test.git testdata/.git
go test -coverprofile=coverage-git.out -covermode=count github.com/zaquestion/lab/internal/git
go test -coverprofile=coverage-gitlab.out -covermode=count github.com/zaquestion/lab/internal/gitlab
go test -coverprofile=coverage-cmd.out -covermode=count -coverpkg ./... github.com/zaquestion/lab/cmd
go test -coverprofile=coverage-main.out -covermode=count -coverpkg ./... -run=$(run) github.com/zaquestion/lab/cmd
mv testdata/.git testdata/test.git
go get github.com/wadey/gocovmerge
gocovmerge coverage-*.out > coverage.txt && rm coverage-*.out

.PHONY: install test internal-test
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ go install -ldflags "-X \"main.version=$(git rev-parse --short=10 HEAD)\"" git
or

```
make dep
make install
```

Expand Down
50 changes: 32 additions & 18 deletions cmd/ciTrace.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,22 @@ import (
"io"
"io/ioutil"
"log"
"strings"
"sync"
"time"

"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/zaquestion/lab/internal/git"
lab "github.com/zaquestion/lab/internal/gitlab"
)

// ciLintCmd represents the lint command
var ciTraceCmd = &cobra.Command{
Use: "trace [remote [job]]",
Use: "trace [remote [[<tree-ish>:]job]]",
Aliases: []string{"logs"},
Short: "Trace the output of a ci job",
Long: ``,
Long: `If a job is not specified the latest running job or last job in the pipeline is used`,
Run: func(cmd *cobra.Command, args []string) {
var (
remote string
Expand All @@ -31,15 +34,10 @@ var ciTraceCmd = &cobra.Command{
}
remote = args[0]
}
if len(args) > 1 {
jobName = args[1]
}
if remote == "" {
remote = forkedFromRemote
}

// See if we're in a git repo or if global is set to determine
// if this should be a personal snippet
rn, err := git.PathWithNameSpace(remote)
if err != nil {
log.Fatal(err)
Expand All @@ -48,28 +46,42 @@ var ciTraceCmd = &cobra.Command{
if err != nil {
log.Fatal(err)
}
sha, err := git.Sha("HEAD")
var ref = "HEAD"
if len(args) > 1 {
jobName = args[1]
if strings.Contains(args[1], ":") {
ps := strings.Split(args[1], ":")
ref, jobName = ps[0], ps[1]
}
}
sha, err := git.Sha(ref)
if err != nil {
log.Fatal(err)
}
var (
once sync.Once
offset int64
tick = time.Second * 3
)
FOR:
for range time.NewTicker(tick).C {
trace, status, err := lab.CITrace(project.ID, sha, jobName)
switch status {
for range time.NewTicker(time.Second * 3).C {
trace, job, err := lab.CITrace(project.ID, sha, jobName)
if job == nil {
log.Fatal(errors.Wrap(err, "failed to find job"))
}
switch job.Status {
case "pending":
fmt.Println(err)
fmt.Printf("%s is pending...\n", job.Name)
continue
case "manual":
fmt.Println(err)
fmt.Printf("Manual job %s not started\n", job.Name)
break FOR
}
if err != nil {
log.Fatal(err)
}
once.Do(func() {
if jobName == "" {
jobName = job.Name
}
fmt.Printf("Showing logs for %s job #%d\n", job.Name, job.ID)
})
buf, err := ioutil.ReadAll(trace)
if err != nil {
log.Fatal(err)
Expand All @@ -80,7 +92,9 @@ var ciTraceCmd = &cobra.Command{

offset += int64(len(new))
fmt.Print(string(new))
if status == "success" || status == "failed" {
if job.Status == "success" ||
job.Status == "failed" ||
job.Status == "cancelled" {
break
}
}
Expand Down
90 changes: 90 additions & 0 deletions cmd/ciTrace_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package cmd

import (
"os/exec"
"testing"

"github.com/stretchr/testify/assert"
)

func Test_ciTrace(t *testing.T) {
t.Parallel()
repo := copyTestRepo(t)
cmd := exec.Command("../lab_bin", "fetch", "origin")
cmd.Dir = repo
if b, err := cmd.CombinedOutput(); err != nil {
t.Log(string(b))
t.Fatal(err)
}

cmd = exec.Command("../lab_bin", "checkout", "origin/ci_test_pipeline")
cmd.Dir = repo
if b, err := cmd.CombinedOutput(); err != nil {
t.Log(string(b))
t.Fatal(err)
}

tests := []struct {
desc string
args []string
assertContains func(t *testing.T, out string)
}{
{
desc: "noargs",
args: []string{},
assertContains: func(t *testing.T, out string) {
assert.Contains(t, out, "Showing logs for deploy10 job #62958489")
assert.Contains(t, out, "Checking out 09b519cb as ci_test_pipeline...")
assert.Contains(t, out, "For example you might run an update here or install a build dependency")
assert.Contains(t, out, "$ echo \"Or perhaps you might print out some debugging details\"")
assert.Contains(t, out, "Job succeeded")
},
},
{
desc: "manual",
args: []string{"origin", "deploy2"},
assertContains: func(t *testing.T, out string) {
assert.Contains(t, out, "Manual job deploy2 not started\n")
},
},
{
desc: "arg job name",
args: []string{"origin", "deploy1"},
assertContains: func(t *testing.T, out string) {
assert.Contains(t, out, "Showing logs for deploy1 job #62958479")
assert.Contains(t, out, "Checking out 09b519cb as ci_test_pipeline...")
assert.Contains(t, out, "For example you might run an update here or install a build dependency")
assert.Contains(t, out, "$ echo \"Or perhaps you might print out some debugging details\"")
assert.Contains(t, out, "Job succeeded")
},
},
{
desc: "explicit sha:job",
args: []string{"origin", "09b519cba018b707c98fc56e37df15806d89d866:deploy1"},
assertContains: func(t *testing.T, out string) {
assert.Contains(t, out, "Showing logs for deploy1 job #62958479")
assert.Contains(t, out, "Checking out 09b519cb as ci_test_pipeline...")
assert.Contains(t, out, "For example you might do some cleanup here")
assert.Contains(t, out, "Job succeeded")
},
},
}

for _, test := range tests {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
cmd = exec.Command("../lab_bin", append([]string{"ci", "trace"}, test.args...)...)
cmd.Dir = repo

b, err := cmd.CombinedOutput()
if err != nil {
t.Log(string(b))
t.Fatal(err)
}
out := string(b)
test.assertContains(t, out)
})
}

}
51 changes: 31 additions & 20 deletions internal/gitlab/gitlab.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ import (
"net/http"
"os"
"path/filepath"
"sort"
"strings"

"github.com/davecgh/go-spew/spew"
"github.com/pkg/errors"
"github.com/xanzy/go-gitlab"
"github.com/zaquestion/lab/internal/git"
Expand Down Expand Up @@ -362,14 +362,13 @@ func ProjectDelete(pid interface{}) error {
return nil
}

// CIJobs returns a list of jobs in a pipeline for a given sha. The jobs are
// returned sorted by their CreatedAt time
func CIJobs(pid interface{}, sha string) ([]gitlab.Job, error) {
pipelines, _, err := lab.Pipelines.ListProjectPipelines(pid)
if err != nil {
return nil, err
}
if os.Getenv("DEBUG") != "" {
spew.Dump(pipelines)
}
var target int
for _, p := range pipelines {
if p.Sha != sha {
Expand All @@ -382,36 +381,48 @@ func CIJobs(pid interface{}, sha string) ([]gitlab.Job, error) {
if err != nil {
return nil, err
}
if os.Getenv("DEBUG") != "" {
spew.Dump(jobs)
}
// The jobs seem to be returned in reverse order
// NOTE: more recent testing seems to suggest jobs are returned in last modified order
//for i, j := 0, len(jobs)-1; i < j; i, j = i+1, j-1 {
// jobs[i], jobs[j] = jobs[j], jobs[i]
//}
sort.Sort(ciJobs(jobs))
return jobs, nil
}

func CITrace(pid interface{}, sha, name string) (io.Reader, string, error) {
type ciJobs []gitlab.Job

func (js ciJobs) Len() int {
return len(js)
}

func (js ciJobs) Less(i, j int) bool {
return js[i].CreatedAt.Before(*js[j].CreatedAt)
}

func (js ciJobs) Swap(i, j int) {
js[i], js[j] = js[j], js[i]
}

// CITrace searches by name for a job and returns its trace file. The trace is
// static so may only be a portion of the logs if the job is till running. If
// no name is provided the most recent running job
func CITrace(pid interface{}, sha, name string) (io.Reader, *gitlab.Job, error) {
jobs, err := CIJobs(pid, sha)
if err != nil {
return nil, "", err
return nil, nil, err
}
var job gitlab.Job
var (
job = jobs[len(jobs)-1]
)
for _, j := range jobs {
if j.Status == "running" {
job = j
}
if j.Name == name {
job = j
break
}
}
if os.Getenv("DEBUG") != "" {
log.Printf("found job: %d status: %s\n", job.ID, job.Status)
}
r, _, err := lab.Jobs.GetTraceFile(pid, job.ID)
if err != nil {
return nil, "", err
return nil, &job, err
}

return r, job.Status, err
return r, &job, err
}

0 comments on commit 381b503

Please sign in to comment.