From ecc8c3d1d06d9c13e60616625fa059edbc6aa0e2 Mon Sep 17 00:00:00 2001 From: Michel Vocks Date: Fri, 11 Jan 2019 17:20:06 +0100 Subject: [PATCH 01/12] First implementation to test the ruby sdk --- gaia.go | 3 +++ workers/scheduler/scheduler.go | 24 +++++++++++++++++++++--- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/gaia.go b/gaia.go index e5478295..8d4173f2 100644 --- a/gaia.go +++ b/gaia.go @@ -38,6 +38,9 @@ const ( // PTypeCpp C++ plugin type PTypeCpp PipelineType = "cpp" + // PTypeRuby ruby plugin type + PTypeRuby PipelineType = "ruby" + // CreatePipelineFailed status CreatePipelineFailed CreatePipelineType = "failed" diff --git a/workers/scheduler/scheduler.go b/workers/scheduler/scheduler.go index 19f544b0..96534d51 100644 --- a/workers/scheduler/scheduler.go +++ b/workers/scheduler/scheduler.go @@ -39,11 +39,14 @@ var ( // a plugin. errCreateCMDForPipeline = errors.New("could not create execute command for plugin") - // Java executeable name + // Java executable name javaExecName = "java" - // Python executeable name + // Python executable name pythonExecName = "python" + + // Ruby executable name + rubyExecName = "ruby" ) // Plugin represents the plugin implementation which is used @@ -725,7 +728,7 @@ func createPipelineCmd(p *gaia.Pipeline) *exec.Cmd { // Look for java executable path, err := exec.LookPath(javaExecName) if err != nil { - gaia.Cfg.Logger.Debug("cannot find java executable", "error", err.Error()) + gaia.Cfg.Logger.Error("cannot find java executable", "error", err.Error()) return nil } @@ -747,6 +750,21 @@ func createPipelineCmd(p *gaia.Pipeline) *exec.Cmd { c.Dir = filepath.Join(gaia.Cfg.HomePath, gaia.TmpFolder, gaia.TmpPythonFolder, p.Name) case gaia.PTypeCpp: c.Path = p.ExecPath + case gaia.PTypeRuby: + // Look for ruby executable + path, err := exec.LookPath(rubyExecName) + if err != nil { + gaia.Cfg.Logger.Error("cannot find ruby executable", "error", err.Error()) + return nil + } + + // Build start command + c.Path = path + c.Args = []string{ + path, + "-Ilib", + p.ExecPath, + } default: c = nil } From c2607498503b376ff549bd2f32ac1285fd2edb79 Mon Sep 17 00:00:00 2001 From: Michel Vocks Date: Sun, 13 Jan 2019 15:39:25 +0100 Subject: [PATCH 02/12] Small improvements --- gaia.go | 3 ++ go.mod | 1 + go.sum | 3 ++ workers/pipeline/ticker.go | 2 ++ workers/pipeline/update_pipeline.go | 30 ++++++++++++++++++ workers/scheduler/scheduler.go | 47 +++++++++++++++++++++++++++-- 6 files changed, 84 insertions(+), 2 deletions(-) diff --git a/gaia.go b/gaia.go index 8d4173f2..d4b89382 100644 --- a/gaia.go +++ b/gaia.go @@ -100,6 +100,9 @@ const ( // TmpCppFolder is the name of the c++ temporary folder TmpCppFolder = "cpp" + + // TmpRubyFolder is the name of the ruby temporary folder + TmpRubyFolder = "ruby" ) // User is the user object diff --git a/go.mod b/go.mod index bbd35297..28097d44 100644 --- a/go.mod +++ b/go.mod @@ -43,4 +43,5 @@ require ( gopkg.in/src-d/go-billy.v4 v4.2.0 gopkg.in/src-d/go-git.v4 v4.5.0 gopkg.in/warnings.v0 v0.1.2 + gopkg.in/yaml.v2 v2.2.2 ) diff --git a/go.sum b/go.sum index 48d8d373..f1ceaa2c 100644 --- a/go.sum +++ b/go.sum @@ -74,9 +74,12 @@ google.golang.org/genproto v0.0.0-20180808183934-383e8b2c3b9e h1:8mImbC+7codRhTI google.golang.org/genproto v0.0.0-20180808183934-383e8b2c3b9e/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/grpc v1.14.0 h1:ArxJuB1NWfPY6r9Gp9gqwplT0Ge7nqv9msgu03lHLmo= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/src-d/go-billy.v4 v4.2.0 h1:VGbrP1EsYxtvVPEiHui+4//imr4E5MGEFLx66bQtusg= gopkg.in/src-d/go-billy.v4 v4.2.0/go.mod h1:ZHSF0JP+7oD97194otDUCD7Ofbk63+xFcfWP5bT6h+Q= gopkg.in/src-d/go-git.v4 v4.5.0 h1:6VjUh+5ATbfmlCAhV/Fb+1uQ7GnwLIuBPkwcRtxHZkk= gopkg.in/src-d/go-git.v4 v4.5.0/go.mod h1:CzbUWqMn4pvmvndg3gnh5iZFmSsbhyhUWdI0IQ60AQo= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/workers/pipeline/ticker.go b/workers/pipeline/ticker.go index bf67ecac..b734effd 100644 --- a/workers/pipeline/ticker.go +++ b/workers/pipeline/ticker.go @@ -237,6 +237,8 @@ func getPipelineType(n string) (gaia.PipelineType, error) { return gaia.PTypePython, nil case gaia.PTypeCpp.String(): return gaia.PTypeCpp, nil + case gaia.PTypeRuby.String(): + return gaia.PTypeRuby, nil } return gaia.PTypeUnknown, errMissingType diff --git a/workers/pipeline/update_pipeline.go b/workers/pipeline/update_pipeline.go index c27d4b3e..92296a10 100644 --- a/workers/pipeline/update_pipeline.go +++ b/workers/pipeline/update_pipeline.go @@ -17,6 +17,9 @@ var ( // pythonPipInstallCmd is the command used to install the python distribution // package. pythonPipInstallCmd = ". bin/activate; python -m pip install %s.tar.gz" + + // Ruby gem binary name. + rubyGemName = "gem" ) // updatePipeline executes update steps dependent on the pipeline type. @@ -51,6 +54,33 @@ func updatePipeline(p *gaia.Pipeline) error { if err := cmd.Run(); err != nil { return err } + case gaia.PTypeRuby: + // Find gem binary in path variable. + path, err := exec.LookPath(rubyGemName) + if err != nil { + return err + } + + // Gem expects that the file suffix is ".gem". + // Copy gem file to temp folder before we install it. + tmpFolder := filepath.Join(gaia.Cfg.HomePath, gaia.TmpFolder, gaia.TmpRubyFolder) + err = os.MkdirAll(tmpFolder, 0700) + if err != nil { + return err + } + pipelineCopyPath := filepath.Join(tmpFolder, filepath.Base(p.ExecPath)+".gem") + err = copyFileContents(p.ExecPath, pipelineCopyPath) + if err != nil { + return err + } + defer os.Remove(pipelineCopyPath) + + // Install gem forcefully. + cmd := exec.Command(path, "install", "-f", "-l", pipelineCopyPath) + if out, err := cmd.CombinedOutput(); err != nil { + gaia.Cfg.Logger.Debug("error", string(out[:])) + return err + } } // Update checksum diff --git a/workers/scheduler/scheduler.go b/workers/scheduler/scheduler.go index 96534d51..824667a2 100644 --- a/workers/scheduler/scheduler.go +++ b/workers/scheduler/scheduler.go @@ -14,6 +14,7 @@ import ( "github.com/gaia-pipeline/gaia/security" "github.com/gaia-pipeline/gaia/store" uuid "github.com/satori/go.uuid" + "gopkg.in/yaml.v2" ) const ( @@ -47,6 +48,9 @@ var ( // Ruby executable name rubyExecName = "ruby" + + // Ruby gem binary name. + rubyGemName = "gem" ) // Plugin represents the plugin implementation which is used @@ -758,12 +762,21 @@ func createPipelineCmd(p *gaia.Pipeline) *exec.Cmd { return nil } + // Get the gem name from the gem file. + gemName, err := findRubyGemName(p.ExecPath) + if err != nil { + gaia.Cfg.Logger.Error("cannot find the gem name from the gem file", "error", err.Error()) + return nil + } + // Build start command c.Path = path c.Args = []string{ path, - "-Ilib", - p.ExecPath, + "-r", + gemName, + "-e", + "'Main.main'", } default: c = nil @@ -786,3 +799,33 @@ func (s *Scheduler) finishPipelineRun(r *gaia.PipelineRun, status gaia.PipelineR gaia.Cfg.Logger.Error("cannot store finished pipeline", "error", err.Error()) } } + +// findRubyGemName finds the gem name of a ruby gem file. +func findRubyGemName(execPath string) (name string, err error) { + // Find the gem binary path. + path, err := exec.LookPath(rubyGemName) + if err != nil { + return + } + + // Get the gem specification in YAML format. + cmd := exec.Command(path, "specification", "--yaml", execPath) + output, err := cmd.Output() + if err != nil { + return + } + + // Struct helper to filter for what we need. + type gemSpecOutput struct { + Name string + } + + // Transform and filter the gem specification. + gemSpec := gemSpecOutput{} + err = yaml.Unmarshal(output, &gemSpec) + if err != nil { + return + } + name = gemSpec.Name + return +} From d4559a9fe1336483852b0c83e4e36b19a75881ea Mon Sep 17 00:00:00 2001 From: Michel Vocks Date: Wed, 16 Jan 2019 21:31:46 +0100 Subject: [PATCH 03/12] Implemented ruby support. WIP tests --- frontend/client/assets/ruby.png | Bin 0 -> 148402 bytes frontend/client/views/overview/index.vue | 11 +- frontend/client/views/pipeline/create.vue | 3 + plugin/plugin.go | 2 +- workers/pipeline/build_ruby.go | 153 ++++++++++++++ workers/pipeline/build_ruby_test.go | 235 ++++++++++++++++++++++ workers/pipeline/pipeline.go | 4 + workers/pipeline/update_pipeline.go | 2 +- workers/scheduler/scheduler.go | 4 +- 9 files changed, 409 insertions(+), 5 deletions(-) create mode 100644 frontend/client/assets/ruby.png create mode 100644 workers/pipeline/build_ruby.go create mode 100644 workers/pipeline/build_ruby_test.go diff --git a/frontend/client/assets/ruby.png b/frontend/client/assets/ruby.png new file mode 100644 index 0000000000000000000000000000000000000000..3a149d71d707180013773d1324b9fe1cae0d7eb8 GIT binary patch literal 148402 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

N0Iq}(FD`vK18wzvI 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

d)Q~HNN$CQw{CaI1bVDvd>9LPEc>EGecxk# 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 +

+ +
diff --git a/plugin/plugin.go b/plugin/plugin.go index 0e4fa03c..33fc6751 100644 --- a/plugin/plugin.go +++ b/plugin/plugin.go @@ -13,7 +13,7 @@ import ( "github.com/gaia-pipeline/gaia" "github.com/gaia-pipeline/gaia/security" "github.com/gaia-pipeline/gaia/workers/scheduler" - "github.com/gaia-pipeline/protobuf" + proto "github.com/gaia-pipeline/protobuf" plugin "github.com/hashicorp/go-plugin" ) diff --git a/workers/pipeline/build_ruby.go b/workers/pipeline/build_ruby.go new file mode 100644 index 00000000..8e5f0d04 --- /dev/null +++ b/workers/pipeline/build_ruby.go @@ -0,0 +1,153 @@ +package pipeline + +import ( + "errors" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "strings" + "time" + + "github.com/gaia-pipeline/gaia" + "github.com/gaia-pipeline/gaia/services" + uuid "github.com/satori/go.uuid" +) + +const ( + gemBinaryName = "gem" +) + +// BuildPipelineRuby is the real implementation of BuildPipeline for Ruby +type BuildPipelineRuby struct { + Type gaia.PipelineType +} + +// PrepareEnvironment prepares the environment before we start the build process. +func (b *BuildPipelineRuby) PrepareEnvironment(p *gaia.CreatePipeline) error { + // create uuid for destination folder + uuid := uuid.Must(uuid.NewV4(), nil) + + // Create local temp folder for clone + cloneFolder := filepath.Join(gaia.Cfg.HomePath, gaia.TmpFolder, gaia.TmpRubyFolder, srcFolder, uuid.String()) + err := os.MkdirAll(cloneFolder, 0700) + if err != nil { + return err + } + + // Set new generated path in pipeline obj for later usage + p.Pipeline.Repo.LocalDest = cloneFolder + p.Pipeline.UUID = uuid.String() + return err +} + +// ExecuteBuild executes the ruby build process +func (b *BuildPipelineRuby) ExecuteBuild(p *gaia.CreatePipeline) error { + // Look for gem binary executable + path, err := exec.LookPath(gemBinaryName) + if err != nil { + gaia.Cfg.Logger.Debug("cannot find gem binary executable", "error", err.Error()) + return err + } + + // Get all gemspec files in cloned folder. + gemspec, err := filterPathContentBySuffix(p.Pipeline.Repo.LocalDest, ".gemspec") + if err != nil { + gaia.Cfg.Logger.Error("cannot find gemspec file in cloned repository folder", "path", p.Pipeline.Repo.LocalDest) + return err + } + + // if we found more or less than one gemspec we have a problem. + if len(gemspec) != 1 { + gaia.Cfg.Logger.Debug("cannot find gemspec file in cloned repo", "foundGemspecs", len(gemspec), "gemspecs", gemspec) + return errors.New("cannot find gemspec file in cloned repo") + } + + // Set command args for build + args := []string{ + "build", + gemspec[0], + } + + // Execute and wait until finish or timeout + output, err := executeCmd(path, args, os.Environ(), p.Pipeline.Repo.LocalDest) + p.Output = string(output) + if err != nil { + gaia.Cfg.Logger.Debug("cannot build pipeline", "error", err.Error(), "output", string(output)) + return err + } + + // Search for resulting gem file. + gemfile, err := filterPathContentBySuffix(p.Pipeline.Repo.LocalDest, ".gem") + if err != nil { + gaia.Cfg.Logger.Error("cannot find final gem file after build", "path", p.Pipeline.Repo.LocalDest) + return err + } + + // if we found more or less than one gem file then we have a problem. + if len(gemfile) != 1 { + gaia.Cfg.Logger.Debug("cannot find gem file in cloned repo", "foundGemFiles", len(gemfile), "gems", gemfile) + return errors.New("cannot find gem file in cloned repo") + } + + // Build has been finished. Set execution path to the build result archive. + // This will be used during pipeline verification phase which will happen after this step. + p.Pipeline.ExecPath = gemfile[0] + + return nil +} + +// filterPathContentBySuffix reads the whole directory given by path and +// returns all files with full path which have the same suffix like provided. +func filterPathContentBySuffix(path, suffix string) ([]string, error) { + filteredFiles := []string{} + + // Read complete directory. + files, err := ioutil.ReadDir(path) + if err != nil { + return filteredFiles, err + } + + // filter for files ending with given suffix. + for _, file := range files { + if strings.HasSuffix(file.Name(), suffix) { + filteredFiles = append(filteredFiles, filepath.Join(path, file.Name())) + } + } + return filteredFiles, nil +} + +// CopyBinary copies the final compiled binary to the +// destination folder. +func (b *BuildPipelineRuby) CopyBinary(p *gaia.CreatePipeline) error { + // Search for resulting gem file. + gemfile, err := filterPathContentBySuffix(p.Pipeline.Repo.LocalDest, ".gem") + if err != nil { + gaia.Cfg.Logger.Error("cannot find final gem file during copy", "path", p.Pipeline.Repo.LocalDest) + return err + } + + // Define src and destination + src := gemfile[0] + dest := filepath.Join(gaia.Cfg.PipelinePath, appendTypeToName(p.Pipeline.Name, p.Pipeline.Type)) + + // Copy binary + if err := copyFileContents(src, dest); err != nil { + return err + } + + // Set +x (execution right) for pipeline + return os.Chmod(dest, 0766) +} + +// SavePipeline saves the current pipeline configuration. +func (b *BuildPipelineRuby) SavePipeline(p *gaia.Pipeline) error { + dest := filepath.Join(gaia.Cfg.PipelinePath, appendTypeToName(p.Name, p.Type)) + p.ExecPath = dest + p.Type = gaia.PTypeRuby + p.Name = strings.TrimSuffix(filepath.Base(dest), typeDelimiter+gaia.PTypeRuby.String()) + p.Created = time.Now() + // Our pipeline is finished constructing. Save it. + storeService, _ := services.StorageService() + return storeService.PipelinePut(p) +} diff --git a/workers/pipeline/build_ruby_test.go b/workers/pipeline/build_ruby_test.go new file mode 100644 index 00000000..ebea1297 --- /dev/null +++ b/workers/pipeline/build_ruby_test.go @@ -0,0 +1,235 @@ +package pipeline + +import ( + "bytes" + "errors" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "regexp" + "strings" + "testing" + + "github.com/gaia-pipeline/gaia" + "github.com/gaia-pipeline/gaia/services" + "github.com/gaia-pipeline/gaia/store" + hclog "github.com/hashicorp/go-hclog" +) + +func TestPrepareEnvironmentCpp(t *testing.T) { + tmp, _ := ioutil.TempDir("", "TestPrepareEnvironmentGo") + gaia.Cfg = new(gaia.Config) + gaia.Cfg.HomePath = tmp + b := new(BuildPipelineCpp) + p := new(gaia.CreatePipeline) + err := b.PrepareEnvironment(p) + if err != nil { + t.Fatal("error was not expected when preparing environment: ", err) + } + var expectedDest = regexp.MustCompile(`^/.*/tmp/cpp/src/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$`) + if !expectedDest.MatchString(p.Pipeline.Repo.LocalDest) { + t.Fatalf("expected destination is '%s', but was '%s'", expectedDest, p.Pipeline.Repo.LocalDest) + } +} + +func TestPrepareEnvironmentInvalidPathForMkdirCpp(t *testing.T) { + gaia.Cfg = new(gaia.Config) + gaia.Cfg.HomePath = "/notexists" + b := new(BuildPipelineCpp) + p := new(gaia.CreatePipeline) + err := b.PrepareEnvironment(p) + if err == nil { + t.Fatal("error was expected but none occurred") + } +} + +func TestExecuteBuildCpp(t *testing.T) { + execCommandContext = fakeExecCommandContext + defer func() { + execCommandContext = exec.CommandContext + }() + tmp, _ := ioutil.TempDir("", "TestExecuteBuildCpp") + gaia.Cfg = new(gaia.Config) + gaia.Cfg.HomePath = tmp + b := new(BuildPipelineCpp) + p := new(gaia.CreatePipeline) + err := b.ExecuteBuild(p) + if err != nil { + t.Fatal("error while running executebuild. none was expected") + } + expectedBuildArgs := "" + actualArgs := os.Getenv("CMD_ARGS") + if !strings.Contains(actualArgs, expectedBuildArgs) { + t.Fatalf("expected args '%s' actual args '%s'", expectedBuildArgs, actualArgs) + } +} + +func TestExecuteBuildContextTimeoutCpp(t *testing.T) { + execCommandContext = fakeExecCommandContext + buildKillContext = true + defer func() { + execCommandContext = exec.CommandContext + buildKillContext = false + }() + tmp, _ := ioutil.TempDir("", "TestExecuteBuildContextTimeoutCpp") + gaia.Cfg = new(gaia.Config) + gaia.Cfg.HomePath = tmp + // Initialize shared logger + buf := new(bytes.Buffer) + gaia.Cfg.Logger = hclog.New(&hclog.LoggerOptions{ + Level: hclog.Trace, + Output: buf, + Name: "Gaia", + }) + b := new(BuildPipelineCpp) + p := new(gaia.CreatePipeline) + err := b.ExecuteBuild(p) + if err == nil { + t.Fatal("no error found while expecting error.") + } + if err.Error() != "context deadline exceeded" { + t.Fatal("context deadline should have been exceeded. was instead: ", err) + } +} + +func TestExecuteBuildBinaryNotFoundErrorCpp(t *testing.T) { + tmp, _ := ioutil.TempDir("", "TestExecuteBuildBinaryNotFoundErrorCpp") + gaia.Cfg = new(gaia.Config) + gaia.Cfg.HomePath = tmp + // Initialize shared logger + buf := new(bytes.Buffer) + gaia.Cfg.Logger = hclog.New(&hclog.LoggerOptions{ + Level: hclog.Trace, + Output: buf, + Name: "Gaia", + }) + currentPath := os.Getenv("PATH") + defer func() { os.Setenv("PATH", currentPath) }() + os.Setenv("PATH", "") + b := new(BuildPipelineCpp) + p := new(gaia.CreatePipeline) + err := b.ExecuteBuild(p) + if err == nil { + t.Fatal("no error found while expecting error.") + } + if err.Error() != "exec: \"make\": executable file not found in $PATH" { + t.Fatal("the error wasn't what we expected. instead it was: ", err) + } +} + +func TestCopyBinaryCpp(t *testing.T) { + tmp, _ := ioutil.TempDir("", "TestCopyBinaryCpp") + gaia.Cfg = new(gaia.Config) + gaia.Cfg.HomePath = tmp + // Initialize shared logger + buf := new(bytes.Buffer) + gaia.Cfg.Logger = hclog.New(&hclog.LoggerOptions{ + Level: hclog.Trace, + Output: buf, + Name: "Gaia", + }) + b := new(BuildPipelineCpp) + p := new(gaia.CreatePipeline) + p.Pipeline.Name = "main" + p.Pipeline.Type = gaia.PTypeCpp + p.Pipeline.Repo.LocalDest = tmp + src := filepath.Join(tmp, cppFinalBinaryName) + dst := appendTypeToName(p.Pipeline.Name, p.Pipeline.Type) + f, _ := os.Create(src) + defer f.Close() + defer os.Remove(dst) + ioutil.WriteFile(src, []byte("testcontent"), 0666) + err := b.CopyBinary(p) + if err != nil { + t.Fatal("error was not expected when copying binary: ", err) + } + content, err := ioutil.ReadFile(dst) + if err != nil { + t.Fatal("error encountered while reading destination file: ", err) + } + if string(content) != "testcontent" { + t.Fatal("file content did not equal src content. was: ", string(content)) + } +} + +func TestCopyBinarySrcDoesNotExistCpp(t *testing.T) { + tmp, _ := ioutil.TempDir("", "TestCopyBinarySrcDoesNotExistCpp") + gaia.Cfg = new(gaia.Config) + gaia.Cfg.HomePath = tmp + // Initialize shared logger + buf := new(bytes.Buffer) + gaia.Cfg.Logger = hclog.New(&hclog.LoggerOptions{ + Level: hclog.Trace, + Output: buf, + Name: "Gaia", + }) + b := new(BuildPipelineCpp) + p := new(gaia.CreatePipeline) + p.Pipeline.Name = "main" + p.Pipeline.Type = gaia.PTypeCpp + p.Pipeline.Repo.LocalDest = "/noneexistent" + err := b.CopyBinary(p) + if err == nil { + t.Fatal("error was expected when copying binary but none occurred ") + } + if err.Error() != "open /noneexistent/"+cppFinalBinaryName+": no such file or directory" { + t.Fatal("a different error occurred then expected: ", err) + } +} + +type cppMockStorer struct { + store.GaiaStore + Error error +} + +// PipelinePut is a Mock implementation for pipelines +func (m *cppMockStorer) PipelinePut(p *gaia.Pipeline) error { + return m.Error +} + +func TestSavePipelineCpp(t *testing.T) { + defer os.Remove("gaia.db") + gaia.Cfg = new(gaia.Config) + gaia.Cfg.HomePath = "/tmp" + gaia.Cfg.PipelinePath = "/tmp/pipelines/" + // Initialize shared logger + p := new(gaia.Pipeline) + p.Name = "main" + p.Type = gaia.PTypeCpp + b := new(BuildPipelineCpp) + m := new(cppMockStorer) + services.MockStorageService(m) + err := b.SavePipeline(p) + if err != nil { + t.Fatal("something went wrong. wasn't supposed to get error: ", err) + } + if p.Name != "main" { + t.Fatal("name of pipeline didn't equal expected 'main'. was instead: ", p.Name) + } + if p.Type != gaia.PTypeCpp { + t.Fatal("type of pipeline was not cpp. instead was: ", p.Type) + } +} + +func TestSavePipelineSaveErrorsCpp(t *testing.T) { + defer os.Remove("gaia.db") + gaia.Cfg = new(gaia.Config) + gaia.Cfg.HomePath = "/tmp" + gaia.Cfg.PipelinePath = "/tmp/pipelines/" + // Initialize shared logger + p := new(gaia.Pipeline) + p.Name = "main" + p.Type = gaia.PTypeCpp + b := new(BuildPipelineCpp) + m := new(cppMockStorer) + m.Error = errors.New("database error") + services.MockStorageService(m) + err := b.SavePipeline(p) + if err == nil { + t.Fatal("expected error which did not occur") + } + if err.Error() != "database error" { + t.Fatal("error message was not the expected message. was: ", err.Error()) + } +} diff --git a/workers/pipeline/pipeline.go b/workers/pipeline/pipeline.go index 5d25e247..dbea174a 100644 --- a/workers/pipeline/pipeline.go +++ b/workers/pipeline/pipeline.go @@ -89,6 +89,10 @@ func newBuildPipeline(t gaia.PipelineType) BuildPipeline { bP = &BuildPipelineCpp{ Type: t, } + case gaia.PTypeRuby: + bP = &BuildPipelineRuby{ + Type: t, + } } return bP diff --git a/workers/pipeline/update_pipeline.go b/workers/pipeline/update_pipeline.go index 92296a10..8f850562 100644 --- a/workers/pipeline/update_pipeline.go +++ b/workers/pipeline/update_pipeline.go @@ -76,7 +76,7 @@ func updatePipeline(p *gaia.Pipeline) error { defer os.Remove(pipelineCopyPath) // Install gem forcefully. - cmd := exec.Command(path, "install", "-f", "-l", pipelineCopyPath) + cmd := exec.Command(path, "install", "-f", pipelineCopyPath) if out, err := cmd.CombinedOutput(); err != nil { gaia.Cfg.Logger.Debug("error", string(out[:])) return err diff --git a/workers/scheduler/scheduler.go b/workers/scheduler/scheduler.go index 824667a2..3709757f 100644 --- a/workers/scheduler/scheduler.go +++ b/workers/scheduler/scheduler.go @@ -14,7 +14,7 @@ import ( "github.com/gaia-pipeline/gaia/security" "github.com/gaia-pipeline/gaia/store" uuid "github.com/satori/go.uuid" - "gopkg.in/yaml.v2" + yaml "gopkg.in/yaml.v2" ) const ( @@ -776,7 +776,7 @@ func createPipelineCmd(p *gaia.Pipeline) *exec.Cmd { "-r", gemName, "-e", - "'Main.main'", + "Main.main", } default: c = nil From b6e6e30dfbba0c26e879e439c411eddb7c3ef8c4 Mon Sep 17 00:00:00 2001 From: Michel Vocks Date: Thu, 17 Jan 2019 12:06:59 +0100 Subject: [PATCH 04/12] Fixed tests --- .circleci/config.yml | 2 +- .circleci/images/primary/Dockerfile | 78 ++++++++++++++- go.mod | 1 + go.sum | 7 ++ workers/pipeline/build_ruby.go | 2 +- workers/pipeline/build_ruby_test.go | 97 +++++++++++-------- .../pipeline/testacc/build_pipeline_test.go | 21 ++++ 7 files changed, 165 insertions(+), 43 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index ffe80b29..e017528e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -34,7 +34,7 @@ jobs: acceptance_tests: working_directory: /go/src/github.com/gaia-pipeline/gaia docker: - - image: gaiapipeline/circleci:0.0.2 + - image: gaiapipeline/circleci:0.0.3 environment: GO111MODULE: "on" steps: diff --git a/.circleci/images/primary/Dockerfile b/.circleci/images/primary/Dockerfile index 7514a230..9476574c 100644 --- a/.circleci/images/primary/Dockerfile +++ b/.circleci/images/primary/Dockerfile @@ -156,7 +156,83 @@ RUN git clone -b ${GRPC_RELEASE_TAG} https://github.com/grpc/grpc /var/local/git echo "--- installing grpc ---" && \ cd /var/local/git/grpc && \ make -j$(nproc) && make install && make clean && ldconfig -# --------------- Start C++ Part --------------- +# --------------- End C++ Part --------------- + +# --------------- Start Ruby Part -------------- +# skip installing gem documentation +RUN mkdir -p /usr/local/etc \ + && { \ + echo 'install: --no-document'; \ + echo 'update: --no-document'; \ + } >> /usr/local/etc/gemrc + +ENV RUBY_MAJOR 2.5 +ENV RUBY_VERSION 2.5.3 +ENV RUBY_DOWNLOAD_SHA256 1cc9d0359a8ea35fc6111ec830d12e60168f3b9b305a3c2578357d360fcf306f +ENV RUBYGEMS_VERSION 3.0.1 + +# some of ruby's build scripts are written in ruby +# we purge system ruby later to make sure our final image uses what we just built +RUN set -ex \ + \ + && buildDeps=' \ + bison \ + dpkg-dev \ + libgdbm-dev \ + ruby \ + ' \ + && apt-get update \ + && apt-get install -y --no-install-recommends $buildDeps \ + && rm -rf /var/lib/apt/lists/* \ + \ + && wget -O ruby.tar.xz "https://cache.ruby-lang.org/pub/ruby/${RUBY_MAJOR%-rc}/ruby-$RUBY_VERSION.tar.xz" \ + && echo "$RUBY_DOWNLOAD_SHA256 *ruby.tar.xz" | sha256sum -c - \ + \ + && mkdir -p /usr/src/ruby \ + && tar -xJf ruby.tar.xz -C /usr/src/ruby --strip-components=1 \ + && rm ruby.tar.xz \ + \ + && cd /usr/src/ruby \ + \ +# hack in "ENABLE_PATH_CHECK" disabling to suppress: +# warning: Insecure world writable dir + && { \ + echo '#define ENABLE_PATH_CHECK 0'; \ + echo; \ + cat file.c; \ + } > file.c.new \ + && mv file.c.new file.c \ + \ + && autoconf \ + && gnuArch="$(dpkg-architecture --query DEB_BUILD_GNU_TYPE)" \ + && ./configure \ + --build="$gnuArch" \ + --disable-install-doc \ + --enable-shared \ + && make -j "$(nproc)" \ + && make install \ + \ + && apt-get purge -y --auto-remove $buildDeps \ + && cd / \ + && rm -r /usr/src/ruby \ +# make sure bundled "rubygems" is older than RUBYGEMS_VERSION (https://github.com/docker-library/ruby/issues/246) + && ruby -e 'exit(Gem::Version.create(ENV["RUBYGEMS_VERSION"]) > Gem::Version.create(Gem::VERSION))' \ + && gem update --system "$RUBYGEMS_VERSION" && rm -r /root/.gem/ \ +# rough smoke test + && ruby --version && gem --version && bundle --version + +# install things globally, for great justice +# and don't create ".bundle" in all our apps +ENV GEM_HOME /usr/local/bundle +ENV BUNDLE_PATH="$GEM_HOME" \ + BUNDLE_SILENCE_ROOT_WARNING=1 \ + BUNDLE_APP_CONFIG="$GEM_HOME" +# path recommendation: https://github.com/bundler/bundler/pull/6469#issuecomment-383235438 +ENV PATH $GEM_HOME/bin:$BUNDLE_PATH/gems/bin:$PATH +# adjust permissions of a few directories for running "gem install" as an arbitrary user +RUN mkdir -p "$GEM_HOME" && chmod 777 "$GEM_HOME" +# (BUNDLE_PATH = GEM_HOME, no need to mkdir/chown both) +# --------------- End Ruby Part --------------- # install additional deps RUN apt-get update && apt-get install -y --no-install-recommends \ diff --git a/go.mod b/go.mod index 28097d44..c66417ac 100644 --- a/go.mod +++ b/go.mod @@ -29,6 +29,7 @@ require ( github.com/satori/go.uuid v1.2.0 github.com/sergi/go-diff v1.0.0 github.com/src-d/gcfg v1.3.0 + github.com/stretchr/testify v1.3.0 // indirect github.com/valyala/bytebufferpool v1.0.0 github.com/valyala/fasttemplate v0.0.0-20170224212429-dcecefd839c4 github.com/xanzy/ssh-agent v0.2.0 diff --git a/go.sum b/go.sum index f1ceaa2c..b4fb41f1 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +4,8 @@ github.com/coreos/bbolt v1.3.0 h1:HIgH5xUWXT914HCI671AxuTTqjj64UOFr7pHn48LUTI= github.com/coreos/bbolt v1.3.0/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/daaku/go.zipexe v0.0.0-20150329023125-a5fe2436ffcb h1:tUf55Po0vzOendQ7NWytcdK0VuzQmfAgvGBUOQvN0WA= github.com/daaku/go.zipexe v0.0.0-20150329023125-a5fe2436ffcb/go.mod h1:U0vRfAucUOohvdCxt5MWLF+TePIL0xbCkbKIiV8TQCE= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/emirpasic/gods v1.9.0 h1:rUF4PuzEjMChMiNsVjdI+SyLu7rEqpQ5reNFnhC7oFo= @@ -46,6 +48,8 @@ github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/pelletier/go-buffruneio v0.2.0 h1:U4t4R6YkofJ5xHm3dJzuRpPZ0mr5MMCoAWooScCR7aA= github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/robfig/cron v0.0.0-20180505203441-b41be1df6967 h1:x7xEyJDP7Hv3LVgvWhzioQqbC/KtuUhTigKlH/8ehhE= github.com/robfig/cron v0.0.0-20180505203441-b41be1df6967/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k= github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= @@ -54,6 +58,9 @@ github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/src-d/gcfg v1.3.0 h1:2BEDr8r0I0b8h/fOqwtxCEiq2HJu8n2JGZJQFGXWLjg= github.com/src-d/gcfg v1.3.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v0.0.0-20170224212429-dcecefd839c4 h1:gKMu1Bf6QINDnvyZuTaACm9ofY+PRh+5vFz4oxBZeF8= diff --git a/workers/pipeline/build_ruby.go b/workers/pipeline/build_ruby.go index 8e5f0d04..434aaf0f 100644 --- a/workers/pipeline/build_ruby.go +++ b/workers/pipeline/build_ruby.go @@ -14,7 +14,7 @@ import ( uuid "github.com/satori/go.uuid" ) -const ( +var ( gemBinaryName = "gem" ) diff --git a/workers/pipeline/build_ruby_test.go b/workers/pipeline/build_ruby_test.go index ebea1297..694a972a 100644 --- a/workers/pipeline/build_ruby_test.go +++ b/workers/pipeline/build_ruby_test.go @@ -17,26 +17,26 @@ import ( hclog "github.com/hashicorp/go-hclog" ) -func TestPrepareEnvironmentCpp(t *testing.T) { - tmp, _ := ioutil.TempDir("", "TestPrepareEnvironmentGo") +func TestPrepareEnvironmentRuby(t *testing.T) { + tmp, _ := ioutil.TempDir("", "TestPrepareEnvironmentRuby") gaia.Cfg = new(gaia.Config) gaia.Cfg.HomePath = tmp - b := new(BuildPipelineCpp) + b := new(BuildPipelineRuby) p := new(gaia.CreatePipeline) err := b.PrepareEnvironment(p) if err != nil { t.Fatal("error was not expected when preparing environment: ", err) } - var expectedDest = regexp.MustCompile(`^/.*/tmp/cpp/src/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$`) + var expectedDest = regexp.MustCompile(`^/.*/tmp/ruby/src/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$`) if !expectedDest.MatchString(p.Pipeline.Repo.LocalDest) { t.Fatalf("expected destination is '%s', but was '%s'", expectedDest, p.Pipeline.Repo.LocalDest) } } -func TestPrepareEnvironmentInvalidPathForMkdirCpp(t *testing.T) { +func TestPrepareEnvironmentInvalidPathForMkdirRuby(t *testing.T) { gaia.Cfg = new(gaia.Config) gaia.Cfg.HomePath = "/notexists" - b := new(BuildPipelineCpp) + b := new(BuildPipelineRuby) p := new(gaia.CreatePipeline) err := b.PrepareEnvironment(p) if err == nil { @@ -44,19 +44,31 @@ func TestPrepareEnvironmentInvalidPathForMkdirCpp(t *testing.T) { } } -func TestExecuteBuildCpp(t *testing.T) { +func TestExecuteBuildRuby(t *testing.T) { execCommandContext = fakeExecCommandContext defer func() { execCommandContext = exec.CommandContext }() - tmp, _ := ioutil.TempDir("", "TestExecuteBuildCpp") + tmp, _ := ioutil.TempDir("", "TestExecuteBuildRuby") gaia.Cfg = new(gaia.Config) gaia.Cfg.HomePath = tmp - b := new(BuildPipelineCpp) + b := new(BuildPipelineRuby) p := new(gaia.CreatePipeline) + p.Pipeline.Name = "main" + p.Pipeline.Type = gaia.PTypeRuby + p.Pipeline.Repo.LocalDest = tmp + src := filepath.Join(tmp, p.Pipeline.Name+".gemspec") + f, _ := os.Create(src) + defer os.RemoveAll(tmp) + defer f.Close() + ioutil.WriteFile(src, []byte("testcontent"), 0666) + dst := filepath.Join(tmp, p.Pipeline.Name+".gem") + resultFile, _ := os.Create(dst) + defer resultFile.Close() + ioutil.WriteFile(dst, []byte("testcontent"), 0666) err := b.ExecuteBuild(p) if err != nil { - t.Fatal("error while running executebuild. none was expected") + t.Fatalf("error while running executebuild. none was expected: %s", err.Error()) } expectedBuildArgs := "" actualArgs := os.Getenv("CMD_ARGS") @@ -65,25 +77,31 @@ func TestExecuteBuildCpp(t *testing.T) { } } -func TestExecuteBuildContextTimeoutCpp(t *testing.T) { +func TestExecuteBuildContextTimeoutRuby(t *testing.T) { execCommandContext = fakeExecCommandContext buildKillContext = true defer func() { execCommandContext = exec.CommandContext buildKillContext = false }() - tmp, _ := ioutil.TempDir("", "TestExecuteBuildContextTimeoutCpp") + tmp, _ := ioutil.TempDir("", "TestExecuteBuildContextTimeoutRuby") gaia.Cfg = new(gaia.Config) gaia.Cfg.HomePath = tmp - // Initialize shared logger buf := new(bytes.Buffer) gaia.Cfg.Logger = hclog.New(&hclog.LoggerOptions{ Level: hclog.Trace, Output: buf, Name: "Gaia", }) - b := new(BuildPipelineCpp) + b := new(BuildPipelineRuby) p := new(gaia.CreatePipeline) + p.Pipeline.Name = "main" + p.Pipeline.Type = gaia.PTypeRuby + p.Pipeline.Repo.LocalDest = tmp + src := filepath.Join(tmp, p.Pipeline.Name+".gemspec") + f, _ := os.Create(src) + defer os.RemoveAll(tmp) + defer f.Close() err := b.ExecuteBuild(p) if err == nil { t.Fatal("no error found while expecting error.") @@ -93,11 +111,10 @@ func TestExecuteBuildContextTimeoutCpp(t *testing.T) { } } -func TestExecuteBuildBinaryNotFoundErrorCpp(t *testing.T) { - tmp, _ := ioutil.TempDir("", "TestExecuteBuildBinaryNotFoundErrorCpp") +func TestExecuteBuildBinaryNotFoundErrorRuby(t *testing.T) { + tmp, _ := ioutil.TempDir("", "TestExecuteBuildBinaryNotFoundErrorRuby") gaia.Cfg = new(gaia.Config) gaia.Cfg.HomePath = tmp - // Initialize shared logger buf := new(bytes.Buffer) gaia.Cfg.Logger = hclog.New(&hclog.LoggerOptions{ Level: hclog.Trace, @@ -107,19 +124,19 @@ func TestExecuteBuildBinaryNotFoundErrorCpp(t *testing.T) { currentPath := os.Getenv("PATH") defer func() { os.Setenv("PATH", currentPath) }() os.Setenv("PATH", "") - b := new(BuildPipelineCpp) + b := new(BuildPipelineRuby) p := new(gaia.CreatePipeline) err := b.ExecuteBuild(p) if err == nil { t.Fatal("no error found while expecting error.") } - if err.Error() != "exec: \"make\": executable file not found in $PATH" { + if err.Error() != "exec: \"gem\": executable file not found in $PATH" { t.Fatal("the error wasn't what we expected. instead it was: ", err) } } -func TestCopyBinaryCpp(t *testing.T) { - tmp, _ := ioutil.TempDir("", "TestCopyBinaryCpp") +func TestCopyBinaryRuby(t *testing.T) { + tmp, _ := ioutil.TempDir("", "TestCopyBinaryRuby") gaia.Cfg = new(gaia.Config) gaia.Cfg.HomePath = tmp // Initialize shared logger @@ -129,12 +146,12 @@ func TestCopyBinaryCpp(t *testing.T) { Output: buf, Name: "Gaia", }) - b := new(BuildPipelineCpp) + b := new(BuildPipelineRuby) p := new(gaia.CreatePipeline) p.Pipeline.Name = "main" - p.Pipeline.Type = gaia.PTypeCpp + p.Pipeline.Type = gaia.PTypeRuby p.Pipeline.Repo.LocalDest = tmp - src := filepath.Join(tmp, cppFinalBinaryName) + src := filepath.Join(tmp, "test.gem") dst := appendTypeToName(p.Pipeline.Name, p.Pipeline.Type) f, _ := os.Create(src) defer f.Close() @@ -153,8 +170,8 @@ func TestCopyBinaryCpp(t *testing.T) { } } -func TestCopyBinarySrcDoesNotExistCpp(t *testing.T) { - tmp, _ := ioutil.TempDir("", "TestCopyBinarySrcDoesNotExistCpp") +func TestCopyBinarySrcDoesNotExistRuby(t *testing.T) { + tmp, _ := ioutil.TempDir("", "TestCopyBinarySrcDoesNotExistRuby") gaia.Cfg = new(gaia.Config) gaia.Cfg.HomePath = tmp // Initialize shared logger @@ -164,31 +181,31 @@ func TestCopyBinarySrcDoesNotExistCpp(t *testing.T) { Output: buf, Name: "Gaia", }) - b := new(BuildPipelineCpp) + b := new(BuildPipelineRuby) p := new(gaia.CreatePipeline) p.Pipeline.Name = "main" - p.Pipeline.Type = gaia.PTypeCpp + p.Pipeline.Type = gaia.PTypeRuby p.Pipeline.Repo.LocalDest = "/noneexistent" err := b.CopyBinary(p) if err == nil { t.Fatal("error was expected when copying binary but none occurred ") } - if err.Error() != "open /noneexistent/"+cppFinalBinaryName+": no such file or directory" { + if err.Error() != "open /noneexistent: no such file or directory" { t.Fatal("a different error occurred then expected: ", err) } } -type cppMockStorer struct { +type rubyMockStorer struct { store.GaiaStore Error error } // PipelinePut is a Mock implementation for pipelines -func (m *cppMockStorer) PipelinePut(p *gaia.Pipeline) error { +func (m *rubyMockStorer) PipelinePut(p *gaia.Pipeline) error { return m.Error } -func TestSavePipelineCpp(t *testing.T) { +func TestSavePipelineRuby(t *testing.T) { defer os.Remove("gaia.db") gaia.Cfg = new(gaia.Config) gaia.Cfg.HomePath = "/tmp" @@ -196,9 +213,9 @@ func TestSavePipelineCpp(t *testing.T) { // Initialize shared logger p := new(gaia.Pipeline) p.Name = "main" - p.Type = gaia.PTypeCpp - b := new(BuildPipelineCpp) - m := new(cppMockStorer) + p.Type = gaia.PTypeRuby + b := new(BuildPipelineRuby) + m := new(rubyMockStorer) services.MockStorageService(m) err := b.SavePipeline(p) if err != nil { @@ -207,12 +224,12 @@ func TestSavePipelineCpp(t *testing.T) { if p.Name != "main" { t.Fatal("name of pipeline didn't equal expected 'main'. was instead: ", p.Name) } - if p.Type != gaia.PTypeCpp { - t.Fatal("type of pipeline was not cpp. instead was: ", p.Type) + if p.Type != gaia.PTypeRuby { + t.Fatal("type of pipeline was not ruby. instead was: ", p.Type) } } -func TestSavePipelineSaveErrorsCpp(t *testing.T) { +func TestSavePipelineSaveErrorsRuby(t *testing.T) { defer os.Remove("gaia.db") gaia.Cfg = new(gaia.Config) gaia.Cfg.HomePath = "/tmp" @@ -221,8 +238,8 @@ func TestSavePipelineSaveErrorsCpp(t *testing.T) { p := new(gaia.Pipeline) p.Name = "main" p.Type = gaia.PTypeCpp - b := new(BuildPipelineCpp) - m := new(cppMockStorer) + b := new(BuildPipelineRuby) + m := new(rubyMockStorer) m.Error = errors.New("database error") services.MockStorageService(m) err := b.SavePipeline(p) diff --git a/workers/pipeline/testacc/build_pipeline_test.go b/workers/pipeline/testacc/build_pipeline_test.go index 47389a21..83aac3d4 100644 --- a/workers/pipeline/testacc/build_pipeline_test.go +++ b/workers/pipeline/testacc/build_pipeline_test.go @@ -40,6 +40,7 @@ func TestBuildPipelineAcceptanceTestTearUp(t *testing.T) { t.Run("BuildJavaPluginTest", buildJavaPluginTest) t.Run("BuildPythonPluginTest", buildPythonPluginTest) t.Run("BuildCppPluginTest", buildCppPluginTest) + t.Run("BuildRubyPluginTest", buildRubyPluginTest) } func buildGoPluginTest(t *testing.T) { @@ -121,3 +122,23 @@ func buildCppPluginTest(t *testing.T) { t.Errorf("create cpp pipeline failed: %s", testPipeline.Output) } } + +func buildRubyPluginTest(t *testing.T) { + // Create test pipeline. + testPipeline := &gaia.CreatePipeline{ + ID: uuid.Must(uuid.NewV4(), nil).String(), + Pipeline: gaia.Pipeline{ + Name: "RubyTestPipeline", + Type: gaia.PTypeRuby, + Repo: gaia.GitRepo{URL: "https://github.com/gaia-pipeline/ruby-example"}, + }, + } + + // Build pipeline. + pipeline.CreatePipeline(testPipeline) + + // Check if everything went smoothly. + if testPipeline.StatusType == gaia.CreatePipelineFailed { + t.Errorf("create ruby pipeline failed: %s", testPipeline.Output) + } +} From e12f4c8bf3e70b274c00a831d32a58c7f53ce0c6 Mon Sep 17 00:00:00 2001 From: Michel Vocks Date: Thu, 17 Jan 2019 12:17:57 +0100 Subject: [PATCH 05/12] Removed unnessesary test --- go.mod | 32 +++++++++++- go.sum | 77 +++++++++++++++++++++++++++++ workers/pipeline/build_ruby_test.go | 25 +--------- 3 files changed, 108 insertions(+), 26 deletions(-) diff --git a/go.mod b/go.mod index c66417ac..8a160418 100644 --- a/go.mod +++ b/go.mod @@ -2,47 +2,75 @@ module github.com/gaia-pipeline/gaia require ( github.com/GeertJohan/go.rice v0.0.0-20170420135705-c02ca9a983da + github.com/alecthomas/gometalinter v2.0.12+incompatible // indirect + github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf // indirect github.com/coreos/bbolt v1.3.0 + github.com/cosiner/argv v0.0.1 // indirect github.com/daaku/go.zipexe v0.0.0-20150329023125-a5fe2436ffcb + github.com/davidrjenni/reftools v0.0.0-20180914123528-654d0ba4f96d // indirect + github.com/derekparker/delve v1.1.0 // indirect github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/emirpasic/gods v1.9.0 + github.com/fatih/gomodifytags v0.0.0-20180914191908-141225bf62b6 // indirect + github.com/fatih/motion v0.0.0-20180408211639-218875ebe238 // indirect github.com/gaia-pipeline/flag v1.7.4-pre github.com/gaia-pipeline/protobuf v0.0.0-20180812091451-7be8a901b55a github.com/golang/protobuf v1.1.0 github.com/google/go-github v15.0.0+incompatible github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135 + github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf // indirect github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd github.com/hashicorp/go-plugin v0.0.0-20180331002553-e8d22c780116 github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 + github.com/josharian/impl v0.0.0-20180228163738-3d0f908298c4 // indirect + github.com/jstemmer/gotags v1.4.1 // indirect github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1 github.com/kevinburke/ssh_config v0.0.0-20180317175531-9fc7bb800b55 + github.com/kisielk/errcheck v1.2.0 // indirect + github.com/klauspost/asmfmt v1.2.0 // indirect + github.com/koron/iferr v0.0.0-20180615142939-bb332a3b1d91 // indirect github.com/labstack/echo v3.3.5+incompatible github.com/labstack/gommon v0.0.0-20180613044413-d6898124de91 github.com/mattn/go-colorable v0.0.9 github.com/mattn/go-isatty v0.0.3 + github.com/mdempsky/gocode v0.0.0-20181226182234-be056ad32a5e // indirect github.com/mitchellh/go-homedir v0.0.0-20180801233206-58046073cbff github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77 + github.com/nicksnyder/go-i18n v1.10.0 // indirect github.com/oklog/run v1.0.0 github.com/pelletier/go-buffruneio v0.2.0 + github.com/pelletier/go-toml v1.2.0 // indirect + github.com/peterh/liner v1.1.0 // indirect github.com/robfig/cron v0.0.0-20180505203441-b41be1df6967 + github.com/rogpeppe/godef v1.1.1 // indirect github.com/satori/go.uuid v1.2.0 github.com/sergi/go-diff v1.0.0 + github.com/sirupsen/logrus v1.3.0 // indirect + github.com/spf13/cobra v0.0.3 // indirect + github.com/spf13/pflag v1.0.3 // indirect github.com/src-d/gcfg v1.3.0 + github.com/stamblerre/gocode v0.0.0-20181212030458-2f9d39d8f31d // indirect github.com/stretchr/testify v1.3.0 // indirect github.com/valyala/bytebufferpool v1.0.0 github.com/valyala/fasttemplate v0.0.0-20170224212429-dcecefd839c4 github.com/xanzy/ssh-agent v0.2.0 - golang.org/x/crypto v0.0.0-20180808211826-de0752318171 + github.com/zmb3/gogetdoc v0.0.0-20190107174152-de0ca1d07687 // indirect + golang.org/x/arch v0.0.0-20181203225421-5a4828bb7045 // indirect + golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 + golang.org/x/lint v0.0.0-20181217174547-8f45f776aaf1 // indirect golang.org/x/net v0.0.0-20180811021610-c39426892332 golang.org/x/oauth2 v0.0.0-20180724155351-3d292e4d0cdc - golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0 + golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33 golang.org/x/text v0.0.0-20180810153555-6e3c4e7365dd + golang.org/x/tools v0.0.0-20190116231616-b258f6da2383 // indirect google.golang.org/appengine v1.1.0 google.golang.org/genproto v0.0.0-20180808183934-383e8b2c3b9e google.golang.org/grpc v1.14.0 + gopkg.in/alecthomas/kingpin.v3-unstable v3.0.0-20180810215634-df19058c872c // indirect gopkg.in/src-d/go-billy.v4 v4.2.0 gopkg.in/src-d/go-git.v4 v4.5.0 gopkg.in/warnings.v0 v0.1.2 gopkg.in/yaml.v2 v2.2.2 + honnef.co/go/tools v0.0.0-20190109154334-5bcec433c8ea // indirect ) diff --git a/go.sum b/go.sum index b4fb41f1..94a00c76 100644 --- a/go.sum +++ b/go.sum @@ -1,15 +1,36 @@ +9fans.net/go v0.0.0-20181112161441-237454027057 h1:OcHlKWkAMJEF1ndWLGxp5dnJQkYM/YImUOvsBoz6h5E= +9fans.net/go v0.0.0-20181112161441-237454027057/go.mod h1:diCsxrliIURU9xsYtjCp5AbpQKqdhKmf0ujWDUSkfoY= github.com/GeertJohan/go.rice v0.0.0-20170420135705-c02ca9a983da h1:UVU3a9pRUyLdnBtn60WjRl0s4SEyJc2ChCY56OAR6wI= github.com/GeertJohan/go.rice v0.0.0-20170420135705-c02ca9a983da/go.mod h1:DgrzXonpdQbfN3uYaGz1EG4Sbhyum/MMIn6Cphlh2bw= +github.com/alecthomas/gometalinter v2.0.12+incompatible h1:RBUbc8pKtqRoVCymENDl7cpWS9Ht5XNnwwk0cKjpteI= +github.com/alecthomas/gometalinter v2.0.12+incompatible/go.mod h1:qfIpQGGz3d+NmgyPBqv+LSh50emm1pt72EtcX2vKYQk= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/coreos/bbolt v1.3.0 h1:HIgH5xUWXT914HCI671AxuTTqjj64UOFr7pHn48LUTI= github.com/coreos/bbolt v1.3.0/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/cosiner/argv v0.0.1 h1:2iAFN+sWPktbZ4tvxm33Ei8VY66FPCxdOxpncUGpAXE= +github.com/cosiner/argv v0.0.1/go.mod h1:p/NrK5tF6ICIly4qwEDsf6VDirFiWWz0FenfYBwJaKQ= github.com/daaku/go.zipexe v0.0.0-20150329023125-a5fe2436ffcb h1:tUf55Po0vzOendQ7NWytcdK0VuzQmfAgvGBUOQvN0WA= github.com/daaku/go.zipexe v0.0.0-20150329023125-a5fe2436ffcb/go.mod h1:U0vRfAucUOohvdCxt5MWLF+TePIL0xbCkbKIiV8TQCE= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davidrjenni/reftools v0.0.0-20180914123528-654d0ba4f96d h1:aRvyac5PN1NEfcANJ1tfs8GMs5I9OXsVeg0FJkpXOys= +github.com/davidrjenni/reftools v0.0.0-20180914123528-654d0ba4f96d/go.mod h1:8o/GRMvsb9VyFbSEZGXfa0dkSXml4G23W0D/h9FksWM= +github.com/derekparker/delve v1.1.0 h1:icd65nMp7s2HiLz6y/6RCVXBdoED3xxYLwX09EMaRCc= +github.com/derekparker/delve v1.1.0/go.mod h1:pMSZMfp0Nhbm8qdZJkuE/yPGOkLpGXLS1I4poXQpuJU= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/emirpasic/gods v1.9.0 h1:rUF4PuzEjMChMiNsVjdI+SyLu7rEqpQ5reNFnhC7oFo= github.com/emirpasic/gods v1.9.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= +github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8= +github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= +github.com/fatih/gomodifytags v0.0.0-20180914191908-141225bf62b6 h1:iXJdM8Uob6EPOG/PFr5q0J124ysiZdJfACHqICBb3b8= +github.com/fatih/gomodifytags v0.0.0-20180914191908-141225bf62b6/go.mod h1:p2/x7bnOQsbq/deXsDIlj2yLiKFGPkD2nuoYqwn8R4Y= +github.com/fatih/motion v0.0.0-20180408211639-218875ebe238 h1:Qo4RxRMFag+fvDqQ6A3MblYBormptQUZ1ssOtV+EeQ8= +github.com/fatih/motion v0.0.0-20180408211639-218875ebe238/go.mod h1:pseIrV+t9A4+po+KJ1LheSnYH8m1qs6WhKx2zFiGi9I= +github.com/fatih/structtag v1.0.0 h1:pTHj65+u3RKWYPSGaU290FpI/dXxTaHdVwVwbcPKmEc= +github.com/fatih/structtag v1.0.0/go.mod h1:IKitwq45uXL/yqi5mYghiD3w9H6eTOvI9vnk8tXMphA= github.com/gaia-pipeline/flag v1.7.4-pre h1:/TAmHVYVQGE4Mw9xl0Qs0D5UruVDMF95thexyEFbTAY= github.com/gaia-pipeline/flag v1.7.4-pre/go.mod h1:rLpsWzqOEPa2K0Yl4aC34nmblLpIYjGqjP/srZbYvEk= github.com/gaia-pipeline/protobuf v0.0.0-20180812091451-7be8a901b55a h1:/5XAmdAyGl4yL9BugdPdBLaXquif1zw6Hih6go8E7Xs= @@ -20,6 +41,8 @@ github.com/google/go-github v15.0.0+incompatible h1:jlPg2Cpsxb/FyEV/MFiIE9tW/2RA github.com/google/go-github v15.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135 h1:zLTLjkaOFEFIOxY5BWLFLwh+cL8vOBW4XJ2aqLE/Tf0= github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf h1:7+FW5aGwISbqUtkfmIpZJGRgNFg2ioYPvFaUxdqpDsg= +github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf/go.mod h1:RpwtwJQFrIEPstU94h88MWPXP2ektJZ8cZ0YntAmXiE= github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd h1:rNuUHR+CvK1IS89MMtcF0EpcVMZtjKfPRp4MEmt/aTs= github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= github.com/hashicorp/go-plugin v0.0.0-20180331002553-e8d22c780116 h1:Y4V/yReWjQo/Ngyc0w6C3EKXKincp4YgvXeo8lI4LrI= @@ -28,10 +51,21 @@ github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +github.com/josharian/impl v0.0.0-20180228163738-3d0f908298c4 h1:gmIVMdGlVf5e6Yo6+ZklxdOrvtOvyrAjJyXAbmOznyo= +github.com/josharian/impl v0.0.0-20180228163738-3d0f908298c4/go.mod h1:t4Tr0tn92eq5ISef4cS5plFAMYAqZlAXtgUcKE6y8nw= +github.com/jstemmer/gotags v1.4.1 h1:aWIyXsU3lTDqhsEC49MP85p2cUUWr2ptvdGNqqGA3r4= +github.com/jstemmer/gotags v1.4.1/go.mod h1:b6J3X0bsLbR4C5SgSx3V3KjuWTtmRzcmWPbTkWZ49PA= github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1 h1:PJPDf8OUfOK1bb/NeTKd4f1QXZItOX389VN3B6qC8ro= github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= github.com/kevinburke/ssh_config v0.0.0-20180317175531-9fc7bb800b55 h1:S38dC4mEwxdw/U41+97VWdbun8mTcTjwg5Ujfg8QPME= github.com/kevinburke/ssh_config v0.0.0-20180317175531-9fc7bb800b55/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/kisielk/errcheck v1.2.0 h1:reN85Pxc5larApoH1keMBiu2GWtPqXQ1nc9gx+jOU+E= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/klauspost/asmfmt v1.2.0 h1:zwsyBYgEdabg32alMful/5pRtMTcR5C5w1LKNg9OD78= +github.com/klauspost/asmfmt v1.2.0/go.mod h1:RAoUvqkWr2rUa2I19qKMEVZQe4BVtcHGTMCUOcCU2Lg= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/koron/iferr v0.0.0-20180615142939-bb332a3b1d91 h1:hunjgdb3b21ZdRmzDPXii0EcnHpjH7uCP+kODoE1JH0= +github.com/koron/iferr v0.0.0-20180615142939-bb332a3b1d91/go.mod h1:C2tFh8w3I6i4lnUJfoBx2Hwku3mgu4wPNTtUNp1i5KI= github.com/labstack/echo v3.3.5+incompatible h1:9PfxPUmasKzeJor9uQTaXLT6WUG/r+vSTmvXxvv3JO4= github.com/labstack/echo v3.3.5+incompatible/go.mod h1:0INS7j/VjnFxD4E2wkz67b8cVwCLbBmJyDaka6Cmk1s= github.com/labstack/gommon v0.0.0-20180613044413-d6898124de91 h1:6R2WAx0PYNGtK2ZED9xKlTGEha51GsCFZijom+NMGEk= @@ -40,25 +74,47 @@ github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRU github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-isatty v0.0.3 h1:ns/ykhmWi7G9O+8a448SecJU3nSMBXJfqQkl0upE1jI= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-runewidth v0.0.3 h1:a+kO+98RDGEfo6asOGMmpodZq4FNtnGP54yps8BzLR4= +github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mdempsky/gocode v0.0.0-20181226182234-be056ad32a5e h1:izuz4mCsxWEajlt9EXVowXPciDGsgn8bDEqylsz98Rw= +github.com/mdempsky/gocode v0.0.0-20181226182234-be056ad32a5e/go.mod h1:hltEC42XzfMNgg0S1v6JTywwra2Mu6F6cLR03debVQ8= github.com/mitchellh/go-homedir v0.0.0-20180801233206-58046073cbff h1:jM4Eo4qMmmcqePS3u6X2lcEELtVuXWkWJIS/pRI3oSk= github.com/mitchellh/go-homedir v0.0.0-20180801233206-58046073cbff/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77 h1:7GoSOOW2jpsfkntVKaS2rAr1TJqfcxotyaUcuxoZSzg= github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/nicksnyder/go-i18n v1.10.0 h1:5AzlPKvXBH4qBzmZ09Ua9Gipyruv6uApMcrNZdo96+Q= +github.com/nicksnyder/go-i18n v1.10.0/go.mod h1:HrK7VCrbOvQoUAQ7Vpy7i87N7JZZZ7R2xBGjv0j365Q= github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/pelletier/go-buffruneio v0.2.0 h1:U4t4R6YkofJ5xHm3dJzuRpPZ0mr5MMCoAWooScCR7aA= github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= +github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/peterh/liner v1.1.0 h1:f+aAedNJA6uk7+6rXsYBnhdo4Xux7ESLe+kcuVUF5os= +github.com/peterh/liner v1.1.0/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/robfig/cron v0.0.0-20180505203441-b41be1df6967 h1:x7xEyJDP7Hv3LVgvWhzioQqbC/KtuUhTigKlH/8ehhE= github.com/robfig/cron v0.0.0-20180505203441-b41be1df6967/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k= +github.com/rogpeppe/godef v1.1.1 h1:NujOtt9q9vIClRTB3sCZpavac+NMRaIayzrcz1h4fSE= +github.com/rogpeppe/godef v1.1.1/go.mod h1:oEo1eMy1VUEHUzUIX4F7IqvMJRiz9UId44mvnR8oPlQ= github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/sirupsen/logrus v1.3.0 h1:hI/7Q+DtNZ2kINb6qt/lS+IyXnHQe9e90POfeewL/ME= +github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/src-d/gcfg v1.3.0 h1:2BEDr8r0I0b8h/fOqwtxCEiq2HJu8n2JGZJQFGXWLjg= github.com/src-d/gcfg v1.3.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI= +github.com/stamblerre/gocode v0.0.0-20181212030458-2f9d39d8f31d h1:Bpu5DolLksGPpggDvoP5l9aruCElc6a47pHOSWwL74A= +github.com/stamblerre/gocode v0.0.0-20181212030458-2f9d39d8f31d/go.mod h1:EM2T8YDoTCvGXbEpFHxarbpv7VE26QD1++Cb1Pbh7Gs= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= @@ -67,20 +123,39 @@ github.com/valyala/fasttemplate v0.0.0-20170224212429-dcecefd839c4 h1:gKMu1Bf6QI github.com/valyala/fasttemplate v0.0.0-20170224212429-dcecefd839c4/go.mod h1:50wTf68f99/Zt14pr046Tgt3Lp2vLyFZKzbFXTOabXw= github.com/xanzy/ssh-agent v0.2.0 h1:Adglfbi5p9Z0BmK2oKU9nTG+zKfniSfnaMYB+ULd+Ro= github.com/xanzy/ssh-agent v0.2.0/go.mod h1:0NyE30eGUDliuLEHJgYte/zncp2zdTStcOnWhgSqHD8= +github.com/zmb3/gogetdoc v0.0.0-20190107174152-de0ca1d07687 h1:bXLRtvvH+pbCL8/Mnqogsh1uk6WiCpWAubhwNmVlTAo= +github.com/zmb3/gogetdoc v0.0.0-20190107174152-de0ca1d07687/go.mod h1:ofmGw6LrMypycsiWcyug6516EXpIxSbZ+uI9ppGypfY= +golang.org/x/arch v0.0.0-20181203225421-5a4828bb7045 h1:Pn8fQdvx+z1avAi7fdM2kRYWQNxGlavNDSyzrQg2SsU= +golang.org/x/arch v0.0.0-20181203225421-5a4828bb7045/go.mod h1:cYlCBUl1MsqxdiKgmc4uh7TxZfWSFLOGSRR090WDxt8= golang.org/x/crypto v0.0.0-20180808211826-de0752318171 h1:vYogbvSFj2YXcjQxFHu/rASSOt9sLytpCaSkiwQ135I= golang.org/x/crypto v0.0.0-20180808211826-de0752318171/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 h1:u+LnwYTOOW7Ukr/fppxEb1Nwz0AtPflrblfvUudpo+I= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/lint v0.0.0-20181217174547-8f45f776aaf1 h1:rJm0LuqUjoDhSk2zO9ISMSToQxGz7Os2jRiOL8AWu4c= +golang.org/x/lint v0.0.0-20181217174547-8f45f776aaf1/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/net v0.0.0-20180811021610-c39426892332 h1:efGso+ep0DjyCBJPjvoz0HI6UldX4Md2F1rZFe1ir0E= golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/oauth2 v0.0.0-20180724155351-3d292e4d0cdc h1:3ElrZeO6IBP+M8kgu5YFwRo92Gqr+zBg3aooYQ6ziqU= golang.org/x/oauth2 v0.0.0-20180724155351-3d292e4d0cdc/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0 h1:8H8QZJ30plJyIVj60H3lr8TZGIq2Fh3Cyrs/ZNg1foU= golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33 h1:I6FyU15t786LL7oL/hn43zqTuEGr4PN7F4XJ1p4E3Y8= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/text v0.0.0-20180810153555-6e3c4e7365dd h1:e/dojZNNKqwK3xq7UQTKTQJim18r/FxvQk7PFXULeZg= golang.org/x/text v0.0.0-20180810153555-6e3c4e7365dd/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20180824175216-6c1c5e93cdc1/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181130195746-895048a75ecf/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181207195948-8634b1ecd393/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190116231616-b258f6da2383 h1:CWP4O+Q3OaGBOLxV1/YRnzRSpvZYJlauwRUu3auRH5s= +golang.org/x/tools v0.0.0-20190116231616-b258f6da2383/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/genproto v0.0.0-20180808183934-383e8b2c3b9e h1:8mImbC+7codRhTIUj7Js3/j98gpxyF7C4RlC0OdGh64= google.golang.org/genproto v0.0.0-20180808183934-383e8b2c3b9e/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/grpc v1.14.0 h1:ArxJuB1NWfPY6r9Gp9gqwplT0Ge7nqv9msgu03lHLmo= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +gopkg.in/alecthomas/kingpin.v3-unstable v3.0.0-20180810215634-df19058c872c h1:vTxShRUnK60yd8DZU+f95p1zSLj814+5CuEh7NjF2/Y= +gopkg.in/alecthomas/kingpin.v3-unstable v3.0.0-20180810215634-df19058c872c/go.mod h1:3HH7i1SgMqlzxCcBmUHW657sD4Kvv9sC3HpL3YukzwA= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/src-d/go-billy.v4 v4.2.0 h1:VGbrP1EsYxtvVPEiHui+4//imr4E5MGEFLx66bQtusg= gopkg.in/src-d/go-billy.v4 v4.2.0/go.mod h1:ZHSF0JP+7oD97194otDUCD7Ofbk63+xFcfWP5bT6h+Q= @@ -90,3 +165,5 @@ gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +honnef.co/go/tools v0.0.0-20190109154334-5bcec433c8ea h1:Mqe+pbbXrgs4O/B8PTc7PMpbZ1YCzT0YAz8FHqE8AcM= +honnef.co/go/tools v0.0.0-20190109154334-5bcec433c8ea/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/workers/pipeline/build_ruby_test.go b/workers/pipeline/build_ruby_test.go index 694a972a..7f1c7713 100644 --- a/workers/pipeline/build_ruby_test.go +++ b/workers/pipeline/build_ruby_test.go @@ -66,6 +66,7 @@ func TestExecuteBuildRuby(t *testing.T) { resultFile, _ := os.Create(dst) defer resultFile.Close() ioutil.WriteFile(dst, []byte("testcontent"), 0666) + gemBinaryName = "go" err := b.ExecuteBuild(p) if err != nil { t.Fatalf("error while running executebuild. none was expected: %s", err.Error()) @@ -111,30 +112,6 @@ func TestExecuteBuildContextTimeoutRuby(t *testing.T) { } } -func TestExecuteBuildBinaryNotFoundErrorRuby(t *testing.T) { - tmp, _ := ioutil.TempDir("", "TestExecuteBuildBinaryNotFoundErrorRuby") - gaia.Cfg = new(gaia.Config) - gaia.Cfg.HomePath = tmp - buf := new(bytes.Buffer) - gaia.Cfg.Logger = hclog.New(&hclog.LoggerOptions{ - Level: hclog.Trace, - Output: buf, - Name: "Gaia", - }) - currentPath := os.Getenv("PATH") - defer func() { os.Setenv("PATH", currentPath) }() - os.Setenv("PATH", "") - b := new(BuildPipelineRuby) - p := new(gaia.CreatePipeline) - err := b.ExecuteBuild(p) - if err == nil { - t.Fatal("no error found while expecting error.") - } - if err.Error() != "exec: \"gem\": executable file not found in $PATH" { - t.Fatal("the error wasn't what we expected. instead it was: ", err) - } -} - func TestCopyBinaryRuby(t *testing.T) { tmp, _ := ioutil.TempDir("", "TestCopyBinaryRuby") gaia.Cfg = new(gaia.Config) From 6c4c052240da172625a1c0245950f7e06eb861f6 Mon Sep 17 00:00:00 2001 From: Michel Vocks Date: Thu, 17 Jan 2019 13:05:24 +0100 Subject: [PATCH 06/12] Added more tests --- workers/pipeline/pipeline_test.go | 8 +++++ workers/pipeline/update_pipeline.go | 2 +- workers/pipeline/update_pipeline_test.go | 33 +++++++++++++++++ workers/scheduler/scheduler.go | 5 ++- workers/scheduler/scheduler_test.go | 46 ++++++++++++++++++++++++ 5 files changed, 92 insertions(+), 2 deletions(-) diff --git a/workers/pipeline/pipeline_test.go b/workers/pipeline/pipeline_test.go index 27b59d49..516b05ad 100644 --- a/workers/pipeline/pipeline_test.go +++ b/workers/pipeline/pipeline_test.go @@ -359,4 +359,12 @@ func TestNewBuildPipeline(t *testing.T) { if pythonBuildPipeline == nil { t.Errorf("should be of type %s but is nil\n", gaia.PTypePython) } + cppBuildPipeline := newBuildPipeline(gaia.PTypeCpp) + if cppBuildPipeline == nil { + t.Errorf("should be of type %s but is nil\n", gaia.PTypeCpp) + } + rubyBuildPipeline := newBuildPipeline(gaia.PTypeRuby) + if rubyBuildPipeline == nil { + t.Errorf("should be of type %s but is nil\n", gaia.PTypeRuby) + } } diff --git a/workers/pipeline/update_pipeline.go b/workers/pipeline/update_pipeline.go index 8f850562..2a4d8d30 100644 --- a/workers/pipeline/update_pipeline.go +++ b/workers/pipeline/update_pipeline.go @@ -78,7 +78,7 @@ func updatePipeline(p *gaia.Pipeline) error { // Install gem forcefully. cmd := exec.Command(path, "install", "-f", pipelineCopyPath) if out, err := cmd.CombinedOutput(); err != nil { - gaia.Cfg.Logger.Debug("error", string(out[:])) + gaia.Cfg.Logger.Error("error", string(out[:])) return err } } diff --git a/workers/pipeline/update_pipeline_test.go b/workers/pipeline/update_pipeline_test.go index 64bfd0cf..d16de6df 100644 --- a/workers/pipeline/update_pipeline_test.go +++ b/workers/pipeline/update_pipeline_test.go @@ -55,3 +55,36 @@ func TestUpdatePipelinePython(t *testing.T) { t.Fatalf("distribution file does not exist: %s", err.Error()) } } + +func TestUpdatePipelineRuby(t *testing.T) { + tmp, _ := ioutil.TempDir("", "TestUpdatePipelineRuby") + gaia.Cfg = new(gaia.Config) + gaia.Cfg.HomePath = tmp + buf := new(bytes.Buffer) + gaia.Cfg.Logger = hclog.New(&hclog.LoggerOptions{ + Level: hclog.Trace, + Output: buf, + Name: "Gaia", + }) + + p1 := gaia.Pipeline{ + Name: "PipelinA", + Type: gaia.PTypeRuby, + Created: time.Now(), + } + + // Create fake test gem file. + src := filepath.Join(tmp, "PipelineA_ruby") + p1.ExecPath = src + defer os.RemoveAll(tmp) + ioutil.WriteFile(src, []byte("testcontent"), 0666) + + // fake execution commands + rubyGemName = "echo" + + // run + err := updatePipeline(&p1) + if err != nil { + t.Fatal(err) + } +} diff --git a/workers/scheduler/scheduler.go b/workers/scheduler/scheduler.go index 3709757f..5a68ccb2 100644 --- a/workers/scheduler/scheduler.go +++ b/workers/scheduler/scheduler.go @@ -800,6 +800,8 @@ func (s *Scheduler) finishPipelineRun(r *gaia.PipelineRun, status gaia.PipelineR } } +var findRubyGemCommands = []string{"specification", "--yaml"} + // findRubyGemName finds the gem name of a ruby gem file. func findRubyGemName(execPath string) (name string, err error) { // Find the gem binary path. @@ -809,7 +811,8 @@ func findRubyGemName(execPath string) (name string, err error) { } // Get the gem specification in YAML format. - cmd := exec.Command(path, "specification", "--yaml", execPath) + findRubyGemCommands = append(findRubyGemCommands, execPath) + cmd := exec.Command(path, findRubyGemCommands...) output, err := cmd.Output() if err != nil { return diff --git a/workers/scheduler/scheduler_test.go b/workers/scheduler/scheduler_test.go index c20d87e3..a2f4c060 100644 --- a/workers/scheduler/scheduler_test.go +++ b/workers/scheduler/scheduler_test.go @@ -286,6 +286,52 @@ func TestPrepareAndExecCppType(t *testing.T) { } } +func TestPrepareAndExecRubyType(t *testing.T) { + gaia.Cfg = &gaia.Config{} + storeInstance := store.NewBoltStore() + tmp, _ := ioutil.TempDir("", "TestPrepareAndExecRubyType") + gaia.Cfg.DataPath = tmp + gaia.Cfg.WorkspacePath = filepath.Join(tmp, "tmp") + gaia.Cfg.Bolt.Mode = 0600 + gaia.Cfg.Logger = hclog.New(&hclog.LoggerOptions{ + Level: hclog.Trace, + Output: hclog.DefaultOutput, + Name: "Gaia", + }) + + if err := storeInstance.Init(); err != nil { + t.Fatal(err) + } + p, r := prepareTestData() + p.Type = gaia.PTypeRuby + rubyExecName = "go" + rubyGemName = "echo" + findRubyGemCommands = []string{"name: rubytest"} + storeInstance.PipelinePut(&p) + s := NewScheduler(storeInstance, &PluginFake{}, &CAFake{}, &VaultFake{}) + s.prepareAndExec(r) + + // get pipeline run from store + run, err := storeInstance.PipelineGetRunByPipelineIDAndID(p.ID, r.ID) + if err != nil { + t.Fatal(err) + } + + // jobs should be existent + if len(run.Jobs) == 0 { + t.Fatal("No jobs in pipeline run found.") + } + + // Iterate jobs + for _, job := range run.Jobs { + if job.Status != gaia.JobSuccess { + t.Fatalf("job status should be success but was %s", string(job.Status)) + } else { + t.Logf("Job %s has been executed...", job.Title) + } + } +} + func TestSchedulePipeline(t *testing.T) { gaia.Cfg = &gaia.Config{} storeInstance := store.NewBoltStore() From 6e50cf2d451685c1787335675e046459730c70f6 Mon Sep 17 00:00:00 2001 From: Michel Vocks Date: Thu, 17 Jan 2019 17:46:06 +0100 Subject: [PATCH 07/12] Fixed small bug --- workers/scheduler/create_cmd.go | 109 ++++++++++++++++++++++++++++++++ workers/scheduler/scheduler.go | 100 ----------------------------- 2 files changed, 109 insertions(+), 100 deletions(-) create mode 100644 workers/scheduler/create_cmd.go diff --git a/workers/scheduler/create_cmd.go b/workers/scheduler/create_cmd.go new file mode 100644 index 00000000..92b162ac --- /dev/null +++ b/workers/scheduler/create_cmd.go @@ -0,0 +1,109 @@ +package scheduler + +import ( + "os/exec" + "path/filepath" + + "github.com/gaia-pipeline/gaia" + yaml "gopkg.in/yaml.v2" +) + +// createPipelineCmd creates the execute command for the plugin system +// dependent on the plugin type. +func createPipelineCmd(p *gaia.Pipeline) *exec.Cmd { + c := &exec.Cmd{} + + // Dependent on the pipeline type + switch p.Type { + case gaia.PTypeGolang: + c.Path = p.ExecPath + case gaia.PTypeJava: + // Look for java executable + path, err := exec.LookPath(javaExecName) + if err != nil { + gaia.Cfg.Logger.Error("cannot find java executable", "error", err.Error()) + return nil + } + + // Build start command + c.Path = path + c.Args = []string{ + path, + "-jar", + p.ExecPath, + } + case gaia.PTypePython: + // Build start command + c.Path = "/bin/sh" + c.Args = []string{ + "/bin/sh", + "-c", + ". bin/activate; exec " + pythonExecName + " -c \"import pipeline; pipeline.main()\"", + } + c.Dir = filepath.Join(gaia.Cfg.HomePath, gaia.TmpFolder, gaia.TmpPythonFolder, p.Name) + case gaia.PTypeCpp: + c.Path = p.ExecPath + case gaia.PTypeRuby: + // Look for ruby executable + path, err := exec.LookPath(rubyExecName) + if err != nil { + gaia.Cfg.Logger.Error("cannot find ruby executable", "error", err.Error()) + return nil + } + + // Get the gem name from the gem file. + gemName, err := findRubyGemName(p.ExecPath) + if err != nil { + gaia.Cfg.Logger.Error("cannot find the gem name from the gem file", "error", err.Error()) + return nil + } + + // Build start command + c.Path = path + c.Args = []string{ + path, + "-r", + gemName, + "-e", + "Main.main", + } + default: + c = nil + } + + return c +} + +var findRubyGemCommands = []string{"specification", "--yaml"} + +// findRubyGemName finds the gem name of a ruby gem file. +func findRubyGemName(execPath string) (name string, err error) { + // Find the gem binary path. + path, err := exec.LookPath(rubyGemName) + if err != nil { + return + } + + // Get the gem specification in YAML format. + gemCommands := append(findRubyGemCommands, execPath) + cmd := exec.Command(path, gemCommands...) + output, err := cmd.CombinedOutput() + if err != nil { + gaia.Cfg.Logger.Debug("output", "output", string(output[:])) + return + } + + // Struct helper to filter for what we need. + type gemSpecOutput struct { + Name string + } + + // Transform and filter the gem specification. + gemSpec := gemSpecOutput{} + err = yaml.Unmarshal(output, &gemSpec) + if err != nil { + return + } + name = gemSpec.Name + return +} diff --git a/workers/scheduler/scheduler.go b/workers/scheduler/scheduler.go index 5a68ccb2..e0b18a90 100644 --- a/workers/scheduler/scheduler.go +++ b/workers/scheduler/scheduler.go @@ -14,7 +14,6 @@ import ( "github.com/gaia-pipeline/gaia/security" "github.com/gaia-pipeline/gaia/store" uuid "github.com/satori/go.uuid" - yaml "gopkg.in/yaml.v2" ) const ( @@ -719,72 +718,6 @@ func (s *Scheduler) SetPipelineJobs(p *gaia.Pipeline) error { return nil } -// createPipelineCmd creates the execute command for the plugin system -// dependent on the plugin type. -func createPipelineCmd(p *gaia.Pipeline) *exec.Cmd { - c := &exec.Cmd{} - - // Dependent on the pipeline type - switch p.Type { - case gaia.PTypeGolang: - c.Path = p.ExecPath - case gaia.PTypeJava: - // Look for java executable - path, err := exec.LookPath(javaExecName) - if err != nil { - gaia.Cfg.Logger.Error("cannot find java executable", "error", err.Error()) - return nil - } - - // Build start command - c.Path = path - c.Args = []string{ - path, - "-jar", - p.ExecPath, - } - case gaia.PTypePython: - // Build start command - c.Path = "/bin/sh" - c.Args = []string{ - "/bin/sh", - "-c", - ". bin/activate; exec " + pythonExecName + " -c \"import pipeline; pipeline.main()\"", - } - c.Dir = filepath.Join(gaia.Cfg.HomePath, gaia.TmpFolder, gaia.TmpPythonFolder, p.Name) - case gaia.PTypeCpp: - c.Path = p.ExecPath - case gaia.PTypeRuby: - // Look for ruby executable - path, err := exec.LookPath(rubyExecName) - if err != nil { - gaia.Cfg.Logger.Error("cannot find ruby executable", "error", err.Error()) - return nil - } - - // Get the gem name from the gem file. - gemName, err := findRubyGemName(p.ExecPath) - if err != nil { - gaia.Cfg.Logger.Error("cannot find the gem name from the gem file", "error", err.Error()) - return nil - } - - // Build start command - c.Path = path - c.Args = []string{ - path, - "-r", - gemName, - "-e", - "Main.main", - } - default: - c = nil - } - - return c -} - // finishPipelineRun finishes the pipeline run and stores the results. func (s *Scheduler) finishPipelineRun(r *gaia.PipelineRun, status gaia.PipelineRunStatus) { // Mark pipeline run as success @@ -799,36 +732,3 @@ func (s *Scheduler) finishPipelineRun(r *gaia.PipelineRun, status gaia.PipelineR gaia.Cfg.Logger.Error("cannot store finished pipeline", "error", err.Error()) } } - -var findRubyGemCommands = []string{"specification", "--yaml"} - -// findRubyGemName finds the gem name of a ruby gem file. -func findRubyGemName(execPath string) (name string, err error) { - // Find the gem binary path. - path, err := exec.LookPath(rubyGemName) - if err != nil { - return - } - - // Get the gem specification in YAML format. - findRubyGemCommands = append(findRubyGemCommands, execPath) - cmd := exec.Command(path, findRubyGemCommands...) - output, err := cmd.Output() - if err != nil { - return - } - - // Struct helper to filter for what we need. - type gemSpecOutput struct { - Name string - } - - // Transform and filter the gem specification. - gemSpec := gemSpecOutput{} - err = yaml.Unmarshal(output, &gemSpec) - if err != nil { - return - } - name = gemSpec.Name - return -} From b8b350adb9227a3d72da407aa8b6b1f61815c5b0 Mon Sep 17 00:00:00 2001 From: Michel Vocks Date: Thu, 17 Jan 2019 18:01:04 +0100 Subject: [PATCH 08/12] Added additional test --- workers/scheduler/create_cmd_test.go | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 workers/scheduler/create_cmd_test.go diff --git a/workers/scheduler/create_cmd_test.go b/workers/scheduler/create_cmd_test.go new file mode 100644 index 00000000..efcb47dc --- /dev/null +++ b/workers/scheduler/create_cmd_test.go @@ -0,0 +1,20 @@ +package scheduler + +import "testing" + +func TestFindRubyGemName(t *testing.T) { + // Adjust gubyGemName (might be not available in test container) + rubyGemName = "echo" + + // Overwrite gem commands + findRubyGemCommands = []string{"name: testruby"} + + // Run command and compare output + gemName, err := findRubyGemName("") + if err != nil { + t.Errorf("error thrown during findRubyGemName: %s", err.Error()) + } + if gemName != "testruby" { + t.Errorf("Gem name should be 'testruby' but was %s", gemName) + } +} From 5e46edb451e51dd89bdd37495178d1ba6c87ebe2 Mon Sep 17 00:00:00 2001 From: Michel Vocks Date: Fri, 18 Jan 2019 10:01:52 +0100 Subject: [PATCH 09/12] Added new dockerfile and updated readme --- README.rst | 32 ++++++++++++++++- docker/Dockerfile | 78 +++++++++++++++++++++++++++++++++++++++++- docker/Dockerfile.ruby | 27 +++++++++++++++ go.mod | 6 +++- go.sum | 10 ++++++ 5 files changed, 150 insertions(+), 3 deletions(-) create mode 100644 docker/Dockerfile.ruby diff --git a/README.rst b/README.rst index 750660dc..dce35e4e 100644 --- a/README.rst +++ b/README.rst @@ -229,6 +229,36 @@ C++ } } +Ruby +~~~~ + +.. code:: ruby + + require 'rubysdk' + + class Main + AwesomeJob = lambda do |args| + STDERR.puts "This output will be streamed back to gaia and will be displayed in the pipeline logs." + + # An error occurred? Raise an exception and gaia will fail the pipeline. + # raise "Oh gosh! Something went wrong!" + end + + def self.main + awesomejob = Interface::Job.new(title: "Awesome Job", + handler: AwesomeJob, + desc: "This job does something awesome.") + + begin + RubySDK.Serve([awesomejob]) + rescue => e + puts "Error occured: #{e}" + exit(false) + end + end + end + + Pipelines are defined by jobs and a function usually represents a job. You can define as many jobs in your pipeline as you want. Every function accepts arguments. Those arguments can be requested from the pipeline itself and the values passed back in from the UI. @@ -270,7 +300,7 @@ The SDK implements the Gaia plugin gRPC interface and offers helper functions li Which programming languages are supported? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -We currently fully support Golang, Java, Python and C++. +We currently fully support Golang, Java, Python, C++ and Ruby. When do you support programming language **XYZ**? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docker/Dockerfile b/docker/Dockerfile index 3e1d20d2..07e70e0f 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -149,7 +149,83 @@ RUN git clone -b ${GRPC_RELEASE_TAG} https://github.com/grpc/grpc /var/local/git echo "--- installing grpc ---" && \ cd /var/local/git/grpc && \ make -j$(nproc) && make install && make clean && ldconfig -# --------------- Start C++ Part --------------- +# --------------- End C++ Part --------------- + +# --------------- Start Ruby Part --------------- +# skip installing gem documentation +RUN mkdir -p /usr/local/etc \ + && { \ + echo 'install: --no-document'; \ + echo 'update: --no-document'; \ + } >> /usr/local/etc/gemrc + +ENV RUBY_MAJOR 2.5 +ENV RUBY_VERSION 2.5.3 +ENV RUBY_DOWNLOAD_SHA256 1cc9d0359a8ea35fc6111ec830d12e60168f3b9b305a3c2578357d360fcf306f +ENV RUBYGEMS_VERSION 3.0.1 + +# some of ruby's build scripts are written in ruby +# we purge system ruby later to make sure our final image uses what we just built +RUN set -ex \ + \ + && buildDeps=' \ + bison \ + dpkg-dev \ + libgdbm-dev \ + ruby \ + ' \ + && apt-get update \ + && apt-get install -y --no-install-recommends $buildDeps \ + && rm -rf /var/lib/apt/lists/* \ + \ + && wget -O ruby.tar.xz "https://cache.ruby-lang.org/pub/ruby/${RUBY_MAJOR%-rc}/ruby-$RUBY_VERSION.tar.xz" \ + && echo "$RUBY_DOWNLOAD_SHA256 *ruby.tar.xz" | sha256sum -c - \ + \ + && mkdir -p /usr/src/ruby \ + && tar -xJf ruby.tar.xz -C /usr/src/ruby --strip-components=1 \ + && rm ruby.tar.xz \ + \ + && cd /usr/src/ruby \ + \ +# hack in "ENABLE_PATH_CHECK" disabling to suppress: +# warning: Insecure world writable dir + && { \ + echo '#define ENABLE_PATH_CHECK 0'; \ + echo; \ + cat file.c; \ + } > file.c.new \ + && mv file.c.new file.c \ + \ + && autoconf \ + && gnuArch="$(dpkg-architecture --query DEB_BUILD_GNU_TYPE)" \ + && ./configure \ + --build="$gnuArch" \ + --disable-install-doc \ + --enable-shared \ + && make -j "$(nproc)" \ + && make install \ + \ + && apt-get purge -y --auto-remove $buildDeps \ + && cd / \ + && rm -r /usr/src/ruby \ +# make sure bundled "rubygems" is older than RUBYGEMS_VERSION (https://github.com/docker-library/ruby/issues/246) + && ruby -e 'exit(Gem::Version.create(ENV["RUBYGEMS_VERSION"]) > Gem::Version.create(Gem::VERSION))' \ + && gem update --system "$RUBYGEMS_VERSION" && rm -r /root/.gem/ \ +# rough smoke test + && ruby --version && gem --version && bundle --version + +# install things globally, for great justice +# and don't create ".bundle" in all our apps +ENV GEM_HOME /usr/local/bundle +ENV BUNDLE_PATH="$GEM_HOME" \ + BUNDLE_SILENCE_ROOT_WARNING=1 \ + BUNDLE_APP_CONFIG="$GEM_HOME" +# path recommendation: https://github.com/bundler/bundler/pull/6469#issuecomment-383235438 +ENV PATH $GEM_HOME/bin:$BUNDLE_PATH/gems/bin:$PATH +# adjust permissions of a few directories for running "gem install" as an arbitrary user +RUN mkdir -p "$GEM_HOME" && chmod 777 "$GEM_HOME" +# (BUNDLE_PATH = GEM_HOME, no need to mkdir/chown both) +# --------------- End Ruby Part --------------- # install additional deps RUN apt-get update && apt-get install -y --no-install-recommends \ diff --git a/docker/Dockerfile.ruby b/docker/Dockerfile.ruby new file mode 100644 index 00000000..c7d64abb --- /dev/null +++ b/docker/Dockerfile.ruby @@ -0,0 +1,27 @@ +FROM ruby:2.5.3-stretch + +# Version and other variables which can be changed. +ENV GAIA_PORT=8080 \ + GAIA_WORKER=2 \ + GAIA_HOMEPATH=/data + +# Directory for the binary +WORKDIR /app + +# Copy gaia binary into docker image +COPY gaia-linux-amd64 /app + +# Fix permissions +RUN chmod +x ./gaia-linux-amd64 + +# Set homepath as volume +VOLUME [ "${GAIA_HOMEPATH}" ] + +# Expose port +EXPOSE ${GAIA_PORT} + +# Copy entry point script +COPY docker-entrypoint.sh /usr/local/bin/ + +# Start gaia +ENTRYPOINT [ "docker-entrypoint.sh" ] diff --git a/go.mod b/go.mod index 8a160418..1c31be44 100644 --- a/go.mod +++ b/go.mod @@ -1,7 +1,9 @@ module github.com/gaia-pipeline/gaia require ( - github.com/GeertJohan/go.rice v0.0.0-20170420135705-c02ca9a983da + github.com/GeertJohan/go.incremental v0.0.0-20161212213043-1172aab96510 // indirect + github.com/GeertJohan/go.rice v0.0.0-20181229193832-0af3f3b09a0a + github.com/akavel/rsrc v0.0.0-20170831122431-f6a15ece2cfd // indirect github.com/alecthomas/gometalinter v2.0.12+incompatible // indirect github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf // indirect github.com/coreos/bbolt v1.3.0 @@ -23,6 +25,7 @@ require ( github.com/hashicorp/go-plugin v0.0.0-20180331002553-e8d22c780116 github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 + github.com/jessevdk/go-flags v1.4.0 // indirect github.com/josharian/impl v0.0.0-20180228163738-3d0f908298c4 // indirect github.com/jstemmer/gotags v1.4.1 // indirect github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1 @@ -38,6 +41,7 @@ require ( github.com/mitchellh/go-homedir v0.0.0-20180801233206-58046073cbff github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77 github.com/nicksnyder/go-i18n v1.10.0 // indirect + github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229 // indirect github.com/oklog/run v1.0.0 github.com/pelletier/go-buffruneio v0.2.0 github.com/pelletier/go-toml v1.2.0 // indirect diff --git a/go.sum b/go.sum index 94a00c76..66dc9c26 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,13 @@ 9fans.net/go v0.0.0-20181112161441-237454027057 h1:OcHlKWkAMJEF1ndWLGxp5dnJQkYM/YImUOvsBoz6h5E= 9fans.net/go v0.0.0-20181112161441-237454027057/go.mod h1:diCsxrliIURU9xsYtjCp5AbpQKqdhKmf0ujWDUSkfoY= +github.com/GeertJohan/go.incremental v0.0.0-20161212213043-1172aab96510 h1:XKmpFaGpsBo5B7NC6RxawBYk6BFi0a6fw03J5PYW/9g= +github.com/GeertJohan/go.incremental v0.0.0-20161212213043-1172aab96510/go.mod h1:0K8QLSiwClOppBKLLSRX1sFvYdX5/fWqAZkjboOEzak= github.com/GeertJohan/go.rice v0.0.0-20170420135705-c02ca9a983da h1:UVU3a9pRUyLdnBtn60WjRl0s4SEyJc2ChCY56OAR6wI= github.com/GeertJohan/go.rice v0.0.0-20170420135705-c02ca9a983da/go.mod h1:DgrzXonpdQbfN3uYaGz1EG4Sbhyum/MMIn6Cphlh2bw= +github.com/GeertJohan/go.rice v0.0.0-20181229193832-0af3f3b09a0a h1:QgnJzkfb29JXtLXJN8alxzPWZhiNcAYZOa06dU5O46w= +github.com/GeertJohan/go.rice v0.0.0-20181229193832-0af3f3b09a0a/go.mod h1:DgrzXonpdQbfN3uYaGz1EG4Sbhyum/MMIn6Cphlh2bw= +github.com/akavel/rsrc v0.0.0-20170831122431-f6a15ece2cfd h1:yumR8733CaQ3P76MFbIbBKdrJmy4EqnQ5DIhqq8gq2Q= +github.com/akavel/rsrc v0.0.0-20170831122431-f6a15ece2cfd/go.mod h1:2+aQMrY0hBFBaIr2xxnZ/ctfwnYmMRMbTczYLAC34v4= github.com/alecthomas/gometalinter v2.0.12+incompatible h1:RBUbc8pKtqRoVCymENDl7cpWS9Ht5XNnwwk0cKjpteI= github.com/alecthomas/gometalinter v2.0.12+incompatible/go.mod h1:qfIpQGGz3d+NmgyPBqv+LSh50emm1pt72EtcX2vKYQk= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY= @@ -51,6 +57,8 @@ github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/josharian/impl v0.0.0-20180228163738-3d0f908298c4 h1:gmIVMdGlVf5e6Yo6+ZklxdOrvtOvyrAjJyXAbmOznyo= github.com/josharian/impl v0.0.0-20180228163738-3d0f908298c4/go.mod h1:t4Tr0tn92eq5ISef4cS5plFAMYAqZlAXtgUcKE6y8nw= github.com/jstemmer/gotags v1.4.1 h1:aWIyXsU3lTDqhsEC49MP85p2cUUWr2ptvdGNqqGA3r4= @@ -84,6 +92,8 @@ github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77 h1: github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/nicksnyder/go-i18n v1.10.0 h1:5AzlPKvXBH4qBzmZ09Ua9Gipyruv6uApMcrNZdo96+Q= github.com/nicksnyder/go-i18n v1.10.0/go.mod h1:HrK7VCrbOvQoUAQ7Vpy7i87N7JZZZ7R2xBGjv0j365Q= +github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229 h1:E2B8qYyeSgv5MXpmzZXRNp8IAQ4vjxIjhpAf5hv/tAg= +github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E= github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/pelletier/go-buffruneio v0.2.0 h1:U4t4R6YkofJ5xHm3dJzuRpPZ0mr5MMCoAWooScCR7aA= From b814a12507ef4e9f619394172d506bd0c590ea70 Mon Sep 17 00:00:00 2001 From: Michel Vocks Date: Sat, 19 Jan 2019 18:19:48 +0100 Subject: [PATCH 10/12] Removed indirect dependencies --- go.mod | 35 +---------------------------------- go.sum | 2 ++ 2 files changed, 3 insertions(+), 34 deletions(-) diff --git a/go.mod b/go.mod index 1c31be44..89adc615 100644 --- a/go.mod +++ b/go.mod @@ -1,80 +1,47 @@ module github.com/gaia-pipeline/gaia require ( - github.com/GeertJohan/go.incremental v0.0.0-20161212213043-1172aab96510 // indirect github.com/GeertJohan/go.rice v0.0.0-20181229193832-0af3f3b09a0a - github.com/akavel/rsrc v0.0.0-20170831122431-f6a15ece2cfd // indirect - github.com/alecthomas/gometalinter v2.0.12+incompatible // indirect - github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf // indirect github.com/coreos/bbolt v1.3.0 - github.com/cosiner/argv v0.0.1 // indirect github.com/daaku/go.zipexe v0.0.0-20150329023125-a5fe2436ffcb - github.com/davidrjenni/reftools v0.0.0-20180914123528-654d0ba4f96d // indirect - github.com/derekparker/delve v1.1.0 // indirect github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/emirpasic/gods v1.9.0 - github.com/fatih/gomodifytags v0.0.0-20180914191908-141225bf62b6 // indirect - github.com/fatih/motion v0.0.0-20180408211639-218875ebe238 // indirect github.com/gaia-pipeline/flag v1.7.4-pre github.com/gaia-pipeline/protobuf v0.0.0-20180812091451-7be8a901b55a github.com/golang/protobuf v1.1.0 github.com/google/go-github v15.0.0+incompatible github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135 - github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf // indirect github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd github.com/hashicorp/go-plugin v0.0.0-20180331002553-e8d22c780116 github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 - github.com/jessevdk/go-flags v1.4.0 // indirect - github.com/josharian/impl v0.0.0-20180228163738-3d0f908298c4 // indirect - github.com/jstemmer/gotags v1.4.1 // indirect github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1 github.com/kevinburke/ssh_config v0.0.0-20180317175531-9fc7bb800b55 - github.com/kisielk/errcheck v1.2.0 // indirect - github.com/klauspost/asmfmt v1.2.0 // indirect - github.com/koron/iferr v0.0.0-20180615142939-bb332a3b1d91 // indirect github.com/labstack/echo v3.3.5+incompatible github.com/labstack/gommon v0.0.0-20180613044413-d6898124de91 github.com/mattn/go-colorable v0.0.9 github.com/mattn/go-isatty v0.0.3 - github.com/mdempsky/gocode v0.0.0-20181226182234-be056ad32a5e // indirect github.com/mitchellh/go-homedir v0.0.0-20180801233206-58046073cbff github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77 - github.com/nicksnyder/go-i18n v1.10.0 // indirect - github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229 // indirect github.com/oklog/run v1.0.0 github.com/pelletier/go-buffruneio v0.2.0 - github.com/pelletier/go-toml v1.2.0 // indirect - github.com/peterh/liner v1.1.0 // indirect github.com/robfig/cron v0.0.0-20180505203441-b41be1df6967 - github.com/rogpeppe/godef v1.1.1 // indirect github.com/satori/go.uuid v1.2.0 github.com/sergi/go-diff v1.0.0 - github.com/sirupsen/logrus v1.3.0 // indirect - github.com/spf13/cobra v0.0.3 // indirect - github.com/spf13/pflag v1.0.3 // indirect github.com/src-d/gcfg v1.3.0 - github.com/stamblerre/gocode v0.0.0-20181212030458-2f9d39d8f31d // indirect - github.com/stretchr/testify v1.3.0 // indirect github.com/valyala/bytebufferpool v1.0.0 github.com/valyala/fasttemplate v0.0.0-20170224212429-dcecefd839c4 github.com/xanzy/ssh-agent v0.2.0 - github.com/zmb3/gogetdoc v0.0.0-20190107174152-de0ca1d07687 // indirect - golang.org/x/arch v0.0.0-20181203225421-5a4828bb7045 // indirect - golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 - golang.org/x/lint v0.0.0-20181217174547-8f45f776aaf1 // indirect + golang.org/x/crypto v0.0.0-20190103213133-ff983b9c42bc golang.org/x/net v0.0.0-20180811021610-c39426892332 golang.org/x/oauth2 v0.0.0-20180724155351-3d292e4d0cdc golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33 golang.org/x/text v0.0.0-20180810153555-6e3c4e7365dd - golang.org/x/tools v0.0.0-20190116231616-b258f6da2383 // indirect google.golang.org/appengine v1.1.0 google.golang.org/genproto v0.0.0-20180808183934-383e8b2c3b9e google.golang.org/grpc v1.14.0 - gopkg.in/alecthomas/kingpin.v3-unstable v3.0.0-20180810215634-df19058c872c // indirect gopkg.in/src-d/go-billy.v4 v4.2.0 gopkg.in/src-d/go-git.v4 v4.5.0 gopkg.in/warnings.v0 v0.1.2 gopkg.in/yaml.v2 v2.2.2 - honnef.co/go/tools v0.0.0-20190109154334-5bcec433c8ea // indirect ) diff --git a/go.sum b/go.sum index 66dc9c26..1bd9e865 100644 --- a/go.sum +++ b/go.sum @@ -141,6 +141,8 @@ golang.org/x/crypto v0.0.0-20180808211826-de0752318171 h1:vYogbvSFj2YXcjQxFHu/rA golang.org/x/crypto v0.0.0-20180808211826-de0752318171/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 h1:u+LnwYTOOW7Ukr/fppxEb1Nwz0AtPflrblfvUudpo+I= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190103213133-ff983b9c42bc h1:F5tKCVGp+MUAHhKp5MZtGqAlGX3+oCsiL1Q629FL90M= +golang.org/x/crypto v0.0.0-20190103213133-ff983b9c42bc/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/lint v0.0.0-20181217174547-8f45f776aaf1 h1:rJm0LuqUjoDhSk2zO9ISMSToQxGz7Os2jRiOL8AWu4c= golang.org/x/lint v0.0.0-20181217174547-8f45f776aaf1/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/net v0.0.0-20180811021610-c39426892332 h1:efGso+ep0DjyCBJPjvoz0HI6UldX4Md2F1rZFe1ir0E= From 5fae1807c37d9afb820aacdf819ccbf5e08c1c4a Mon Sep 17 00:00:00 2001 From: Michel Vocks Date: Sun, 20 Jan 2019 11:35:57 +0100 Subject: [PATCH 11/12] Implemented small fix for conflicting gem names --- workers/pipeline/build_ruby.go | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/workers/pipeline/build_ruby.go b/workers/pipeline/build_ruby.go index 434aaf0f..c681eb1d 100644 --- a/workers/pipeline/build_ruby.go +++ b/workers/pipeline/build_ruby.go @@ -18,6 +18,12 @@ var ( gemBinaryName = "gem" ) +// gemspecNameKey is the variable key which is filtered for during build. +const gemspecNameKey = "${NAME}" + +// gemInitFile is the initial file of the gem. +const gemInitFile = "gaia.rb" + // BuildPipelineRuby is the real implementation of BuildPipeline for Ruby type BuildPipelineRuby struct { Type gaia.PipelineType @@ -63,6 +69,32 @@ func (b *BuildPipelineRuby) ExecuteBuild(p *gaia.CreatePipeline) error { return errors.New("cannot find gemspec file in cloned repo") } + // Generate a new UUID for the gem name to prevent conflicts with other gems. + uuid := uuid.Must(uuid.NewV4(), nil).String() + + // Read gemspec file. + gemspecContent, err := ioutil.ReadFile(gemspec[0]) + if err != nil { + gaia.Cfg.Logger.Debug("cannot read gemspec file", "error", err.Error(), "pipeline", p.Pipeline.Name) + return err + } + + // Replace name variable with new UUID and write content to file. + gemspecContentStr := strings.Replace(string(gemspecContent[:]), gemspecNameKey, uuid, 1) + err = ioutil.WriteFile(gemspec[0], []byte(gemspecContentStr), 0644) + if err != nil { + gaia.Cfg.Logger.Debug("cannot write/edit gemspec file", "error", err.Error(), "pipeline", p.Pipeline.Name) + return err + } + + // The initial ruby file in the gem must be named like the gem name. + // We expect that the init file is always `gemInitFile`. + err = os.Rename(filepath.Join(p.Pipeline.Repo.LocalDest, "lib", gemInitFile), filepath.Join(p.Pipeline.Repo.LocalDest, "lib", uuid+".rb")) + if err != nil { + gaia.Cfg.Logger.Debug("cannot rename initial ruby file", "error", err.Error(), "pipeline", p.Pipeline.Name) + return err + } + // Set command args for build args := []string{ "build", From 5ceebcc7dbfcc85f75e8df5e7d81943a11cd98ac Mon Sep 17 00:00:00 2001 From: Michel Vocks Date: Sun, 20 Jan 2019 12:22:12 +0100 Subject: [PATCH 12/12] Fixed tests --- go.mod | 3 +++ go.sum | 4 +++ workers/pipeline/build_ruby.go | 2 +- workers/pipeline/build_ruby_test.go | 41 +++++++++++++++++++++-------- 4 files changed, 38 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index 89adc615..cb7b9da0 100644 --- a/go.mod +++ b/go.mod @@ -11,9 +11,11 @@ require ( github.com/golang/protobuf v1.1.0 github.com/google/go-github v15.0.0+incompatible github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135 + github.com/google/pprof v0.0.0-20190109223431-e84dfd68c163 // indirect github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd github.com/hashicorp/go-plugin v0.0.0-20180331002553-e8d22c780116 github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb + github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1 github.com/kevinburke/ssh_config v0.0.0-20180317175531-9fc7bb800b55 @@ -32,6 +34,7 @@ require ( github.com/valyala/bytebufferpool v1.0.0 github.com/valyala/fasttemplate v0.0.0-20170224212429-dcecefd839c4 github.com/xanzy/ssh-agent v0.2.0 + golang.org/x/arch v0.0.0-20181203225421-5a4828bb7045 // indirect golang.org/x/crypto v0.0.0-20190103213133-ff983b9c42bc golang.org/x/net v0.0.0-20180811021610-c39426892332 golang.org/x/oauth2 v0.0.0-20180724155351-3d292e4d0cdc diff --git a/go.sum b/go.sum index 1bd9e865..8b5b7316 100644 --- a/go.sum +++ b/go.sum @@ -47,6 +47,8 @@ github.com/google/go-github v15.0.0+incompatible h1:jlPg2Cpsxb/FyEV/MFiIE9tW/2RA github.com/google/go-github v15.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135 h1:zLTLjkaOFEFIOxY5BWLFLwh+cL8vOBW4XJ2aqLE/Tf0= github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/pprof v0.0.0-20190109223431-e84dfd68c163 h1:beB+Da4k9B1zmgag78k3k1Bx4L/fdWr5FwNa0f8RxmY= +github.com/google/pprof v0.0.0-20190109223431-e84dfd68c163/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf h1:7+FW5aGwISbqUtkfmIpZJGRgNFg2ioYPvFaUxdqpDsg= github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf/go.mod h1:RpwtwJQFrIEPstU94h88MWPXP2ektJZ8cZ0YntAmXiE= github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd h1:rNuUHR+CvK1IS89MMtcF0EpcVMZtjKfPRp4MEmt/aTs= @@ -55,6 +57,8 @@ github.com/hashicorp/go-plugin v0.0.0-20180331002553-e8d22c780116 h1:Y4V/yReWjQo github.com/hashicorp/go-plugin v0.0.0-20180331002553-e8d22c780116/go.mod h1:JSqWYsict+jzcj0+xElxyrBQRPNoiWQuddnxArJ7XHQ= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6 h1:UDMh68UUwekSh5iP2OMhRRZJiiBccgV7axzUG8vi56c= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA= diff --git a/workers/pipeline/build_ruby.go b/workers/pipeline/build_ruby.go index c681eb1d..df7e5cf2 100644 --- a/workers/pipeline/build_ruby.go +++ b/workers/pipeline/build_ruby.go @@ -91,7 +91,7 @@ func (b *BuildPipelineRuby) ExecuteBuild(p *gaia.CreatePipeline) error { // We expect that the init file is always `gemInitFile`. err = os.Rename(filepath.Join(p.Pipeline.Repo.LocalDest, "lib", gemInitFile), filepath.Join(p.Pipeline.Repo.LocalDest, "lib", uuid+".rb")) if err != nil { - gaia.Cfg.Logger.Debug("cannot rename initial ruby file", "error", err.Error(), "pipeline", p.Pipeline.Name) + gaia.Cfg.Logger.Debug("cannot rename initial ruby file", "error", err.Error(), "pipeline", p.Pipeline) return err } diff --git a/workers/pipeline/build_ruby_test.go b/workers/pipeline/build_ruby_test.go index 7f1c7713..98046fdd 100644 --- a/workers/pipeline/build_ruby_test.go +++ b/workers/pipeline/build_ruby_test.go @@ -50,6 +50,7 @@ func TestExecuteBuildRuby(t *testing.T) { execCommandContext = exec.CommandContext }() tmp, _ := ioutil.TempDir("", "TestExecuteBuildRuby") + defer os.RemoveAll(tmp) gaia.Cfg = new(gaia.Config) gaia.Cfg.HomePath = tmp b := new(BuildPipelineRuby) @@ -58,14 +59,21 @@ func TestExecuteBuildRuby(t *testing.T) { p.Pipeline.Type = gaia.PTypeRuby p.Pipeline.Repo.LocalDest = tmp src := filepath.Join(tmp, p.Pipeline.Name+".gemspec") - f, _ := os.Create(src) - defer os.RemoveAll(tmp) - defer f.Close() - ioutil.WriteFile(src, []byte("testcontent"), 0666) + if err := ioutil.WriteFile(src, []byte("testcontent"), 0666); err != nil { + t.Fatal(err) + } dst := filepath.Join(tmp, p.Pipeline.Name+".gem") - resultFile, _ := os.Create(dst) - defer resultFile.Close() - ioutil.WriteFile(dst, []byte("testcontent"), 0666) + if err := ioutil.WriteFile(dst, []byte("testcontent"), 0666); err != nil { + t.Fatal(err) + } + libFolder := filepath.Join(tmp, "lib") + if err := os.MkdirAll(libFolder, 0766); err != nil { + t.Fatal(err) + } + initFile := filepath.Join(libFolder, gemInitFile) + if err := ioutil.WriteFile(initFile, []byte("testcontent"), 0644); err != nil { + t.Error(err) + } gemBinaryName = "go" err := b.ExecuteBuild(p) if err != nil { @@ -86,6 +94,7 @@ func TestExecuteBuildContextTimeoutRuby(t *testing.T) { buildKillContext = false }() tmp, _ := ioutil.TempDir("", "TestExecuteBuildContextTimeoutRuby") + defer os.RemoveAll(tmp) gaia.Cfg = new(gaia.Config) gaia.Cfg.HomePath = tmp buf := new(bytes.Buffer) @@ -100,10 +109,20 @@ func TestExecuteBuildContextTimeoutRuby(t *testing.T) { p.Pipeline.Type = gaia.PTypeRuby p.Pipeline.Repo.LocalDest = tmp src := filepath.Join(tmp, p.Pipeline.Name+".gemspec") - f, _ := os.Create(src) - defer os.RemoveAll(tmp) - defer f.Close() - err := b.ExecuteBuild(p) + f, err := os.Create(src) + if err != nil { + t.Fatal(err) + } + f.Close() + libFolder := filepath.Join(tmp, "lib") + if err = os.MkdirAll(libFolder, 0766); err != nil { + t.Fatal(err) + } + initFile := filepath.Join(libFolder, gemInitFile) + if err = ioutil.WriteFile(initFile, []byte("testcontent"), 0644); err != nil { + t.Error(err) + } + err = b.ExecuteBuild(p) if err == nil { t.Fatal("no error found while expecting error.") }