github.com/abayer/test-infra@v0.0.5/velodrome/transform/plugins/bundle.go (about) 1 /* 2 Copyright 2017 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package plugins 18 19 import ( 20 "fmt" 21 "math" 22 "sort" 23 "time" 24 ) 25 26 // ByDuration sorts a slice of time.Duration 27 type ByDuration []time.Duration 28 29 func (b ByDuration) Len() int { return len(b) } 30 func (b ByDuration) Less(i, j int) bool { return b[i] < b[j] } 31 func (b ByDuration) Swap(i, j int) { b[i], b[j] = b[j], b[i] } 32 33 // BundledStates saves the state of multiple issues/pull-requests. This 34 // will also allow us to then compute statistics on these states like: 35 // - Number of pull-requests in activated states (first return value of 36 // Total()) 37 // - Sum of time since activated pull-requests are activated (second 38 // return value of Total()) 39 // - Get a specific percentile time for activated pull-requests 40 // (Percentile()) 41 type BundledStates struct { 42 description string 43 states map[string]State 44 } 45 46 // NewBundledStates is the constructor for BundledStates 47 func NewBundledStates(description string) BundledStates { 48 return BundledStates{ 49 description: description, 50 states: map[string]State{}, 51 } 52 } 53 54 // ReceiveEvent is called when something happens on an issue. The state 55 // for that issue is updated. 56 func (b BundledStates) ReceiveEvent(ID string, eventName, label string, t time.Time) bool { 57 state, ok := b.states[ID] 58 if !ok { 59 state = NewState(b.description) 60 } 61 state, changed := state.ReceiveEvent(eventName, label, t) 62 b.states[ID] = state 63 return changed 64 } 65 66 // ages return the age of each active states 67 func (b BundledStates) ages(t time.Time) map[string]time.Duration { 68 ages := map[string]time.Duration{} 69 70 for id, state := range b.states { 71 if !state.Active() { 72 continue 73 } 74 ages[id] = state.Age(t) 75 } 76 return ages 77 } 78 79 // Total counts number of active state, and total age (in minutes, to compute average) 80 func (b BundledStates) Total(t time.Time) (count int, sum int64) { 81 for _, age := range b.ages(t) { 82 count++ 83 sum += int64(age / time.Minute) 84 } 85 return 86 } 87 88 // Percentile returns given percentile for age of all active states at time t 89 func (b BundledStates) Percentile(t time.Time, percentile int) time.Duration { 90 if percentile > 100 || percentile <= 0 { 91 panic(fmt.Errorf("percentile %d is out of scope", percentile)) 92 } 93 94 ages := []time.Duration{} 95 for _, age := range b.ages(t) { 96 ages = append(ages, age) 97 } 98 99 if len(ages) == 0 { 100 return 0 101 } 102 103 sort.Sort(ByDuration(ages)) 104 105 index := int(math.Ceil(float64(percentile)*float64(len(ages))/100) - 1) 106 if index >= len(ages) { 107 panic(fmt.Errorf("Index is out of range: %d/%d", index, len(ages))) 108 } 109 return ages[index] 110 }