Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Java support #60

Merged
merged 1 commit into from
Aug 1, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions frontend/client/views/pipeline/create.vue
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,12 @@
<div class="pipelinetype" title="Golang" v-tippy="{ arrow : true, animation : 'shift-away'}" v-on:click="createPipeline.pipeline.type = 'golang'" v-bind:class="{ pipelinetypeactive: createPipeline.pipeline.type === 'golang' }" data-tippy-hideOnClick="false">
<img src="~assets/golang.png" class="typeimage">
</div>
<div class="pipelinetype" title="Java" v-tippy="{ arrow : true, animation : 'shift-away'}" v-on:click="createPipeline.pipeline.type = 'java'" v-bind:class="{ pipelinetypeactive: createPipeline.pipeline.type === 'java' }" data-tippy-hideOnClick="false">
<img src="~assets/java.png" class="typeimage">
</div>
<div class="pipelinetype" title="Python (not yet supported)" v-tippy="{ arrow : true, animation : 'shift-away'}" v-bind:class="{ pipelinetypeactive: createPipeline.pipeline.type === 'python' }" data-tippy-hideOnClick="false">
<img src="~assets/python.png" class="typeimage typeimagenotyetsupported">
</div>
<div class="pipelinetype" title="Java (not yet supported)" v-tippy="{ arrow : true, animation : 'shift-away'}" v-bind:class="{ pipelinetypeactive: createPipeline.pipeline.type === 'java' }" data-tippy-hideOnClick="false">
<img src="~assets/java.png" class="typeimage typeimagenotyetsupported">
</div>
</div>
<div class="content" style="display: flex;">
<div class="pipelinetype" title="C++ (not yet supported)" v-tippy="{ arrow : true, animation : 'shift-away'}" v-bind:class="{ pipelinetypeactive: createPipeline.pipeline.type === 'cplusplus' }" data-tippy-hideOnClick="false">
Expand Down
3 changes: 3 additions & 0 deletions gaia.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ const (
// PTypeGolang golang plugin type
PTypeGolang PipelineType = "golang"

// PTypeJava java plugin type
PTypeJava PipelineType = "java"

// CreatePipelineFailed status
CreatePipelineFailed CreatePipelineType = "failed"

Expand Down
44 changes: 0 additions & 44 deletions pipeline/build_golang.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package pipeline

import (
"context"
"io"
"os"
"os/exec"
"path/filepath"
Expand All @@ -16,11 +14,8 @@ import (
const (
golangBinaryName = "go"
golangFolder = "golang"
srcFolder = "src"
)

var execCommandContext = exec.CommandContext

// BuildPipelineGolang is the real implementation of BuildPipeline for golang
type BuildPipelineGolang struct {
Type gaia.PipelineType
Expand Down Expand Up @@ -90,21 +85,6 @@ func (b *BuildPipelineGolang) ExecuteBuild(p *gaia.CreatePipeline) error {
return nil
}

// executeCmd wraps a context around the command and executes it.
func executeCmd(path string, args []string, env []string, dir string) ([]byte, error) {
// Create context with timeout
ctx, cancel := context.WithTimeout(context.Background(), maxTimeoutMinutes*time.Minute)
defer cancel()

// Create command
cmd := execCommandContext(ctx, path, args...)
cmd.Env = env
cmd.Dir = dir

// Execute command
return cmd.CombinedOutput()
}

// CopyBinary copies the final compiled archive to the
// destination folder.
func (b *BuildPipelineGolang) CopyBinary(p *gaia.CreatePipeline) error {
Expand All @@ -131,27 +111,3 @@ func (b *BuildPipelineGolang) SavePipeline(p *gaia.Pipeline) error {
// Our pipeline is finished constructing. Save it.
return storeService.PipelinePut(p)
}

// copyFileContents copies the content from source to destination.
func copyFileContents(src, dst string) (err error) {
in, err := os.Open(src)
if err != nil {
return
}
defer in.Close()
out, err := os.Create(dst)
if err != nil {
return
}
defer func() {
cerr := out.Close()
if err == nil {
err = cerr
}
}()
if _, err = io.Copy(out, in); err != nil {
return
}
err = out.Sync()
return
}
57 changes: 13 additions & 44 deletions pipeline/build_golang_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,11 @@ package pipeline

import (
"bytes"
"context"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"regexp"
"strconv"
"strings"
"testing"

Expand All @@ -18,39 +15,7 @@ import (
hclog "github.com/hashicorp/go-hclog"
)

var killContext = false
var killOnBuild = false

func fakeExecCommandContext(ctx context.Context, name string, args ...string) *exec.Cmd {
if killContext {
c, cancel := context.WithTimeout(context.Background(), 0)
defer cancel()
ctx = c
}
cs := []string{"-test.run=TestExecCommandContextHelper", "--", name}
cs = append(cs, args...)
cmd := exec.CommandContext(ctx, os.Args[0], cs...)
arg := strings.Join(cs, ",")
envArgs := os.Getenv("CMD_ARGS")
if len(envArgs) != 0 {
envArgs += ":" + arg
} else {
envArgs = arg
}
os.Setenv("CMD_ARGS", envArgs)
return cmd
}

func TestExecCommandContextHelper(t *testing.T) {
if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
return
}
fmt.Fprintf(os.Stdout, os.Getenv("STDOUT"))
i, _ := strconv.Atoi(os.Getenv("EXIT_STATUS"))
os.Exit(i)
}

func TestPrepareEnvironment(t *testing.T) {
func TestPrepareEnvironmentGo(t *testing.T) {
tmp := os.TempDir()
gaia.Cfg = new(gaia.Config)
gaia.Cfg.HomePath = tmp
Expand All @@ -66,7 +31,7 @@ func TestPrepareEnvironment(t *testing.T) {
}
}

func TestPrepareEnvironmentInvalidPathForMkdir(t *testing.T) {
func TestPrepareEnvironmentInvalidPathForMkdirGo(t *testing.T) {
gaia.Cfg = new(gaia.Config)
gaia.Cfg.HomePath = "/notexists"
b := new(BuildPipelineGolang)
Expand All @@ -77,7 +42,7 @@ func TestPrepareEnvironmentInvalidPathForMkdir(t *testing.T) {
}
}

func TestExecuteBuild(t *testing.T) {
func TestExecuteBuildGo(t *testing.T) {
execCommandContext = fakeExecCommandContext
defer func() {
execCommandContext = exec.CommandContext
Expand All @@ -99,7 +64,7 @@ func TestExecuteBuild(t *testing.T) {
}
}

func TestExecuteBuildFailPipelineBuild(t *testing.T) {
func TestExecuteBuildFailPipelineBuildGo(t *testing.T) {
os.Mkdir("tmp", 0744)
ioutil.WriteFile(filepath.Join("tmp", "main.go"), []byte(`package main
import "os"
Expand Down Expand Up @@ -132,7 +97,7 @@ func TestExecuteBuildFailPipelineBuild(t *testing.T) {
}
}

func TestExecuteBuildContextTimeout(t *testing.T) {
func TestExecuteBuildContextTimeoutGo(t *testing.T) {
execCommandContext = fakeExecCommandContext
killContext = true
defer func() {
Expand Down Expand Up @@ -160,7 +125,7 @@ func TestExecuteBuildContextTimeout(t *testing.T) {
}
}

func TestExecuteBuildBinaryNotFoundError(t *testing.T) {
func TestExecuteBuildBinaryNotFoundErrorGo(t *testing.T) {
tmp := os.TempDir()
gaia.Cfg = new(gaia.Config)
gaia.Cfg.HomePath = tmp
Expand All @@ -185,7 +150,7 @@ func TestExecuteBuildBinaryNotFoundError(t *testing.T) {
}
}

func TestCopyBinary(t *testing.T) {
func TestCopyBinaryGo(t *testing.T) {
tmp := os.TempDir()
gaia.Cfg = new(gaia.Config)
gaia.Cfg.HomePath = tmp
Expand Down Expand Up @@ -220,7 +185,7 @@ func TestCopyBinary(t *testing.T) {
}
}

func TestCopyBinarySrcDoesNotExist(t *testing.T) {
func TestCopyBinarySrcDoesNotExistGo(t *testing.T) {
tmp := os.TempDir()
gaia.Cfg = new(gaia.Config)
gaia.Cfg.HomePath = tmp
Expand All @@ -245,7 +210,11 @@ func TestCopyBinarySrcDoesNotExist(t *testing.T) {
}
}

func TestSavePipeline(t *testing.T) {
func TestSavePipelineGo(t *testing.T) {
tmp := os.TempDir()
gaia.Cfg = new(gaia.Config)
gaia.Cfg.HomePath = tmp
defer os.Remove(tmp)
s := store.NewStore()
s.Init()
storeService = s
Expand Down
101 changes: 101 additions & 0 deletions pipeline/build_java.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package pipeline

import (
"os"
"os/exec"
"path/filepath"
"strings"
"time"

"github.com/gaia-pipeline/gaia"
"github.com/satori/go.uuid"
)

var (
mavenBinaryName = "mvn"
)

const (
javaFolder = "java"
javaFinalJarName = "plugin-jar-with-dependencies.jar"
mavenTargetFolder = "target"
)

// BuildPipelineJava is the real implementation of BuildPipeline for java
type BuildPipelineJava struct {
Type gaia.PipelineType
}

// PrepareEnvironment prepares the environment before we start the build process.
func (b *BuildPipelineJava) PrepareEnvironment(p *gaia.CreatePipeline) error {
// create uuid for destination folder
uuid := uuid.Must(uuid.NewV4(), nil)

// Create local temp folder for clone
rootPath := filepath.Join(gaia.Cfg.HomePath, tmpFolder, javaFolder)
cloneFolder := filepath.Join(rootPath, 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 java build process
func (b *BuildPipelineJava) ExecuteBuild(p *gaia.CreatePipeline) error {
// Look for maven executeable
path, err := exec.LookPath(mavenBinaryName)
if err != nil {
gaia.Cfg.Logger.Debug("cannot find maven executeable", "error", err.Error())
return err
}
env := os.Environ()

// Set command args for build
args := []string{
"clean",
"compile",
"assembly:single",
}

// Execute and wait until finish or timeout
output, err := executeCmd(path, args, env, 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
}

return nil
}

// CopyBinary copies the final compiled archive to the
// destination folder.
func (b *BuildPipelineJava) CopyBinary(p *gaia.CreatePipeline) error {
// Define src and destination
src := filepath.Join(p.Pipeline.Repo.LocalDest, mavenTargetFolder, javaFinalJarName)
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 *BuildPipelineJava) SavePipeline(p *gaia.Pipeline) error {
dest := filepath.Join(gaia.Cfg.PipelinePath, appendTypeToName(p.Name, p.Type))
p.ExecPath = dest
p.Type = gaia.PTypeJava
p.Name = strings.TrimSuffix(filepath.Base(dest), typeDelimiter+gaia.PTypeJava.String())
p.Created = time.Now()
// Our pipeline is finished constructing. Save it.
return storeService.PipelinePut(p)
}
Loading