Skip to content

Commit

Permalink
Merge pull request #1130 from wakatime/bugfix/exclude-include-bool-param
Browse files Browse the repository at this point in the history
Accept boolean value for exclude and include params
  • Loading branch information
gandarez authored Nov 21, 2024
2 parents 1415a29 + 6e99337 commit f8aabde
Show file tree
Hide file tree
Showing 4 changed files with 185 additions and 75 deletions.
38 changes: 38 additions & 0 deletions cmd/heartbeat/heartbeat_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,44 @@ func TestSendHeartbeats_WithFiltering_Exclude(t *testing.T) {
assert.Equal(t, 0, numCalls)
}

func TestSendHeartbeats_WithFiltering_Exclude_All(t *testing.T) {
resetSingleton(t)

testServerURL, router, tearDown := setupTestServer()
defer tearDown()

var numCalls int

router.HandleFunc("/users/current/heartbeats.bulk", func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusInternalServerError)

numCalls++
})

v := viper.New()
v.SetDefault("sync-offline-activity", 1000)
v.Set("api-url", testServerURL)
v.Set("category", "debugging")
v.Set("entity", `\tmp\main.go`)
v.Set("exclude", `true`)
v.Set("entity-type", "file")
v.Set("key", "00000000-0000-4000-8000-000000000000")
v.Set("plugin", "plugin")
v.Set("time", 1585598059.1)
v.Set("timeout", 5)
v.Set("write", true)

offlineQueueFile, err := os.CreateTemp(t.TempDir(), "")
require.NoError(t, err)

defer offlineQueueFile.Close()

err = cmdheartbeat.SendHeartbeats(context.Background(), v, offlineQueueFile.Name())
require.NoError(t, err)

assert.Equal(t, 0, numCalls)
}

func TestSendHeartbeats_ExtraHeartbeats(t *testing.T) {
resetSingleton(t)

Expand Down
69 changes: 38 additions & 31 deletions cmd/params/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -437,12 +437,17 @@ func LoadHeartbeatParams(ctx context.Context, v *viper.Viper) (Heartbeat, error)
timeSecs = float64(time.Now().UnixNano()) / 1000000000
}

filterParams, err := loadFilterParams(ctx, v)
if err != nil {
return Heartbeat{}, fmt.Errorf("failed to load filter params: %s", err)
}

projectParams, err := loadProjectParams(ctx, v)
if err != nil {
return Heartbeat{}, fmt.Errorf("failed to parse project params: %s", err)
}

sanitizeParams, err := loadSanitizeParams(v)
sanitizeParams, err := loadSanitizeParams(ctx, v)
if err != nil {
return Heartbeat{}, fmt.Errorf("failed to load sanitize params: %s", err)
}
Expand All @@ -469,34 +474,30 @@ func LoadHeartbeatParams(ctx context.Context, v *viper.Viper) (Heartbeat, error)
LinesInFile: linesInFile,
LocalFile: vipertools.GetString(v, "local-file"),
Time: timeSecs,
Filter: loadFilterParams(ctx, v),
Filter: filterParams,
Project: projectParams,
Sanitize: sanitizeParams,
}, nil
}

