Commit 8cc39c9f authored by Kamil Trzciński's avatar Kamil Trzciński

WIP

parent 792784d0
*.iml
config.toml
.project
......@@ -3,6 +3,7 @@ package src
import (
"bufio"
"os"
"fmt"
"io/ioutil"
)
......@@ -10,7 +11,34 @@ type Build struct {
GetBuildResponse
}
func (b *Build) Generate() *string {
func (b *Build) projectDir() string {
return fmt.Sprintf("project-%d", b.ProjectId)
}
func (b *Build) writeCloneCmd(w *bufio.Writer, builds_dir string) {
w.WriteString(fmt.Sprintf("cd %s &&", builds_dir))
w.WriteString(fmt.Sprintf("rm -rf %s &&", b.projectDir()))
w.WriteString(fmt.Sprintf("git clone %s %s &&", b.RepoURL, b.projectDir()))
w.WriteString(fmt.Sprintf("cd %s"))
w.WriteString("\n")
}
func (b *Build) writeFetchCmd(w *bufio.Writer, builds_dir string) {
w.WriteString(fmt.Sprintf("cd %s &&", builds_dir))
w.WriteString(fmt.Sprintf("cd %s &&", b.projectDir()))
w.WriteString(fmt.Sprintf("git reset --hard &&"))
w.WriteString(fmt.Sprintf("git remote set-url origin %s &&", b.RepoURL))
w.WriteString(fmt.Sprintf("git fetch origin"))
w.WriteString("\n")
}
func (b *Build) writeCheckoutCmd(w *bufio.Writer, builds_dir string) {
w.WriteString(fmt.Sprintf("git checkout %s &&", b.RefName))
w.WriteString(fmt.Sprintf("git reset --hard %s", b.Sha))
w.WriteString("\n")
}
func (b *Build) Generate(builds_dir string) *string {
file, err := ioutil.TempFile("", "build_script")
if err != nil {
return nil
......@@ -25,9 +53,19 @@ func (b *Build) Generate() *string {
w.WriteString("\n")
w.WriteString("echo Using $(hostname)\n")
w.WriteString("\n")
w.WriteString("set -e\n")
w.WriteString("trap 'kill -s INT 0' EXIT\n")
w.WriteString("set -ev\n")
w.WriteString("\n")
if b.AllowGitFetch {
b.writeFetchCmd(w, builds_dir)
} else {
b.writeCloneCmd(w, builds_dir)
}
b.writeCheckoutCmd(w, builds_dir)
w.WriteString("\n")
w.WriteString(b.Commands)
name := file.Name()
......
package src
import (
)
type DockerExecutor struct {
}
func (s *DockerExecutor) Run(config RunnerConfig, build Build) error {
return nil
}
......@@ -9,11 +9,13 @@ type Executor interface {
func GetExecutor(config RunnerConfig) Executor {
switch config.Executor {
case "shell":
return &ShellExecutor{}
case "":
return &ShellExecutor{}
default:
return nil
case "shell":
return &ShellExecutor{}
case "docker":
return &DockerExecutor{}
case "":
return &ShellExecutor{}
default:
return nil
}
}
package src
import (
"errors"
"os"
"time"
"fmt"
"bytes"
"io/ioutil"
"os/exec"
)
type ShellExecutor struct {
}
func sendBuildLog(config RunnerConfig, buildId int, build_log string, state BuildState) UpdateState {
file, err := os.Open(build_log)
if err != nil {
return UpdateBuild(config, buildId, state, bytes.NewBufferString(""))
}
defer file.Close()
return UpdateBuild(config, buildId, state, file)
}
func updateBuildLog(config RunnerConfig, buildId int, build_log string, abort chan bool, finished chan bool) {
for {
select {
case <-time.After(time.Second * 3):
switch sendBuildLog(config, buildId, build_log, Running) {
case UpdateSucceeded:
case UpdateAbort:
abort <- true
<- finished
return
case UpdateFailed:
}
case <-finished:
return
}
}
}
func (s *ShellExecutor) Run(config RunnerConfig, build Build) error {
builds_dir := "tmp/builds"
// generate build script
script_file := build.Generate(builds_dir)
if script_file == nil {
return errors.New("Failed to generate build script")
}
defer os.Remove(*script_file)
// create build log
build_log, err := ioutil.TempFile("", "build_log")
if err != nil {
return errors.New("Failed to create build log file")
}
defer build_log.Close()
defer os.Remove(build_log.Name())
// create execution command
cmd := exec.Command("setsid", *script_file)
if cmd == nil {
return errors.New("Failed to generate execution command")
}
cmd.Env = []string{
"CI_SERVER=yes",
"CI_SERVER_NAME=GitLab CI",
"CI_SERVER_VERSION=",
"CI_SERVER_REVISION=",
fmt.Sprintf("CI_BUILD_REF=%s", build.Sha),
fmt.Sprintf("CI_BUILD_BEFORE_SHA=%s", build.BeforeSha),
fmt.Sprintf("CI_BUILD_REF_NAME=%s", build.RefName),
fmt.Sprintf("CI_BUILD_ID=%d", build.Id),
fmt.Sprintf("CI_BUILD_REPO=%s", build.RepoURL),
fmt.Sprintf("CI_PROJECT_ID=%d", build.ProjectId),
"RUBYLIB=",
"RUBYOPT=",
"BNDLE_BIN_PATH=",
"BUNDLE_GEMFILE=",
}
// cmd.Stdin = ioutil.
cmd.Stdout = build_log
cmd.Stderr = build_log
// Start process
err = cmd.Start()
if err != nil {
return errors.New("Failed to start process")
}
// Wait for process to exit
command_finish := make(chan error, 1)
go func() {
command_finish <- cmd.Wait()
}()
// Update build log
abort := make(chan bool, 1)
finishBuildLog := make(chan bool)
go updateBuildLog(config, build.Id, build_log.Name(), abort, finishBuildLog)
var buildState BuildState
// Wait for signals: abort, timeout or finish
select {
case <-abort:
// abort build
buildState = Failed
case <-time.After(time.Second * time.Duration(build.Timeout)):
// command timeout
if err := cmd.Process.Kill(); err != nil {
}
buildState = Failed
case err := <-command_finish:
// command finished
if err != nil {
buildState = Failed
} else {
buildState = Success
}
}
// wait for update log routine to finish
finishBuildLog <- true
// Send final build state to server
for {
switch sendBuildLog(config, build.Id, build_log.Name(), buildState) {
case UpdateSucceeded:
return nil
case UpdateAbort:
return nil
case UpdateFailed:
time.Sleep(3 * time.Second)
}
}
return nil
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment