forked from remind101/conveyor
/
conveyor.go
168 lines (138 loc) · 3.54 KB
/
conveyor.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
package conveyor
import (
"io"
"github.com/jmoiron/sqlx"
"github.com/remind101/conveyor/builder"
"github.com/remind101/conveyor/logs"
"golang.org/x/net/context"
"code.google.com/p/go-uuid/uuid"
)
// newID returns a new unique identifier.
var newID = uuid.New
// Conveyor provides the primary api for triggering builds.
type Conveyor struct {
// BuildQueue is used to enqueue a build.
BuildQueue
// Logger is the log storage backend to read and write logs for builds.
Logger logs.Logger
db *sqlx.DB
}
// New returns a new Conveyor instance.
func New(db *sqlx.DB) *Conveyor {
return &Conveyor{db: db}
}
// BuildRequest is provided when triggering a new build.
type BuildRequest struct {
// Repository is the repo to build.
Repository string
// Sha is the git commit to build.
Sha string
// Branch is the name of the branch that this build relates to.
Branch string
// Set to true to disable the layer cache. The zero value is to enable
// caching.
NoCache bool
}
// Build enqueues a build to run.
func (c *Conveyor) Build(ctx context.Context, req BuildRequest) (*Build, error) {
tx, err := c.db.Beginx()
if err != nil {
return nil, err
}
b := &Build{
Repository: req.Repository,
Sha: req.Sha,
Branch: req.Branch,
}
if err := buildsCreate(tx, b); err != nil {
tx.Rollback()
return b, err
}
if err := c.BuildQueue.Push(ctx, builder.BuildOptions{
ID: b.ID,
Repository: req.Repository,
Sha: req.Sha,
Branch: req.Branch,
NoCache: req.NoCache,
}); err != nil {
tx.Rollback()
return b, err
}
return b, tx.Commit()
}
// FindBuild finds a build by id.
func (c *Conveyor) FindBuild(ctx context.Context, buildID string) (*Build, error) {
tx, err := c.db.Beginx()
if err != nil {
return nil, err
}
b, err := buildsFind(tx, buildID)
if err != nil {
tx.Rollback()
return b, err
}
return b, tx.Commit()
}
// Writer returns an io.Writer to write logs for the build.
func (c *Conveyor) Writer(ctx context.Context, buildID string) (io.Writer, error) {
return c.Logger.Create(buildID)
}
// Reader returns an io.Reader to read logs for the build.
func (c *Conveyor) Reader(ctx context.Context, buildID string) (io.Reader, error) {
return c.Logger.Open(buildID)
}
// BuildStarted marks the build as started.
func (c *Conveyor) BuildStarted(ctx context.Context, buildID string) error {
tx, err := c.db.Beginx()
if err != nil {
return err
}
if err := buildsUpdateStatus(tx, buildID, StatusBuilding); err != nil {
tx.Rollback()
return err
}
return tx.Commit()
}
// BuildComplete marks a build as successful and adds the image as an artifact.
func (c *Conveyor) BuildComplete(ctx context.Context, buildID, image string) error {
tx, err := c.db.Beginx()
if err != nil {
return err
}
if err := buildsUpdateStatus(tx, buildID, StatusSucceeded); err != nil {
tx.Rollback()
return err
}
if err := artifactsCreate(tx, buildID, &Artifact{
Image: image,
}); err != nil {
tx.Rollback()
return err
}
return tx.Commit()
}
// BuildFailed marks the build as failed.
func (c *Conveyor) BuildFailed(ctx context.Context, buildID string, err error) error {
tx, err := c.db.Beginx()
if err != nil {
return err
}
if err := buildsUpdateStatus(tx, buildID, StatusFailed); err != nil {
tx.Rollback()
return err
}
return tx.Commit()
}
func insert(tx *sqlx.Tx, sql string, v interface{}, id *string) error {
rows, err := tx.NamedQuery(sql, v)
if err != nil {
return err
}
defer rows.Close()
if rows.Next() {
rows.Scan(id)
} else {
panic("expected id to be returned")
}
return nil
}