Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: alias detection for removed flags #71

Merged
merged 17 commits into from
Nov 13, 2023
Merged
54 changes: 35 additions & 19 deletions diff/diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,53 +6,69 @@ import (
"strings"

lflags "github.com/launchdarkly/find-code-references-in-pull-request/flags"
"github.com/launchdarkly/find-code-references-in-pull-request/ignore"
diff_util "github.com/launchdarkly/find-code-references-in-pull-request/internal/util/diff_util"
i "github.com/launchdarkly/find-code-references-in-pull-request/ignore"
diff_util "github.com/launchdarkly/find-code-references-in-pull-request/internal/utils/diff_util"
"github.com/launchdarkly/ld-find-code-refs/v2/aliases"
lsearch "github.com/launchdarkly/ld-find-code-refs/v2/search"
"github.com/sourcegraph/go-diff/diff"
)

type DiffPaths struct {
FileToParse string
Skip bool
func PreprocessDiffs(dir string, multiFiles []*diff.FileDiff) aliases.FileContentsMap {
diffMap := make(map[string][]byte, len(multiFiles))

for _, parsedDiff := range multiFiles {
filePath, ignore := checkDiffFile(parsedDiff, dir)
if ignore {
continue
}

if _, ok := diffMap[filePath]; !ok {
diffMap[filePath] = make([]byte, 0)
}

for _, hunk := range parsedDiff.Hunks {
diffMap[filePath] = append(diffMap[filePath], hunk.Body...)
}
}

return diffMap
}

func CheckDiff(parsedDiff *diff.FileDiff, workspace string) *DiffPaths {
diffPaths := DiffPaths{}
allIgnores := ignore.NewIgnore(workspace)
func checkDiffFile(parsedDiff *diff.FileDiff, workspace string) (filePath string, ignore bool) {
allIgnores := i.NewIgnore(workspace)

// If file is being renamed we don't want to check it for flags.
parsedFileA := strings.SplitN(parsedDiff.OrigName, "/", 2)
parsedFileB := strings.SplitN(parsedDiff.NewName, "/", 2)
fullPathToA := workspace + "/" + parsedFileA[1]
fullPathToB := workspace + "/" + parsedFileB[1]
info, err := os.Stat(fullPathToB)
if err != nil {
fmt.Println(err)
}
var isDir bool
// If there is no 'b' parse 'a', means file is deleted.
if info == nil {
isDir = false
diffPaths.FileToParse = fullPathToA
filePath = fullPathToA
} else {
isDir = info.IsDir()
diffPaths.FileToParse = fullPathToB
}
if err != nil {
fmt.Println(err)
filePath = fullPathToB
}
// Similar to ld-find-code-refs do not match dotfiles, and read in ignore files.
if strings.HasPrefix(parsedFileB[1], ".") && strings.HasPrefix(parsedFileA[1], ".") || allIgnores.Match(diffPaths.FileToParse, isDir) {
diffPaths.Skip = true
if strings.HasPrefix(parsedFileB[1], ".") && strings.HasPrefix(parsedFileA[1], ".") || allIgnores.Match(filePath, isDir) {
return filePath, true
}
// We don't want to run on renaming of files.
if (parsedFileA[1] != parsedFileB[1]) && (!strings.Contains(parsedFileB[1], "dev/null") && !strings.Contains(parsedFileA[1], "dev/null")) {
diffPaths.Skip = true
return filePath, true
}

return &diffPaths
return filePath, false
}

func ProcessDiffs(matcher lsearch.Matcher, hunk *diff.Hunk, builder *lflags.ReferenceBuilder) {
diffLines := strings.Split(string(hunk.Body), "\n")
func ProcessDiffs(matcher lsearch.Matcher, contents []byte, builder *lflags.ReferenceBuilder) {
diffLines := strings.Split(string(contents), "\n")
for _, line := range diffLines {
op := diff_util.LineOperation(line)
if op == diff_util.OperationEqual {
Expand Down
18 changes: 6 additions & 12 deletions diff/diff_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func newProcessFlagAccEnv() *testProcessor {
}
}

func TestCheckDiff(t *testing.T) {
func Test_checkDiffFile(t *testing.T) {
cases := []struct {
name string
fileName string
Expand Down Expand Up @@ -105,8 +105,10 @@ func TestCheckDiff(t *testing.T) {
NewName: tc.newName,
Hunks: []*diff.Hunk{hunk},
}
results := CheckDiff(&diff, "../testdata")
assert.Equal(t, &DiffPaths{FileToParse: "../testdata/" + tc.fileName, Skip: tc.skip}, results, "")
filePath, ignore := checkDiffFile(&diff, "../testdata")
expectedFilePath := "../testdata/" + tc.fileName
assert.Equal(t, expectedFilePath, filePath)
assert.Equal(t, tc.skip, ignore)
})
}
}
Expand Down Expand Up @@ -236,20 +238,12 @@ func TestProcessDiffs_BuildReferences(t *testing.T) {
for _, tc := range cases {
processor := newProcessFlagAccEnv()
t.Run(tc.name, func(t *testing.T) {
hunk := &diff.Hunk{
NewLines: 1,
NewStartLine: 1,
OrigLines: 0,
OrigStartLine: 0,
StartPosition: 1,
Body: []byte(tc.sampleBody),
}
elements := []lsearch.ElementMatcher{}
elements = append(elements, lsearch.NewElementMatcher("default", "", tc.delimiters, processor.flagKeys(), tc.aliases))
matcher := lsearch.Matcher{
Elements: elements,
}
ProcessDiffs(matcher, hunk, processor.Builder)
ProcessDiffs(matcher, []byte(tc.sampleBody), processor.Builder)
flagsRef := processor.Builder.Build()
assert.Equal(t, tc.expected, flagsRef)
})
Expand Down
2 changes: 1 addition & 1 deletion flags/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"sort"
"strings"

diff_util "github.com/launchdarkly/find-code-references-in-pull-request/internal/util/diff_util"
diff_util "github.com/launchdarkly/find-code-references-in-pull-request/internal/utils/diff_util"
)

type ReferenceBuilder struct {
Expand Down
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ require (
github.com/jstemmer/go-junit-report/v2 v2.1.0
github.com/kyoh86/richgo v0.3.12
github.com/launchdarkly/api-client-go/v13 v13.0.0
github.com/launchdarkly/ld-find-code-refs/v2 v2.11.4
github.com/launchdarkly/ld-find-code-refs/v2 v2.11.5-0.20231103194119-5133ae5a5429
)

require (
Expand All @@ -33,10 +33,10 @@ require (
require (
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.2.0 // indirect
github.com/bmatcuk/doublestar/v4 v4.6.0 // indirect
github.com/bmatcuk/doublestar/v4 v4.6.1 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/go-git/go-git/v5 v5.9.0 // indirect
github.com/go-git/go-git/v5 v5.10.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
Expand Down
12 changes: 6 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7Y
github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA=
github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM=
github.com/bmatcuk/doublestar/v4 v4.6.0 h1:HTuxyug8GyFbRkrffIpzNCSK4luc0TY3wzXvzIZhEXc=
github.com/bmatcuk/doublestar/v4 v4.6.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
github.com/bmatcuk/doublestar/v4 v4.6.1 h1:FH9SifrbvJhnlQpztAx++wlkk70QBf0iBWDwNy7PA4I=
github.com/bmatcuk/doublestar/v4 v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
Expand All @@ -68,8 +68,8 @@ github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w=
github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/go-git/go-git/v5 v5.9.0 h1:cD9SFA7sHVRdJ7AYck1ZaAa/yeuBvGPxwXDL8cxrObY=
github.com/go-git/go-git/v5 v5.9.0/go.mod h1:RKIqga24sWdMGZF+1Ekv9kylsDz6LzdTSI2s/OsZWE0=
github.com/go-git/go-git/v5 v5.10.0 h1:F0x3xXrAWmhwtzoCokU4IMPcBdncG+HAAqi9FcOOjbQ=
github.com/go-git/go-git/v5 v5.10.0/go.mod h1:1FOZ/pQnqw24ghP2n7cunVl0ON55BsjPYvhWHvZGhoo=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
Expand Down Expand Up @@ -180,8 +180,8 @@ github.com/launchdarkly/api-client-go/v7 v7.1.1 h1:3VBkFt9xHljMw5KDlVFDUogxfH78Y
github.com/launchdarkly/api-client-go/v7 v7.1.1/go.mod h1:GVl1inKsWoKX3yLgdqrjxWw8k4ih0HlSmdnrhi5NNDs=
github.com/launchdarkly/json-patch v0.0.0-20180720210516-dd68d883319f h1:jfiPiz2hE/7mHv2NOS4cm07sSJCsKlbxmR7pzPhhvpU=
github.com/launchdarkly/json-patch v0.0.0-20180720210516-dd68d883319f/go.mod h1:CHbYdMs8UjvNnS2fatlQvi4UYnBTRYGxRHc/0kQupSQ=
github.com/launchdarkly/ld-find-code-refs/v2 v2.11.4 h1:kIKFvpaO+zGjvDNPiem5GwZZYFsdA4CLPtJJzFLmM8E=
github.com/launchdarkly/ld-find-code-refs/v2 v2.11.4/go.mod h1:fbIEMBJ4dZYNRC0vrc7V4s2sUWlZhujVef3k8pPGv88=
github.com/launchdarkly/ld-find-code-refs/v2 v2.11.5-0.20231103194119-5133ae5a5429 h1:BzV5r4c7tYaiAngMi3dnU3JcWIkMwS7q4kDR14Tumbc=
github.com/launchdarkly/ld-find-code-refs/v2 v2.11.5-0.20231103194119-5133ae5a5429/go.mod h1:0cSnc1X1lrnw/9uDnuzfLfi//ZsGahmC2Xq2QfudEiA=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
Expand Down
42 changes: 42 additions & 0 deletions internal/aliases/aliases.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package aliases

import (
"github.com/launchdarkly/ld-find-code-refs/v2/aliases"
"github.com/launchdarkly/ld-find-code-refs/v2/options"

"github.com/launchdarkly/find-code-references-in-pull-request/internal/utils"
)

// Generate aliases, making sure to identify aliases in the removed diff contents
func GenerateAliases(opts options.Options, flagKeys []string, diffContents aliases.FileContentsMap) (map[string][]string, error) {
aliasesByFlagKey, err := aliases.GenerateAliases(flagKeys, opts.Aliases, opts.Dir)
if err != nil {
return nil, err
}

filePatternAliases := getFilepatternAliases(opts.Aliases)
for _, flag := range flagKeys {
for _, alias := range filePatternAliases {
aliases, err := aliases.GenerateAliasesFromFilePattern(alias, flag, opts.Dir, diffContents)
if err != nil {
// skip aliases that fail to generate
continue
}
aliasesByFlagKey[flag] = append(aliasesByFlagKey[flag], aliases...)
}
aliasesByFlagKey[flag] = utils.Dedupe(aliasesByFlagKey[flag])
}

return aliasesByFlagKey, nil
}

func getFilepatternAliases(aliases []options.Alias) []options.Alias {
filePatternAliases := make([]options.Alias, 0, len(aliases))
for _, alias := range aliases {
if alias.Type.Canonical() == options.FilePattern {
filePatternAliases = append(filePatternAliases, alias)
}
}

return filePatternAliases
}
16 changes: 16 additions & 0 deletions internal/utils/utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package utils

func Dedupe(s []string) []string {
if len(s) <= 1 {
return s
}
keys := make(map[string]struct{}, len(s))
ret := make([]string, 0, len(s))
for _, elem := range s {
if _, ok := keys[elem]; !ok {
keys[elem] = struct{}{}
ret = append(ret, elem)
}
}
return ret
}
17 changes: 7 additions & 10 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,21 +48,17 @@ func main() {
opts, err := getOptions(config)
failExit(err)

matcher, err := search.GetMatcher(config, opts, flags)
multiFiles, err := getDiffs(ctx, config, *event.PullRequest.Number)
failExit(err)

multiFiles, err := getDiffs(ctx, config, *event.PullRequest.Number)
diffMap := ldiff.PreprocessDiffs(opts.Dir, multiFiles)

matcher, err := search.GetMatcher(opts, flags, diffMap)
failExit(err)

builder := lflags.NewReferenceBuilder(config.MaxFlags)
for _, parsedDiff := range multiFiles {
getPath := ldiff.CheckDiff(parsedDiff, config.Workspace)
if getPath.Skip {
continue
}
for _, hunk := range parsedDiff.Hunks {
ldiff.ProcessDiffs(matcher, hunk, builder)
}
for _, contents := range diffMap {
ldiff.ProcessDiffs(matcher, contents, builder)
}
flagsRef := builder.Build()

Expand Down Expand Up @@ -152,6 +148,7 @@ func getDiffs(ctx context.Context, config *lcr.Config, prNumber int) ([]*diff.Fi
return diff.ParseMultiFileDiff([]byte(raw))
}

// Get options from config. Note: dir will be set to workspace
func getOptions(config *lcr.Config) (options.Options, error) {
// Needed for ld-find-code-refs to work as a library
viper.Set("dir", config.Workspace)
Expand Down
60 changes: 8 additions & 52 deletions search/search.go
Original file line number Diff line number Diff line change
@@ -1,78 +1,34 @@
package search

import (
"log"
"strings"

ldapi "github.com/launchdarkly/api-client-go/v13"
"github.com/launchdarkly/ld-find-code-refs/v2/aliases"
laliases "github.com/launchdarkly/ld-find-code-refs/v2/aliases"
"github.com/launchdarkly/ld-find-code-refs/v2/options"
lsearch "github.com/launchdarkly/ld-find-code-refs/v2/search"

lcr "github.com/launchdarkly/find-code-references-in-pull-request/config"
"github.com/spf13/viper"
"github.com/launchdarkly/find-code-references-in-pull-request/internal/aliases"
)

func GetMatcher(config *lcr.Config, opts options.Options, flags []ldapi.FeatureFlag) (matcher lsearch.Matcher, err error) {
func GetMatcher(opts options.Options, flags []ldapi.FeatureFlag, diffContents laliases.FileContentsMap) (matcher lsearch.Matcher, err error) {
flagKeys := make([]string, 0, len(flags))
for _, flag := range flags {
flagKeys = append(flagKeys, flag.Key)
}

aliasesByFlagKey, err := aliases.GenerateAliases(flagKeys, opts.Aliases, config.Workspace)
aliasesByFlagKey, err := aliases.GenerateAliases(opts, flagKeys, diffContents)
if err != nil {
return lsearch.Matcher{}, err
}

delimiters := strings.Join(Dedupe(getDelimiters(opts)), "")
elements := []lsearch.ElementMatcher{}
elements = append(elements, lsearch.NewElementMatcher(config.LdProject, "", delimiters, flagKeys, aliasesByFlagKey))
delimiters := strings.Join(lsearch.GetDelimiters(opts), "")
elements := make([]lsearch.ElementMatcher, 0, 1)
elements = append(elements, lsearch.NewElementMatcher(opts.ProjKey, "", delimiters, flagKeys, aliasesByFlagKey))

matcher = lsearch.Matcher{
Elements: elements,
}

return matcher, nil
}

func getAliases(config *lcr.Config, flagKeys []string) (map[string][]string, error) {
// Needed for ld-find-code-refs to work as a library
viper.Set("dir", config.Workspace)
viper.Set("accessToken", config.ApiToken)

err := options.InitYAML()
if err != nil {
log.Println(err)
}
opts, err := options.GetOptions()
if err != nil {
log.Println(err)
}

return aliases.GenerateAliases(flagKeys, opts.Aliases, config.Workspace)
}

func getDelimiters(opts options.Options) []string {
delims := []string{`"`, `'`, "`"}
if opts.Delimiters.DisableDefaults {
delims = []string{}
}

delims = append(delims, opts.Delimiters.Additional...)

return delims
}

func Dedupe(s []string) []string {
if len(s) <= 1 {
return s
}
keys := make(map[string]struct{}, len(s))
ret := make([]string, 0, len(s))
for _, entry := range s {
if _, value := keys[entry]; !value {
keys[entry] = struct{}{}
ret = append(ret, entry)
}
}
return ret
}
2 changes: 1 addition & 1 deletion testdata/aliases
Original file line number Diff line number Diff line change
@@ -1 +1 @@
const myRandomAlias = useFlagValue('beta-ui')
const newRandomAlias = useFlagValue('show-widgets')
2 changes: 0 additions & 2 deletions vendor/github.com/bmatcuk/doublestar/v4/README.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading