| OLD | NEW |
| 1 // Copyright 2016 The LUCI Authors. All rights reserved. | 1 // Copyright 2016 The LUCI Authors. All rights reserved. |
| 2 // Use of this source code is governed under the Apache License, Version 2.0 | 2 // Use of this source code is governed under the Apache License, Version 2.0 |
| 3 // that can be found in the LICENSE file. | 3 // that can be found in the LICENSE file. |
| 4 | 4 |
| 5 package logdog | 5 package logdog |
| 6 | 6 |
| 7 import ( | 7 import ( |
| 8 "fmt" | 8 "fmt" |
| 9 "time" | 9 "time" |
| 10 | 10 |
| 11 "golang.org/x/net/context" | 11 "golang.org/x/net/context" |
| 12 | 12 |
| 13 "github.com/luci/luci-go/common/clock" | 13 "github.com/luci/luci-go/common/clock" |
| 14 "github.com/luci/luci-go/common/proto/google" | 14 "github.com/luci/luci-go/common/proto/google" |
| 15 miloProto "github.com/luci/luci-go/common/proto/milo" | 15 miloProto "github.com/luci/luci-go/common/proto/milo" |
| 16 "github.com/luci/luci-go/milo/api/resp" | 16 "github.com/luci/luci-go/milo/api/resp" |
| 17 "github.com/luci/luci-go/milo/appengine/common/model" |
| 17 ) | 18 ) |
| 18 | 19 |
| 19 // URLBuilder constructs URLs for various link types. | 20 // URLBuilder constructs URLs for various link types. |
| 20 type URLBuilder interface { | 21 type URLBuilder interface { |
| 21 // LinkURL returns the URL associated with the supplied Link. | 22 // LinkURL returns the URL associated with the supplied Link. |
| 22 // | 23 // |
| 23 // If no URL could be built for that Link, nil will be returned. | 24 // If no URL could be built for that Link, nil will be returned. |
| 24 BuildLink(l *miloProto.Link) *resp.Link | 25 BuildLink(l *miloProto.Link) *resp.Link |
| 25 } | 26 } |
| 26 | 27 |
| 27 // HACK(hinoka): This should be a part of recipes, but just hardcoding a list | 28 // HACK(hinoka): This should be a part of recipes, but just hardcoding a list |
| 28 // of unimportant things for now. | 29 // of unimportant things for now. |
| 29 var builtIn = map[string]struct{}{ | 30 var builtIn = map[string]struct{}{ |
| 30 "recipe bootstrap": {}, | 31 "recipe bootstrap": {}, |
| 31 "setup_build": {}, | 32 "setup_build": {}, |
| 32 "recipe result": {}, | 33 "recipe result": {}, |
| 33 } | 34 } |
| 34 | 35 |
| 35 // miloBuildStep converts a logdog/milo step to a BuildComponent struct. | 36 // miloBuildStep converts a logdog/milo step to a BuildComponent struct. |
| 36 // buildCompletedTime must be zero if build did not complete yet. | 37 // buildCompletedTime must be zero if build did not complete yet. |
| 37 func miloBuildStep(ub URLBuilder, anno *miloProto.Step, isMain bool, buildComple
tedTime, | 38 func miloBuildStep(ub URLBuilder, anno *miloProto.Step, isMain bool, buildComple
tedTime, |
| 38 now time.Time) []*resp.BuildComponent { | 39 now time.Time) []*resp.BuildComponent { |
| 39 | 40 |
| 40 comp := &resp.BuildComponent{Label: anno.Name} | 41 comp := &resp.BuildComponent{Label: anno.Name} |
| 41 switch anno.Status { | 42 switch anno.Status { |
| 42 case miloProto.Status_RUNNING: | 43 case miloProto.Status_RUNNING: |
| 43 » » comp.Status = resp.Running | 44 » » comp.Status = model.Running |
| 44 | 45 |
| 45 case miloProto.Status_SUCCESS: | 46 case miloProto.Status_SUCCESS: |
| 46 » » comp.Status = resp.Success | 47 » » comp.Status = model.Success |
| 47 | 48 |
| 48 case miloProto.Status_FAILURE: | 49 case miloProto.Status_FAILURE: |
| 49 if fd := anno.GetFailureDetails(); fd != nil { | 50 if fd := anno.GetFailureDetails(); fd != nil { |
| 50 switch fd.Type { | 51 switch fd.Type { |
| 51 case miloProto.FailureDetails_EXCEPTION, miloProto.Failu
reDetails_INFRA: | 52 case miloProto.FailureDetails_EXCEPTION, miloProto.Failu
reDetails_INFRA: |
| 52 » » » » comp.Status = resp.InfraFailure | 53 » » » » comp.Status = model.InfraFailure |
| 53 | 54 |
| 54 case miloProto.FailureDetails_EXPIRED: | 55 case miloProto.FailureDetails_EXPIRED: |
| 55 » » » » comp.Status = resp.Expired | 56 » » » » comp.Status = model.Expired |
| 56 | 57 |
| 57 case miloProto.FailureDetails_DM_DEPENDENCY_FAILED: | 58 case miloProto.FailureDetails_DM_DEPENDENCY_FAILED: |
| 58 » » » » comp.Status = resp.DependencyFailure | 59 » » » » comp.Status = model.DependencyFailure |
| 59 | 60 |
| 60 default: | 61 default: |
| 61 » » » » comp.Status = resp.Failure | 62 » » » » comp.Status = model.Failure |
| 62 } | 63 } |
| 63 | 64 |
| 64 if fd.Text != "" { | 65 if fd.Text != "" { |
| 65 comp.Text = append(comp.Text, fd.Text) | 66 comp.Text = append(comp.Text, fd.Text) |
| 66 } | 67 } |
| 67 } else { | 68 } else { |
| 68 » » » comp.Status = resp.Failure | 69 » » » comp.Status = model.Failure |
| 69 } | 70 } |
| 70 | 71 |
| 71 case miloProto.Status_PENDING: | 72 case miloProto.Status_PENDING: |
| 72 » » comp.Status = resp.NotRun | 73 » » comp.Status = model.NotRun |
| 73 | 74 |
| 74 // Missing the case of waiting on unfinished dependency... | 75 // Missing the case of waiting on unfinished dependency... |
| 75 default: | 76 default: |
| 76 » » comp.Status = resp.NotRun | 77 » » comp.Status = model.NotRun |
| 77 } | 78 } |
| 78 | 79 |
| 79 if !(buildCompletedTime.IsZero() || comp.Status.Terminal()) { | 80 if !(buildCompletedTime.IsZero() || comp.Status.Terminal()) { |
| 80 // The build has completed, but this step has not. Mark it as an | 81 // The build has completed, but this step has not. Mark it as an |
| 81 // infrastructure failure. | 82 // infrastructure failure. |
| 82 » » comp.Status = resp.InfraFailure | 83 » » comp.Status = model.InfraFailure |
| 83 } | 84 } |
| 84 | 85 |
| 85 // Hide the unimportant steps, highlight the interesting ones. | 86 // Hide the unimportant steps, highlight the interesting ones. |
| 86 switch comp.Status { | 87 switch comp.Status { |
| 87 » case resp.NotRun, resp.Running: | 88 » case model.NotRun, model.Running: |
| 88 if isMain { | 89 if isMain { |
| 89 comp.Verbosity = resp.Hidden | 90 comp.Verbosity = resp.Hidden |
| 90 } | 91 } |
| 91 | 92 |
| 92 » case resp.Success: | 93 » case model.Success: |
| 93 if _, ok := builtIn[anno.Name]; ok || isMain { | 94 if _, ok := builtIn[anno.Name]; ok || isMain { |
| 94 comp.Verbosity = resp.Hidden | 95 comp.Verbosity = resp.Hidden |
| 95 } | 96 } |
| 96 » case resp.InfraFailure, resp.Failure: | 97 » case model.InfraFailure, model.Failure: |
| 97 comp.Verbosity = resp.Interesting | 98 comp.Verbosity = resp.Interesting |
| 98 } | 99 } |
| 99 | 100 |
| 100 // Main link is a link to the stdout. | 101 // Main link is a link to the stdout. |
| 101 var stdoutLink *miloProto.Link | 102 var stdoutLink *miloProto.Link |
| 102 if anno.StdoutStream != nil { | 103 if anno.StdoutStream != nil { |
| 103 stdoutLink = &miloProto.Link{ | 104 stdoutLink = &miloProto.Link{ |
| 104 Label: "stdout", | 105 Label: "stdout", |
| 105 Value: &miloProto.Link_LogdogStream{ | 106 Value: &miloProto.Link_LogdogStream{ |
| 106 LogdogStream: anno.StdoutStream, | 107 LogdogStream: anno.StdoutStream, |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 143 comp.LevelsDeep = 0 | 144 comp.LevelsDeep = 0 |
| 144 | 145 |
| 145 // Timestamps | 146 // Timestamps |
| 146 comp.Started = google.TimeFromProto(anno.Started) | 147 comp.Started = google.TimeFromProto(anno.Started) |
| 147 comp.Finished = google.TimeFromProto(anno.Ended) | 148 comp.Finished = google.TimeFromProto(anno.Ended) |
| 148 | 149 |
| 149 var till time.Time | 150 var till time.Time |
| 150 switch { | 151 switch { |
| 151 case !comp.Finished.IsZero(): | 152 case !comp.Finished.IsZero(): |
| 152 till = comp.Finished | 153 till = comp.Finished |
| 153 » case comp.Status == resp.Running: | 154 » case comp.Status == model.Running: |
| 154 till = now | 155 till = now |
| 155 case !buildCompletedTime.IsZero(): | 156 case !buildCompletedTime.IsZero(): |
| 156 till = buildCompletedTime | 157 till = buildCompletedTime |
| 157 } | 158 } |
| 158 if !comp.Started.IsZero() && till.After(comp.Started) { | 159 if !comp.Started.IsZero() && till.After(comp.Started) { |
| 159 comp.Duration = till.Sub(comp.Started) | 160 comp.Duration = till.Sub(comp.Started) |
| 160 } | 161 } |
| 161 | 162 |
| 162 // This should be the exact same thing. | 163 // This should be the exact same thing. |
| 163 comp.Text = append(comp.Text, anno.Text...) | 164 comp.Text = append(comp.Text, anno.Text...) |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 196 build.Summary = *(miloBuildStep(ub, mainAnno, true, buildCompletedTime,
now)[0]) | 197 build.Summary = *(miloBuildStep(ub, mainAnno, true, buildCompletedTime,
now)[0]) |
| 197 for _, substepContainer := range mainAnno.Substep { | 198 for _, substepContainer := range mainAnno.Substep { |
| 198 anno := substepContainer.GetStep() | 199 anno := substepContainer.GetStep() |
| 199 if anno == nil { | 200 if anno == nil { |
| 200 // TODO: We ignore non-embedded substeps for now. | 201 // TODO: We ignore non-embedded substeps for now. |
| 201 continue | 202 continue |
| 202 } | 203 } |
| 203 | 204 |
| 204 bss := miloBuildStep(ub, anno, false, buildCompletedTime, now) | 205 bss := miloBuildStep(ub, anno, false, buildCompletedTime, now) |
| 205 for _, bs := range bss { | 206 for _, bs := range bss { |
| 206 » » » if bs.Status != resp.Success { | 207 » » » if bs.Status != model.Success { |
| 207 build.Summary.Text = append( | 208 build.Summary.Text = append( |
| 208 build.Summary.Text, fmt.Sprintf("%s %s",
bs.Status, bs.Label)) | 209 build.Summary.Text, fmt.Sprintf("%s %s",
bs.Status, bs.Label)) |
| 209 } | 210 } |
| 210 build.Components = append(build.Components, bs) | 211 build.Components = append(build.Components, bs) |
| 211 propGroup := &resp.PropertyGroup{GroupName: bs.Label} | 212 propGroup := &resp.PropertyGroup{GroupName: bs.Label} |
| 212 for _, prop := range anno.Property { | 213 for _, prop := range anno.Property { |
| 213 propGroup.Property = append(propGroup.Property,
&resp.Property{ | 214 propGroup.Property = append(propGroup.Property,
&resp.Property{ |
| 214 Key: prop.Name, | 215 Key: prop.Name, |
| 215 Value: prop.Value, | 216 Value: prop.Value, |
| 216 }) | 217 }) |
| 217 } | 218 } |
| 218 build.PropertyGroup = append(build.PropertyGroup, propGr
oup) | 219 build.PropertyGroup = append(build.PropertyGroup, propGr
oup) |
| 219 } | 220 } |
| 220 } | 221 } |
| 221 | 222 |
| 222 // Take care of properties | 223 // Take care of properties |
| 223 propGroup := &resp.PropertyGroup{GroupName: "Main"} | 224 propGroup := &resp.PropertyGroup{GroupName: "Main"} |
| 224 for _, prop := range mainAnno.Property { | 225 for _, prop := range mainAnno.Property { |
| 225 propGroup.Property = append(propGroup.Property, &resp.Property{ | 226 propGroup.Property = append(propGroup.Property, &resp.Property{ |
| 226 Key: prop.Name, | 227 Key: prop.Name, |
| 227 Value: prop.Value, | 228 Value: prop.Value, |
| 228 }) | 229 }) |
| 229 } | 230 } |
| 230 build.PropertyGroup = append(build.PropertyGroup, propGroup) | 231 build.PropertyGroup = append(build.PropertyGroup, propGroup) |
| 231 | 232 |
| 232 return | 233 return |
| 233 } | 234 } |
| OLD | NEW |