diff --git a/cmd/pint/ci.go b/cmd/pint/ci.go index 30d25cdf..354d9d84 100644 --- a/cmd/pint/ci.go +++ b/cmd/pint/ci.go @@ -47,7 +47,7 @@ func actionCI(c *cli.Context) error { return nil } - finder := discovery.NewGitBranchFinder(git.RunGit, includeRe, meta.cfg.CI.BaseBranch, meta.cfg.CI.MaxCommits) + finder := discovery.NewGitBranchFinder(git.RunGit, includeRe, meta.cfg.CI.BaseBranch, meta.cfg.CI.MaxCommits, meta.cfg.Parser.CompileRelaxed()) entries, err := finder.Find() if err != nil { return err diff --git a/cmd/pint/lint.go b/cmd/pint/lint.go index 6c1d1f69..b181b587 100644 --- a/cmd/pint/lint.go +++ b/cmd/pint/lint.go @@ -41,7 +41,7 @@ func actionLint(c *cli.Context) error { return fmt.Errorf("at least one file or directory required") } - finder := discovery.NewGlobFinder(paths...) + finder := discovery.NewGlobFinder(paths, meta.cfg.Parser.CompileRelaxed()) entries, err := finder.Find() if err != nil { return err diff --git a/cmd/pint/lint_test.go b/cmd/pint/lint_test.go index e193744e..17b4453e 100644 --- a/cmd/pint/lint_test.go +++ b/cmd/pint/lint_test.go @@ -30,7 +30,10 @@ func mockRules(dir string, filesCount, rulesPerFile int) error { } func mockConfig(configPath string) error { - content := ` + content := ` +parser { + relaxed = ["(.*)"] +} rule { reject ".* +.*" { label_keys = true diff --git a/cmd/pint/tests/0001_match_path.txt b/cmd/pint/tests/0001_match_path.txt index 69bc1986..f42dad9a 100644 --- a/cmd/pint/tests/0001_match_path.txt +++ b/cmd/pint/tests/0001_match_path.txt @@ -18,6 +18,9 @@ level=fatal msg="Fatal error" error="problems found" - record: "colo:test2" expr: sum(foo) without(job) -- .pint.hcl -- +parser { + relaxed = [".*"] +} rule { match { path = "rules/0002.yml" diff --git a/cmd/pint/tests/0003_lint_workdir.txt b/cmd/pint/tests/0003_lint_workdir.txt index 02e50331..d97118f7 100644 --- a/cmd/pint/tests/0003_lint_workdir.txt +++ b/cmd/pint/tests/0003_lint_workdir.txt @@ -142,6 +142,9 @@ level=fatal msg="Fatal error" error="problems found" expr: up == 0 -- .pint.hcl -- +parser { + relaxed = [".*"] +} rule { match { kind = "recording" diff --git a/cmd/pint/tests/0004_fail_invalid_yaml.txt b/cmd/pint/tests/0004_fail_invalid_yaml.txt index 95b2ae84..e075391e 100644 --- a/cmd/pint/tests/0004_fail_invalid_yaml.txt +++ b/cmd/pint/tests/0004_fail_invalid_yaml.txt @@ -3,19 +3,23 @@ pint.error --no-color lint rules cmp stderr stderr.txt -- stderr.txt -- +level=info msg="Loading configuration file" path=.pint.hcl level=error msg="Failed to parse file content" error="yaml: line 4: did not find expected key" path=rules/bad.yaml level=info msg="File parsed" path=rules/ok.yml rules=1 rules/bad.yaml:4: did not find expected key (yaml/parse) -rules/ok.yml:2: syntax error: unclosed left bracket (promql/syntax) - expr: sum(foo[5m) +rules/ok.yml:5: syntax error: unclosed left bracket (promql/syntax) + expr: sum(foo[5m) level=info msg="Problems found" Fatal=2 level=fatal msg="Fatal error" error="problems found" -- rules/ok.yml -- -- record: sum:missing - expr: sum(foo[5m) +groups: +- name: foo + rules: + - record: sum:missing + expr: sum(foo[5m) -- rules/bad.yaml -- xxx: @@ -24,3 +28,8 @@ xxx: - xx - yyy + +-- .pint.hcl -- +parser { + relaxed = [".*"] +} diff --git a/cmd/pint/tests/0005_false_positive.txt b/cmd/pint/tests/0005_false_positive.txt index 17101a4b..fa153328 100644 --- a/cmd/pint/tests/0005_false_positive.txt +++ b/cmd/pint/tests/0005_false_positive.txt @@ -12,6 +12,9 @@ level=info msg="File parsed" path=rules/0001.yml rules=2 expr: topk(6, sum(rate(edgeworker_subrequest_errorCount{cordon="free"}[10m])) without (instance)) -- .pint.hcl -- +parser { + relaxed = ["rules/.*"] +} rule { aggregate ".+" { keep = [ "job" ] diff --git a/cmd/pint/tests/0006_rr_labels.txt b/cmd/pint/tests/0006_rr_labels.txt index 63b8758d..01ca0373 100644 --- a/cmd/pint/tests/0006_rr_labels.txt +++ b/cmd/pint/tests/0006_rr_labels.txt @@ -5,19 +5,22 @@ cmp stderr stderr.txt -- stderr.txt -- level=info msg="Loading configuration file" path=.pint.hcl level=info msg="File parsed" path=rules/0001.yml rules=2 -rules/0001.yml:5: incomplete rule, no alert or record key (yaml/parse) -- expr: sum(foo) +rules/0001.yml:8: incomplete rule, no alert or record key (yaml/parse) + - expr: sum(foo) level=info msg="Problems found" Fatal=1 level=fatal msg="Fatal error" error="problems found" -- rules/0001.yml -- -- record: "colo:test1" - expr: sum(foo) without(job) - labels: - job: foo -- expr: sum(foo) - labels: - job: foo +groups: +- name: foo + rules: + - record: "colo:test1" + expr: sum(foo) without(job) + labels: + job: foo + - expr: sum(foo) + labels: + job: foo -- .pint.hcl -- rule { aggregate ".+" { diff --git a/cmd/pint/tests/0007_alerts.txt b/cmd/pint/tests/0007_alerts.txt index 2204965b..cb003655 100644 --- a/cmd/pint/tests/0007_alerts.txt +++ b/cmd/pint/tests/0007_alerts.txt @@ -91,6 +91,9 @@ level=fatal msg="Fatal error" error="problems found" ignore: '$value is not a variable' -- .pint.hcl -- +parser { + relaxed = ["rules/.*"] +} rule { annotation "url" { severity = "bug" diff --git a/cmd/pint/tests/0010_syntax_check.txt b/cmd/pint/tests/0010_syntax_check.txt index 6c55409a..e43f55a3 100644 --- a/cmd/pint/tests/0010_syntax_check.txt +++ b/cmd/pint/tests/0010_syntax_check.txt @@ -3,6 +3,7 @@ pint.error --no-color lint rules cmp stderr stderr.txt -- stderr.txt -- +level=info msg="Loading configuration file" path=.pint.hcl level=error msg="Failed to parse file content" error="yaml: line 6: did not find expected '-' indicator" path=rules/1.yaml rules/1.yaml:6: did not find expected '-' indicator (yaml/parse) @@ -21,3 +22,8 @@ alert: Bad for: 2m labels: component: foo + +-- .pint.hcl -- +parser { + relaxed = ["rules/.*"] +} diff --git a/cmd/pint/tests/0011_ignore_rules.txt b/cmd/pint/tests/0011_ignore_rules.txt index 5efa5c97..480d3810 100644 --- a/cmd/pint/tests/0011_ignore_rules.txt +++ b/cmd/pint/tests/0011_ignore_rules.txt @@ -58,6 +58,9 @@ level=fatal msg="Fatal error" error="problems found" expr: sum(errors_total) without(job) -- .pint.hcl -- +parser { + relaxed = [".*"] +} rule { aggregate ".+" { keep = [ "job" ] diff --git a/cmd/pint/tests/0014_issue49_2.txt b/cmd/pint/tests/0014_issue49_2.txt index 07ffb4b9..39b8d930 100644 --- a/cmd/pint/tests/0014_issue49_2.txt +++ b/cmd/pint/tests/0014_issue49_2.txt @@ -3,7 +3,13 @@ pint.ok --no-color lint rules cmp stderr stderr.txt -- stderr.txt -- +level=info msg="Loading configuration file" path=.pint.hcl level=info msg="File parsed" path=rules/0001.yaml rules=1 -- rules/0001.yaml -- - record: down expr: up == 0 + +-- .pint.hcl -- +parser { + relaxed = ["rules/.*"] +} diff --git a/cmd/pint/tests/0017_issue69.txt b/cmd/pint/tests/0017_issue69.txt index 49491bfb..b95f8712 100644 --- a/cmd/pint/tests/0017_issue69.txt +++ b/cmd/pint/tests/0017_issue69.txt @@ -4273,6 +4273,9 @@ func main() { expr: up == 0 -- .pint.hcl -- +parser { + relaxed = ["rules/.*"] +} rule { match { kind = "alerting" diff --git a/cmd/pint/tests/0018_match_alerting.txt b/cmd/pint/tests/0018_match_alerting.txt index 45ab434b..626f4d5c 100644 --- a/cmd/pint/tests/0018_match_alerting.txt +++ b/cmd/pint/tests/0018_match_alerting.txt @@ -24,6 +24,9 @@ level=info msg="Problems found" Warning=2 expr: sum(bar) without(job) -- .pint.hcl -- +parser { + relaxed = ["rules/.*"] +} rule { match { kind = "alerting" diff --git a/cmd/pint/tests/0019_match_recording.txt b/cmd/pint/tests/0019_match_recording.txt index d8c921ee..6861fc0d 100644 --- a/cmd/pint/tests/0019_match_recording.txt +++ b/cmd/pint/tests/0019_match_recording.txt @@ -21,6 +21,9 @@ level=info msg="Problems found" Warning=1 expr: sum(bar) without(job) > 0 -- .pint.hcl -- +parser { + relaxed = ["rules/.*"] +} rule { match { kind = "recording" diff --git a/cmd/pint/tests/0020_ignore_kind.txt b/cmd/pint/tests/0020_ignore_kind.txt index b6f1e347..d1fc0e53 100644 --- a/cmd/pint/tests/0020_ignore_kind.txt +++ b/cmd/pint/tests/0020_ignore_kind.txt @@ -5,23 +5,26 @@ cmp stderr stderr.txt -- stderr.txt -- level=info msg="Loading configuration file" path=.pint.hcl level=info msg="File parsed" path=rules/0001.yml rules=2 -level=debug msg="Found recording rule" lines=1-2 path=rules/0001.yml record=colo:recording +level=debug msg="Found recording rule" lines=4-5 path=rules/0001.yml record=colo:recording level=debug msg="Configured checks for rule" enabled=["promql/syntax","alerts/for","alerts/comparison","alerts/template","promql/fragile","promql/regexp","promql/aggregate(job:true)"] path=rules/0001.yml rule=colo:recording -level=debug msg="Found alerting rule" alert=colo:alerting lines=4-5 path=rules/0001.yml +level=debug msg="Found alerting rule" alert=colo:alerting lines=7-8 path=rules/0001.yml level=debug msg="Configured checks for rule" enabled=["promql/syntax","alerts/for","alerts/comparison","alerts/template","promql/fragile","promql/regexp"] path=rules/0001.yml rule=colo:alerting -rules/0001.yml:2: job label is required and should be preserved when aggregating "^.+$" rules, remove job from without() (promql/aggregate) - expr: sum(foo) without(job) +rules/0001.yml:5: job label is required and should be preserved when aggregating "^.+$" rules, remove job from without() (promql/aggregate) + expr: sum(foo) without(job) -rules/0001.yml:5: alert query doesn't have any condition, it will always fire if the metric exists (alerts/comparison) - expr: sum(bar) without(job) +rules/0001.yml:8: alert query doesn't have any condition, it will always fire if the metric exists (alerts/comparison) + expr: sum(bar) without(job) level=info msg="Problems found" Warning=2 -- rules/0001.yml -- -- record: "colo:recording" - expr: sum(foo) without(job) +groups: +- name: foo + rules: + - record: "colo:recording" + expr: sum(foo) without(job) -- alert: "colo:alerting" - expr: sum(bar) without(job) + - alert: "colo:alerting" + expr: sum(bar) without(job) -- .pint.hcl -- rule { diff --git a/cmd/pint/tests/0021_ignore_all.txt b/cmd/pint/tests/0021_ignore_all.txt index 8d27c8ee..261fd3a7 100644 --- a/cmd/pint/tests/0021_ignore_all.txt +++ b/cmd/pint/tests/0021_ignore_all.txt @@ -13,6 +13,9 @@ level=fatal msg="Fatal error" error="failed to load config file \".pint.hcl\": i expr: sum(bar) without(job) -- .pint.hcl -- +parser { + relaxed = ["rules/.*"] +} rule { ignore {} aggregate ".+" { diff --git a/cmd/pint/tests/0022_ignore_multi.txt b/cmd/pint/tests/0022_ignore_multi.txt index 7574dc86..f2963a96 100644 --- a/cmd/pint/tests/0022_ignore_multi.txt +++ b/cmd/pint/tests/0022_ignore_multi.txt @@ -25,6 +25,9 @@ level=info msg="Problems found" Warning=2 expr: sum(sum(errors_total) without(keep)) by(dropped) -- .pint.hcl -- +parser { + relaxed = ["rules/.*"] +} rule { aggregate ".+" { keep = [ "keep" ] diff --git a/cmd/pint/tests/0023_enabled_checks.txt b/cmd/pint/tests/0023_enabled_checks.txt index 0fb6ef00..50a47f94 100644 --- a/cmd/pint/tests/0023_enabled_checks.txt +++ b/cmd/pint/tests/0023_enabled_checks.txt @@ -17,6 +17,9 @@ stderr 'level=debug msg="Configured checks for rule" enabled=\["promql/syntax"," expr: up == 0 -- .pint.hcl -- +parser { + relaxed = ["rules/.*"] +} prometheus "prom" { uri = "https://" timeout = "2m" diff --git a/cmd/pint/tests/0024_color_output.txt b/cmd/pint/tests/0024_color_output.txt index 1667a41b..f1592639 100644 --- a/cmd/pint/tests/0024_color_output.txt +++ b/cmd/pint/tests/0024_color_output.txt @@ -133,6 +133,9 @@ level=fatal msg="Fatal error" error="problems found" expr: up == 0 -- .pint.hcl -- +parser { + relaxed = ["rules/.*"] +} rule { match { kind = "recording" diff --git a/cmd/pint/tests/0025_config.txt b/cmd/pint/tests/0025_config.txt index 721b6465..03ed62c1 100644 --- a/cmd/pint/tests/0025_config.txt +++ b/cmd/pint/tests/0025_config.txt @@ -9,6 +9,7 @@ level=info msg="Loading configuration file" path=.pint.hcl "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom", diff --git a/cmd/pint/tests/0027_ci_branch.txt b/cmd/pint/tests/0027_ci_branch.txt index 630506e6..320a480d 100644 --- a/cmd/pint/tests/0027_ci_branch.txt +++ b/cmd/pint/tests/0027_ci_branch.txt @@ -43,3 +43,6 @@ level=fatal msg="Fatal error" error="problems found" ci { baseBranch = "main" } +parser { + relaxed = [".*"] +} \ No newline at end of file diff --git a/cmd/pint/tests/0028_ci_git_error.txt b/cmd/pint/tests/0028_ci_git_error.txt index 253c5ef8..84b729ed 100644 --- a/cmd/pint/tests/0028_ci_git_error.txt +++ b/cmd/pint/tests/0028_ci_git_error.txt @@ -41,3 +41,6 @@ level=fatal msg="Fatal error" error="failed to get the list of commits to scan: ci { baseBranch = "notmain" } +parser { + relaxed = [".*"] +} diff --git a/cmd/pint/tests/0029_ci_too_many_commits.txt b/cmd/pint/tests/0029_ci_too_many_commits.txt index bf4ff568..b2b04dc0 100644 --- a/cmd/pint/tests/0029_ci_too_many_commits.txt +++ b/cmd/pint/tests/0029_ci_too_many_commits.txt @@ -46,3 +46,6 @@ ci { maxCommits = 2 baseBranch = "main" } +parser { + relaxed = [".*"] +} diff --git a/cmd/pint/tests/0032_ci_github.txt b/cmd/pint/tests/0032_ci_github.txt index 67874d67..00f3235c 100644 --- a/cmd/pint/tests/0032_ci_github.txt +++ b/cmd/pint/tests/0032_ci_github.txt @@ -45,6 +45,9 @@ exec sh -c 'cat ../server.pid | xargs kill' ci { baseBranch = "main" } +parser { + relaxed = [".*"] +} repository { github { baseuri = "http://127.0.0.1:6032" diff --git a/cmd/pint/tests/0033_ci_github_multi.txt b/cmd/pint/tests/0033_ci_github_multi.txt index 0d8a28ec..03a848f3 100644 --- a/cmd/pint/tests/0033_ci_github_multi.txt +++ b/cmd/pint/tests/0033_ci_github_multi.txt @@ -50,6 +50,9 @@ exec sh -c 'cat ../server.pid | xargs kill' ci { baseBranch = "main" } +parser { + relaxed = [".*"] +} repository { github { baseuri = "http://127.0.0.1:6033" diff --git a/cmd/pint/tests/0036_ci_basebranch.txt b/cmd/pint/tests/0036_ci_basebranch.txt index fddda6fc..889e4a6d 100644 --- a/cmd/pint/tests/0036_ci_basebranch.txt +++ b/cmd/pint/tests/0036_ci_basebranch.txt @@ -28,3 +28,6 @@ level=info msg="Running from base branch, skipping checks" branch=main ci { baseBranch = "main" } +parser { + relaxed = [".*"] +} diff --git a/cmd/pint/tests/0037_disable_checks.txt b/cmd/pint/tests/0037_disable_checks.txt index 4af4204b..20d49d3c 100644 --- a/cmd/pint/tests/0037_disable_checks.txt +++ b/cmd/pint/tests/0037_disable_checks.txt @@ -21,6 +21,9 @@ level=info msg="Problems found" Warning=1 expr: foo -- .pint.hcl -- +parser { + relaxed = [".*"] +} rule { match { kind = "recording" diff --git a/cmd/pint/tests/0038_disable_checks_regex.txt b/cmd/pint/tests/0038_disable_checks_regex.txt index 92352afa..a3f7ad0a 100644 --- a/cmd/pint/tests/0038_disable_checks_regex.txt +++ b/cmd/pint/tests/0038_disable_checks_regex.txt @@ -21,6 +21,9 @@ level=info msg="Problems found" Warning=1 expr: foo -- .pint.hcl -- +parser { + relaxed = [".*"] +} rule { match { kind = "recording" diff --git a/cmd/pint/tests/0039_prom_selected_path.txt b/cmd/pint/tests/0039_prom_selected_path.txt index 9293c79f..8d459fba 100644 --- a/cmd/pint/tests/0039_prom_selected_path.txt +++ b/cmd/pint/tests/0039_prom_selected_path.txt @@ -27,6 +27,9 @@ level=info msg="Problems found" Warning=1 expr: count(foo) > 0 -- .pint.hcl -- +parser { + relaxed = [".*"] +} prometheus "disabled" { uri = "http://127.0.0.1:123" timeout = "5s" diff --git a/cmd/pint/tests/0040_rule_match_label.txt b/cmd/pint/tests/0040_rule_match_label.txt index 0aa87181..15019319 100644 --- a/cmd/pint/tests/0040_rule_match_label.txt +++ b/cmd/pint/tests/0040_rule_match_label.txt @@ -38,6 +38,9 @@ level=info msg="Problems found" Warning=2 foo: bar -- .pint.hcl -- +parser { + relaxed = [".*"] +} rule { match { label "foo" { diff --git a/cmd/pint/tests/0042_watch_metrics.txt b/cmd/pint/tests/0042_watch_metrics.txt index 9ff2b87e..3bc369be 100644 --- a/cmd/pint/tests/0042_watch_metrics.txt +++ b/cmd/pint/tests/0042_watch_metrics.txt @@ -30,6 +30,9 @@ cat pint.pid | xargs kill # pint rule/owner alice -- .pint.hcl -- +parser { + relaxed = [".*"] +} rule { match { kind = "recording" diff --git a/cmd/pint/tests/0043_watch_cancel.txt b/cmd/pint/tests/0043_watch_cancel.txt index c6d03ee2..a64ebe64 100644 --- a/cmd/pint/tests/0043_watch_cancel.txt +++ b/cmd/pint/tests/0043_watch_cancel.txt @@ -21,6 +21,9 @@ cat prometheus.pid | xargs kill expr: sum(foo) without(job) -- .pint.hcl -- +parser { + relaxed = [".*"] +} prometheus "slow" { uri = "http://127.0.0.1:7043" timeout = "2m" diff --git a/cmd/pint/tests/0048_watch_limit.txt b/cmd/pint/tests/0048_watch_limit.txt index e5520950..4806f951 100644 --- a/cmd/pint/tests/0048_watch_limit.txt +++ b/cmd/pint/tests/0048_watch_limit.txt @@ -19,6 +19,9 @@ cat pint.pid | xargs kill expr: foo -- .pint.hcl -- +parser { + relaxed = [".*"] +} rule { match { kind = "recording" diff --git a/cmd/pint/tests/0049_watch_severity_warning.txt b/cmd/pint/tests/0049_watch_severity_warning.txt index ae41333b..70047cb2 100644 --- a/cmd/pint/tests/0049_watch_severity_warning.txt +++ b/cmd/pint/tests/0049_watch_severity_warning.txt @@ -19,6 +19,9 @@ cat pint.pid | xargs kill expr: foo -- .pint.hcl -- +parser { + relaxed = [".*"] +} rule { match { kind = "recording" diff --git a/cmd/pint/tests/0050_watch_severity_fatal.txt b/cmd/pint/tests/0050_watch_severity_fatal.txt index ddd8efd8..c2075207 100644 --- a/cmd/pint/tests/0050_watch_severity_fatal.txt +++ b/cmd/pint/tests/0050_watch_severity_fatal.txt @@ -19,6 +19,9 @@ cat pint.pid | xargs kill expr: foo -- .pint.hcl -- +parser { + relaxed = [".*"] +} rule { match { kind = "recording" diff --git a/cmd/pint/tests/0052_match_multiple.txt b/cmd/pint/tests/0052_match_multiple.txt index 37e05ba3..b403c381 100644 --- a/cmd/pint/tests/0052_match_multiple.txt +++ b/cmd/pint/tests/0052_match_multiple.txt @@ -5,23 +5,26 @@ cmp stderr stderr.txt -- stderr.txt -- level=info msg="Loading configuration file" path=.pint.hcl level=info msg="File parsed" path=rules/0001.yml rules=2 -level=debug msg="Found recording rule" lines=1-2 path=rules/0001.yml record=colo:recording +level=debug msg="Found recording rule" lines=4-5 path=rules/0001.yml record=colo:recording level=debug msg="Configured checks for rule" enabled=["promql/syntax","alerts/for","alerts/comparison","alerts/template","promql/fragile","promql/regexp","promql/aggregate(job:true)"] path=rules/0001.yml rule=colo:recording -level=debug msg="Found alerting rule" alert=colo:alerting lines=4-5 path=rules/0001.yml +level=debug msg="Found alerting rule" alert=colo:alerting lines=7-8 path=rules/0001.yml level=debug msg="Configured checks for rule" enabled=["promql/syntax","alerts/for","alerts/comparison","alerts/template","promql/fragile","promql/regexp","promql/aggregate(job:true)"] path=rules/0001.yml rule=colo:alerting -rules/0001.yml:2: job label is required and should be preserved when aggregating "^.+$" rules, remove job from without() (promql/aggregate) - expr: sum(foo) without(job) - rules/0001.yml:5: job label is required and should be preserved when aggregating "^.+$" rules, remove job from without() (promql/aggregate) - expr: sum(bar) without(job) > 0 + expr: sum(foo) without(job) + +rules/0001.yml:8: job label is required and should be preserved when aggregating "^.+$" rules, remove job from without() (promql/aggregate) + expr: sum(bar) without(job) > 0 level=info msg="Problems found" Warning=2 -- rules/0001.yml -- -- record: "colo:recording" - expr: sum(foo) without(job) +groups: +- name: foo + rules: + - record: "colo:recording" + expr: sum(foo) without(job) -- alert: "colo:alerting" - expr: sum(bar) without(job) > 0 + - alert: "colo:alerting" + expr: sum(bar) without(job) > 0 -- .pint.hcl -- rule { diff --git a/cmd/pint/tests/0053_ignore_multiple.txt b/cmd/pint/tests/0053_ignore_multiple.txt index e726bd49..4bc1fb09 100644 --- a/cmd/pint/tests/0053_ignore_multiple.txt +++ b/cmd/pint/tests/0053_ignore_multiple.txt @@ -5,16 +5,19 @@ cmp stderr stderr.txt -- stderr.txt -- level=info msg="Loading configuration file" path=.pint.hcl level=info msg="File parsed" path=rules/0001.yml rules=2 -level=debug msg="Found recording rule" lines=1-2 path=rules/0001.yml record=colo:recording +level=debug msg="Found recording rule" lines=4-5 path=rules/0001.yml record=colo:recording level=debug msg="Configured checks for rule" enabled=["promql/syntax","alerts/for","alerts/comparison","alerts/template","promql/fragile","promql/regexp"] path=rules/0001.yml rule=colo:recording -level=debug msg="Found alerting rule" alert=colo:alerting lines=4-5 path=rules/0001.yml +level=debug msg="Found alerting rule" alert=colo:alerting lines=7-8 path=rules/0001.yml level=debug msg="Configured checks for rule" enabled=["promql/syntax","alerts/for","alerts/comparison","alerts/template","promql/fragile","promql/regexp"] path=rules/0001.yml rule=colo:alerting -- rules/0001.yml -- -- record: "colo:recording" - expr: sum(foo) without(job) +groups: +- name: foo + rules: + - record: "colo:recording" + expr: sum(foo) without(job) -- alert: "colo:alerting" - expr: sum(bar) without(job) > 0 + - alert: "colo:alerting" + expr: sum(bar) without(job) > 0 -- .pint.hcl -- rule { diff --git a/cmd/pint/tests/0054_watch_metrics_prometheus.txt b/cmd/pint/tests/0054_watch_metrics_prometheus.txt index fa1c3bf9..45b32843 100644 --- a/cmd/pint/tests/0054_watch_metrics_prometheus.txt +++ b/cmd/pint/tests/0054_watch_metrics_prometheus.txt @@ -30,12 +30,14 @@ prometheus "prom1" { timeout = "5s" required = true } - prometheus "prom2" { uri = "http://127.0.0.1:1054" timeout = "5s" required = true } +parser { + relaxed = [".*"] +} -- metrics.txt -- # HELP pint_check_duration_seconds How long did a check took to complete diff --git a/cmd/pint/tests/0055_prometheus_failover.txt b/cmd/pint/tests/0055_prometheus_failover.txt index be0c780b..d2c6e70d 100644 --- a/cmd/pint/tests/0055_prometheus_failover.txt +++ b/cmd/pint/tests/0055_prometheus_failover.txt @@ -19,6 +19,9 @@ prometheus "prom" { timeout = "5s" required = true } +parser { + relaxed = [".*"] +} -- prometheus.go -- package main diff --git a/cmd/pint/tests/0056_prometheus_required.txt b/cmd/pint/tests/0056_prometheus_required.txt index d6351ccd..33e7a165 100644 --- a/cmd/pint/tests/0056_prometheus_required.txt +++ b/cmd/pint/tests/0056_prometheus_required.txt @@ -21,5 +21,8 @@ prometheus "prom" { timeout = "2m" required = false } +parser { + relaxed = [".*"] +} rule{} diff --git a/cmd/pint/tests/0057_watch_metrics_prometheus_ignore.txt b/cmd/pint/tests/0057_watch_metrics_prometheus_ignore.txt index e63804d0..63a39f31 100644 --- a/cmd/pint/tests/0057_watch_metrics_prometheus_ignore.txt +++ b/cmd/pint/tests/0057_watch_metrics_prometheus_ignore.txt @@ -28,12 +28,14 @@ prometheus "prom1" { timeout = "5s" required = false } - prometheus "prom2" { uri = "http://127.0.0.1:1057" timeout = "5s" required = false } +parser { + relaxed = [".*"] +} -- metrics.txt -- # HELP pint_check_duration_seconds How long did a check took to complete diff --git a/cmd/pint/tests/0058_templated_check.txt b/cmd/pint/tests/0058_templated_check.txt index b000c3b1..7a2747d2 100644 --- a/cmd/pint/tests/0058_templated_check.txt +++ b/cmd/pint/tests/0058_templated_check.txt @@ -30,6 +30,9 @@ level=fatal msg="Fatal error" error="problems found" alert_for: 4m -- .pint.hcl -- +parser { + relaxed = [".*"] +} rule { match { for = "> 0" diff --git a/cmd/pint/tests/0059_templated_check_bad_template.txt b/cmd/pint/tests/0059_templated_check_bad_template.txt index 3d8ea640..7bab1178 100644 --- a/cmd/pint/tests/0059_templated_check_bad_template.txt +++ b/cmd/pint/tests/0059_templated_check_bad_template.txt @@ -10,6 +10,9 @@ level=fatal msg="Fatal error" error="failed to load config file \".pint.hcl\": t expr: up == 0 -- .pint.hcl -- +parser { + relaxed = [".*"] +} rule { match { for = "> 0" diff --git a/cmd/pint/tests/0060_ci_noop.txt b/cmd/pint/tests/0060_ci_noop.txt index 27d673a0..517892c5 100644 --- a/cmd/pint/tests/0060_ci_noop.txt +++ b/cmd/pint/tests/0060_ci_noop.txt @@ -46,3 +46,6 @@ level=fatal msg="Fatal error" error="problems found" ci { baseBranch = "main" } +parser { + relaxed = [".*"] +} diff --git a/cmd/pint/tests/0061_lint_workers_zero.txt b/cmd/pint/tests/0061_lint_workers_zero.txt index 1fc81c39..6774b582 100644 --- a/cmd/pint/tests/0061_lint_workers_zero.txt +++ b/cmd/pint/tests/0061_lint_workers_zero.txt @@ -4,7 +4,3 @@ cmp stderr stderr.txt -- stderr.txt -- level=fatal msg="Fatal error" error="--workers flag must be > 0" --- rules/ok.yml -- -- record: sum:missing - expr: sum(foo[5m) - diff --git a/cmd/pint/tests/0063_lint_offline.txt b/cmd/pint/tests/0063_lint_offline.txt index 30bf6f9c..a04ea01b 100644 --- a/cmd/pint/tests/0063_lint_offline.txt +++ b/cmd/pint/tests/0063_lint_offline.txt @@ -15,3 +15,6 @@ prometheus "disabled" { required = true paths = ["invalid/.+"] } +parser { + relaxed = [".*"] +} diff --git a/cmd/pint/tests/0065_ci_include.txt b/cmd/pint/tests/0065_ci_include.txt index d8ddfaf8..5453e4aa 100644 --- a/cmd/pint/tests/0065_ci_include.txt +++ b/cmd/pint/tests/0065_ci_include.txt @@ -39,3 +39,6 @@ ci { baseBranch = "main" include = ["xxx"] } +parser { + relaxed = [".*"] +} diff --git a/cmd/pint/tests/0066_lint_owner.txt b/cmd/pint/tests/0066_lint_owner.txt index 6806f934..0675aef0 100644 --- a/cmd/pint/tests/0066_lint_owner.txt +++ b/cmd/pint/tests/0066_lint_owner.txt @@ -3,11 +3,12 @@ pint.error --no-color lint --require-owner rules cmp stderr stderr.txt -- stderr.txt -- +level=info msg="Loading configuration file" path=.pint.hcl level=info msg="File parsed" path=rules/1.yml rules=2 level=info msg="File parsed" path=rules/2.yml rules=1 level=info msg="File parsed" path=rules/3.yml rules=1 rules/1.yml:1: rule/owner comments are required in all files, please add a "# pint file/owner $owner" somewhere in this file and/or "# pint rule/owner $owner" on top of each rule (rule/owner) -- alert: No Owner +groups: rules/3.yml:1: rule/owner comments are required in all files, please add a "# pint file/owner $owner" somewhere in this file and/or "# pint rule/owner $owner" on top of each rule (rule/owner) - alert: No Owner @@ -15,15 +16,21 @@ rules/3.yml:1: rule/owner comments are required in all files, please add a "# pi level=info msg="Problems found" Bug=2 level=fatal msg="Fatal error" error="problems found" -- rules/1.yml -- -- alert: No Owner - expr: up > 0 -# pint rule/owner bob -- alert: Owner Set - expr: up == 0 +groups: +- name: foo + rules: + - alert: No Owner + expr: up > 0 + # pint rule/owner bob + - alert: Owner Set + expr: up == 0 -- rules/2.yml -- -- alert: Owner Set - expr: up{job="foo"} == 0 +groups: +- name: foo + rules: + - alert: Owner Set + expr: up{job="foo"} == 0 # pint file/owner bob @@ -32,3 +39,8 @@ level=fatal msg="Fatal error" error="problems found" expr: up{job="foo"} == 0 # pint rule/owner bob + +-- .pint.hcl -- +parser { + relaxed = ["foo", "bar", "rules/3.yml"] +} diff --git a/cmd/pint/tests/0067_relaxed.txt b/cmd/pint/tests/0067_relaxed.txt new file mode 100644 index 00000000..dd2fa02a --- /dev/null +++ b/cmd/pint/tests/0067_relaxed.txt @@ -0,0 +1,25 @@ +pint.error --no-color lint rules +! stdout . +cmp stderr stderr.txt + +-- stderr.txt -- +level=info msg="Loading configuration file" path=.pint.hcl +level=info msg="File parsed" path=rules/relaxed.yml rules=1 +level=error msg="Failed to parse file content" error="yaml: unmarshal errors:\n line 1: cannot unmarshal !!seq into rulefmt.RuleGroups" path=rules/strict.yml +rules/strict.yml:1: yaml: unmarshal errors: + line 1: cannot unmarshal !!seq into rulefmt.RuleGroups (yaml/parse) +- alert: No Owner + +level=info msg="Problems found" Fatal=1 +level=fatal msg="Fatal error" error="problems found" +-- rules/strict.yml -- +- alert: No Owner + expr: up > 0 + +-- rules/relaxed.yml -- +- alert: Owner Set + expr: up{job="foo"} == 0 +-- .pint.hcl -- +parser { + relaxed = ["rules/relaxed.*"] +} diff --git a/cmd/pint/watch.go b/cmd/pint/watch.go index 22d35dd8..e3cb3f1c 100644 --- a/cmd/pint/watch.go +++ b/cmd/pint/watch.go @@ -230,7 +230,7 @@ func newProblemCollector(cfg config.Config, paths []string, minSeverity checks.S } func (c *problemCollector) scan(ctx context.Context, workers int) error { - finder := discovery.NewGlobFinder(c.paths...) + finder := discovery.NewGlobFinder(c.paths, c.cfg.Parser.CompileRelaxed()) entries, err := finder.Find() if err != nil { return err diff --git a/docs/changelog.md b/docs/changelog.md index fe94cbc4..0b34df71 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -2,6 +2,32 @@ ## v0.17.0 +### Changed + +- By default pint will now parse all files in strict mode, where all rule files + must have the exact syntax Prometheus expects: + + ```yaml + groups: + - name: example + rules: + - record: ... + expr: ... + ``` + + Previous releases were only looking for individual rules so `groups` object + wasn't required. Now pint will fail to read any file that doesn't follow + Prometheus syntax exactly. + To enable old behavior add `parser { relaxed = ["(.+)", ...]}` option in + the config file. See [Configuration](/docs/configuration.md) for details. + To enable old (relaxed) behavior for all files add: + + ```yaml + parser { + relaxed = ["(.*)"] + } + ``` + ### Fixed - Improved `promql/vector_matching` checks to detect more issues. diff --git a/docs/configuration.md b/docs/configuration.md index 15c8dd19..dac3e28b 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -36,6 +36,36 @@ Rule fields are exposed as: Accessing a field that's not present in the rule will return an empty string. +## Parser + +Configure how pint parses Prometheus rule files. + +Syntax: + +```js +parser { + relaxed = [ "(.*)", ... ] +} +``` + +- `relaxed` - by default pint will now parse all files in strict mode, where + all rule files must have the exact syntax Prometheus expects: + + ```yaml + groups: + - name: example + rules: + - record: ... + expr: ... + ``` + + If you're using pint to lint rules that are embedded inside a different structure + you can set this option to allow fuzzy parsing, which will try to find rule + definitions anywhere in the file, without requiring `groups -> rules -> rule` + structure to be present. + This option takes a list of file patterns, all files matching those regexp rules + will be parsed in relaxed mode. + ## CI Configure continuous integration environments. diff --git a/internal/config/__snapshots__/config_test.snap b/internal/config/__snapshots__/config_test.snap index 626a086d..a1c16ca8 100755 --- a/internal/config/__snapshots__/config_test.snap +++ b/internal/config/__snapshots__/config_test.snap @@ -5,6 +5,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -33,6 +34,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom", @@ -69,6 +71,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom", @@ -108,6 +111,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom", @@ -147,6 +151,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom", @@ -195,6 +200,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -226,6 +232,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -275,6 +282,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -324,6 +332,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -361,6 +370,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom1", @@ -416,6 +426,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -489,6 +500,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom1", @@ -559,6 +571,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -607,6 +620,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -656,6 +670,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -705,6 +720,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -754,6 +770,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -803,6 +820,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -852,6 +870,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -901,6 +920,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -950,6 +970,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom1", @@ -1002,6 +1023,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom1", @@ -1032,6 +1054,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom1", @@ -1067,6 +1090,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom1", @@ -1107,6 +1131,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom1", @@ -1147,6 +1172,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom1", @@ -1192,6 +1218,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom", @@ -1232,6 +1259,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -1275,6 +1303,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -1318,6 +1347,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -1361,6 +1391,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -1404,6 +1435,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -1447,6 +1479,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -1490,6 +1523,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -1518,6 +1552,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom", @@ -1554,6 +1589,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom", @@ -1594,6 +1630,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom1", @@ -1639,6 +1676,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom", @@ -1678,6 +1716,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom", @@ -1717,6 +1756,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom", @@ -1765,6 +1805,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -1796,6 +1837,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -1845,6 +1887,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -1894,6 +1937,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -1931,6 +1975,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom1", @@ -1986,6 +2031,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -2059,6 +2105,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom1", @@ -2129,6 +2176,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -2177,6 +2225,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -2226,6 +2275,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -2275,6 +2325,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -2324,6 +2375,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -2373,6 +2425,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -2422,6 +2475,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -2471,6 +2525,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -2520,6 +2575,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom1", @@ -2572,6 +2628,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom1", @@ -2602,6 +2659,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom1", @@ -2637,6 +2695,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom1", @@ -2677,6 +2736,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom1", @@ -2717,6 +2777,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -2760,6 +2821,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -2803,6 +2865,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -2846,6 +2909,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -2889,6 +2953,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -2932,6 +2997,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -2975,6 +3041,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -3003,6 +3070,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom", @@ -3039,6 +3107,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom", @@ -3079,6 +3148,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom1", @@ -3124,6 +3194,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom", @@ -3163,6 +3234,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom", @@ -3202,6 +3274,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom", @@ -3250,6 +3323,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -3281,6 +3355,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -3330,6 +3405,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -3379,6 +3455,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -3416,6 +3493,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom1", @@ -3471,6 +3549,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -3544,6 +3623,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom1", @@ -3614,6 +3694,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -3662,6 +3743,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -3711,6 +3793,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -3760,6 +3843,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -3809,6 +3893,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -3858,6 +3943,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -3907,6 +3993,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -3956,6 +4043,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -4005,6 +4093,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom1", @@ -4057,6 +4146,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom1", @@ -4087,6 +4177,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom1", @@ -4122,6 +4213,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom1", @@ -4162,6 +4254,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom1", @@ -4202,6 +4295,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -4245,6 +4339,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -4288,6 +4383,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -4331,6 +4427,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -4374,6 +4471,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -4417,6 +4515,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -4460,6 +4559,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -4488,6 +4588,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom", @@ -4524,6 +4625,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom", @@ -4564,6 +4666,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom1", @@ -4609,6 +4712,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom", @@ -4648,6 +4752,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom", @@ -4687,6 +4792,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom", @@ -4735,6 +4841,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -4766,6 +4873,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -4815,6 +4923,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -4864,6 +4973,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -4901,6 +5011,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom1", @@ -4956,6 +5067,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -5029,6 +5141,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom1", @@ -5099,6 +5212,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -5147,6 +5261,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -5196,6 +5311,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -5245,6 +5361,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -5294,6 +5411,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -5343,6 +5461,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -5392,6 +5511,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -5441,6 +5561,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -5490,6 +5611,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom1", @@ -5542,6 +5664,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom1", @@ -5572,6 +5695,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom1", @@ -5607,6 +5731,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom1", @@ -5647,6 +5772,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom1", @@ -5687,6 +5813,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -5730,6 +5857,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -5773,6 +5901,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -5816,6 +5945,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -5859,6 +5989,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -5902,6 +6033,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -5945,6 +6077,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -5973,6 +6106,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom", @@ -6009,6 +6143,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom", @@ -6049,6 +6184,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom1", @@ -6094,6 +6230,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom", @@ -6133,6 +6270,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom", @@ -6172,6 +6310,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom", @@ -6220,6 +6359,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -6251,6 +6391,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -6300,6 +6441,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -6349,6 +6491,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -6386,6 +6529,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom1", @@ -6441,6 +6585,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -6514,6 +6659,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom1", @@ -6584,6 +6730,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -6632,6 +6779,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -6681,6 +6829,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -6730,6 +6879,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -6779,6 +6929,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -6828,6 +6979,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -6877,6 +7029,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -6926,6 +7079,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -6975,6 +7129,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom1", @@ -7027,6 +7182,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom1", @@ -7057,6 +7213,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom1", @@ -7092,6 +7249,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom1", @@ -7132,6 +7290,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "prometheus": [ { "name": "prom1", @@ -7172,6 +7331,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -7215,6 +7375,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -7258,6 +7419,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -7301,6 +7463,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -7344,6 +7507,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", @@ -7387,6 +7551,7 @@ "maxCommits": 20, "baseBranch": "master" }, + "parser": {}, "checks": { "enabled": [ "alerts/annotation", diff --git a/internal/config/config.go b/internal/config/config.go index d8675af6..9e84fb34 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -18,6 +18,7 @@ import ( type Config struct { CI *CI `hcl:"ci,block" json:"ci,omitempty"` + Parser *Parser `hcl:"parser,block" json:"parser,omitempty"` Repository *Repository `hcl:"repository,block" json:"repository,omitempty"` Prometheus []PrometheusConfig `hcl:"prometheus,block" json:"prometheus,omitempty"` Checks *Checks `hcl:"checks,block" json:"checks,omitempty"` @@ -175,6 +176,7 @@ func Load(path string, failOnMissing bool) (cfg Config, err error) { MaxCommits: 20, BaseBranch: "master", }, + Parser: &Parser{}, Checks: &Checks{ Enabled: checks.CheckNames, Disabled: []string{}, @@ -196,6 +198,12 @@ func Load(path string, failOnMissing bool) (cfg Config, err error) { } } + if cfg.Parser != nil { + if err = cfg.Parser.validate(); err != nil { + return cfg, err + } + } + if cfg.Repository != nil && cfg.Repository.BitBucket != nil { if err = cfg.Repository.BitBucket.validate(); err != nil { return cfg, err diff --git a/internal/config/config_test.go b/internal/config/config_test.go index ff5ae09e..593cefdd 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -1276,6 +1276,12 @@ func TestConfigErrors(t *testing.T) { }`, err: `not a valid duration string: "!1s"`, }, + { + config: `parser { + relaxed = ["foo", ".+", "(.+++)"] +}`, + err: "error parsing regexp: invalid nested repetition operator: `++`", + }, } dir := t.TempDir() diff --git a/internal/config/parser.go b/internal/config/parser.go new file mode 100644 index 00000000..af206dc2 --- /dev/null +++ b/internal/config/parser.go @@ -0,0 +1,26 @@ +package config + +import ( + "regexp" +) + +type Parser struct { + Relaxed []string `hcl:"relaxed,optional" json:"relaxed,omitempty"` +} + +func (p Parser) validate() error { + for _, pattern := range p.Relaxed { + _, err := regexp.Compile(pattern) + if err != nil { + return err + } + } + return nil +} + +func (p Parser) CompileRelaxed() (r []*regexp.Regexp) { + for _, pattern := range p.Relaxed { + r = append(r, regexp.MustCompile("^"+pattern+"$")) + } + return +} diff --git a/internal/config/parser_test.go b/internal/config/parser_test.go new file mode 100644 index 00000000..3c93f5a6 --- /dev/null +++ b/internal/config/parser_test.go @@ -0,0 +1,45 @@ +package config + +import ( + "errors" + "fmt" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestParserSettings(t *testing.T) { + type testCaseT struct { + conf Parser + err error + } + + testCases := []testCaseT{ + { + conf: Parser{}, + }, + { + conf: Parser{ + Relaxed: []string{"foo.+"}, + }, + }, + { + conf: Parser{ + Relaxed: []string{"(.+++)"}, + }, + err: errors.New("error parsing regexp: invalid nested repetition operator: `++`"), + }, + } + + for _, tc := range testCases { + t.Run(fmt.Sprintf("%v", tc.conf), func(t *testing.T) { + assert := assert.New(t) + err := tc.conf.validate() + if err == nil || tc.err == nil { + assert.Equal(err, tc.err) + } else { + assert.EqualError(err, tc.err.Error()) + } + }) + } +} diff --git a/internal/discovery/discovery.go b/internal/discovery/discovery.go index 4dc1dd9a..f7e2b407 100644 --- a/internal/discovery/discovery.go +++ b/internal/discovery/discovery.go @@ -2,6 +2,10 @@ package discovery import ( "os" + "regexp" + + "github.com/prometheus/prometheus/model/rulefmt" + "gopkg.in/yaml.v3" "github.com/cloudflare/pint/internal/parser" @@ -25,7 +29,7 @@ type Entry struct { Owner string } -func readFile(path string) (entries []Entry, err error) { +func readFile(path string, isStrict bool) (entries []Entry, err error) { p := parser.NewParser() f, err := os.Open(path) @@ -41,6 +45,19 @@ func readFile(path string) (entries []Entry, err error) { fileOwner, _ := parser.GetComment(string(content), FileOwnerComment) + if isStrict { + var r rulefmt.RuleGroups + if err = yaml.Unmarshal(content, &r); err != nil { + log.Error().Str("path", path).Err(err).Msg("Failed to parse file content") + entries = append(entries, Entry{ + Path: path, + PathError: err, + Owner: fileOwner, + }) + return entries, nil + } + } + rules, err := p.Parse(content) if err != nil { log.Error().Str("path", path).Err(err).Msg("Failed to parse file content") @@ -66,3 +83,12 @@ func readFile(path string) (entries []Entry, err error) { log.Info().Str("path", path).Int("rules", len(entries)).Msg("File parsed") return entries, nil } + +func matchesAny(re []*regexp.Regexp, s string) bool { + for _, r := range re { + if v := r.MatchString(s); v { + return true + } + } + return false +} diff --git a/internal/discovery/git_branch.go b/internal/discovery/git_branch.go index 5c9a0e3c..45395917 100644 --- a/internal/discovery/git_branch.go +++ b/internal/discovery/git_branch.go @@ -10,12 +10,19 @@ import ( "github.com/rs/zerolog/log" ) -func NewGitBranchFinder(gitCmd git.CommandRunner, include []*regexp.Regexp, baseBranch string, maxCommits int) GitBranchFinder { +func NewGitBranchFinder( + gitCmd git.CommandRunner, + include []*regexp.Regexp, + baseBranch string, + maxCommits int, + relaxed []*regexp.Regexp, +) GitBranchFinder { return GitBranchFinder{ gitCmd: gitCmd, include: include, baseBranch: baseBranch, maxCommits: maxCommits, + relaxed: relaxed, } } @@ -24,6 +31,7 @@ type GitBranchFinder struct { include []*regexp.Regexp baseBranch string maxCommits int + relaxed []*regexp.Regexp } func (f GitBranchFinder) Find() (entries []Entry, err error) { @@ -99,7 +107,7 @@ func (f GitBranchFinder) Find() (entries []Entry, err error) { alloweLines = append(alloweLines, lb.Line) } - els, err := readFile(path) + els, err := readFile(path, !matchesAny(f.relaxed, path)) if err != nil { return nil, err } diff --git a/internal/discovery/git_branch_test.go b/internal/discovery/git_branch_test.go index 0c6f161d..df6ef5a5 100644 --- a/internal/discovery/git_branch_test.go +++ b/internal/discovery/git_branch_test.go @@ -82,6 +82,7 @@ func TestGitBranchFinder(t *testing.T) { nil, "main", 0, + nil, ), err: "failed to get the list of commits to scan: mock error", }, @@ -99,6 +100,7 @@ func TestGitBranchFinder(t *testing.T) { nil, "main", 0, + nil, ), err: "failed to get the list of modified files from git: mock error", }, @@ -122,6 +124,7 @@ func TestGitBranchFinder(t *testing.T) { nil, "main", 0, + []*regexp.Regexp{regexp.MustCompile(".*")}, ), err: "failed to run git blame for foo.yml: mock error", }, @@ -150,6 +153,7 @@ func TestGitBranchFinder(t *testing.T) { nil, "main", 0, + []*regexp.Regexp{regexp.MustCompile(".*")}, ), err: "open foo.yml: no such file or directory", }, @@ -180,6 +184,7 @@ func TestGitBranchFinder(t *testing.T) { nil, "main", 0, + []*regexp.Regexp{regexp.MustCompile(".*")}, ), rules: map[string][]string{"foo.yml": {"first", "second"}}, }, @@ -282,6 +287,7 @@ R090 foo/c2c.yml c2c.yml }, "main", 0, + []*regexp.Regexp{regexp.MustCompile(".*")}, ), rules: map[string][]string{ "foo/c1a.yml": {"first", "third"}, @@ -293,6 +299,37 @@ R090 foo/c2c.yml c2c.yml "c3d.yml": {"first", "second", "third"}, }, }, + { + files: map[string]string{ + "foo.yml": testRuleBody, + }, + finder: discovery.NewGitBranchFinder( + func(args ...string) ([]byte, error) { + switch strings.Join(args, " ") { + case "log --format=%H --no-abbrev-commit --reverse main..HEAD": + return []byte("commit1\n"), nil + case "log --reverse --no-merges --pretty=format:%H --name-status commit1^..commit1": + return []byte("commit1\nM foo.yml\n"), nil + case "blame --line-porcelain -- foo.yml": + return blame(map[string][]blameRange{ + "foo.yml": { + {sha: "commitX", lines: []int{1, 3, 4, 5, 6, 9, 10, 11, 12}}, + {sha: "commit1", lines: []int{2, 7, 8}}, + }, + }), nil + default: + t.Errorf("unknown args: %v", args) + t.FailNow() + return nil, nil + } + }, + nil, + "main", + 0, + nil, + ), + rules: map[string][]string{}, + }, } for i, tc := range testCases { diff --git a/internal/discovery/glob.go b/internal/discovery/glob.go index 2c2732e0..6f0c7cdf 100644 --- a/internal/discovery/glob.go +++ b/internal/discovery/glob.go @@ -5,16 +5,19 @@ import ( "io/fs" "os" "path/filepath" + "regexp" ) -func NewGlobFinder(patterns ...string) GlobFinder { +func NewGlobFinder(patterns []string, relaxed []*regexp.Regexp) GlobFinder { return GlobFinder{ patterns: patterns, + relaxed: relaxed, } } type GlobFinder struct { patterns []string + relaxed []*regexp.Regexp } func (f GlobFinder) Find() (entries []Entry, err error) { @@ -47,9 +50,9 @@ func (f GlobFinder) Find() (entries []Entry, err error) { } for _, path := range paths { - e, err := readFile(path) + e, err := readFile(path, !matchesAny(f.relaxed, path)) if err != nil { - return nil, err + return nil, fmt.Errorf("invalid file syntax: %w", err) } entries = append(entries, e...) } diff --git a/internal/discovery/glob_test.go b/internal/discovery/glob_test.go index b5f5a4a9..709e5933 100644 --- a/internal/discovery/glob_test.go +++ b/internal/discovery/glob_test.go @@ -6,11 +6,14 @@ import ( "os" "path" "path/filepath" + "regexp" "strconv" "strings" "testing" + "github.com/prometheus/prometheus/model/rulefmt" "github.com/stretchr/testify/require" + "gopkg.in/yaml.v3" "github.com/cloudflare/pint/internal/discovery" "github.com/cloudflare/pint/internal/parser" @@ -29,35 +32,38 @@ func TestGlobPathFinder(t *testing.T) { testRules, err := p.Parse([]byte(testRuleBody)) require.NoError(t, err) + var r rulefmt.RuleGroups + strictErr := yaml.Unmarshal([]byte(testRuleBody), &r) + testCases := []testCaseT{ { files: map[string]string{}, - finder: discovery.NewGlobFinder("[]"), + finder: discovery.NewGlobFinder([]string{"[]"}, nil), err: filepath.ErrBadPattern, }, { files: map[string]string{}, - finder: discovery.NewGlobFinder("*"), + finder: discovery.NewGlobFinder([]string{"*"}, nil), err: fmt.Errorf("no matching files"), }, { files: map[string]string{}, - finder: discovery.NewGlobFinder("*"), + finder: discovery.NewGlobFinder([]string{"*"}, nil), err: fmt.Errorf("no matching files"), }, { files: map[string]string{}, - finder: discovery.NewGlobFinder("foo/*"), + finder: discovery.NewGlobFinder([]string{"foo/*"}, nil), err: fmt.Errorf("no matching files"), }, { files: map[string]string{"bar.yml": testRuleBody}, - finder: discovery.NewGlobFinder("foo/*"), + finder: discovery.NewGlobFinder([]string{"foo/*"}, nil), err: fmt.Errorf("no matching files"), }, { files: map[string]string{"bar.yml": testRuleBody}, - finder: discovery.NewGlobFinder("*"), + finder: discovery.NewGlobFinder([]string{"*"}, []*regexp.Regexp{regexp.MustCompile(".*")}), entries: []discovery.Entry{ { Path: "bar.yml", @@ -68,7 +74,7 @@ func TestGlobPathFinder(t *testing.T) { }, { files: map[string]string{"foo/bar.yml": testRuleBody + "\n\n# pint file/owner alice\n"}, - finder: discovery.NewGlobFinder("*"), + finder: discovery.NewGlobFinder([]string{"*"}, []*regexp.Regexp{regexp.MustCompile(".*")}), entries: []discovery.Entry{ { Path: "foo/bar.yml", @@ -77,6 +83,17 @@ func TestGlobPathFinder(t *testing.T) { }, }, }, + { + files: map[string]string{"bar.yml": testRuleBody}, + finder: discovery.NewGlobFinder([]string{"*"}, nil), + entries: []discovery.Entry{ + { + Path: "bar.yml", + PathError: strictErr, + Owner: "bob", + }, + }, + }, } for i, tc := range testCases {