go.fuchsia.dev/infra@v0.0.0-20240507153436-9b593402251b/cmd/autogardener/changed_files.go (about) 1 // Copyright 2022 The Fuchsia Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package main 6 7 import ( 8 "strings" 9 ) 10 11 // scoreChangedFileProximity computes a 0-100 score of the proximity of a Gerrit 12 // change's affected files to the given test GN label. 13 func scoreChangedFileProximity(changedFiles []string, gnLabel string) int { 14 // If there's no GN label and we can't do this analysis, that significantly 15 // lowers the confidence. 16 if gnLabel == "" { 17 return 0 18 } 19 20 strippedLabel := strings.Trim(strings.Split(gnLabel, ":")[0], "/") 21 labelParts := strings.Split(strippedLabel, "/") 22 23 var proximityScores []float64 24 25 for _, file := range changedFiles { 26 pl := sharedPrefixLength(labelParts, strings.Split(file, "/")) 27 28 // Proximity is determined by the ratio of the shared prefix length to 29 // the length of the GN label directory. 30 // 31 // If a test is declared in directory `src/foo/bar`, any files within 32 // `src/foo/bar` or any subdirectory thereof will have a proximity ratio 33 // of 1. 34 proximityScore := 100 * float64(pl) / float64(len(labelParts)) 35 36 proximityScores = append(proximityScores, proximityScore) 37 38 // Add extra weighting for higher proximity scores. If a change touches 39 // a couple files close to the test, along with a large number of 40 // unrelated files, it should still be scored higher than a change that 41 // touches only files that are moderately close to the test. 42 for range int(proximityScore/25) + 1 { 43 proximityScores = append(proximityScores, proximityScore) 44 } 45 } 46 47 return int(average(proximityScores)) 48 } 49 50 // sharedPrefixLength computes the length of the longest shared prefix of the 51 // two slices, i.e. the maximum number N such that p1[:N] == p2[:N]. 52 func sharedPrefixLength(p1, p2 []string) int { 53 var i int 54 for ; i < len(p1) && i < len(p2); i++ { 55 if p1[i] != p2[i] { 56 break 57 } 58 } 59 return i 60 }