-
Notifications
You must be signed in to change notification settings - Fork 125
/
build_task.go
145 lines (124 loc) · 4.4 KB
/
build_task.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
package route
import (
"context"
"net/http"
"github.com/evergreen-ci/evergreen/model/task"
"github.com/evergreen-ci/evergreen/rest/data"
"github.com/evergreen-ci/evergreen/rest/model"
"github.com/evergreen-ci/gimlet"
"github.com/evergreen-ci/utility"
"github.com/pkg/errors"
)
type tasksByBuildHandler struct {
buildId string
status string
fetchAllExecutions bool
fetchParentIds bool
limit int
key string
url string
parsleyURL string
}
func makeFetchTasksByBuild(parsleyURL, url string) gimlet.RouteHandler {
return &tasksByBuildHandler{
limit: defaultLimit,
url: url,
parsleyURL: parsleyURL,
}
}
// Factory creates an instance of the handler.
//
// @Summary List tasks by build
// @Description List all tasks within a specific build.
// @Tags tasks
// @Router /builds/{build_id}/tasks [get]
// @Security Api-User || Api-Key
// @Param build_id path string true "the build ID"
// @Param start_at query string false "The identifier of the task to start at in the pagination"
// @Param limit query int false "The number of tasks to be returned per page of pagination. Defaults to 100"
// @Param fetch_all_executions query boolean false "Fetches previous executions of tasks if they are available"
// @Param fetch_parent_ids query boolean false "Fetches the parent display task ID for each returned execution task"
// @Success 200 {array} model.APITask
func (tbh *tasksByBuildHandler) Factory() gimlet.RouteHandler {
return &tasksByBuildHandler{
limit: tbh.limit,
url: tbh.url,
parsleyURL: tbh.parsleyURL,
}
}
func (tbh *tasksByBuildHandler) Parse(ctx context.Context, r *http.Request) error {
vals := r.URL.Query()
tbh.buildId = gimlet.GetVars(r)["build_id"]
if tbh.buildId == "" {
return errors.New("build ID cannot be empty")
}
tbh.status = vals.Get("status")
tbh.key = vals.Get("start_at")
var err error
tbh.limit, err = getLimit(vals)
if err != nil {
return errors.Wrap(err, "getting limit")
}
tbh.fetchAllExecutions = vals.Get("fetch_all_executions") == "true"
tbh.fetchParentIds = vals.Get("fetch_parent_ids") == "true"
return nil
}
func (tbh *tasksByBuildHandler) Run(ctx context.Context) gimlet.Responder {
// Fetch all of the tasks to be returned in this page plus the tasks used for
// calculating information about the next page. Here the limit is multiplied
// by two to fetch the next page.
tasks, err := data.FindTasksByBuildId(tbh.buildId, tbh.key, tbh.status, tbh.limit+1, 1)
if err != nil {
return gimlet.MakeJSONInternalErrorResponder(errors.Wrapf(err, "finding tasks for build '%s'", tbh.buildId))
}
resp := gimlet.NewResponseBuilder()
lastIndex := len(tasks)
if len(tasks) > tbh.limit {
lastIndex = tbh.limit
err = resp.SetPages(&gimlet.ResponsePages{
Next: &gimlet.Page{
Relation: "next",
LimitQueryParam: "limit",
KeyQueryParam: "start_at",
BaseURL: tbh.url,
Key: tasks[tbh.limit].Id,
Limit: tbh.limit,
},
})
if err != nil {
return gimlet.MakeJSONInternalErrorResponder(errors.Wrap(err, "paginating response"))
}
}
tasks = tasks[:lastIndex]
for i := range tasks {
taskModel := &model.APITask{}
if err = taskModel.BuildFromService(ctx, &tasks[i], &model.APITaskArgs{
IncludeAMI: true,
IncludeArtifacts: true,
IncludeProjectIdentifier: true,
LogURL: tbh.url,
ParsleyLogURL: tbh.parsleyURL,
}); err != nil {
return gimlet.MakeJSONInternalErrorResponder(errors.Wrapf(err, "converting task '%s' to API model", tasks[i].Id))
}
if tbh.fetchAllExecutions {
var oldTasks []task.Task
oldTasks, err = task.FindOldWithDisplayTasks(task.ByOldTaskID(tasks[i].Id))
if err != nil {
return gimlet.MakeJSONInternalErrorResponder(errors.Wrapf(err, "finding archived task '%s'", tasks[i].Id))
}
if err = taskModel.BuildPreviousExecutions(ctx, oldTasks, tbh.url, tbh.parsleyURL); err != nil {
return gimlet.MakeJSONInternalErrorResponder(errors.Wrap(err, "adding previous task executions to API model"))
}
}
if tbh.fetchParentIds {
if tasks[i].IsPartOfDisplay() {
taskModel.ParentTaskId = utility.FromStringPtr(tasks[i].DisplayTaskId)
}
}
if err = resp.AddData(taskModel); err != nil {
return gimlet.MakeJSONInternalErrorResponder(errors.Wrap(err, "adding response data"))
}
}
return resp
}