14 Commits
v1.0 ... v1.1

Author SHA1 Message Date
54104e61cf Added / stole some code to handle cmd execs better
It'll now use any custom environment path to lookup executables to run
as part of the project scripts
2016-04-22 21:25:33 +00:00
9891301ca4 Added better error handling.
Moved main project list columns around
2016-04-22 20:39:06 +00:00
77f2f8c5aa Build script change 2016-04-21 13:41:21 +00:00
5f776e0757 Updated build script 2016-04-20 16:42:16 +00:00
20084b9429 Post trigger test 2016-04-20 16:22:42 +00:00
b5bfd93cff Fixed issue with environment not getting set in projects 2016-04-20 16:15:53 +00:00
ead3e6ebf0 Updated build script, and addded environment option for projects 2016-04-20 16:05:59 +00:00
6e482121ed Fixed type in build script 2016-04-20 15:44:03 +00:00
f73a57d13b Build script change 2016-04-20 15:42:26 +00:00
6d7cee5f48 Added option to pass in working directory into scripts 2016-04-20 15:40:07 +00:00
e568177ea6 Working on build script 2016-04-20 15:07:58 +00:00
6d74144a3b Updated import paths to new townsourced organization 2016-04-19 19:52:55 +00:00
7f94b454a7 work on build scripts 2016-04-19 19:26:35 +00:00
e17ec20f79 Ran final bindata build, added build script 2016-04-19 15:47:47 +00:00
10 changed files with 205 additions and 71 deletions

View File

@ -17,8 +17,21 @@ You'll setup a project which will need the following information:
5. Path to the release file
6. Script to set release name / version
An optional set of environment strings can be set to define the environment in which the scripts run.
```
"environment": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/local/go/bin",
"GOPATH=@dir"
]
```
Projects will be defined in a project.json file for now. I may add a web interface later.
@dir in any of the script strings or environment entries will be replaced with an absolute path to the current working directory of the specific version being worked on.
```
sh ./build.sh @dir
```
Ironsmith will take the information for the defined project above and do the following
@ -26,7 +39,8 @@ Ironsmith will take the information for the defined project above and do the fol
2. Change to that directory
2. Create a bolt DB file for the project to keep a log of all the builds
3. Run an initial pull of the repository using the pull script
4. If pull succeeds, Run the Build Scripts
4. Run version script
4. If pull is a new version, then Run the Build Scripts
5. If build succeeds, run the test scripts
6. If test succeeds, run the release scripts
7. Load the release file into project release folder with the release name

File diff suppressed because one or more lines are too long

3
build.sh Normal file
View File

@ -0,0 +1,3 @@
#!/bin/bash
go-bindata web/... && go build -a -v -o ironsmith

View File

