forked from evergreen-ci/evergreen
/
build.go
157 lines (139 loc) · 5.49 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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
package build
import (
"github.com/evergreen-ci/evergreen"
"github.com/evergreen-ci/evergreen/apimodels"
"github.com/evergreen-ci/evergreen/db"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
"time"
)
// IdTimeLayout is used time time.Time.Format() to produce timestamps for our ids.
const IdTimeLayout = "06_01_02_15_04_05"
// TaskCache represents some duped information about tasks,
// mainly for ui purposes.
type TaskCache struct {
Id string `bson:"id" json:"id"`
DisplayName string `bson:"d" json:"display_name"`
Status string `bson:"s" json:"status"`
StatusDetails apimodels.TaskEndDetail `bson:"ed" json:"task_end_details"`
StartTime time.Time `bson:"st" json:"start_time"`
TimeTaken time.Duration `bson:"tt" json:"time_taken"`
Activated bool `bson:"a" json:"activated"`
}
// Build represents a set of tasks on one variant of a Project
// e.g. one build might be "Ubuntu with Python 2.4" and
// another might be "OSX with Python 3.0", etc.
type Build struct {
Id string `bson:"_id" json:"_id"`
CreateTime time.Time `bson:"create_time" json:"create_time,omitempty"`
StartTime time.Time `bson:"start_time" json:"start_time,omitempty"`
FinishTime time.Time `bson:"finish_time" json:"finish_time,omitempty"`
PushTime time.Time `bson:"push_time" json:"push_time,omitempty"`
Version string `bson:"version" json:"version,omitempty"`
Project string `bson:"branch" json:"branch,omitempty"`
Revision string `bson:"gitspec" json:"gitspec,omitempty"`
BuildVariant string `bson:"build_variant" json:"build_variant,omitempty"`
BuildNumber string `bson:"build_number" json:"build_number,omitempty"`
Status string `bson:"status" json:"status,omitempty"`
Activated bool `bson:"activated" json:"activated,omitempty"`
ActivatedTime time.Time `bson:"activated_time" json:"activated_time,omitempty"`
RevisionOrderNumber int `bson:"order,omitempty" json:"order,omitempty"`
Tasks []TaskCache `bson:"tasks" json:"tasks,omitempty"`
TimeTaken time.Duration `bson:"time_taken" json:"time_taken,omitempty"`
DisplayName string `bson:"display_name" json:"display_name,omitempty"`
// build requester - this is used to help tell the
// reason this build was created. e.g. it could be
// because the repotracker requested it (via tracking the
// repository) or it was triggered by a developer
// patch request
Requester string `bson:"r" json:"r,omitempty"`
}
// Returns whether or not the build has finished, based on its status.
func (b *Build) IsFinished() bool {
return b.Status == evergreen.BuildFailed ||
b.Status == evergreen.BuildCancelled ||
b.Status == evergreen.BuildSucceeded
}
// Find
// FindBuildOnBaseCommit returns the build that a patch build is based on.
func (b *Build) FindBuildOnBaseCommit() (*Build, error) {
return FindOne(ByRevisionAndVariant(b.Revision, b.BuildVariant))
}
// Find all builds on the same project + variant + requester between
// the current b and the specified previous build.
func (b *Build) FindIntermediateBuilds(previous *Build) ([]Build, error) {
return Find(ByBetweenBuilds(b, previous))
}
// Find the most recent activated build with the same variant +
// requester + project as the current build.
func (b *Build) PreviousActivated(project string, requester string) (*Build, error) {
return FindOne(ByRecentlyActivatedForProjectAndVariant(
b.RevisionOrderNumber, project, b.BuildVariant, requester))
}
// Find the most recent b on with the same build variant + requester +
// project as the current build, with any of the specified statuses.
func (b *Build) PreviousSuccessful() (*Build, error) {
return FindOne(ByRecentlySuccessfulForProjectAndVariant(
b.RevisionOrderNumber, b.Project, b.BuildVariant))
}
// Update
// UpdateActivation updates one build with the given id
// to the given activation setting.
func UpdateActivation(buildId string, active bool) error {
return UpdateOne(
bson.M{IdKey: buildId},
bson.M{
"$set": bson.M{
ActivatedKey: active,
ActivatedTimeKey: time.Now(),
},
},
)
}
// UpdateStatus sets the build status to the given string.
func (b *Build) UpdateStatus(status string) error {
b.Status = status
return UpdateOne(
bson.M{IdKey: b.Id},
bson.M{"$set": bson.M{StatusKey: status}},
)
}
// TryMarkBuildStarted attempts to mark a b as started if it
// isn't already marked as such
func TryMarkStarted(buildId string, startTime time.Time) error {
selector := bson.M{
IdKey: buildId,
StatusKey: evergreen.BuildCreated,
}
update := bson.M{"$set": bson.M{
StatusKey: evergreen.BuildStarted,
StartTimeKey: startTime,
}}
err := UpdateOne(selector, update)
if err == mgo.ErrNotFound {
return nil
}
return err
}
// MarkFinished sets the build to finished status in the database (this does
// not update task or version data).
func (b *Build) MarkFinished(status string, finishTime time.Time) error {
b.Status = status
b.FinishTime = finishTime
b.TimeTaken = finishTime.Sub(b.StartTime)
return UpdateOne(
bson.M{IdKey: b.Id},
bson.M{
"$set": bson.M{
StatusKey: status,
FinishTimeKey: finishTime,
TimeTakenKey: b.TimeTaken,
},
},
)
}
// Create
// Insert writes the b to the db.
func (b *Build) Insert() error {
return db.Insert(Collection, b)
}