Skip to content

Commit 77fa5af

Browse files
authored
✨ Add confidence and risk to Application and Archetype resources. (#530)
* Add `confidence` and `risk` fields to Application and Archetype resources. Overall confidence calculated using the algorithm from Pathfinder for each assessment, then summed and divided by total number of assessments. Overall risk level is `green` if all assessments are `green`, otherwise the overall risk is `red`, `unknown`, or `yellow` in that priority order if any assessments have that risk level. * Moved some assessment status logic out of the resource and into the assessment package where it belongs. * Added ArchetypeResolver to better encapsulate the related behaviors and for symmetry with ApplicationResolver. * Simplified the Application and Archetype endpoints by replacing several related resource `With*` methods with `WithResolver`. * Improved consistency of the APIs within the `assessment` package. --------- Signed-off-by: Sam Lucidi <[email protected]>
1 parent 5aa81a9 commit 77fa5af

10 files changed

+416
-240
lines changed

Diff for: api/application.go

+45-62
Original file line numberDiff line numberDiff line change
@@ -134,28 +134,13 @@ func (h ApplicationHandler) Get(ctx *gin.Context) {
134134
return
135135
}
136136
resolver := assessment.NewApplicationResolver(m, tagsResolver, membership, questionnaire)
137-
archetypes, err := resolver.Archetypes()
138-
if err != nil {
139-
_ = ctx.Error(err)
140-
return
141-
}
142-
archetypeTags, err := resolver.ArchetypeTags()
143-
if err != nil {
144-
_ = ctx.Error(err)
145-
return
146-
}
147-
148137
r := Application{}
149138
r.With(m, tags)
150-
r.WithArchetypes(archetypes)
151-
r.WithVirtualTags(archetypeTags, SourceArchetype)
152-
r.WithVirtualTags(resolver.AssessmentTags(), SourceAssessment)
153-
r.Assessed, err = resolver.Assessed()
139+
err = r.WithResolver(resolver)
154140
if err != nil {
155141
_ = ctx.Error(err)
156142
return
157143
}
158-
159144
h.Respond(ctx, http.StatusOK, r)
160145
}
161146

@@ -198,22 +183,9 @@ func (h ApplicationHandler) List(ctx *gin.Context) {
198183
return
199184
}
200185
resolver := assessment.NewApplicationResolver(&list[i], tagsResolver, membership, questionnaire)
201-
archetypes, aErr := resolver.Archetypes()
202-
if aErr != nil {
203-
_ = ctx.Error(aErr)
204-
return
205-
}
206-
archetypeTags, aErr := resolver.ArchetypeTags()
207-
if aErr != nil {
208-
_ = ctx.Error(aErr)
209-
return
210-
}
211186
r := Application{}
212187
r.With(&list[i], tags)
213-
r.WithArchetypes(archetypes)
214-
r.WithVirtualTags(archetypeTags, SourceArchetype)
215-
r.WithVirtualTags(resolver.AssessmentTags(), SourceAssessment)
216-
r.Assessed, err = resolver.Assessed()
188+
err = r.WithResolver(resolver)
217189
if err != nil {
218190
_ = ctx.Error(err)
219191
return
@@ -274,27 +246,12 @@ func (h ApplicationHandler) Create(ctx *gin.Context) {
274246
return
275247
}
276248
resolver := assessment.NewApplicationResolver(m, tagsResolver, membership, questionnaire)
277-
archetypes, err := resolver.Archetypes()
278-
if err != nil {
279-
_ = ctx.Error(err)
280-
return
281-
}
282-
archetypeTags, err := resolver.ArchetypeTags()
283-
if err != nil {
284-
_ = ctx.Error(err)
285-
return
286-
}
287-
288249
r.With(m, tags)
289-
r.WithArchetypes(archetypes)
290-
r.WithVirtualTags(archetypeTags, SourceArchetype)
291-
r.WithVirtualTags(resolver.AssessmentTags(), SourceArchetype)
292-
r.Assessed, err = resolver.Assessed()
250+
err = r.WithResolver(resolver)
293251
if err != nil {
294252
_ = ctx.Error(err)
295253
return
296254
}
297-
298255
h.Respond(ctx, http.StatusCreated, r)
299256
}
300257

