Skip to content

Commit

Permalink
build: store build results in the postgresql storage
Browse files Browse the repository at this point in the history
"baur build --upload" now stores informations about builds and the
produced artefact in the postgreSQL storage.

If "--upload" is not passed as parameter, builds are not recorded.
  • Loading branch information
fho committed Jun 19, 2018
1 parent 194ec11 commit 4881fa8
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 11 deletions.
9 changes: 9 additions & 0 deletions README.md
Expand Up @@ -35,6 +35,15 @@ To build the application run `make`
- set the build_command to a command that when it's run in your application
directories, produces build artifacts like a docker container or a tar
archives.
- set the postgresql_url to a valid connection string to a database that will
store informations about builds and aritfacts.
If you do not want to store the password of your database user in the
`baur.toml` file. You can also put in your `.pgpass` file
(https://www.postgresql.org/docs/9.3/static/libpq-pgpass.html).


- create the tables in the database by running the SQL-script
`storage/postgres/migrations/0001.up.sql`

2. Run `baur appinit` in your application directories to create an `.app.toml`
file.
Expand Down
3 changes: 2 additions & 1 deletion build/build.go
Expand Up @@ -9,7 +9,8 @@ type Result struct {
Job *Job
Error error

Duration time.Duration
StartTs time.Time
StopTs time.Time
ExitCode int
Output string
}
Expand Down
3 changes: 2 additions & 1 deletion build/seq/seq.go
Expand Up @@ -33,7 +33,8 @@ func (b *Builder) Start() {
res := build.Result{
Job: j,
Error: err,
Duration: time.Since(startTime),
StartTs: startTime,
StopTs: time.Now(),
ExitCode: exitCode,
Output: out,
}
Expand Down
104 changes: 95 additions & 9 deletions command/build.go
@@ -1,15 +1,18 @@
package command

import (
"fmt"
"os"
"strings"
"sync"
"time"

"github.com/simplesurance/baur"
"github.com/simplesurance/baur/build"
"github.com/simplesurance/baur/build/seq"
"github.com/simplesurance/baur/docker"
"github.com/simplesurance/baur/log"
"github.com/simplesurance/baur/prettyprint"
"github.com/simplesurance/baur/s3"
"github.com/simplesurance/baur/storage"
"github.com/simplesurance/baur/storage/postgres"
Expand All @@ -21,6 +24,75 @@ import (

var buildUpload bool

type uploadUserData struct {
App *baur.App
Artifact baur.Artifact
}

var result = map[string]*storage.Build{}
var resultLock = sync.Mutex{}

var store storage.Storer

func resultAddBuildResult(app *baur.App, r *build.Result) {
resultLock.Lock()
defer resultLock.Unlock()

b := storage.Build{
AppName: app.Name,
StartTimeStamp: r.StartTs,
StopTimeStamp: r.StopTs,
// Sources: // TODO
//TotalSrcHash: // TODO
}

result[app.Name] = &b

}

func resultAddUploadResult(appName string, ar baur.Artifact, r *upload.Result) {
var arType storage.ArtifactType

resultLock.Lock()
defer resultLock.Unlock()

b, exist := result[appName]
if !exist {
panic(fmt.Sprintf("resultAddUploadResult: %q does not exist in build result map", appName))
}

if r.Job.Type() == upload.JobDocker {
arType = storage.DockerArtifact
} else if r.Job.Type() == upload.JobS3 {
arType = storage.S3Artifact
}

b.Artifacts = append(b.Artifacts, &storage.Artifact{
Name: ar.Name(),
// SizeBytes, // TODO implement it
Type: arType,
URL: r.URL,
UploadDuration: r.Duration,
})
}

func recordResultIsComplete(app *baur.App) (bool, *storage.Build) {
resultLock.Lock()
defer resultLock.Unlock()

b, exist := result[app.Name]
if !exist {
panic(fmt.Sprintf("recordResultIfComplete: %q does not exist in build result map", app.Name))
}

if len(app.Artifacts) == len(b.Artifacts) {
return true, b
}

return false, nil

}

func init() {
buildCmd.Flags().BoolVar(&buildUpload, "upload", false,
"upload build artifacts after the application(s) was build")
Expand Down Expand Up @@ -144,17 +216,28 @@ func waitPrintUploadStatus(uploader upload.Manager, uploadChan chan *upload.Resu
var resultCnt int

for res := range uploadChan {
ar, ok := res.Job.GetUserData().(baur.Artifact)
ud, ok := res.Job.GetUserData().(*uploadUserData)
if !ok {
panic("upload result user data has unexpected type")
}

if res.Err != nil {
log.Fatalf("upload of %q failed: %s\n", ar, res.Err)
log.Fatalf("upload of %q failed: %s\n", ud.Artifact, res.Err)
}

log.Actionf("%s uploaded to %s (%.3fs)\n",
ar, res.URL, res.Duration.Seconds())
log.Actionf("%s: artifact %s uploaded to %s (%.3fs)\n",
ud.App.Name, ud.Artifact.LocalPath(), res.URL, res.Duration.Seconds())

resultAddUploadResult(ud.App.Name, ud.Artifact, res)

complete, build := recordResultIsComplete(ud.App)
if complete {
if err := store.Save(build); err != nil {
log.Fatalf("storing build information about %q failed: %s", ud.App.Name, err)
}

log.Debugf("stored the following build information: %s\n", prettyprint.AsString(build))
}

resultCnt++
if resultCnt == artifactCnt {
Expand All @@ -171,7 +254,6 @@ func buildCMD(cmd *cobra.Command, args []string) {
var apps []*baur.App
var uploadWatchFin chan struct{}
var uploader upload.Manager
var storage storage.Storer

repo := mustFindRepository()
startTs := time.Now()
Expand All @@ -193,11 +275,10 @@ func buildCMD(cmd *cobra.Command, args []string) {

if buildUpload {
var err error
storage, err = postgres.New(repo.PSQLURL)
store, err = postgres.New(repo.PSQLURL)
if err != nil {
log.Fatalf("could not establish connection to postgreSQL db: %s", err)
}
storage.ListBuildsPerApp("hello", 3) //TODO

uploadChan := make(chan *upload.Result, artifactCnt)
uploader = startBGUploader(artifactCnt, uploadChan)
Expand Down Expand Up @@ -228,7 +309,8 @@ func buildCMD(cmd *cobra.Command, args []string) {
app.Name, status.Job.Command, status.ExitCode, status.Output)
}

log.Actionf("%s: build successful (%.3fs)\n", app.Name, status.Duration.Seconds())
log.Actionf("%s: build successful (%.3fs)\n", app.Name, status.StopTs.Sub(status.StartTs).Seconds())
resultAddBuildResult(app, status)

for _, ar := range app.Artifacts {
if !ar.Exists() {
Expand All @@ -242,7 +324,10 @@ func buildCMD(cmd *cobra.Command, args []string) {
log.Fatalf("could not get upload job for artifact %s: %s", ar, err)
}

uj.SetUserData(ar)
uj.SetUserData(&uploadUserData{
App: app,
Artifact: ar,
})

uploader.Add(uj)

Expand All @@ -259,4 +344,5 @@ func buildCMD(cmd *cobra.Command, args []string) {

term.PrintSep()
log.Infof("finished in %s\n", time.Since(startTs))

}

0 comments on commit 4881fa8

Please sign in to comment.