@ -15,7 +15,7 @@ import (
"strings"
"time"
"git.townsourced.com/ironsmith/datastore"
"git.townsourced.com/townsourced/ironsmith/datastore"
)
/*
@ -94,13 +94,13 @@ func (p *Project) fetch() {
}
//fetch project
fetchResult, err := runCmd(p.Fetch, tempDir)
fetchResult, err := runCmd(p.Fetch, tempDir, p.Environment)
if p.errHandled(err) {
return
}
// fetched succesfully, determine version
version, err := runCmd(p.Version, tempDir)
version, err := runCmd(p.Version, tempDir, p.Environment)
if p.errHandled(err) {
return
@ -152,7 +152,7 @@ func (p *Project) build() {
return
}
output, err := runCmd(p.Build, p.workingDir())
output, err := runCmd(p.Build, p.workingDir(), p.Environment)
if p.errHandled(err) {
return
@ -173,7 +173,7 @@ func (p *Project) test() {
if p.Test == "" {
return
}
output, err := runCmd(p.Test, p.workingDir())
output, err := runCmd(p.Test, p.workingDir(), p.Environment)
if p.errHandled(err) {
return
@ -195,7 +195,7 @@ func (p *Project) release() {
return
}
output, err := runCmd(p.Release, p.workingDir())
output, err := runCmd(p.Release, p.workingDir(), p.Environment)
if p.errHandled(err) {
return

View File

@ -11,7 +11,7 @@ import (
"log"
"net/http"
"git.townsourced.com/ironsmith/datastore"
"git.townsourced.com/townsourced/ironsmith/datastore"
)
const (

75
exec.go
View File

@ -6,12 +6,18 @@ package main
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
)
func runCmd(cmd, dir string) ([]byte, error) {
s := strings.Fields(cmd)
func runCmd(cmd, dir string, env []string) ([]byte, error) {
s := strings.Fields(strings.Replace(cmd, "@dir", dir, -1))
for i := range env {
env[i] = strings.Replace(env[i], "@dir", dir, -1)
}
var args []string
@ -19,15 +25,74 @@ func runCmd(cmd, dir string) ([]byte, error) {
args = s[1:]
}
ec := exec.Command(s[0], args...)
name := s[0]
ec := &exec.Cmd{
Path: name,
Args: append([]string{name}, args...),
Dir: dir,
Env: env,
}
ec.Dir = dir
if filepath.Base(name) == name {
lp, err := lookPath(name, env)
if err != nil {
return nil, err
}
ec.Path = lp
}
vlog("Executing command: %s in dir %s\n", cmd, dir)
result, err := ec.CombinedOutput()
if err != nil {
return nil, fmt.Errorf("%s", result)
return nil, fmt.Errorf("%s\n%s", err, result)
}
return result, nil
}
// similar to os/exec.LookPath, except it checks if the passed in
// custom environment includes a path definitions and uses that path instead
// note this probably only works on unix, that's all I care about for now
func lookPath(file string, env []string) (string, error) {
if strings.Contains(file, "/") {
err := findExecutable(file)
if err == nil {
return file, nil
}
return "", &exec.Error{file, err}
}
for i := range env {
if strings.HasPrefix(env[i], "PATH=") {
pathenv := env[i][5:]
if pathenv == "" {
return "", &exec.Error{file, exec.ErrNotFound}
}
for _, dir := range strings.Split(pathenv, ":") {
if dir == "" {
// Unix shell semantics: path element "" means "."
dir = "."
}
path := dir + "/" + file
if err := findExecutable(path); err == nil {
return path, nil
}
}
return "", &exec.Error{file, exec.ErrNotFound}
}
}
return exec.LookPath(file)
}
func findExecutable(file string) error {
d, err := os.Stat(file)
if err != nil {
return err
}
if m := d.Mode(); !m.IsDir() && m&0111 != 0 {
return nil
}
return os.ErrPermission
}

View File

@ -11,7 +11,7 @@ import (
"os/signal"
"path/filepath"
"git.townsourced.com/config"
"git.townsourced.com/townsourced/config"
)
//settings

View File

@ -15,7 +15,7 @@ import (
"sync"
"time"
"git.townsourced.com/ironsmith/datastore"
"git.townsourced.com/townsourced/ironsmith/datastore"
)
const (
@ -48,6 +48,8 @@ The project lifecycle goes like this, each step calling the next if successful
type Project struct {
Name string `json:"name"` // name of the project
Environment []string `json:"environment"` // Environment for each of the scripts below, if empty will use the current processes environment
Fetch string `json:"fetch"` //Script to fetch the latest project code into the current directory
Build string `json:"build"` //Script to build the latest project code
Test string `json:"test"` //Script to test the latest project code
@ -273,6 +275,7 @@ func (p *Project) setData(new *Project) {
defer p.Unlock()
p.Name = new.Name
p.Environment = new.Environment
p.Fetch = new.Fetch
p.Build = new.Build

View File

@ -163,10 +163,10 @@
<tr>
<th>Project</th>
<th>Status</th>
<th>Last Release</th>
<th>Last Release File</th>
<th>Last Version</th>
<th>Last Log</th>
<th>Last Release</th>
<th>Last Release File</th>
</tr>
</thead>
<tbody>
@ -174,6 +174,10 @@
<tr title="{{formatDate(.lastLog.when)}}">
<td><a href="/project/{{.id}}/">{{.name}}</a></td>
<td>{{.status}}</td>
<td>
<a href="/project/{{.id}}/{{.lastLog.version}}">{{.lastLog.version}}</a>
</td>
<td title="{{.lastLog.log}}">{{#if .lastLog.log}}{{.lastLog.log.substring(0,100)}}{{/if}}</td>
<td>
<a href="/project/{{.id}}/{{.releaseVersion}}">{{.releaseVersion}}</a>
</td>
@ -184,10 +188,6 @@
No release file available
{{/if}}
</td>
<td>
<a href="/project/{{.id}}/{{.lastLog.version}}">{{.lastLog.version}}</a>
</td>
<td title="{{.lastLog.log}}">{{#if .lastLog.log}}{{.lastLog.log.substring(0,100)}}{{/if}}</td>
</tr>
{{/projects}}
</tbody>

View File

@ -11,7 +11,7 @@ import (
"strings"
"time"
"git.townsourced.com/ironsmith/datastore"
"git.townsourced.com/townsourced/ironsmith/datastore"
)
// /path/<project-id>/<version>/<stage>