diff --git a/cycle.go b/cycle.go index 726fb1d..7e8535d 100644 --- a/cycle.go +++ b/cycle.go @@ -77,6 +77,10 @@ func (p *Project) load() { func (p *Project) fetch() { p.setStage(stageFetch) + if p.Fetch == "" { + return + } + tempDir := filepath.Join(p.dir(), strconv.FormatInt(time.Now().Unix(), 10)) if p.errHandled(os.MkdirAll(tempDir, 0777)) { @@ -137,6 +141,10 @@ func (p *Project) fetch() { func (p *Project) build() { p.setStage(stageBuild) + if p.Build == "" { + return + } + output, err := runCmd(p.Build, p.workingDir()) if p.errHandled(err) { @@ -154,6 +162,10 @@ func (p *Project) build() { // test runs the test scripts func (p *Project) test() { p.setStage(stageTest) + + if p.Test == "" { + return + } output, err := runCmd(p.Test, p.workingDir()) if p.errHandled(err) { @@ -172,6 +184,10 @@ func (p *Project) test() { func (p *Project) release() { p.setStage(stageRelease) + if p.Release == "" { + return + } + output, err := runCmd(p.Release, p.workingDir()) if p.errHandled(err) { @@ -193,7 +209,7 @@ func (p *Project) release() { return } - if p.errHandled(p.ds.AddRelease(p.version, buff)) { + if p.errHandled(p.ds.AddRelease(p.version, p.ReleaseFile, buff)) { return } diff --git a/datastore/ds.go b/datastore/ds.go index 5df327a..edbc9eb 100644 --- a/datastore/ds.go +++ b/datastore/ds.go @@ -15,8 +15,10 @@ import ( "github.com/boltdb/bolt" ) +//TODO: Move this all over to GobStore if I ever get around to finishing it + // ErrNotFound is the error returned when a value cannot be found in the store for the given key -var ErrNotFound = errors.New("Value not found") +var ErrNotFound = errors.New("Value not found in datastore") // Store is a datastore for getting and setting data for a given ironsmith project // run on top of a Bolt DB file diff --git a/datastore/log.go b/datastore/log.go index d40f69a..834d557 100644 --- a/datastore/log.go +++ b/datastore/log.go @@ -58,7 +58,7 @@ func (ds *Store) LastVersion(stage string) (string, error) { } } - return ErrNotFound + return nil // not found return blank }) if err != nil { @@ -102,3 +102,79 @@ func (ds *Store) Versions() ([]*Log, error) { return vers, nil } + +// VersionLog returns all the log entries for a given version +func (ds *Store) VersionLog(version string) ([]*Log, error) { + var logs []*Log + + if version == "" { + return logs, nil + } + + verFound := false + + err := ds.bolt.View(func(tx *bolt.Tx) error { + c := tx.Bucket([]byte(bucketLog)).Cursor() + + for k, v := c.Last(); k != nil; k, v = c.Prev() { + l := &Log{} + err := json.Unmarshal(v, l) + if err != nil { + return err + } + + if verFound && l.Version != version { + return nil + } + + if l.Version == version { + logs = append(logs, l) + verFound = true + } + + } + + return nil + }) + + if err != nil { + return nil, err + } + + return logs, nil +} + +// StageLog returns the log entry for a given version + stage +func (ds *Store) StageLog(version, stage string) (*Log, error) { + var entry *Log + + if version == "" || stage == "" { + return nil, ErrNotFound + } + + err := ds.bolt.View(func(tx *bolt.Tx) error { + c := tx.Bucket([]byte(bucketLog)).Cursor() + + for k, v := c.Last(); k != nil; k, v = c.Prev() { + l := &Log{} + err := json.Unmarshal(v, l) + if err != nil { + return err + } + + if l.Version == version && l.Stage == stage { + entry = l + return nil + } + + } + + return ErrNotFound + }) + + if err != nil { + return nil, err + } + + return entry, nil +} diff --git a/datastore/releases.go b/datastore/releases.go index c1f8dc4..8674517 100644 --- a/datastore/releases.go +++ b/datastore/releases.go @@ -12,9 +12,10 @@ import ( ) type release struct { - When time.Time `json:"when"` - Version string `json:"version"` - FileKey TimeKey `json:"file"` + When time.Time `json:"when"` + Version string `json:"version"` + FileName string `json:"fileName"` + FileKey TimeKey `json:"fileKey"` } const ( @@ -23,14 +24,14 @@ const ( ) // AddRelease adds a new Release -func (ds *Store) AddRelease(version string, fileData []byte) error { - key := NewTimeKey() +func (ds *Store) AddRelease(version, fileName string, fileData []byte) error { fileKey := NewTimeKey() r := &release{ - When: key.Time(), - Version: version, - FileKey: fileKey, + When: fileKey.Time(), + Version: version, + FileName: fileName, + FileKey: fileKey, } dsValue, err := json.Marshal(r) @@ -39,7 +40,7 @@ func (ds *Store) AddRelease(version string, fileData []byte) error { } return ds.bolt.Update(func(tx *bolt.Tx) error { - err = tx.Bucket([]byte(bucketReleases)).Put(key.Bytes(), dsValue) + err = tx.Bucket([]byte(bucketReleases)).Put([]byte(version), dsValue) if err != nil { return err } @@ -47,3 +48,42 @@ func (ds *Store) AddRelease(version string, fileData []byte) error { return tx.Bucket([]byte(bucketFiles)).Put(fileKey.Bytes(), fileData) }) } + +func (ds *Store) Release(version string) { + +} + +// Releases lists all the releases in a given project +func (ds *Store) Releases() ([]*Log, error) { + var vers []*Log + + err := ds.bolt.View(func(tx *bolt.Tx) error { + c := tx.Bucket([]byte(bucketLog)).Cursor() + + var current = "" + + for k, v := c.Last(); k != nil; k, v = c.Prev() { + l := &Log{} + err := json.Unmarshal(v, l) + if err != nil { + return err + } + + // capture the newest entry for each version + if l.Version != current { + l.Log = "" // only care about date, ver and stage + vers = append(vers, l) + current = l.Version + } + + } + + return nil + }) + + if err != nil { + return nil, err + } + + return vers, nil +} diff --git a/error.go b/error.go index 0a8a9e1..e99f3b8 100644 --- a/error.go +++ b/error.go @@ -41,6 +41,7 @@ func errHandled(err error, w http.ResponseWriter) bool { errMsg = fmt.Sprintf("We had trouble parsing your input, please check your input and try again: %s", err) default: status = statusError + log.Printf("An error has occurred from a web request: %s", errMsg) errMsg = "An internal server error has occurred" } diff --git a/project.go b/project.go index 86841c1..cf0bc38 100644 --- a/project.go +++ b/project.go @@ -214,6 +214,20 @@ func (p *Project) versions() ([]*datastore.Log, error) { return p.ds.Versions() } +func (p *Project) versionLog(version string) ([]*datastore.Log, error) { + p.RLock() + defer p.RUnlock() + + return p.ds.VersionLog(version) +} + +func (p *Project) stageLog(version, stage string) (*datastore.Log, error) { + p.RLock() + defer p.RUnlock() + + return p.ds.StageLog(version, stage) +} + func (p *Project) setData(new *Project) { p.Lock() defer p.Unlock() diff --git a/server.go b/server.go index c06aa07..7052a13 100644 --- a/server.go +++ b/server.go @@ -77,14 +77,23 @@ func (m *methodHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } /* -Routes - /project/// +log Routes + /log/// - /project/ - list all projects - /project/ - list all versions in a project, triggers new builds - /project// - list combined output of all stages for a given version - /project/// - list all versions in a project, triggers new builds + /log// - list combined output of all stages for a given version + /log/// - list output of a given stage of a given version +release routes + /release// + + /release/ - list last release for a given project ?all returns all the releases for a project + /release// - list release for a given project version + +trigger routes + /trigger/ + Triggers a project to start a cycle */ func routes() { @@ -94,8 +103,8 @@ func routes() { get: rootGet, }) - webRoot.Handle("/project/", &methodHandler{ - get: projectGet, + webRoot.Handle("/log/", &methodHandler{ + get: logGet, }) } diff --git a/webProject.go b/webProject.go index 4157de0..6b96fa3 100644 --- a/webProject.go +++ b/webProject.go @@ -32,14 +32,17 @@ func splitPath(path string) (project, version, stage string) { return } -// /project/* -func projectGet(w http.ResponseWriter, r *http.Request) { - prj, ver, _ := splitPath(r.URL.Path) - - //values := r.URL.Query() +/* + /log/ - list all projects + /log/ - list all versions in a project, triggers new builds + /log// - list combined output of all stages for a given version + /log/// - list output of a given stage of a given version +*/ +func logGet(w http.ResponseWriter, r *http.Request) { + prj, ver, stg := splitPath(r.URL.Path) if prj == "" { - //get all projects + ///log/ - list all projects pList, err := projects.webList() if errHandled(err, w) { return @@ -62,7 +65,8 @@ func projectGet(w http.ResponseWriter, r *http.Request) { //project found if ver == "" { - //list versions + ///log/ - list all versions in a project, triggers new builds + vers, err := project.versions() if errHandled(err, w) { return @@ -74,4 +78,72 @@ func projectGet(w http.ResponseWriter, r *http.Request) { return } + //ver found + if stg == "" { + ///log// - list combined output of all stages for a given version + logs, err := project.versionLog(ver) + if errHandled(err, w) { + return + } + respondJsend(w, &JSend{ + Status: statusSuccess, + Data: logs, + }) + return + } + + //stage found + ///log/// - list output of a given stage of a given version + + log, err := project.stageLog(ver, stg) + if errHandled(err, w) { + return + } + + respondJsend(w, &JSend{ + Status: statusSuccess, + Data: log, + }) + return +} + +/* + /release// + + /release/ - list last release for a given project ?all returns all the releases for a project + /release// - list release for a given project version +*/ +func releaseGet(w http.ResponseWriter, r *http.Request) { + prj, ver, stg := splitPath(r.URL.Path) + + values := r.URL.Query() + + if prj == "" { + four04(w, r) + return + } + + project, ok := projects.get(prj) + if !ok { + four04(w, r) + return + } + + //project found + + if ver == "" { + ///release/ - list last release for a given project ?all returns all the releases for a project + + vers, err := project.versions() + if errHandled(err, w) { + return + } + respondJsend(w, &JSend{ + Status: statusSuccess, + Data: vers, + }) + return + } + + //ver found }