-
Notifications
You must be signed in to change notification settings - Fork 10
/
build.go
142 lines (114 loc) · 3.67 KB
/
build.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
package postgres
import (
"database/sql"
"fmt"
"github.com/pkg/errors"
"github.com/simplesurance/baur/storage"
)
const buildQueryWithoutInputsOutputs = `
SELECT application.id, application.name,
build.id, build.start_timestamp, build.stop_timestamp, build.total_input_digest,
vcs.commit, vcs.dirty,
(EXTRACT(EPOCH FROM (build.stop_timestamp - build.start_timestamp))::bigint * 1000000000) as duration
FROM application
JOIN build ON application.id = build.application_id
LEFT OUTER JOIN vcs ON vcs.id = build.vcs_id`
// GetBuildsWithoutInputsOutputs returns builds from the database
func (c *Client) GetBuildsWithoutInputsOutputs(filters []*storage.Filter, sorters []*storage.Sorter) (
[]*storage.BuildWithDuration, error) {
var builds []*storage.BuildWithDuration
q := Query{
BaseQuery: buildQueryWithoutInputsOutputs,
Filters: filters,
Sorters: sorters,
}
query, args, err := q.Compile()
if err != nil {
return nil, errors.Wrap(err, "compiling query string failed")
}
rows, err := c.Db.Query(query, args...)
if err != nil {
return nil, errors.Wrapf(err, "db query '%s' (%q) failed", query, args)
}
for rows.Next() {
build, err := scanBuildRows(rows)
if err != nil {
rows.Close()
return nil, errors.Wrapf(err, "scanning result of db query '%s' (%q) failed", query, args)
}
builds = append(builds, build)
}
if err := rows.Err(); err != nil {
return nil, errors.Wrap(err, "iterating over db results failed:")
}
return builds, nil
}
func scanBuildRows(rows *sql.Rows) (*storage.BuildWithDuration, error) {
var build storage.BuildWithDuration
err := rows.Scan(
&build.Build.Application.ID,
&build.Build.Application.Name,
&build.Build.ID,
&build.Build.StartTimeStamp,
&build.Build.StopTimeStamp,
&build.Build.TotalInputDigest,
&build.Build.VCSState.CommitID,
&build.Build.VCSState.IsDirty,
&build.Duration,
)
if err != nil {
return nil, err
}
return &build, nil
}
// GetLatestBuildByDigest returns the build id of a build for the application
// with the passed digest. If multiple builds exist, the one with the lastest
// stop_timestamp is returned.
// Inputs are not fetched from the database.
// If no builds exist storage.ErrNotExist is returned
func (c *Client) GetLatestBuildByDigest(appName, totalInputDigest string) (*storage.BuildWithDuration, error) {
const query = buildQueryWithoutInputsOutputs + `
WHERE application.name = $1 AND build.total_input_digest = $2
ORDER BY build.stop_timestamp DESC LIMIT 1
`
rows, err := c.Db.Query(query, appName, totalInputDigest)
if err != nil {
return nil, errors.Wrapf(err, "db query '%s' failed", query)
}
if !rows.Next() {
return nil, storage.ErrNotExist
}
if err := rows.Err(); err != nil {
return nil, errors.Wrap(err, "iterating over db results failed:")
}
build, err := scanBuildRows(rows)
rows.Close()
if err != nil {
return nil, errors.Wrapf(err, "scanning result of db query '%s' failed", query)
}
builds, err := c.GetBuildOutputs(build.ID)
if err != nil {
return nil, errors.Wrap(err, "fetching build outputs failed")
}
build.Outputs = builds
return build, err
}
// GetBuildWithoutInputsOutputs retrieves a single build from the database
func (c *Client) GetBuildWithoutInputsOutputs(id int) (*storage.BuildWithDuration, error) {
builds, err := c.GetBuildsWithoutInputsOutputs([]*storage.Filter{
{
Field: storage.FieldBuildID,
Operator: storage.OpEQ,
Value: id,
}}, nil)
if err != nil {
return nil, err
}
if len(builds) == 0 {
return nil, storage.ErrNotExist
}
if len(builds) > 1 {
panic(fmt.Sprintf("GetBuilds returned >%d records for build id '%d', expected max. 1", len(builds), id))
}
return builds[0], nil
}