generated from broadinstitute/golang-project-template
-
Notifications
You must be signed in to change notification settings - Fork 0
/
chart_release_version.go
317 lines (305 loc) · 18.5 KB
/
chart_release_version.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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
package v2models
import (
"fmt"
"github.com/broadinstitute/sherlock/internal/utils"
"time"
"github.com/broadinstitute/sherlock/internal/errors"
"gorm.io/gorm"
)
// ChartReleaseVersion isn't stored in the database on its own, it is included as a part of a ChartRelease or
// Changeset. It has especially strict validation that requires it being fully loaded from the database. The resolve
// method will help "load" it fully from the database so it can survive validation.
type ChartReleaseVersion struct {
ResolvedAt *time.Time
AppVersionResolver *string
AppVersionExact *string
AppVersionBranch *string
AppVersionCommit *string
AppVersionFollowChartRelease *ChartRelease
AppVersionFollowChartReleaseID *uint
AppVersion *AppVersion
AppVersionID *uint
ChartVersionResolver *string
ChartVersionExact *string
ChartVersionFollowChartRelease *ChartRelease
ChartVersionFollowChartReleaseID *uint
ChartVersion *ChartVersion
ChartVersionID *uint
HelmfileRef *string
FirecloudDevelopRef *string
}
func (chartReleaseVersion *ChartReleaseVersion) resolve(db *gorm.DB, chartQuery Chart) error {
chart, err := chartStore.get(db, chartQuery)
if err != nil {
return fmt.Errorf("failed to get %T: %v", chartQuery, err)
}
if chartReleaseVersion.AppVersionResolver != nil {
switch *chartReleaseVersion.AppVersionResolver {
case "branch":
if chartReleaseVersion.AppVersionBranch != nil {
appVersions, err := appVersionStore.listAllMatchingByCreated(db, 1, AppVersion{ChartID: chart.ID, GitBranch: *chartReleaseVersion.AppVersionBranch})
if err != nil {
return fmt.Errorf("(%s) failed to get matching app versions for branch '%s': %v", errors.InternalServerError, *chartReleaseVersion.AppVersionBranch, err)
} else if len(appVersions) == 0 {
return fmt.Errorf("(%s) no app versions for the %s chart match a branch name of '%s'", errors.BadRequest, chart.Name, *chartReleaseVersion.AppVersionBranch)
}
chartReleaseVersion.AppVersion = &appVersions[0]
chartReleaseVersion.AppVersionID = &appVersions[0].ID
chartReleaseVersion.AppVersionCommit = &appVersions[0].GitCommit
chartReleaseVersion.AppVersionExact = &appVersions[0].AppVersion
chartReleaseVersion.AppVersionFollowChartRelease = nil
chartReleaseVersion.AppVersionFollowChartReleaseID = nil
}
case "commit":
if chartReleaseVersion.AppVersionCommit != nil {
if !utils.IsAlphaNumeric(*chartReleaseVersion.AppVersionCommit) {
return fmt.Errorf("(%s) the given commit '%s' seems to have an invalid format", errors.BadRequest, *chartReleaseVersion.AppVersionCommit)
}
// It's ugly but we go down to basically raw SQL here so we can handle the fact that people are definitely going
// to specify commits with less than the full hash.
appVersions, err := appVersionStore.listAllMatchingByCreated(db, 1, "chart_id = ? and git_commit LIKE ?", chart.ID, fmt.Sprintf("%s%%", *chartReleaseVersion.AppVersionCommit))
if err != nil {
return fmt.Errorf("(%s) failed to get matching app versions for commit '%s': %v", errors.InternalServerError, *chartReleaseVersion.AppVersionCommit, err)
} else if len(appVersions) == 0 {
return fmt.Errorf("(%s) no app versions for the %s chart match a commit hash of '%s'", errors.BadRequest, chart.Name, *chartReleaseVersion.AppVersionBranch)
}
chartReleaseVersion.AppVersion = &appVersions[0]
chartReleaseVersion.AppVersionID = &appVersions[0].ID
chartReleaseVersion.AppVersionBranch = &appVersions[0].GitBranch
chartReleaseVersion.AppVersionExact = &appVersions[0].AppVersion
// Since we might've matched against less than the full hash, copy that too
chartReleaseVersion.AppVersionCommit = &appVersions[0].GitCommit
chartReleaseVersion.AppVersionFollowChartRelease = nil
chartReleaseVersion.AppVersionFollowChartReleaseID = nil
}
case "exact":
if chartReleaseVersion.AppVersionExact != nil {
appVersions, err := appVersionStore.listAllMatchingByCreated(db, 1, AppVersion{ChartID: chart.ID, AppVersion: *chartReleaseVersion.AppVersionExact})
if err == nil && len(appVersions) > 0 {
chartReleaseVersion.AppVersion = &appVersions[0]
chartReleaseVersion.AppVersionID = &appVersions[0].ID
chartReleaseVersion.AppVersionBranch = &appVersions[0].GitBranch
chartReleaseVersion.AppVersionCommit = &appVersions[0].GitCommit
} else {
chartReleaseVersion.AppVersion = nil
chartReleaseVersion.AppVersionID = nil
chartReleaseVersion.AppVersionBranch = nil
chartReleaseVersion.AppVersionCommit = nil
}
chartReleaseVersion.AppVersionFollowChartRelease = nil
chartReleaseVersion.AppVersionFollowChartReleaseID = nil
}
case "follow":
if chartReleaseVersion.AppVersionFollowChartReleaseID != nil {
chartReleases, err := chartReleaseStore.listAllMatchingByCreated(db, 1, ChartRelease{ChartID: chart.ID, Model: gorm.Model{ID: *chartReleaseVersion.AppVersionFollowChartReleaseID}})
if err != nil {
return fmt.Errorf("(%s) failed to follow app version of chart release %d: %v", errors.InternalServerError, *chartReleaseVersion.AppVersionFollowChartReleaseID, err)
} else if len(chartReleases) == 0 {
return fmt.Errorf("(%s) failed to follow app version of chart release %d: not found", errors.NotFound, *chartReleaseVersion.AppVersionFollowChartReleaseID)
} else {
chartReleaseVersion.AppVersion = chartReleases[0].AppVersion
chartReleaseVersion.AppVersionID = chartReleases[0].AppVersionID
chartReleaseVersion.AppVersionBranch = chartReleases[0].AppVersionBranch
chartReleaseVersion.AppVersionCommit = chartReleases[0].AppVersionCommit
chartReleaseVersion.AppVersionExact = chartReleases[0].AppVersionExact
chartReleaseVersion.AppVersionFollowChartRelease = &chartReleases[0]
}
}
case "none":
chartReleaseVersion.AppVersion = nil
chartReleaseVersion.AppVersionID = nil
chartReleaseVersion.AppVersionBranch = nil
chartReleaseVersion.AppVersionCommit = nil
chartReleaseVersion.AppVersionExact = nil
chartReleaseVersion.AppVersionFollowChartRelease = nil
chartReleaseVersion.AppVersionFollowChartReleaseID = nil
}
}
if chartReleaseVersion.ChartVersionResolver != nil {
switch *chartReleaseVersion.ChartVersionResolver {
case "latest":
chartVersions, err := chartVersionStore.listAllMatchingByCreated(db, 1, ChartVersion{ChartID: chart.ID})
if err != nil {
return fmt.Errorf("(%s) failed to get latest chart versions for %s", errors.InternalServerError, chart.Name)
} else if len(chartVersions) == 0 {
return fmt.Errorf("(%s) no chart versions exist for %s", errors.BadRequest, chart.Name)
}
chartReleaseVersion.ChartVersion = &chartVersions[0]
chartReleaseVersion.ChartVersionID = &chartVersions[0].ID
chartReleaseVersion.ChartVersionExact = &chartVersions[0].ChartVersion
chartReleaseVersion.ChartVersionFollowChartRelease = nil
chartReleaseVersion.ChartVersionFollowChartReleaseID = nil
case "exact":
if chartReleaseVersion.ChartVersionExact != nil {
chartVersions, err := chartVersionStore.listAllMatchingByCreated(db, 1, ChartVersion{ChartID: chart.ID, ChartVersion: *chartReleaseVersion.ChartVersionExact})
if err == nil && len(chartVersions) > 0 {
chartReleaseVersion.ChartVersion = &chartVersions[0]
chartReleaseVersion.ChartVersionID = &chartVersions[0].ID
} else {
chartReleaseVersion.ChartVersion = nil
chartReleaseVersion.ChartVersionID = nil
}
chartReleaseVersion.ChartVersionFollowChartRelease = nil
chartReleaseVersion.ChartVersionFollowChartReleaseID = nil
}
case "follow":
if chartReleaseVersion.ChartVersionFollowChartReleaseID != nil {
chartReleases, err := chartReleaseStore.listAllMatchingByCreated(db, 1, ChartRelease{ChartID: chart.ID, Model: gorm.Model{ID: *chartReleaseVersion.ChartVersionFollowChartReleaseID}})
if err != nil {
return fmt.Errorf("(%s) failed to follow chart version of chart release %d: %v", errors.InternalServerError, *chartReleaseVersion.ChartVersionFollowChartReleaseID, err)
} else if len(chartReleases) == 0 {
return fmt.Errorf("(%s) failed to follow chart version of chart release %d: not found", errors.NotFound, *chartReleaseVersion.ChartVersionFollowChartReleaseID)
} else {
chartReleaseVersion.ChartVersion = chartReleases[0].ChartVersion
chartReleaseVersion.ChartVersionID = chartReleases[0].ChartVersionID
chartReleaseVersion.ChartVersionExact = chartReleases[0].ChartVersionExact
chartReleaseVersion.ChartVersionFollowChartRelease = &chartReleases[0]
}
}
}
}
now := time.Now()
chartReleaseVersion.ResolvedAt = &now
return nil
}
func (chartReleaseVersion *ChartReleaseVersion) validate() error {
if chartReleaseVersion.ResolvedAt == nil {
return fmt.Errorf("a %T must be resolved before being entered into a database", chartReleaseVersion)
}
if chartReleaseVersion.AppVersionResolver == nil {
return fmt.Errorf("a %T must have an AppVersionResolver (it can be 'none')", chartReleaseVersion)
} else {
// This might seem overly strict but remember that validation happens after resolving--if that works,
// it'll handle many of these fields.
switch *chartReleaseVersion.AppVersionResolver {
case "branch":
if chartReleaseVersion.AppVersionBranch == nil || *chartReleaseVersion.AppVersionBranch == "" {
return fmt.Errorf("a %T with an AppVersionResolver of %s must have an AppVersionBranch",
chartReleaseVersion, *chartReleaseVersion.AppVersionResolver)
}
if chartReleaseVersion.AppVersion == nil || chartReleaseVersion.AppVersion.GitBranch != *chartReleaseVersion.AppVersionBranch {
return fmt.Errorf("a %T with an AppVersionResolver of %s must be associated to an internal AppVersion with a version for that same branch, here '%s'",
chartReleaseVersion, *chartReleaseVersion.AppVersionResolver, *chartReleaseVersion.AppVersionBranch)
}
fallthrough
case "commit":
if chartReleaseVersion.AppVersionCommit == nil || *chartReleaseVersion.AppVersionCommit == "" {
return fmt.Errorf("a %T with an AppVersionResolver of %s must have an AppVersionCommit",
chartReleaseVersion, *chartReleaseVersion.AppVersionResolver)
}
if chartReleaseVersion.AppVersion == nil || chartReleaseVersion.AppVersion.GitCommit != *chartReleaseVersion.AppVersionCommit {
return fmt.Errorf("a %T with an AppVersionResolver of %s must be associated to an internal AppVersion with a version for that same branch, here '%s'",
chartReleaseVersion, *chartReleaseVersion.AppVersionResolver, *chartReleaseVersion.AppVersionBranch)
}
fallthrough
case "exact":
if chartReleaseVersion.AppVersionExact == nil || *chartReleaseVersion.AppVersionExact == "" {
return fmt.Errorf("a %T with an AppVersionResolver of %s must have an AppVersionExact",
chartReleaseVersion, *chartReleaseVersion.AppVersionResolver)
}
if chartReleaseVersion.AppVersion != nil && chartReleaseVersion.AppVersion.AppVersion != *chartReleaseVersion.AppVersionExact {
return fmt.Errorf("a %T must not have an associated internal AppVersion in conflict with the exact version on the %T, here '%s'",
chartReleaseVersion, chartReleaseVersion, *chartReleaseVersion.AppVersionExact)
}
case "follow":
if chartReleaseVersion.AppVersionFollowChartReleaseID == nil {
return fmt.Errorf("a %T with an AppVersionResolver of %s must have an AppVersionFollowChartReleaseID", chartReleaseVersion, *chartReleaseVersion.AppVersionResolver)
}
case "none":
if !(chartReleaseVersion.AppVersionBranch == nil || *chartReleaseVersion.AppVersionBranch == "") {
return fmt.Errorf("a %T with an AppVersionResolver of %s must not have an AppVersionBranch",
chartReleaseVersion, *chartReleaseVersion.AppVersionResolver)
}
if !(chartReleaseVersion.AppVersionCommit == nil || *chartReleaseVersion.AppVersionCommit == "") {
return fmt.Errorf("a %T with an AppVersionResolver of %s must not have an AppVersionCommit",
chartReleaseVersion, *chartReleaseVersion.AppVersionResolver)
}
if !(chartReleaseVersion.AppVersionExact == nil || *chartReleaseVersion.AppVersionExact == "") {
return fmt.Errorf("a %T with an AppVersionResolver of %s must not have an AppVersionExact",
chartReleaseVersion, *chartReleaseVersion.AppVersionResolver)
}
if chartReleaseVersion.AppVersion != nil || chartReleaseVersion.AppVersionID != nil {
return fmt.Errorf("a %T with an AppVersionResolver of %s must not be associated to an internal AppVersion",
chartReleaseVersion, *chartReleaseVersion.AppVersionResolver)
}
if chartReleaseVersion.AppVersionFollowChartRelease != nil || chartReleaseVersion.AppVersionFollowChartReleaseID != nil {
return fmt.Errorf("a %T with an AppVersionResolver of %s must not be following with an AppVersionFollowChartReleaseID", chartReleaseVersion, *chartReleaseVersion.AppVersionResolver)
}
default:
return fmt.Errorf("a %T must have an AppVersionResolver of 'branch', 'commit', 'exact', or 'none'", chartReleaseVersion)
}
if chartReleaseVersion.AppVersion != nil && (chartReleaseVersion.AppVersionID == nil || chartReleaseVersion.AppVersion.ID != *chartReleaseVersion.AppVersionID) {
return fmt.Errorf("a %T cannot have conflicting %T IDs", chartReleaseVersion, *chartReleaseVersion.AppVersion)
}
}
if chartReleaseVersion.ChartVersionResolver == nil {
return fmt.Errorf("a %T must have a ChartVersionResolver (it can be 'latest')", chartReleaseVersion)
} else {
if chartReleaseVersion.ChartVersionExact == nil || *chartReleaseVersion.ChartVersionExact == "" {
return fmt.Errorf("a %T must have an exact chart version", chartReleaseVersion)
}
switch *chartReleaseVersion.ChartVersionResolver {
case "latest":
if chartReleaseVersion.ChartVersion == nil || chartReleaseVersion.ChartVersion.ChartVersion != *chartReleaseVersion.ChartVersionExact {
return fmt.Errorf("a %T with a ChartVersionResolver of %s must be associated to an internal ChartVersion matching the exact version, here '%s'",
chartReleaseVersion, *chartReleaseVersion.ChartVersionResolver, *chartReleaseVersion.ChartVersionExact)
}
case "exact":
if chartReleaseVersion.ChartVersion != nil && chartReleaseVersion.ChartVersion.ChartVersion != *chartReleaseVersion.ChartVersionExact {
return fmt.Errorf("a %T must not have an associated internal ChartVersion (ID: %d, %s) in conflict with the exact version on %T, here '%s'",
chartReleaseVersion, *chartReleaseVersion.ChartVersionID, chartReleaseVersion.ChartVersion.ChartVersion, chartReleaseVersion, *chartReleaseVersion.ChartVersionExact)
}
case "follow":
if chartReleaseVersion.ChartVersionFollowChartReleaseID == nil {
return fmt.Errorf("a %T with an ChartVersionResolver of %s must have an ChartVersionFollowChartReleaseID", chartReleaseVersion, *chartReleaseVersion.ChartVersionResolver)
}
default:
return fmt.Errorf("a %T must have a ChartVersionResolver of 'latest' or 'exact'", chartReleaseVersion)
}
if chartReleaseVersion.ChartVersion != nil && (chartReleaseVersion.ChartVersionID == nil || chartReleaseVersion.ChartVersion.ID != *chartReleaseVersion.ChartVersionID) {
return fmt.Errorf("a %T cannot have conflicting %T IDs", chartReleaseVersion, *chartReleaseVersion.ChartVersion)
}
}
if chartReleaseVersion.HelmfileRef == nil || *chartReleaseVersion.HelmfileRef == "" {
return fmt.Errorf("a %T must have a terra-helmfile git reference", chartReleaseVersion)
}
return nil
}
func (chartReleaseVersion *ChartReleaseVersion) equalTo(other ChartReleaseVersion) bool {
return ((chartReleaseVersion.AppVersionResolver == nil && other.AppVersionResolver == nil) ||
(chartReleaseVersion.AppVersionResolver != nil && other.AppVersionResolver != nil &&
*chartReleaseVersion.AppVersionResolver == *other.AppVersionResolver)) &&
((chartReleaseVersion.AppVersionExact == nil && other.AppVersionExact == nil) ||
(chartReleaseVersion.AppVersionExact != nil && other.AppVersionExact != nil &&
*chartReleaseVersion.AppVersionExact == *other.AppVersionExact)) &&
((chartReleaseVersion.AppVersionBranch == nil && other.AppVersionBranch == nil) ||
(chartReleaseVersion.AppVersionBranch != nil && other.AppVersionBranch != nil &&
*chartReleaseVersion.AppVersionBranch == *other.AppVersionBranch)) &&
((chartReleaseVersion.AppVersionCommit == nil && other.AppVersionCommit == nil) ||
(chartReleaseVersion.AppVersionCommit != nil && other.AppVersionCommit != nil &&
*chartReleaseVersion.AppVersionCommit == *other.AppVersionCommit)) &&
((chartReleaseVersion.AppVersionFollowChartReleaseID == nil && other.AppVersionFollowChartReleaseID == nil) ||
(chartReleaseVersion.AppVersionFollowChartReleaseID != nil && other.AppVersionFollowChartReleaseID != nil &&
*chartReleaseVersion.AppVersionFollowChartReleaseID == *other.AppVersionFollowChartReleaseID)) &&
((chartReleaseVersion.AppVersionID == nil && other.AppVersionID == nil) ||
(chartReleaseVersion.AppVersionID != nil && other.AppVersionID != nil &&
*chartReleaseVersion.AppVersionID == *other.AppVersionID)) &&
((chartReleaseVersion.ChartVersionResolver == nil && other.ChartVersionResolver == nil) ||
(chartReleaseVersion.ChartVersionResolver != nil && other.ChartVersionResolver != nil &&
*chartReleaseVersion.ChartVersionResolver == *other.ChartVersionResolver)) &&
((chartReleaseVersion.ChartVersionExact == nil && other.ChartVersionExact == nil) ||
(chartReleaseVersion.ChartVersionExact != nil && other.ChartVersionExact != nil &&
*chartReleaseVersion.ChartVersionExact == *other.ChartVersionExact)) &&
((chartReleaseVersion.ChartVersionFollowChartReleaseID == nil && other.ChartVersionFollowChartReleaseID == nil) ||
(chartReleaseVersion.ChartVersionFollowChartReleaseID != nil && other.ChartVersionFollowChartReleaseID != nil &&
*chartReleaseVersion.ChartVersionFollowChartReleaseID == *other.ChartVersionFollowChartReleaseID)) &&
((chartReleaseVersion.ChartVersionID == nil && other.ChartVersionID == nil) ||
(chartReleaseVersion.ChartVersionID != nil && other.ChartVersionID != nil &&
*chartReleaseVersion.ChartVersionID == *other.ChartVersionID)) &&
((chartReleaseVersion.HelmfileRef == nil && other.HelmfileRef == nil) ||
(chartReleaseVersion.HelmfileRef != nil && other.HelmfileRef != nil &&
*chartReleaseVersion.HelmfileRef == *other.HelmfileRef)) &&
((chartReleaseVersion.FirecloudDevelopRef == nil && other.FirecloudDevelopRef == nil) ||
(chartReleaseVersion.FirecloudDevelopRef != nil && other.FirecloudDevelopRef != nil &&
*chartReleaseVersion.FirecloudDevelopRef == *other.FirecloudDevelopRef))
}