Skip to content

Commit

Permalink
Persist exit codes across cached builds
Browse files Browse the repository at this point in the history
We need to be able to find out what the exit code of a failed job
was, without actually re-running the build.
  • Loading branch information
agis committed Mar 28, 2018
1 parent 555ea8f commit aa35a67
Show file tree
Hide file tree
Showing 8 changed files with 75 additions and 11 deletions.
4 changes: 4 additions & 0 deletions client/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,10 @@ EXAMPLES:
return err
}

if br.ExitCode != 0 {
return fmt.Errorf("Build failed with exit code %d", br.ExitCode)
}

out, err := utils.RunCmd(ts.Copy(transportUser, host, br.Path+"/*", target))
fmt.Println(out)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion config.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ type Config struct {
BuildPath string `json:"build_path"`
UID string

// map[source]target
// [source]target
Mounts map[string]string `json:"mounts"`
}

Expand Down
17 changes: 16 additions & 1 deletion end_to_end_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,20 @@ func TestResultCache(t *testing.T) {
// assert(result2.ExitCode, 0, t)
}

func TestResultCacheExitCode(t *testing.T) {
cmdOut1, err := cliBuildJob("--project", "result-cache-exitcode")
if err == nil || !strings.Contains(cmdOut1, "33") {
fmt.Println("hi")
t.Fatalf("Expected '%s' to contain the exit code 33", cmdOut1)
}

cmdOut2, err := cliBuildJob("--project", "result-cache-exitcode")
if err == nil || !strings.Contains(cmdOut2, "33") {
fmt.Println("yo")
t.Fatalf("Expected '%s' to contain the exit code 33", cmdOut2)
}
}

func TestBuildCoalescing(t *testing.T) {
var wg sync.WaitGroup

Expand Down Expand Up @@ -129,7 +143,8 @@ func TestBuildCoalescing(t *testing.T) {
}

// cliBuildJob uses the CLI binary to issue a new job request to the server.
// It returns an error if the request could not be issued.
// It returns an error if the request could not be issued or if the job
// failed to build.
//
// NOTE: The CLI binary is expected to be present in the working
// directory where the tests are ran from.
Expand Down
6 changes: 4 additions & 2 deletions job.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ type Job struct {

// NOTE: after a job is complete, this points to an invalid path
// (pending)
BuildLogPath string
BuildLogPath string
BuildResultFilePath string
}

func NewJob(project string, params map[string]string, group string) (*Job, error) {
Expand Down Expand Up @@ -74,7 +75,8 @@ func NewJob(project string, params map[string]string, group string) (*Job, error
}

j.ProjectPath = filepath.Join(cfg.ProjectsPath, j.Project)
j.BuildLogPath = filepath.Join(j.PendingBuildPath, BuildLogName)
j.BuildLogPath = filepath.Join(j.PendingBuildPath, BuildLogFname)
j.BuildResultFilePath = filepath.Join(j.PendingBuildPath, BuildResultFname)

return j, nil
}
Expand Down
4 changes: 3 additions & 1 deletion job_queue.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package main

import "sync"
import (
"sync"
)

type JobQueue struct {
j map[string]bool
Expand Down
11 changes: 6 additions & 5 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@ import (
)

const (
DataDir = "/data" // - data/
CacheDir = "/cache" // |- cache/
ArtifactsDir = "/artifacts" // |- artifacts/
ParamsDir = "/params" // |- params/
BuildLogName = "out.log" // - out.log
DataDir = "/data" // - data/
CacheDir = "/cache" // |- cache/
ArtifactsDir = "/artifacts" // |- artifacts/
ParamsDir = "/params" // |- params/
BuildLogFname = "out.log" // - out.log
BuildResultFname = "result.json" // - result.json
)

var (
Expand Down
38 changes: 37 additions & 1 deletion worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
"context"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
Expand All @@ -28,8 +29,16 @@ func Work(ctx context.Context, j *Job, fs FileSystem) (buildResult *types.BuildR

_, err = os.Stat(j.ReadyBuildPath)
if err == nil {
cachedResult := new(types.BuildResult)
f, err := os.Open(filepath.Join(j.ReadyBuildPath, BuildResultFname))
if err != nil {
return buildResult, err
}
dec := json.NewDecoder(f)
dec.Decode(cachedResult)
buildResult.Cached = true
return
buildResult.ExitCode = cachedResult.ExitCode
return buildResult, err
} else if !os.IsNotExist(err) {
err = workErr("could not check for ready path", err)
return
Expand Down Expand Up @@ -192,6 +201,33 @@ func Work(ctx context.Context, j *Job, fs FileSystem) (buildResult *types.BuildR
return
}

resultFile, err := os.Create(j.BuildResultFilePath)
if err != nil {
err = workErr("could not create build result file", err)
return
}
defer func() {
ferr := resultFile.Close()
errstr := "could not close build result file"
if ferr != nil {
if err == nil {
err = fmt.Errorf("%s; %s", errstr, ferr)
} else {
err = fmt.Errorf("%s; %s | %s", errstr, ferr, err)
}
}
}()
brJson, err := json.Marshal(buildResult)
if err != nil {
err = workErr("could not serialize build result", err)
return
}
_, err = resultFile.Write(brJson)
if err != nil {
err = workErr("could not write build result to file", err)
return
}

err = os.Rename(j.PendingBuildPath, j.ReadyBuildPath)
if err != nil {
err = workErr("could not rename pending to ready path", err)
Expand Down
4 changes: 4 additions & 0 deletions worker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,13 @@ func TestMain(m *testing.M) {
}()
waitForServer("8462")

// TODO: fix race with main() and TestMain() concurrently messing
// with cfg
cfg.BuildPath, err = ioutil.TempDir("", "mistry-tests")
if err != nil {
panic(err)
}
fmt.Println("Running tests in", cfg.BuildPath)

cfg.BuildPath, err = filepath.EvalSymlinks(cfg.BuildPath)
if err != nil {
Expand Down Expand Up @@ -146,6 +149,7 @@ func TestBuildCache(t *testing.T) {
assert(result2.ExitCode, 0, t)
}

// TODO: CHECK FOR PATH, NOT FOR THE ERROR
func TestFailedPendingBuildCleanup(t *testing.T) {
var err error
project := "failed-build-cleanup"
Expand Down

0 comments on commit aa35a67

Please sign in to comment.