@@ -1018,12 +975,12 @@ func (h ApplicationHandler) AssessmentList(ctx *gin.Context) {
1018975
_ = ctx.Error(err)
1019976
return
1020977
}
1021-
1022978
assessments := m.Assessments
1023-
for _, a := range archetypes {
1024-
assessments = append(assessments, a.Assessments...)
979+
for _, arch := range archetypes {
980+
for _, a := range arch.Assessments {
981+
assessments = append(assessments, *a.Assessment)
982+
}
1025983
}
1026-
1027984
resources := []Assessment{}
1028985
for i := range assessments {
1029986
r := Assessment{}
@@ -1112,13 +1069,15 @@ type Application struct {
11121069
Comments string `json:"comments"`
11131070
Identities []Ref `json:"identities"`
11141071
Tags []TagRef `json:"tags"`
1115-
BusinessService *Ref `json:"businessService"`
1072+
BusinessService *Ref `json:"businessService" yaml:"businessService"`
11161073
Owner *Ref `json:"owner"`
11171074
Contributors []Ref `json:"contributors"`
1118-
MigrationWave *Ref `json:"migrationWave"`
1075+
MigrationWave *Ref `json:"migrationWave" yaml:"migrationWave"`
11191076
Archetypes []Ref `json:"archetypes"`
11201077
Assessments []Ref `json:"assessments"`
11211078
Assessed bool `json:"assessed"`
1079+
Risk string `json:"risk"`
1080+
Confidence int `json:"confidence"`
11221081
}
11231082

11241083
//
@@ -1168,16 +1127,6 @@ func (r *Application) With(m *model.Application, tags []model.ApplicationTag) {
11681127
}
11691128
}
11701129

1171-
//
1172-
// WithArchetypes updates the resource with archetypes.
1173-
func (r *Application) WithArchetypes(archetypes []model.Archetype) {
1174-
for _, a := range archetypes {
1175-
ref := Ref{}
1176-
ref.With(a.ID, a.Name)
1177-
r.Archetypes = append(r.Archetypes, ref)
1178-
}
1179-
}
1180-
11811130
//
11821131
// WithVirtualTags updates the resource with tags derived from assessments.
11831132
func (r *Application) WithVirtualTags(tags []model.Tag, source string) {
@@ -1188,6 +1137,40 @@ func (r *Application) WithVirtualTags(tags []model.Tag, source string) {
11881137
}
11891138
}
11901139

1140+
//
1141+
// WithResolver uses an ApplicationResolver to update the resource with
1142+
// values derived from the application's assessments and archetypes.
1143+
func (r *Application) WithResolver(resolver *assessment.ApplicationResolver) (err error) {
1144+
archetypes, err := resolver.Archetypes()
1145+
if err != nil {
1146+
return
1147+
}
1148+
for _, a := range archetypes {
1149+
ref := Ref{}
1150+
ref.With(a.ID, a.Name)
1151+
r.Archetypes = append(r.Archetypes, ref)
1152+
}
1153+
archetypeTags, err := resolver.ArchetypeTags()
1154+
if err != nil {
1155+
return
1156+
}
1157+
r.WithVirtualTags(archetypeTags, SourceArchetype)
1158+
r.WithVirtualTags(resolver.AssessmentTags(), SourceAssessment)
1159+
r.Assessed, err = resolver.Assessed()
1160+
if err != nil {
1161+
return
1162+
}
1163+
r.Confidence, err = resolver.Confidence()
1164+
if err != nil {
1165+
return
1166+
}
1167+
r.Risk, err = resolver.Risk()
1168+
if err != nil {
1169+
return
1170+
}
1171+
return
1172+
}
1173+
11911174
//
11921175
// Model builds a model.
11931176
func (r *Application) Model() (m *model.Application) {

Diff for: api/archetype.go

+23-34
Original file line numberDiff line numberDiff line change
@@ -57,32 +57,24 @@ func (h ArchetypeHandler) Get(ctx *gin.Context) {
5757
_ = ctx.Error(result.Error)
5858
return
5959
}
60-
6160
membership := assessment.NewMembershipResolver(h.DB(ctx))
62-
applications, err := membership.Applications(m)
63-
if err != nil {
64-
_ = ctx.Error(err)
65-
return
66-
}
67-
6861
questionnaires, err := assessment.NewQuestionnaireResolver(h.DB(ctx))
6962
if err != nil {
7063
_ = ctx.Error(err)
7164
return
7265
}
73-
7466
tags, err := assessment.NewTagResolver(h.DB(ctx))
7567
if err != nil {
7668
_ = ctx.Error(err)
7769
}
78-
79-
resolver := assessment.NewArchetypeResolver(m, tags)
80-
70+
resolver := assessment.NewArchetypeResolver(m, tags, membership, questionnaires)
8171
r := Archetype{}
8272
r.With(m)
83-
r.WithApplications(applications)
84-
r.WithAssessmentTags(resolver.AssessmentTags())
85-
r.Assessed = questionnaires.Assessed(m.Assessments)
73+
err = r.WithResolver(resolver)
74+
if err != nil {
75+
_ = ctx.Error(err)
76+
return
77+
}
8678
h.Respond(ctx, http.StatusOK, r)
8779
}
8880

@@ -101,7 +93,6 @@ func (h ArchetypeHandler) List(ctx *gin.Context) {
10193
_ = ctx.Error(result.Error)
10294
return
10395
}
104-
10596
questionnaires, err := assessment.NewQuestionnaireResolver(h.DB(ctx))
10697
if err != nil {
10798
_ = ctx.Error(err)
@@ -111,22 +102,18 @@ func (h ArchetypeHandler) List(ctx *gin.Context) {
111102
if err != nil {
112103
_ = ctx.Error(err)
113104
}
114-
115105
membership := assessment.NewMembershipResolver(h.DB(ctx))
116106
resources := []Archetype{}
117107
for i := range list {
118108
m := &list[i]
109+
resolver := assessment.NewArchetypeResolver(m, tags, membership, questionnaires)
119110
r := Archetype{}
120-
applications, err := membership.Applications(m)
111+
r.With(m)
112+
err = r.WithResolver(resolver)
121113
if err != nil {
122114
_ = ctx.Error(err)
123115
return
124116
}
125-
resolver := assessment.NewArchetypeResolver(m, tags)
126-
r.With(m)
127-
r.WithApplications(applications)
128-
r.WithAssessmentTags(resolver.AssessmentTags())
129-
r.Assessed = questionnaires.Assessed(m.Assessments)
130117
resources = append(resources, r)
131118
}
132119

@@ -165,14 +152,13 @@ func (h ArchetypeHandler) Create(ctx *gin.Context) {
165152
}
166153

167154
membership := assessment.NewMembershipResolver(h.DB(ctx))
168-
applications, err := membership.Applications(m)
155+
resolver := assessment.NewArchetypeResolver(m, nil, membership, nil)
156+
r.With(m)
157+
err = r.WithResolver(resolver)
169158
if err != nil {
170159
_ = ctx.Error(err)
171160
return
172161
}
173-
174-
r.With(m)
175-
r.WithApplications(applications)
176162
h.Respond(ctx, http.StatusCreated, r)
177163
}
178164

@@ -356,6 +342,8 @@ type Archetype struct {
356342
Applications []Ref `json:"applications" yaml:"applications"`
357343
Assessments []Ref `json:"assessments" yaml:"assessments"`
358344
Assessed bool `json:"assessed"`
345+
Risk string `json:"risk"`
346+
Confidence int `json:"confidence"`
359347
Review *Ref `json:"review"`
360348
}
361349

@@ -398,23 +386,24 @@ func (r *Archetype) With(m *model.Archetype) {
398386
}
399387

400388
//
401-
// WithApplications updates the Archetype resource with the applications.
402-
func (r *Archetype) WithApplications(apps []model.Application) {
389+
// WithResolver uses an ArchetypeResolver to update the resource with
390+
// values derived from the archetype's assessments.
391+
func (r *Archetype) WithResolver(resolver *assessment.ArchetypeResolver) (err error) {
392+
r.Risk = resolver.Risk()
393+
r.Confidence = resolver.Confidence()
394+
r.Assessed = resolver.Assessed()
395+
apps, err := resolver.Applications()
403396
for i := range apps {
404397
ref := Ref{}
405398
ref.With(apps[i].ID, apps[i].Name)
406399
r.Applications = append(r.Applications, ref)
407400
}
408-
}
409-
410-
//
411-
// WithAssessmentTags updates the Archetype resource with tags inherited from assessments.
412-
func (r *Archetype) WithAssessmentTags(tags []model.Tag) {
413-
for _, t := range tags {
401+
for _, t := range resolver.AssessmentTags() {
414402
ref := TagRef{}
415403
ref.With(t.ID, t.Name, SourceAssessment, true)
416404
r.Tags = append(r.Tags, ref)
417405
}
406+
return
418407
}
419408

420409
//

0 commit comments

Comments
 (0)