Compare commits
14 Commits
Author | SHA1 | Date | |
---|---|---|---|
54104e61cf | |||
9891301ca4 | |||
77f2f8c5aa | |||
5f776e0757 | |||
20084b9429 | |||
b5bfd93cff | |||
ead3e6ebf0 | |||
6e482121ed | |||
f73a57d13b | |||
6d7cee5f48 | |||
e568177ea6 | |||
6d74144a3b | |||
7f94b454a7 | |||
e17ec20f79 |
16
README.md
16
README.md
@ -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
|
||||
|
135
bindata.go
135
bindata.go
File diff suppressed because one or more lines are too long
3
build.sh
Normal file
3
build.sh
Normal file
@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
go-bindata web/... && go build -a -v -o ironsmith
|
12
cycle.go
12
cycle.go
@ -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
|
||||
|
2
error.go
2
error.go
@ -11,7 +11,7 @@ import (
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"git.townsourced.com/ironsmith/datastore"
|
||||
"git.townsourced.com/townsourced/ironsmith/datastore"
|
||||
)
|
||||
|
||||
const (
|
||||
|
75
exec.go
75
exec.go
@ -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
|
||||
}
|
||||
|
2
main.go
2
main.go
@ -11,7 +11,7 @@ import (
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
|
||||
"git.townsourced.com/config"
|
||||
"git.townsourced.com/townsourced/config"
|
||||
)
|
||||
|
||||
//settings
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -11,7 +11,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.townsourced.com/ironsmith/datastore"
|
||||
"git.townsourced.com/townsourced/ironsmith/datastore"
|
||||
)
|
||||
|
||||
// /path/<project-id>/<version>/<stage>
|
||||
|
Reference in New Issue
Block a user