| 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 "strings" | 9 "strings" |
| 10 "time" |
| 10 | 11 |
| 11 "golang.org/x/net/context" | 12 "golang.org/x/net/context" |
| 12 | 13 |
| 13 "github.com/luci/luci-go/appengine/cmd/milo/resp" | 14 "github.com/luci/luci-go/appengine/cmd/milo/resp" |
| 14 "github.com/luci/luci-go/common/clock" | 15 "github.com/luci/luci-go/common/clock" |
| 15 "github.com/luci/luci-go/common/logging" | 16 "github.com/luci/luci-go/common/logging" |
| 16 miloProto "github.com/luci/luci-go/common/proto/milo" | 17 miloProto "github.com/luci/luci-go/common/proto/milo" |
| 17 ) | 18 ) |
| 18 | 19 |
| 19 // Given a logdog/milo step, translate it to a BuildComponent struct. | 20 // miloBuildStep converts a logdog/milo step to a BuildComponent struct. |
| 20 func miloBuildStep(c context.Context, linkBase string, anno *miloProto.Step) *re
sp.BuildComponent { | 21 // buildCompletedTime must be zero if build did not complete yet. |
| 22 func miloBuildStep(c context.Context, linkBase string, anno *miloProto.Step, bui
ldCompletedTime time.Time) *resp.BuildComponent { |
| 21 linkBase = strings.TrimSuffix(linkBase, "/") | 23 linkBase = strings.TrimSuffix(linkBase, "/") |
| 22 comp := &resp.BuildComponent{Label: anno.Name} | 24 comp := &resp.BuildComponent{Label: anno.Name} |
| 23 switch anno.Status { | 25 switch anno.Status { |
| 24 case miloProto.Status_RUNNING: | 26 case miloProto.Status_RUNNING: |
| 25 comp.Status = resp.Running | 27 comp.Status = resp.Running |
| 26 | 28 |
| 27 case miloProto.Status_SUCCESS: | 29 case miloProto.Status_SUCCESS: |
| 28 comp.Status = resp.Success | 30 comp.Status = resp.Success |
| 29 | 31 |
| 30 case miloProto.Status_FAILURE: | 32 case miloProto.Status_FAILURE: |
| 31 if anno.GetFailureDetails() != nil { | 33 if anno.GetFailureDetails() != nil { |
| 32 switch anno.GetFailureDetails().Type { | 34 switch anno.GetFailureDetails().Type { |
| 33 case miloProto.FailureDetails_EXCEPTION, miloProto.Failu
reDetails_INFRA: | 35 case miloProto.FailureDetails_EXCEPTION, miloProto.Failu
reDetails_INFRA: |
| 34 comp.Status = resp.InfraFailure | 36 comp.Status = resp.InfraFailure |
| 35 | 37 |
| 36 case miloProto.FailureDetails_DM_DEPENDENCY_FAILED: | 38 case miloProto.FailureDetails_DM_DEPENDENCY_FAILED: |
| 37 comp.Status = resp.DependencyFailure | 39 comp.Status = resp.DependencyFailure |
| 38 | 40 |
| 39 default: | 41 default: |
| 40 comp.Status = resp.Failure | 42 comp.Status = resp.Failure |
| 41 } | 43 } |
| 42 } else { | 44 } else { |
| 43 comp.Status = resp.Failure | 45 comp.Status = resp.Failure |
| 44 } | 46 } |
| 45 | 47 |
| 46 // Missing the case of waiting on unfinished dependency... | 48 // Missing the case of waiting on unfinished dependency... |
| 47 default: | 49 default: |
| 48 comp.Status = resp.NotRun | 50 comp.Status = resp.NotRun |
| 49 } | 51 } |
| 52 |
| 53 if !buildCompletedTime.IsZero() && !comp.Status.Terminal() { |
| 54 // we cannot have unfinished steps in finished builds. |
| 55 comp.Status = resp.InfraFailure |
| 56 } |
| 57 |
| 50 // Sub link is for one link per log that isn't stdout. | 58 // Sub link is for one link per log that isn't stdout. |
| 51 for _, link := range anno.GetOtherLinks() { | 59 for _, link := range anno.GetOtherLinks() { |
| 52 lds := link.GetLogdogStream() | 60 lds := link.GetLogdogStream() |
| 53 if lds == nil { | 61 if lds == nil { |
| 54 logging.Warningf(c, "Warning: %v of %v has an empty logd
og stream.", link, anno) | 62 logging.Warningf(c, "Warning: %v of %v has an empty logd
og stream.", link, anno) |
| 55 continue // DNE??? | 63 continue // DNE??? |
| 56 } | 64 } |
| 57 newLink := &resp.Link{ | 65 newLink := &resp.Link{ |
| 58 Label: lds.Name, | 66 Label: lds.Name, |
| 59 URL: linkBase + "/" + lds.Name, | 67 URL: linkBase + "/" + lds.Name, |
| (...skipping 12 matching lines...) Expand all Loading... |
| 72 // This should always be a step. | 80 // This should always be a step. |
| 73 comp.Type = resp.Step | 81 comp.Type = resp.Step |
| 74 | 82 |
| 75 // This should always be 0 | 83 // This should always be 0 |
| 76 comp.LevelsDeep = 0 | 84 comp.LevelsDeep = 0 |
| 77 | 85 |
| 78 // Timestamps | 86 // Timestamps |
| 79 comp.Started = anno.Started.Time() | 87 comp.Started = anno.Started.Time() |
| 80 comp.Finished = anno.Ended.Time() | 88 comp.Finished = anno.Ended.Time() |
| 81 | 89 |
| 82 » till := comp.Finished | 90 » var till time.Time |
| 83 » if anno.Status == miloProto.Status_RUNNING { | 91 » switch { |
| 92 » case comp.Status == resp.Running: |
| 84 till = clock.Now(c) | 93 till = clock.Now(c) |
| 94 case !comp.Finished.IsZero(): |
| 95 till = comp.Finished |
| 96 default: |
| 97 till = buildCompletedTime |
| 85 } | 98 } |
| 86 if !comp.Started.IsZero() && !till.IsZero() { | 99 if !comp.Started.IsZero() && !till.IsZero() { |
| 87 comp.Duration = till.Sub(comp.Started) | 100 comp.Duration = till.Sub(comp.Started) |
| 88 } | 101 } |
| 89 | 102 |
| 90 // This should be the exact same thing. | 103 // This should be the exact same thing. |
| 91 comp.Text = anno.Text | 104 comp.Text = anno.Text |
| 92 | 105 |
| 93 return comp | 106 return comp |
| 94 } | 107 } |
| 95 | 108 |
| 96 // AddLogDogToBuild takes a set of logdog streams and populate a milo build. | 109 // AddLogDogToBuild takes a set of logdog streams and populate a milo build. |
| 110 // build.Summary.Finished must be set. |
| 97 func AddLogDogToBuild(c context.Context, linkBase string, s *Streams, build *res
p.MiloBuild) { | 111 func AddLogDogToBuild(c context.Context, linkBase string, s *Streams, build *res
p.MiloBuild) { |
| 98 if s.MainStream == nil { | 112 if s.MainStream == nil { |
| 99 panic("missing main stream") | 113 panic("missing main stream") |
| 100 } | 114 } |
| 101 // Now Fetch the main annotation of the build. | 115 // Now Fetch the main annotation of the build. |
| 102 mainAnno := s.MainStream.Data | 116 mainAnno := s.MainStream.Data |
| 103 | 117 |
| 104 // Now fill in each of the step components. | 118 // Now fill in each of the step components. |
| 105 // TODO(hinoka): This is totes cachable. | 119 // TODO(hinoka): This is totes cachable. |
| 106 for _, substepContainer := range mainAnno.Substep { | 120 for _, substepContainer := range mainAnno.Substep { |
| 107 anno := substepContainer.GetStep() | 121 anno := substepContainer.GetStep() |
| 108 if anno == nil { | 122 if anno == nil { |
| 109 // TODO: We ignore non-embedded substeps for now. | 123 // TODO: We ignore non-embedded substeps for now. |
| 110 continue | 124 continue |
| 111 } | 125 } |
| 112 | 126 |
| 113 » » bs := miloBuildStep(c, linkBase, anno) | 127 » » bs := miloBuildStep(c, linkBase, anno, build.Summary.Finished) |
| 114 if bs.Status != resp.Success && bs.Status != resp.NotRun { | 128 if bs.Status != resp.Success && bs.Status != resp.NotRun { |
| 115 build.Summary.Text = append( | 129 build.Summary.Text = append( |
| 116 build.Summary.Text, fmt.Sprintf("%s %s", bs.Stat
us, bs.Label)) | 130 build.Summary.Text, fmt.Sprintf("%s %s", bs.Stat
us, bs.Label)) |
| 117 } | 131 } |
| 118 build.Components = append(build.Components, bs) | 132 build.Components = append(build.Components, bs) |
| 119 propGroup := &resp.PropertyGroup{GroupName: bs.Label} | 133 propGroup := &resp.PropertyGroup{GroupName: bs.Label} |
| 120 for _, prop := range anno.Property { | 134 for _, prop := range anno.Property { |
| 121 propGroup.Property = append(propGroup.Property, &resp.Pr
operty{ | 135 propGroup.Property = append(propGroup.Property, &resp.Pr
operty{ |
| 122 Key: prop.Name, | 136 Key: prop.Name, |
| 123 Value: prop.Value, | 137 Value: prop.Value, |
| 124 }) | 138 }) |
| 125 } | 139 } |
| 126 build.PropertyGroup = append(build.PropertyGroup, propGroup) | 140 build.PropertyGroup = append(build.PropertyGroup, propGroup) |
| 127 } | 141 } |
| 128 | 142 |
| 129 // Take care of properties | 143 // Take care of properties |
| 130 propGroup := &resp.PropertyGroup{GroupName: "Main"} | 144 propGroup := &resp.PropertyGroup{GroupName: "Main"} |
| 131 for _, prop := range mainAnno.Property { | 145 for _, prop := range mainAnno.Property { |
| 132 propGroup.Property = append(propGroup.Property, &resp.Property{ | 146 propGroup.Property = append(propGroup.Property, &resp.Property{ |
| 133 Key: prop.Name, | 147 Key: prop.Name, |
| 134 Value: prop.Value, | 148 Value: prop.Value, |
| 135 }) | 149 }) |
| 136 } | 150 } |
| 137 build.PropertyGroup = append(build.PropertyGroup, propGroup) | 151 build.PropertyGroup = append(build.PropertyGroup, propGroup) |
| 138 | 152 |
| 139 return | 153 return |
| 140 } | 154 } |
| OLD | NEW |