func loadFilterParams(ctx context.Context, v *viper.Viper) FilterParams {
func loadFilterParams(ctx context.Context, v *viper.Viper) (FilterParams, error) {
exclude := v.GetStringSlice("exclude")
exclude = append(exclude, v.GetStringSlice("settings.exclude")...)
exclude = append(exclude, v.GetStringSlice("settings.ignore")...)

logger := log.Extract(ctx)

var excludePatterns []regex.Regex

for _, s := range exclude {
// make all regex case insensitive
if !strings.HasPrefix(s, "(?i)") {
s = "(?i)" + s
}

compiled, err := regex.Compile(s)
patterns, err := parseBoolOrRegexList(ctx, s)
if err != nil {
logger.Warnf("failed to compile exclude regex pattern %q", s)
continue
return FilterParams{}, fmt.Errorf(
"failed to parse regex exclude param %q: %s",
s,
err,
)
}

excludePatterns = append(excludePatterns, compiled)
excludePatterns = append(excludePatterns, patterns...)
}

include := v.GetStringSlice("include")
Expand All @@ -505,18 +506,16 @@ func loadFilterParams(ctx context.Context, v *viper.Viper) FilterParams {
var includePatterns []regex.Regex

for _, s := range include {
// make all regex case insensitive
if !strings.HasPrefix(s, "(?i)") {
s = "(?i)" + s
}

compiled, err := regex.Compile(s)
patterns, err := parseBoolOrRegexList(ctx, s)
if err != nil {
logger.Warnf("failed to compile include regex pattern %q", s)
continue
return FilterParams{}, fmt.Errorf(
"failed to parse regex include param %q: %s",
s,
err,
)
}

includePatterns = append(includePatterns, compiled)
includePatterns = append(includePatterns, patterns...)
}

return FilterParams{
Expand All @@ -532,10 +531,10 @@ func loadFilterParams(ctx context.Context, v *viper.Viper) FilterParams {
"include-only-with-project-file",
"settings.include_only_with_project_file",
),
}
}, nil
}

func loadSanitizeParams(v *viper.Viper) (SanitizeParams, error) {
func loadSanitizeParams(ctx context.Context, v *viper.Viper) (SanitizeParams, error) {
// hide branch names
hideBranchNamesStr := vipertools.FirstNonEmptyString(
v,
Expand All @@ -545,7 +544,7 @@ func loadSanitizeParams(v *viper.Viper) (SanitizeParams, error) {
"settings.hidebranchnames",
)

hideBranchNamesPatterns, err := parseBoolOrRegexList(hideBranchNamesStr)
hideBranchNamesPatterns, err := parseBoolOrRegexList(ctx, hideBranchNamesStr)
if err != nil {
return SanitizeParams{}, fmt.Errorf(
"failed to parse regex hide branch names param %q: %s",
Expand All @@ -563,7 +562,7 @@ func loadSanitizeParams(v *viper.Viper) (SanitizeParams, error) {
"settings.hideprojectnames",
)

hideProjectNamesPatterns, err := parseBoolOrRegexList(hideProjectNamesStr)
hideProjectNamesPatterns, err := parseBoolOrRegexList(ctx, hideProjectNamesStr)
if err != nil {
return SanitizeParams{}, fmt.Errorf(
"failed to parse regex hide project names param %q: %s",
Expand All @@ -583,7 +582,7 @@ func loadSanitizeParams(v *viper.Viper) (SanitizeParams, error) {
"settings.hidefilenames",
)

hideFileNamesPatterns, err := parseBoolOrRegexList(hideFileNamesStr)
hideFileNamesPatterns, err := parseBoolOrRegexList(ctx, hideFileNamesStr)
if err != nil {
return SanitizeParams{}, fmt.Errorf(
"failed to parse regex hide file names param %q: %s",
Expand All @@ -602,7 +601,7 @@ func loadSanitizeParams(v *viper.Viper) (SanitizeParams, error) {
}

func loadProjectParams(ctx context.Context, v *viper.Viper) (ProjectParams, error) {
submodulesDisabled, err := parseBoolOrRegexList(vipertools.GetString(v, "git.submodules_disabled"))
submodulesDisabled, err := parseBoolOrRegexList(ctx, vipertools.GetString(v, "git.submodules_disabled"))
if err != nil {
return ProjectParams{}, fmt.Errorf(
"failed to parse regex submodules disabled param: %s",
Expand Down Expand Up @@ -1154,9 +1153,11 @@ func (p StatusBar) String() string {
)
}

func parseBoolOrRegexList(s string) ([]regex.Regex, error) {
func parseBoolOrRegexList(ctx context.Context, s string) ([]regex.Regex, error) {
var patterns []regex.Regex

logger := log.Extract(ctx)

s = strings.ReplaceAll(s, "\r", "\n")
s = strings.Trim(s, "\n\t ")

Expand All @@ -1174,9 +1175,15 @@ func parseBoolOrRegexList(s string) ([]regex.Regex, error) {
continue
}

// make all regex case insensitive
if !strings.HasPrefix(s, "(?i)") {
s = "(?i)" + s
}

compiled, err := regex.Compile(s)
if err != nil {
return nil, fmt.Errorf("failed to compile regex %q: %s", s, err)
logger.Warnf("failed to compile regex pattern %q, it will be ignored", s)
continue
}

patterns = append(patterns, compiled)
Expand Down
17 changes: 10 additions & 7 deletions cmd/params/params_internal_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package params

import (
"context"
"regexp"
"testing"
"time"
Expand All @@ -13,6 +14,8 @@ import (
)

func TestParseBoolOrRegexList(t *testing.T) {
ctx := context.Background()

tests := map[string]struct {
Input string
Expected []regex.Regex
Expand All @@ -32,29 +35,29 @@ func TestParseBoolOrRegexList(t *testing.T) {
"valid regex": {
Input: "\t.?\n\t\n \n\t\twakatime.? \t\n",
Expected: []regex.Regex{
regex.NewRegexpWrap(regexp.MustCompile(".?")),
regex.NewRegexpWrap(regexp.MustCompile("wakatime.?")),
regex.NewRegexpWrap(regexp.MustCompile("(?i).?")),
regex.NewRegexpWrap(regexp.MustCompile("(?i)wakatime.?")),
},
},
"valid regex with windows style": {
Input: "\t.?\r\n\t\t\twakatime.? \t\r\n",
Expected: []regex.Regex{
regex.NewRegexpWrap(regexp.MustCompile(".?")),
regex.NewRegexpWrap(regexp.MustCompile("wakatime.?")),
regex.NewRegexpWrap(regexp.MustCompile("(?i).?")),
regex.NewRegexpWrap(regexp.MustCompile("(?i)wakatime.?")),
},
},
"valid regex with old mac style": {
Input: "\t.?\r\t\t\twakatime.? \t\r",
Expected: []regex.Regex{
regex.NewRegexpWrap(regexp.MustCompile(".?")),
regex.NewRegexpWrap(regexp.MustCompile("wakatime.?")),
regex.NewRegexpWrap(regexp.MustCompile("(?i).?")),
regex.NewRegexpWrap(regexp.MustCompile("(?i)wakatime.?")),
},
},
}

for name, test := range tests {
t.Run(name, func(t *testing.T) {
regex, err := parseBoolOrRegexList(test.Input)
regex, err := parseBoolOrRegexList(ctx, test.Input)
require.NoError(t, err)

assert.Equal(t, test.Expected, regex)
Expand Down
Loading

0 comments on commit f8aabde

Please sign in to comment.