From e6354f4ef1a9ed477e74cf994b80d5a5365c62c6 Mon Sep 17 00:00:00 2001 From: Lukasz Mierzwa Date: Fri, 23 Aug 2024 09:44:35 +0100 Subject: [PATCH] Add enable flag to cli commands --- cmd/pint/bench_test.go | 2 +- cmd/pint/config.go | 2 +- cmd/pint/main.go | 20 +- cmd/pint/tests/0018_match_alerting.txt | 1 + cmd/pint/tests/0019_match_recording.txt | 1 + cmd/pint/tests/0020_ignore_kind.txt | 1 + cmd/pint/tests/0028_ci_git_error.txt | 3 +- cmd/pint/tests/0037_disable_checks.txt | 1 + cmd/pint/tests/0039_prom_selected_path.txt | 1 + cmd/pint/tests/0040_rule_match_label.txt | 1 + cmd/pint/tests/0052_match_multiple.txt | 1 + cmd/pint/tests/0053_ignore_multiple.txt | 1 + cmd/pint/tests/0095_rulefmt_symlink.txt | 1 + cmd/pint/tests/0099_symlink_outside_glob.txt | 1 + cmd/pint/tests/0103_file_disable.txt | 1 + cmd/pint/tests/0111_snooze.txt | 1 + cmd/pint/tests/0112_expired_snooze.txt | 1 + cmd/pint/tests/0115_file_disable_tag.txt | 1 + cmd/pint/tests/0116_file_snooze.txt | 1 + .../tests/0134_ci_base_branch_flag_path.txt | 3 +- .../tests/0135_ci_base_branch_config_path.txt | 3 +- cmd/pint/tests/0144_discovery_filepath.txt | 1 + .../tests/0145_discovery_filepath_dup.txt | 1 + .../tests/0147_discovery_filepath_error.txt | 1 + cmd/pint/tests/0148_discovery_prom_zero.txt | 1 + cmd/pint/tests/0149_discovery_prom.txt | 1 + .../tests/0150_discovery_prom_dup_tags.txt | 1 + cmd/pint/tests/0151_discovery_prom_error.txt | 1 + .../tests/0152_discovery_prom_dup_uptime.txt | 1 + .../tests/0155_discovery_prom_dup_include.txt | 1 + .../tests/0156_discovery_prom_dup_exclude.txt | 1 + .../tests/0167_rule_duplicate_symlink.txt | 1 - .../tests/0169_watch_rule_files_noprom.txt | 1 + .../tests/0170_watch_rule_files_error.txt | 1 + cmd/pint/tests/0173_rule_duplicate_move.txt | 1 - cmd/pint/tests/0178_parser_include.txt | 1 + cmd/pint/tests/0179_parser_exclude.txt | 3 +- cmd/pint/tests/0180_parser_exclude_md.txt | 3 +- cmd/pint/tests/0183_cli_enable.txt | 44 +++ cmd/pint/tests/0184_ci_file_ignore.txt | 40 +++ docs/changelog.md | 3 + internal/checks/promql_rate_test.go | 52 +++ internal/config/config.go | 31 +- internal/config/config_test.go | 21 +- internal/config/match.go | 38 +-- internal/config/rule.go | 7 +- internal/config/rule_test.go | 302 ++++++++++++------ internal/discovery/git_branch.go | 12 +- internal/reporter/github.go | 23 +- 49 files changed, 469 insertions(+), 173 deletions(-) create mode 100644 cmd/pint/tests/0183_cli_enable.txt create mode 100644 cmd/pint/tests/0184_ci_file_ignore.txt diff --git a/cmd/pint/bench_test.go b/cmd/pint/bench_test.go index eff74211..0077ac82 100644 --- a/cmd/pint/bench_test.go +++ b/cmd/pint/bench_test.go @@ -94,7 +94,7 @@ rule { require.NoError(b, os.WriteFile(tmp+"/.pint.hcl", content, 0o644)) ctx := context.Background() - cfg, err := config.Load(tmp+"/.pint.hcl", false) + cfg, _, err := config.Load(tmp+"/.pint.hcl", false) require.NoError(b, err) gen := config.NewPrometheusGenerator(cfg, prometheus.NewRegistry()) diff --git a/cmd/pint/config.go b/cmd/pint/config.go index 12ec04bd..f93ce1e7 100644 --- a/cmd/pint/config.go +++ b/cmd/pint/config.go @@ -21,7 +21,7 @@ func actionConfig(c *cli.Context) (err error) { return fmt.Errorf("failed to set log level: %w", err) } - cfg, err := config.Load(c.Path(configFlag), c.IsSet(configFlag)) + cfg, _, err := config.Load(c.Path(configFlag), c.IsSet(configFlag)) if err != nil { return fmt.Errorf("failed to load config file %q: %w", c.Path(configFlag), err) } diff --git a/cmd/pint/main.go b/cmd/pint/main.go index c2afc174..d4e0bc51 100644 --- a/cmd/pint/main.go +++ b/cmd/pint/main.go @@ -14,6 +14,7 @@ import ( const ( configFlag = "config" logLevelFlag = "log-level" + enabledFlag = "enabled" disabledFlag = "disabled" offlineFlag = "offline" noColorFlag = "no-color" @@ -59,6 +60,12 @@ func newApp() *cli.App { Value: cli.NewStringSlice(), Usage: "List of checks to disable (example: promql/cost).", }, + &cli.StringSliceFlag{ + Name: enabledFlag, + Aliases: []string{"e"}, + Value: cli.NewStringSlice(), + Usage: "Only enable these checks (example: promql/cost).", + }, &cli.BoolFlag{ Name: offlineFlag, Aliases: []string{"o"}, @@ -100,11 +107,22 @@ func actionSetup(c *cli.Context) (meta actionMeta, err error) { return meta, fmt.Errorf("--%s flag must be > 0", workersFlag) } - meta.cfg, err = config.Load(c.Path(configFlag), c.IsSet(configFlag)) + var fromFile bool + meta.cfg, fromFile, err = config.Load(c.Path(configFlag), c.IsSet(configFlag)) if err != nil { return meta, fmt.Errorf("failed to load config file %q: %w", c.Path(configFlag), err) } + if fromFile { + slog.Debug("Adding pint config to the parser exclude list", slog.String("path", c.Path(configFlag))) + meta.cfg.Parser.Exclude = append(meta.cfg.Parser.Exclude, c.Path(configFlag)) + } + meta.cfg.SetDisabledChecks(c.StringSlice(disabledFlag)) + enabled := c.StringSlice(enabledFlag) + if len(enabled) > 0 { + meta.cfg.Checks.Enabled = enabled + } + if c.Bool(offlineFlag) { meta.isOffline = true meta.cfg.DisableOnlineChecks() diff --git a/cmd/pint/tests/0018_match_alerting.txt b/cmd/pint/tests/0018_match_alerting.txt index 8b0fff03..b60e0ded 100644 --- a/cmd/pint/tests/0018_match_alerting.txt +++ b/cmd/pint/tests/0018_match_alerting.txt @@ -4,6 +4,7 @@ cmp stderr stderr.txt -- stderr.txt -- level=INFO msg="Loading configuration file" path=.pint.hcl +level=DEBUG msg="Adding pint config to the parser exclude list" path=.pint.hcl level=INFO msg="Finding all rules to check" paths=["rules"] level=DEBUG msg="File parsed" path=rules/0001.yml rules=2 level=DEBUG msg="Glob finder completed" count=2 diff --git a/cmd/pint/tests/0019_match_recording.txt b/cmd/pint/tests/0019_match_recording.txt index f533671d..3b4e568b 100644 --- a/cmd/pint/tests/0019_match_recording.txt +++ b/cmd/pint/tests/0019_match_recording.txt @@ -4,6 +4,7 @@ cmp stderr stderr.txt -- stderr.txt -- level=INFO msg="Loading configuration file" path=.pint.hcl +level=DEBUG msg="Adding pint config to the parser exclude list" path=.pint.hcl level=INFO msg="Finding all rules to check" paths=["rules"] level=DEBUG msg="File parsed" path=rules/0001.yml rules=2 level=DEBUG msg="Glob finder completed" count=2 diff --git a/cmd/pint/tests/0020_ignore_kind.txt b/cmd/pint/tests/0020_ignore_kind.txt index 48f040c8..f615366c 100644 --- a/cmd/pint/tests/0020_ignore_kind.txt +++ b/cmd/pint/tests/0020_ignore_kind.txt @@ -4,6 +4,7 @@ cmp stderr stderr.txt -- stderr.txt -- level=INFO msg="Loading configuration file" path=.pint.hcl +level=DEBUG msg="Adding pint config to the parser exclude list" path=.pint.hcl level=INFO msg="Finding all rules to check" paths=["rules"] level=DEBUG msg="File parsed" path=rules/0001.yml rules=2 level=DEBUG msg="Glob finder completed" count=2 diff --git a/cmd/pint/tests/0028_ci_git_error.txt b/cmd/pint/tests/0028_ci_git_error.txt index 609d7576..0dd931e8 100644 --- a/cmd/pint/tests/0028_ci_git_error.txt +++ b/cmd/pint/tests/0028_ci_git_error.txt @@ -21,11 +21,12 @@ cmp stderr ../stderr.txt -- stderr.txt -- level=INFO msg="Loading configuration file" path=.pint.hcl +level=DEBUG msg="Adding pint config to the parser exclude list" path=.pint.hcl level=DEBUG msg="Running git command" args=["rev-parse","--abbrev-ref","HEAD"] level=DEBUG msg="Got branch information" base=notmain current=v2 level=INFO msg="Finding all rules to check on current git branch" base=notmain level=DEBUG msg="Excluding git directory from glob results" path=.git glob=* -level=DEBUG msg="File parsed" path=.pint.hcl rules=0 +level=DEBUG msg="File path is in the exclude list" path=.pint.hcl exclude=["^.pint.hcl$"] level=DEBUG msg="File parsed" path=rules.yml rules=2 level=DEBUG msg="Glob finder completed" count=2 level=DEBUG msg="Running git command" args=["log","--reverse","--no-merges","--first-parent","--format=%H","--name-status","notmain..HEAD"] diff --git a/cmd/pint/tests/0037_disable_checks.txt b/cmd/pint/tests/0037_disable_checks.txt index 84178faf..391a03b9 100644 --- a/cmd/pint/tests/0037_disable_checks.txt +++ b/cmd/pint/tests/0037_disable_checks.txt @@ -4,6 +4,7 @@ cmp stderr stderr.txt -- stderr.txt -- level=INFO msg="Loading configuration file" path=.pint.hcl +level=DEBUG msg="Adding pint config to the parser exclude list" path=.pint.hcl level=INFO msg="Finding all rules to check" paths=["rules"] level=DEBUG msg="File parsed" path=rules/0001.yml rules=3 level=DEBUG msg="Glob finder completed" count=3 diff --git a/cmd/pint/tests/0039_prom_selected_path.txt b/cmd/pint/tests/0039_prom_selected_path.txt index be5ea151..9af0421c 100644 --- a/cmd/pint/tests/0039_prom_selected_path.txt +++ b/cmd/pint/tests/0039_prom_selected_path.txt @@ -4,6 +4,7 @@ cmp stderr stderr.txt -- stderr.txt -- level=INFO msg="Loading configuration file" path=.pint.hcl +level=DEBUG msg="Adding pint config to the parser exclude list" path=.pint.hcl level=INFO msg="Finding all rules to check" paths=["rules"] level=DEBUG msg="File parsed" path=rules/0001.yml rules=3 level=DEBUG msg="Glob finder completed" count=3 diff --git a/cmd/pint/tests/0040_rule_match_label.txt b/cmd/pint/tests/0040_rule_match_label.txt index 77d8d2f7..ecdaae08 100644 --- a/cmd/pint/tests/0040_rule_match_label.txt +++ b/cmd/pint/tests/0040_rule_match_label.txt @@ -4,6 +4,7 @@ cmp stderr stderr.txt -- stderr.txt -- level=INFO msg="Loading configuration file" path=.pint.hcl +level=DEBUG msg="Adding pint config to the parser exclude list" path=.pint.hcl level=INFO msg="Finding all rules to check" paths=["rules"] level=DEBUG msg="File parsed" path=rules/rules.yml rules=4 level=DEBUG msg="Glob finder completed" count=4 diff --git a/cmd/pint/tests/0052_match_multiple.txt b/cmd/pint/tests/0052_match_multiple.txt index 99b39a95..b21b15e8 100644 --- a/cmd/pint/tests/0052_match_multiple.txt +++ b/cmd/pint/tests/0052_match_multiple.txt @@ -4,6 +4,7 @@ cmp stderr stderr.txt -- stderr.txt -- level=INFO msg="Loading configuration file" path=.pint.hcl +level=DEBUG msg="Adding pint config to the parser exclude list" path=.pint.hcl level=INFO msg="Finding all rules to check" paths=["rules"] level=DEBUG msg="File parsed" path=rules/0001.yml rules=2 level=DEBUG msg="Glob finder completed" count=2 diff --git a/cmd/pint/tests/0053_ignore_multiple.txt b/cmd/pint/tests/0053_ignore_multiple.txt index 738e4cd0..a768734b 100644 --- a/cmd/pint/tests/0053_ignore_multiple.txt +++ b/cmd/pint/tests/0053_ignore_multiple.txt @@ -4,6 +4,7 @@ cmp stderr stderr.txt -- stderr.txt -- level=INFO msg="Loading configuration file" path=.pint.hcl +level=DEBUG msg="Adding pint config to the parser exclude list" path=.pint.hcl level=INFO msg="Finding all rules to check" paths=["rules"] level=DEBUG msg="File parsed" path=rules/0001.yml rules=2 level=DEBUG msg="Glob finder completed" count=2 diff --git a/cmd/pint/tests/0095_rulefmt_symlink.txt b/cmd/pint/tests/0095_rulefmt_symlink.txt index 4c20a525..4569d6b1 100644 --- a/cmd/pint/tests/0095_rulefmt_symlink.txt +++ b/cmd/pint/tests/0095_rulefmt_symlink.txt @@ -7,6 +7,7 @@ cmp stderr stderr.txt -- stderr.txt -- level=INFO msg="Loading configuration file" path=.pint.hcl +level=DEBUG msg="Adding pint config to the parser exclude list" path=.pint.hcl level=INFO msg="Finding all rules to check" paths=["rules"] level=DEBUG msg="File parsed" path=rules/relaxed/1.yml rules=1 level=DEBUG msg="File parsed" path=rules/strict/symlink.yml rules=1 diff --git a/cmd/pint/tests/0099_symlink_outside_glob.txt b/cmd/pint/tests/0099_symlink_outside_glob.txt index f58ee7b4..8fa8a567 100644 --- a/cmd/pint/tests/0099_symlink_outside_glob.txt +++ b/cmd/pint/tests/0099_symlink_outside_glob.txt @@ -7,6 +7,7 @@ cmp stderr stderr.txt -- stderr.txt -- level=INFO msg="Loading configuration file" path=.pint.hcl +level=DEBUG msg="Adding pint config to the parser exclude list" path=.pint.hcl level=INFO msg="Finding all rules to check" paths=["rules/relaxed"] level=DEBUG msg="File parsed" path=rules/relaxed/1.yml rules=1 level=DEBUG msg="Glob finder completed" count=1 diff --git a/cmd/pint/tests/0103_file_disable.txt b/cmd/pint/tests/0103_file_disable.txt index b0a54823..ca0b7645 100644 --- a/cmd/pint/tests/0103_file_disable.txt +++ b/cmd/pint/tests/0103_file_disable.txt @@ -4,6 +4,7 @@ cmp stderr stderr.txt -- stderr.txt -- level=INFO msg="Loading configuration file" path=.pint.hcl +level=DEBUG msg="Adding pint config to the parser exclude list" path=.pint.hcl level=INFO msg="Finding all rules to check" paths=["rules"] level=DEBUG msg="File parsed" path=rules/0001.yml rules=1 level=DEBUG msg="Glob finder completed" count=1 diff --git a/cmd/pint/tests/0111_snooze.txt b/cmd/pint/tests/0111_snooze.txt index 067ffb64..899088df 100644 --- a/cmd/pint/tests/0111_snooze.txt +++ b/cmd/pint/tests/0111_snooze.txt @@ -4,6 +4,7 @@ cmp stderr stderr.txt -- stderr.txt -- level=INFO msg="Loading configuration file" path=.pint.hcl +level=DEBUG msg="Adding pint config to the parser exclude list" path=.pint.hcl level=INFO msg="Finding all rules to check" paths=["rules"] level=DEBUG msg="File parsed" path=rules/0001.yml rules=1 level=DEBUG msg="Glob finder completed" count=1 diff --git a/cmd/pint/tests/0112_expired_snooze.txt b/cmd/pint/tests/0112_expired_snooze.txt index ee770c9b..172b6d4b 100644 --- a/cmd/pint/tests/0112_expired_snooze.txt +++ b/cmd/pint/tests/0112_expired_snooze.txt @@ -4,6 +4,7 @@ cmp stderr stderr.txt -- stderr.txt -- level=INFO msg="Loading configuration file" path=.pint.hcl +level=DEBUG msg="Adding pint config to the parser exclude list" path=.pint.hcl level=INFO msg="Finding all rules to check" paths=["rules"] level=DEBUG msg="File parsed" path=rules/0001.yml rules=1 level=DEBUG msg="Glob finder completed" count=1 diff --git a/cmd/pint/tests/0115_file_disable_tag.txt b/cmd/pint/tests/0115_file_disable_tag.txt index 502d0c8a..db49d85f 100644 --- a/cmd/pint/tests/0115_file_disable_tag.txt +++ b/cmd/pint/tests/0115_file_disable_tag.txt @@ -4,6 +4,7 @@ cmp stderr stderr.txt -- stderr.txt -- level=INFO msg="Loading configuration file" path=.pint.hcl +level=DEBUG msg="Adding pint config to the parser exclude list" path=.pint.hcl level=INFO msg="Finding all rules to check" paths=["rules"] level=DEBUG msg="File parsed" path=rules/0001.yml rules=1 level=DEBUG msg="Glob finder completed" count=1 diff --git a/cmd/pint/tests/0116_file_snooze.txt b/cmd/pint/tests/0116_file_snooze.txt index ac70bfbf..11aed777 100644 --- a/cmd/pint/tests/0116_file_snooze.txt +++ b/cmd/pint/tests/0116_file_snooze.txt @@ -4,6 +4,7 @@ cmp stderr stderr.txt -- stderr.txt -- level=INFO msg="Loading configuration file" path=.pint.hcl +level=DEBUG msg="Adding pint config to the parser exclude list" path=.pint.hcl level=INFO msg="Finding all rules to check" paths=["rules"] level=DEBUG msg="Check snoozed by comment" check=promql/aggregate(job:true) match=promql/aggregate(job:true) until="2099-11-28T10:24:18Z" level=DEBUG msg="Check snoozed by comment" check=alerts/for match=alerts/for until="2099-11-28T10:24:18Z" diff --git a/cmd/pint/tests/0134_ci_base_branch_flag_path.txt b/cmd/pint/tests/0134_ci_base_branch_flag_path.txt index 5b2fc91e..530728ad 100644 --- a/cmd/pint/tests/0134_ci_base_branch_flag_path.txt +++ b/cmd/pint/tests/0134_ci_base_branch_flag_path.txt @@ -21,11 +21,12 @@ cmp stderr ../stderr.txt -- stderr.txt -- level=INFO msg="Loading configuration file" path=.pint.hcl +level=DEBUG msg="Adding pint config to the parser exclude list" path=.pint.hcl level=DEBUG msg="Running git command" args=["rev-parse","--abbrev-ref","HEAD"] level=DEBUG msg="Got branch information" base=origin/main current=v2 level=INFO msg="Finding all rules to check on current git branch" base=origin/main level=DEBUG msg="Excluding git directory from glob results" path=.git glob=* -level=DEBUG msg="File parsed" path=.pint.hcl rules=0 +level=DEBUG msg="File path is in the exclude list" path=.pint.hcl exclude=["^.pint.hcl$"] level=DEBUG msg="File parsed" path=rules.yml rules=1 level=DEBUG msg="Glob finder completed" count=1 level=DEBUG msg="Running git command" args=["log","--reverse","--no-merges","--first-parent","--format=%H","--name-status","origin/main..HEAD"] diff --git a/cmd/pint/tests/0135_ci_base_branch_config_path.txt b/cmd/pint/tests/0135_ci_base_branch_config_path.txt index bcd99329..87395209 100644 --- a/cmd/pint/tests/0135_ci_base_branch_config_path.txt +++ b/cmd/pint/tests/0135_ci_base_branch_config_path.txt @@ -21,11 +21,12 @@ cmp stderr ../stderr.txt -- stderr.txt -- level=INFO msg="Loading configuration file" path=.pint.hcl +level=DEBUG msg="Adding pint config to the parser exclude list" path=.pint.hcl level=DEBUG msg="Running git command" args=["rev-parse","--abbrev-ref","HEAD"] level=DEBUG msg="Got branch information" base=origin/main current=v2 level=INFO msg="Finding all rules to check on current git branch" base=origin/main level=DEBUG msg="Excluding git directory from glob results" path=.git glob=* -level=DEBUG msg="File parsed" path=.pint.hcl rules=0 +level=DEBUG msg="File path is in the exclude list" path=.pint.hcl exclude=["^.pint.hcl$"] level=DEBUG msg="File parsed" path=rules.yml rules=1 level=DEBUG msg="Glob finder completed" count=1 level=DEBUG msg="Running git command" args=["log","--reverse","--no-merges","--first-parent","--format=%H","--name-status","origin/main..HEAD"] diff --git a/cmd/pint/tests/0144_discovery_filepath.txt b/cmd/pint/tests/0144_discovery_filepath.txt index e8e9de78..3ab79b22 100644 --- a/cmd/pint/tests/0144_discovery_filepath.txt +++ b/cmd/pint/tests/0144_discovery_filepath.txt @@ -4,6 +4,7 @@ cmp stderr stderr.txt -- stderr.txt -- level=INFO msg="Loading configuration file" path=.pint.hcl +level=DEBUG msg="Adding pint config to the parser exclude list" path=.pint.hcl level=INFO msg="Finding all rules to check" paths=["rules"] level=DEBUG msg="File parsed" path=rules/0001.yml rules=1 level=DEBUG msg="Glob finder completed" count=1 diff --git a/cmd/pint/tests/0145_discovery_filepath_dup.txt b/cmd/pint/tests/0145_discovery_filepath_dup.txt index 6cea1829..058087d0 100644 --- a/cmd/pint/tests/0145_discovery_filepath_dup.txt +++ b/cmd/pint/tests/0145_discovery_filepath_dup.txt @@ -4,6 +4,7 @@ cmp stderr stderr.txt -- stderr.txt -- level=INFO msg="Loading configuration file" path=.pint.hcl +level=DEBUG msg="Adding pint config to the parser exclude list" path=.pint.hcl level=INFO msg="Finding all rules to check" paths=["rules"] level=DEBUG msg="File parsed" path=rules/0001.yml rules=1 level=DEBUG msg="Glob finder completed" count=1 diff --git a/cmd/pint/tests/0147_discovery_filepath_error.txt b/cmd/pint/tests/0147_discovery_filepath_error.txt index a6cecc65..789e9165 100644 --- a/cmd/pint/tests/0147_discovery_filepath_error.txt +++ b/cmd/pint/tests/0147_discovery_filepath_error.txt @@ -4,6 +4,7 @@ cmp stderr stderr.txt -- stderr.txt -- level=INFO msg="Loading configuration file" path=.pint.hcl +level=DEBUG msg="Adding pint config to the parser exclude list" path=.pint.hcl level=INFO msg="Finding all rules to check" paths=["rules"] level=DEBUG msg="File parsed" path=rules/0001.yml rules=1 level=DEBUG msg="Glob finder completed" count=1 diff --git a/cmd/pint/tests/0148_discovery_prom_zero.txt b/cmd/pint/tests/0148_discovery_prom_zero.txt index 8cd2fc8e..4e84ad84 100644 --- a/cmd/pint/tests/0148_discovery_prom_zero.txt +++ b/cmd/pint/tests/0148_discovery_prom_zero.txt @@ -7,6 +7,7 @@ cmp stderr stderr.txt -- stderr.txt -- level=INFO msg="Loading configuration file" path=.pint.hcl +level=DEBUG msg="Adding pint config to the parser exclude list" path=.pint.hcl level=INFO msg="Finding all rules to check" paths=["rules"] level=DEBUG msg="File parsed" path=rules/0001.yml rules=1 level=DEBUG msg="Glob finder completed" count=1 diff --git a/cmd/pint/tests/0149_discovery_prom.txt b/cmd/pint/tests/0149_discovery_prom.txt index 82704e49..e40b0581 100644 --- a/cmd/pint/tests/0149_discovery_prom.txt +++ b/cmd/pint/tests/0149_discovery_prom.txt @@ -7,6 +7,7 @@ cmp stderr stderr.txt -- stderr.txt -- level=INFO msg="Loading configuration file" path=.pint.hcl +level=DEBUG msg="Adding pint config to the parser exclude list" path=.pint.hcl level=INFO msg="Finding all rules to check" paths=["rules"] level=DEBUG msg="File parsed" path=rules/0001.yml rules=1 level=DEBUG msg="Glob finder completed" count=1 diff --git a/cmd/pint/tests/0150_discovery_prom_dup_tags.txt b/cmd/pint/tests/0150_discovery_prom_dup_tags.txt index 29adeaf6..8880dc0b 100644 --- a/cmd/pint/tests/0150_discovery_prom_dup_tags.txt +++ b/cmd/pint/tests/0150_discovery_prom_dup_tags.txt @@ -7,6 +7,7 @@ cmp stderr stderr.txt -- stderr.txt -- level=INFO msg="Loading configuration file" path=.pint.hcl +level=DEBUG msg="Adding pint config to the parser exclude list" path=.pint.hcl level=INFO msg="Finding all rules to check" paths=["rules"] level=DEBUG msg="File parsed" path=rules/0001.yml rules=1 level=DEBUG msg="Glob finder completed" count=1 diff --git a/cmd/pint/tests/0151_discovery_prom_error.txt b/cmd/pint/tests/0151_discovery_prom_error.txt index a3520891..a32b6c24 100644 --- a/cmd/pint/tests/0151_discovery_prom_error.txt +++ b/cmd/pint/tests/0151_discovery_prom_error.txt @@ -7,6 +7,7 @@ cmp stderr stderr.txt -- stderr.txt -- level=INFO msg="Loading configuration file" path=.pint.hcl +level=DEBUG msg="Adding pint config to the parser exclude list" path=.pint.hcl level=INFO msg="Finding all rules to check" paths=["rules"] level=DEBUG msg="File parsed" path=rules/0001.yml rules=1 level=DEBUG msg="Glob finder completed" count=1 diff --git a/cmd/pint/tests/0152_discovery_prom_dup_uptime.txt b/cmd/pint/tests/0152_discovery_prom_dup_uptime.txt index 1e27c4ec..c71e09c3 100644 --- a/cmd/pint/tests/0152_discovery_prom_dup_uptime.txt +++ b/cmd/pint/tests/0152_discovery_prom_dup_uptime.txt @@ -7,6 +7,7 @@ cmp stderr stderr.txt -- stderr.txt -- level=INFO msg="Loading configuration file" path=.pint.hcl +level=DEBUG msg="Adding pint config to the parser exclude list" path=.pint.hcl level=INFO msg="Finding all rules to check" paths=["rules"] level=DEBUG msg="File parsed" path=rules/0001.yml rules=1 level=DEBUG msg="Glob finder completed" count=1 diff --git a/cmd/pint/tests/0155_discovery_prom_dup_include.txt b/cmd/pint/tests/0155_discovery_prom_dup_include.txt index e98c3b8d..57be5dd4 100644 --- a/cmd/pint/tests/0155_discovery_prom_dup_include.txt +++ b/cmd/pint/tests/0155_discovery_prom_dup_include.txt @@ -7,6 +7,7 @@ cmp stderr stderr.txt -- stderr.txt -- level=INFO msg="Loading configuration file" path=.pint.hcl +level=DEBUG msg="Adding pint config to the parser exclude list" path=.pint.hcl level=INFO msg="Finding all rules to check" paths=["rules"] level=DEBUG msg="File parsed" path=rules/0001.yml rules=1 level=DEBUG msg="Glob finder completed" count=1 diff --git a/cmd/pint/tests/0156_discovery_prom_dup_exclude.txt b/cmd/pint/tests/0156_discovery_prom_dup_exclude.txt index 42b87229..7f727439 100644 --- a/cmd/pint/tests/0156_discovery_prom_dup_exclude.txt +++ b/cmd/pint/tests/0156_discovery_prom_dup_exclude.txt @@ -7,6 +7,7 @@ cmp stderr stderr.txt -- stderr.txt -- level=INFO msg="Loading configuration file" path=.pint.hcl +level=DEBUG msg="Adding pint config to the parser exclude list" path=.pint.hcl level=INFO msg="Finding all rules to check" paths=["rules"] level=DEBUG msg="File parsed" path=rules/0001.yml rules=1 level=DEBUG msg="Glob finder completed" count=1 diff --git a/cmd/pint/tests/0167_rule_duplicate_symlink.txt b/cmd/pint/tests/0167_rule_duplicate_symlink.txt index b7669a23..c992a505 100644 --- a/cmd/pint/tests/0167_rule_duplicate_symlink.txt +++ b/cmd/pint/tests/0167_rule_duplicate_symlink.txt @@ -28,7 +28,6 @@ cmp stderr ../stderrV1.txt -- stderrV1.txt -- level=INFO msg="Loading configuration file" path=.pint.hcl level=INFO msg="Finding all rules to check on current git branch" base=main -level=WARN msg="Failed to parse file content" err="error at line 1: top level field must be a groups key, got string" path=.pint.hcl lines=1-20 level=INFO msg="Configured new Prometheus server" name=prom1 uris=1 uptime=up tags=[] include=["^rules.yml$"] exclude=[] level=INFO msg="Configured new Prometheus server" name=prom2 uris=1 uptime=up tags=[] include=["^symlink.yml$"] exclude=[] -- stderrV2.txt -- diff --git a/cmd/pint/tests/0169_watch_rule_files_noprom.txt b/cmd/pint/tests/0169_watch_rule_files_noprom.txt index 272e10ee..6cf7cfce 100644 --- a/cmd/pint/tests/0169_watch_rule_files_noprom.txt +++ b/cmd/pint/tests/0169_watch_rule_files_noprom.txt @@ -4,6 +4,7 @@ cmp stderr stderr.txt -- stderr.txt -- level=INFO msg="Loading configuration file" path=.pint.hcl +level=DEBUG msg="Adding pint config to the parser exclude list" path=.pint.hcl level=INFO msg="Configured new Prometheus server" name=foo uris=1 uptime=up tags=[] include=[] exclude=[] level=DEBUG msg="Starting query workers" name=foo uri=http://localhost:7169 workers=16 level=ERROR msg="Fatal error" err="no Prometheus named \"prom\" configured in pint" diff --git a/cmd/pint/tests/0170_watch_rule_files_error.txt b/cmd/pint/tests/0170_watch_rule_files_error.txt index 206c5bc8..8c220152 100644 --- a/cmd/pint/tests/0170_watch_rule_files_error.txt +++ b/cmd/pint/tests/0170_watch_rule_files_error.txt @@ -8,6 +8,7 @@ cmp stderr stderr.txt -- stderr.txt -- level=INFO msg="Loading configuration file" path=.pint.hcl +level=DEBUG msg="Adding pint config to the parser exclude list" path=.pint.hcl level=INFO msg="Configured new Prometheus server" name=prom uris=1 uptime=up tags=[] include=[] exclude=[] level=DEBUG msg="Starting query workers" name=prom uri=http://localhost:7170 workers=16 level=DEBUG msg="Starting rule_fules watch" name=prom diff --git a/cmd/pint/tests/0173_rule_duplicate_move.txt b/cmd/pint/tests/0173_rule_duplicate_move.txt index 84e73f05..b2c55999 100644 --- a/cmd/pint/tests/0173_rule_duplicate_move.txt +++ b/cmd/pint/tests/0173_rule_duplicate_move.txt @@ -25,7 +25,6 @@ cmp stderr ../stderr.txt -- stderr.txt -- level=INFO msg="Loading configuration file" path=.pint.hcl level=INFO msg="Finding all rules to check on current git branch" base=main -level=WARN msg="Failed to parse file content" err="error at line 1: top level field must be a groups key, got string" path=.pint.hcl lines=1-24 level=INFO msg="Configured new Prometheus server" name=prom1 uris=1 uptime=up tags=[] include=["^rules/alert.*$"] exclude=[] level=INFO msg="Configured new Prometheus server" name=prom2a uris=1 uptime=up tags=[] include=["^rules/record.*$"] exclude=[] level=INFO msg="Configured new Prometheus server" name=prom2b uris=1 uptime=up tags=[] include=["^rules/record.*$"] exclude=[] diff --git a/cmd/pint/tests/0178_parser_include.txt b/cmd/pint/tests/0178_parser_include.txt index cf1546d3..b5601d93 100644 --- a/cmd/pint/tests/0178_parser_include.txt +++ b/cmd/pint/tests/0178_parser_include.txt @@ -4,6 +4,7 @@ cmp stderr stderr.txt -- stderr.txt -- level=INFO msg="Loading configuration file" path=.pint.hcl +level=DEBUG msg="Adding pint config to the parser exclude list" path=.pint.hcl level=INFO msg="Finding all rules to check" paths=["rules"] level=DEBUG msg="File path is in the include list" path=rules/0001.yml include=["^rules/0001.yml$"] level=DEBUG msg="File parsed" path=rules/0001.yml rules=1 diff --git a/cmd/pint/tests/0179_parser_exclude.txt b/cmd/pint/tests/0179_parser_exclude.txt index a759ebd0..6f29295c 100644 --- a/cmd/pint/tests/0179_parser_exclude.txt +++ b/cmd/pint/tests/0179_parser_exclude.txt @@ -4,9 +4,10 @@ cmp stderr stderr.txt -- stderr.txt -- level=INFO msg="Loading configuration file" path=.pint.hcl +level=DEBUG msg="Adding pint config to the parser exclude list" path=.pint.hcl level=INFO msg="Finding all rules to check" paths=["rules"] level=DEBUG msg="File parsed" path=rules/0001.yml rules=1 -level=DEBUG msg="File path is in the exclude list" path=rules/0002.yml exclude=["^rules/0002.yml$"] +level=DEBUG msg="File path is in the exclude list" path=rules/0002.yml exclude=["^rules/0002.yml$","^.pint.hcl$"] level=DEBUG msg="Glob finder completed" count=1 level=DEBUG msg="Generated all Prometheus servers" count=0 level=DEBUG msg="Found recording rule" path=rules/0001.yml record=ok lines=1-2 diff --git a/cmd/pint/tests/0180_parser_exclude_md.txt b/cmd/pint/tests/0180_parser_exclude_md.txt index 701fda72..aa238fe7 100644 --- a/cmd/pint/tests/0180_parser_exclude_md.txt +++ b/cmd/pint/tests/0180_parser_exclude_md.txt @@ -4,9 +4,10 @@ cmp stderr stderr.txt -- stderr.txt -- level=INFO msg="Loading configuration file" path=.pint.hcl +level=DEBUG msg="Adding pint config to the parser exclude list" path=.pint.hcl level=INFO msg="Finding all rules to check" paths=["rules"] level=DEBUG msg="File parsed" path=rules/0001.yml rules=1 -level=DEBUG msg="File path is in the exclude list" path=rules/README.md exclude=["^.*.md$"] +level=DEBUG msg="File path is in the exclude list" path=rules/README.md exclude=["^.*.md$","^.pint.hcl$"] level=DEBUG msg="Glob finder completed" count=1 level=DEBUG msg="Generated all Prometheus servers" count=0 level=DEBUG msg="Found recording rule" path=rules/0001.yml record=ok lines=1-2 diff --git a/cmd/pint/tests/0183_cli_enable.txt b/cmd/pint/tests/0183_cli_enable.txt new file mode 100644 index 00000000..5ce9f29d --- /dev/null +++ b/cmd/pint/tests/0183_cli_enable.txt @@ -0,0 +1,44 @@ +pint.ok -l debug --no-color -e promql/aggregate lint rules +! stdout . +cmp stderr stderr.txt + +-- stderr.txt -- +level=INFO msg="Loading configuration file" path=.pint.hcl +level=DEBUG msg="Adding pint config to the parser exclude list" path=.pint.hcl +level=INFO msg="Finding all rules to check" paths=["rules"] +level=DEBUG msg="File parsed" path=rules/0001.yml rules=3 +level=DEBUG msg="Glob finder completed" count=3 +level=DEBUG msg="Generated all Prometheus servers" count=0 +level=DEBUG msg="Found alerting rule" path=rules/0001.yml alert=default-for lines=1-3 +level=DEBUG msg="Configured checks for rule" enabled=[] path=rules/0001.yml rule=default-for +level=DEBUG msg="Found recording rule" path=rules/0001.yml record=sum:job lines=5-6 +level=DEBUG msg="Configured checks for rule" enabled=["promql/aggregate(job:true)"] path=rules/0001.yml rule=sum:job +level=DEBUG msg="Found alerting rule" path=rules/0001.yml alert=no-comparison lines=8-9 +level=DEBUG msg="Configured checks for rule" enabled=[] path=rules/0001.yml rule=no-comparison +rules/0001.yml:6 Warning: `job` label is required and should be preserved when aggregating `^.+$` rules, use `by(job, ...)`. (promql/aggregate) + 6 | expr: sum(foo) + +level=INFO msg="Problems found" Warning=1 +-- rules/0001.yml -- +- alert: default-for + expr: foo > 1 + for: 0m + +- record: sum:job + expr: sum(foo) + +- alert: no-comparison + expr: foo + +-- .pint.hcl -- +parser { + relaxed = [".*"] +} +rule { + match { + kind = "recording" + } + aggregate ".+" { + keep = [ "job" ] + } +} \ No newline at end of file diff --git a/cmd/pint/tests/0184_ci_file_ignore.txt b/cmd/pint/tests/0184_ci_file_ignore.txt new file mode 100644 index 00000000..93068a35 --- /dev/null +++ b/cmd/pint/tests/0184_ci_file_ignore.txt @@ -0,0 +1,40 @@ +mkdir testrepo +cd testrepo +exec git init --initial-branch=main . + +cp ../src/rules.yml rules.yml +cp ../src/.pint.hcl . +env GIT_AUTHOR_NAME=pint +env GIT_AUTHOR_EMAIL=pint@example.com +env GIT_COMMITTER_NAME=pint +env GIT_COMMITTER_EMAIL=pint@example.com +exec git add . +exec git commit -am 'import rules and config' + +exec git checkout -b v2 +exec touch .keep +exec git add .keep +exec git commit -am 'v2' + +pint.ok --no-color ci +! stdout . +cmp stderr ../stderr.txt + +-- stderr.txt -- +level=INFO msg="Loading configuration file" path=.pint.hcl +level=INFO msg="Finding all rules to check on current git branch" base=main +-- src/rules.yml -- +# pint ignore/file +- record: rule1 + expr: sum(foo) by(job) +- record: rule2 + expr: sum(foo) + +-- src/.pint.hcl -- +ci { + baseBranch = "main" +} +parser { + relaxed = [".*"] + include = ["rules.yml"] +} diff --git a/docs/changelog.md b/docs/changelog.md index 29f495d9..572a64bf 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -8,10 +8,13 @@ See check docs for details. - [promql/range_query](checks/promql/range_query.md) now allows to configure a custom maximum duration for range queries - #1064. +- Added `--enabled` flag to the pint command. Passing this flag will only run selected check(s). ### Fixed - Don't try to report problem on unmodified files when using GitHub reporter. +- If there is a pint config file present then pint will now always add it to the `parser` block `exclude` list. + This is to avoid trying to parse it as a rule file if it's included in the same folder as rules. ## v0.64.1 diff --git a/internal/checks/promql_rate_test.go b/internal/checks/promql_rate_test.go index 18a5ef4f..2bd95839 100644 --- a/internal/checks/promql_rate_test.go +++ b/internal/checks/promql_rate_test.go @@ -1,6 +1,7 @@ package checks_test import ( + "errors" "fmt" "testing" "time" @@ -8,6 +9,7 @@ import ( v1 "github.com/prometheus/client_golang/api/prometheus/v1" "github.com/cloudflare/pint/internal/checks" + "github.com/cloudflare/pint/internal/discovery" "github.com/cloudflare/pint/internal/parser" "github.com/cloudflare/pint/internal/promapi" ) @@ -787,6 +789,56 @@ func TestRateCheck(t *testing.T) { }, }, }, + { + description: "sum_over_rate / ignore entry with PathError", + content: "- alert: my alert\n expr: rate(my:sum[5m])\n", + entries: []discovery.Entry{{PathError: errors.New("mock error")}}, + checker: newRateCheck, + prometheus: newSimpleProm, + problems: noProblems, + mocks: []*prometheusMock{ + { + conds: []requestCondition{requireConfigPath}, + resp: configResponse{yaml: "global:\n scrape_interval: 1m\n"}, + }, + { + conds: []requestCondition{ + requireMetadataPath, + formCond{"metric", "my:sum"}, + }, + resp: metadataResponse{metadata: map[string][]v1.Metadata{}}, + }, + }, + }, + { + description: "sum_over_rate / ignore entry with rule error", + content: "- alert: my alert\n expr: rate(my:sum[5m])\n", + entries: []discovery.Entry{ + { + Rule: parser.Rule{ + Error: parser.ParseError{ + Err: errors.New("mock error"), + }, + }, + }, + }, + checker: newRateCheck, + prometheus: newSimpleProm, + problems: noProblems, + mocks: []*prometheusMock{ + { + conds: []requestCondition{requireConfigPath}, + resp: configResponse{yaml: "global:\n scrape_interval: 1m\n"}, + }, + { + conds: []requestCondition{ + requireMetadataPath, + formCond{"metric", "my:sum"}, + }, + resp: metadataResponse{metadata: map[string][]v1.Metadata{}}, + }, + }, + }, } runTests(t, testCases) } diff --git a/internal/config/config.go b/internal/config/config.go index a53519c9..57764bb8 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -165,7 +165,7 @@ func (cfg *Config) GetChecksForRule(ctx context.Context, gen *PrometheusGenerato } for _, rule := range cfg.Rules { - allChecks = append(allChecks, rule.resolveChecks(ctx, entry.Path.Name, entry.Rule, proms)...) + allChecks = append(allChecks, rule.resolveChecks(ctx, entry, proms)...) } for _, cm := range allChecks { @@ -219,7 +219,7 @@ func getContext() *hcl.EvalContext { return &hcl.EvalContext{Variables: vars} } -func Load(path string, failOnMissing bool) (cfg Config, err error) { +func Load(path string, failOnMissing bool) (cfg Config, fromFile bool, err error) { cfg = Config{ CI: &CI{ MaxCommits: 20, @@ -237,81 +237,82 @@ func Load(path string, failOnMissing bool) (cfg Config, err error) { } if _, err = os.Stat(path); err == nil || failOnMissing { + fromFile = true slog.Info("Loading configuration file", slog.String("path", path)) ectx := getContext() err = hclsimple.DecodeFile(path, ectx, &cfg) if err != nil { - return cfg, err + return cfg, fromFile, err } } if cfg.CI != nil { if err = cfg.CI.validate(); err != nil { - return cfg, err + return cfg, fromFile, err } } if cfg.Owners != nil { if err = cfg.Owners.validate(); err != nil { - return cfg, err + return cfg, fromFile, err } } if cfg.Parser != nil { if err = cfg.Parser.validate(); err != nil { - return cfg, err + return cfg, fromFile, err } } if cfg.Repository != nil { if err = cfg.Repository.validate(); err != nil { - return cfg, err + return cfg, fromFile, err } } if cfg.Checks != nil { if err = cfg.Checks.validate(); err != nil { - return cfg, err + return cfg, fromFile, err } } for _, chk := range cfg.Check { if err = chk.validate(); err != nil { - return cfg, err + return cfg, fromFile, err } } promNames := make([]string, 0, len(cfg.Prometheus)) for i, prom := range cfg.Prometheus { if err = prom.validate(); err != nil { - return cfg, err + return cfg, fromFile, err } if slices.Contains(promNames, prom.Name) { - return cfg, fmt.Errorf("prometheus server name must be unique, found two or more config blocks using %q name", prom.Name) + return cfg, fromFile, fmt.Errorf("prometheus server name must be unique, found two or more config blocks using %q name", prom.Name) } promNames = append(promNames, prom.Name) cfg.Prometheus[i].applyDefaults() if _, err = prom.TLS.toHTTPConfig(); err != nil { - return cfg, fmt.Errorf("invalid prometheus TLS configuration: %w", err) + return cfg, fromFile, fmt.Errorf("invalid prometheus TLS configuration: %w", err) } } if cfg.Discovery != nil { if err = cfg.Discovery.validate(); err != nil { - return cfg, err + return cfg, fromFile, err } } for _, rule := range cfg.Rules { if err = rule.validate(); err != nil { - return cfg, err + return cfg, fromFile, err } } - return cfg, nil + return cfg, fromFile, nil } func parseDuration(d string) (time.Duration, error) { diff --git a/internal/config/config_test.go b/internal/config/config_test.go index d859b3ce..221d4235 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -24,13 +24,15 @@ func TestMain(t *testing.M) { } func TestConfigLoadMissingFile(t *testing.T) { - _, err := config.Load("/foo/bar/pint.hcl", true) + _, ok, err := config.Load("/foo/bar/pint.hcl", true) require.EqualError(t, err, ": Configuration file not found; The configuration file /foo/bar/pint.hcl does not exist.") + require.True(t, ok) } func TestConfigLoadMissingFileOk(t *testing.T) { - _, err := config.Load("/foo/bar/pint.hcl", false) + _, ok, err := config.Load("/foo/bar/pint.hcl", false) require.NoError(t, err) + require.False(t, ok) } func TestDisableOnlineChecksWithPrometheus(t *testing.T) { @@ -43,8 +45,9 @@ prometheus "prom" { `), 0o644) require.NoError(t, err) - cfg, err := config.Load(path, true) + cfg, ok, err := config.Load(path, true) require.NoError(t, err) + require.True(t, ok) gen := config.NewPrometheusGenerator(cfg, prometheus.NewRegistry()) defer gen.Stop() @@ -64,7 +67,7 @@ func TestDisableOnlineChecksWithoutPrometheus(t *testing.T) { err := os.WriteFile(path, []byte(``), 0o644) require.NoError(t, err) - cfg, err := config.Load(path, true) + cfg, _, err := config.Load(path, true) require.NoError(t, err) gen := config.NewPrometheusGenerator(cfg, prometheus.NewRegistry()) @@ -90,7 +93,7 @@ prometheus "prom" { `), 0o644) require.NoError(t, err) - cfg, err := config.Load(path, true) + cfg, _, err := config.Load(path, true) require.NoError(t, err) gen := config.NewPrometheusGenerator(cfg, prometheus.NewRegistry()) @@ -117,7 +120,7 @@ func TestSetDisabledChecks(t *testing.T) { err := os.WriteFile(path, []byte(``), 0o644) require.NoError(t, err) - cfg, err := config.Load(path, true) + cfg, _, err := config.Load(path, true) require.NoError(t, err) gen := config.NewPrometheusGenerator(cfg, prometheus.NewRegistry()) @@ -1967,7 +1970,7 @@ rule { require.NoError(t, err) } - cfg, err := config.Load(path, false) + cfg, _, err := config.Load(path, false) require.NoError(t, err) gen := config.NewPrometheusGenerator(cfg, prometheus.NewRegistry()) @@ -2322,7 +2325,7 @@ func TestConfigErrors(t *testing.T) { require.NoError(t, err) } - _, err := config.Load(path, false) + _, _, err := config.Load(path, false) require.EqualError(t, err, tc.err, tc.config) }) } @@ -2343,6 +2346,6 @@ prometheus "prom" { `), 0o644) require.NoError(t, err) - _, err = config.Load(path, true) + _, _, err = config.Load(path, true) require.EqualError(t, err, `prometheus server name must be unique, found two or more config blocks using "prom" name`) } diff --git a/internal/config/match.go b/internal/config/match.go index ef0c1573..1b7edb6c 100644 --- a/internal/config/match.go +++ b/internal/config/match.go @@ -8,6 +8,7 @@ import ( "strings" "time" + "github.com/cloudflare/pint/internal/discovery" "github.com/cloudflare/pint/internal/parser" ) @@ -83,12 +84,20 @@ func (m Match) validate(allowEmpty bool) error { return nil } -func (m Match) IsMatch(ctx context.Context, path string, r parser.Rule) bool { +func (m Match) IsMatch(ctx context.Context, path string, e discovery.Entry) bool { + cmd := ctx.Value(CommandKey).(ContextCommandVal) + + if m.Command != nil { + if cmd != *m.Command { + return false + } + } + if m.Kind != "" { - if r.AlertingRule != nil && m.Kind != AlertingRuleType { + if e.Rule.AlertingRule != nil && m.Kind != AlertingRuleType { return false } - if r.RecordingRule != nil && m.Kind != RecordingRuleType { + if e.Rule.RecordingRule != nil && m.Kind != RecordingRuleType { return false } } @@ -102,37 +111,30 @@ func (m Match) IsMatch(ctx context.Context, path string, r parser.Rule) bool { if m.Name != "" { re := strictRegex(m.Name) - if r.AlertingRule != nil && !re.MatchString(r.AlertingRule.Alert.Value) { + if e.Rule.AlertingRule != nil && !re.MatchString(e.Rule.AlertingRule.Alert.Value) { return false } - if r.RecordingRule != nil && !re.MatchString(r.RecordingRule.Record.Value) { + if e.Rule.RecordingRule != nil && !re.MatchString(e.Rule.RecordingRule.Record.Value) { return false } } if m.Label != nil { - if !m.Label.isMatching(r) { + if !m.Label.isMatching(e.Rule) { return false } } if m.Annotation != nil { - if !m.Annotation.isMatching(r) { - return false - } - } - - if m.Command != nil { - cmd := ctx.Value(CommandKey).(ContextCommandVal) - if cmd != *m.Command { + if !m.Annotation.isMatching(e.Rule) { return false } } if m.For != "" { - if r.AlertingRule != nil && r.AlertingRule.For != nil { + if e.Rule.AlertingRule != nil && e.Rule.AlertingRule.For != nil { dm, _ := parseDurationMatch(m.For) - if dur, err := parseDuration(r.AlertingRule.For.Value); err == nil { + if dur, err := parseDuration(e.Rule.AlertingRule.For.Value); err == nil { if !dm.isMatch(dur) { return false } @@ -143,9 +145,9 @@ func (m Match) IsMatch(ctx context.Context, path string, r parser.Rule) bool { } if m.KeepFiringFor != "" { - if r.AlertingRule != nil && r.AlertingRule.KeepFiringFor != nil { + if e.Rule.AlertingRule != nil && e.Rule.AlertingRule.KeepFiringFor != nil { dm, _ := parseDurationMatch(m.KeepFiringFor) - if dur, err := parseDuration(r.AlertingRule.KeepFiringFor.Value); err == nil { + if dur, err := parseDuration(e.Rule.AlertingRule.KeepFiringFor.Value); err == nil { if !dm.isMatch(dur) { return false } diff --git a/internal/config/rule.go b/internal/config/rule.go index 3a5a3e3f..18da02c6 100644 --- a/internal/config/rule.go +++ b/internal/config/rule.go @@ -9,6 +9,7 @@ import ( "github.com/cloudflare/pint/internal/checks" "github.com/cloudflare/pint/internal/comments" + "github.com/cloudflare/pint/internal/discovery" "github.com/cloudflare/pint/internal/parser" "github.com/cloudflare/pint/internal/promapi" ) @@ -111,11 +112,11 @@ func (rule Rule) validate() (err error) { return nil } -func (rule Rule) resolveChecks(ctx context.Context, path string, r parser.Rule, prometheusServers []*promapi.FailoverGroup) []checkMeta { +func (rule Rule) resolveChecks(ctx context.Context, e discovery.Entry, prometheusServers []*promapi.FailoverGroup) []checkMeta { enabled := []checkMeta{} for _, ignore := range rule.Ignore { - if ignore.IsMatch(ctx, path, r) { + if ignore.IsMatch(ctx, e.Path.Name, e) { return enabled } } @@ -123,7 +124,7 @@ func (rule Rule) resolveChecks(ctx context.Context, path string, r parser.Rule, if len(rule.Match) > 0 { var found bool for _, match := range rule.Match { - if match.IsMatch(ctx, path, r) { + if match.IsMatch(ctx, e.Path.Name, e) { found = true break } diff --git a/internal/config/rule_test.go b/internal/config/rule_test.go index 702be8b6..ac419b6f 100644 --- a/internal/config/rule_test.go +++ b/internal/config/rule_test.go @@ -2,10 +2,14 @@ package config_test import ( "context" + "log/slog" "strconv" "testing" + "github.com/neilotoole/slogt" + "github.com/cloudflare/pint/internal/config" + "github.com/cloudflare/pint/internal/discovery" "github.com/cloudflare/pint/internal/parser" "github.com/stretchr/testify/require" @@ -16,7 +20,7 @@ func TestMatch(t *testing.T) { match config.Match cmd config.ContextCommandVal path string - rule parser.Rule + entry discovery.Entry isMatch bool } @@ -24,15 +28,20 @@ func TestMatch(t *testing.T) { { cmd: config.LintCommand, path: "foo.yaml", - rule: parser.Rule{}, - + entry: discovery.Entry{ + Rule: parser.Rule{}, + State: discovery.Noop, + }, match: config.Match{}, isMatch: true, }, { cmd: config.LintCommand, path: "foo.yaml", - rule: parser.Rule{}, + entry: discovery.Entry{ + Rule: parser.Rule{}, + State: discovery.Noop, + }, match: config.Match{ Path: "bar.yaml", }, @@ -41,7 +50,10 @@ func TestMatch(t *testing.T) { { cmd: config.LintCommand, path: "foo.yaml", - rule: parser.Rule{}, + entry: discovery.Entry{ + Rule: parser.Rule{}, + State: discovery.Noop, + }, match: config.Match{ Path: "foo.yaml", }, @@ -50,7 +62,10 @@ func TestMatch(t *testing.T) { { cmd: config.LintCommand, path: "foo.yaml", - rule: parser.Rule{}, + entry: discovery.Entry{ + Rule: parser.Rule{}, + State: discovery.Noop, + }, match: config.Match{ Path: ".+.yaml", }, @@ -59,7 +74,10 @@ func TestMatch(t *testing.T) { { cmd: config.LintCommand, path: "foo.yaml", - rule: parser.Rule{}, + entry: discovery.Entry{ + Rule: parser.Rule{}, + State: discovery.Noop, + }, match: config.Match{ Path: "bar.+.yaml", }, @@ -68,10 +86,13 @@ func TestMatch(t *testing.T) { { cmd: config.LintCommand, path: "foo.yaml", - rule: parser.Rule{ - AlertingRule: &parser.AlertingRule{ - Alert: parser.YamlNode{Value: "Foo"}, + entry: discovery.Entry{ + Rule: parser.Rule{ + AlertingRule: &parser.AlertingRule{ + Alert: parser.YamlNode{Value: "Foo"}, + }, }, + State: discovery.Noop, }, match: config.Match{ Name: "Foo", @@ -81,10 +102,13 @@ func TestMatch(t *testing.T) { { cmd: config.LintCommand, path: "foo.yaml", - rule: parser.Rule{ - AlertingRule: &parser.AlertingRule{ - Alert: parser.YamlNode{Value: "Foo"}, + entry: discovery.Entry{ + Rule: parser.Rule{ + AlertingRule: &parser.AlertingRule{ + Alert: parser.YamlNode{Value: "Foo"}, + }, }, + State: discovery.Noop, }, match: config.Match{ Name: "Foo", @@ -95,10 +119,13 @@ func TestMatch(t *testing.T) { { cmd: config.LintCommand, path: "foo.yaml", - rule: parser.Rule{ - AlertingRule: &parser.AlertingRule{ - Alert: parser.YamlNode{Value: "Foo"}, + entry: discovery.Entry{ + Rule: parser.Rule{ + AlertingRule: &parser.AlertingRule{ + Alert: parser.YamlNode{Value: "Foo"}, + }, }, + State: discovery.Noop, }, match: config.Match{ Name: "Bar", @@ -108,10 +135,13 @@ func TestMatch(t *testing.T) { { cmd: config.LintCommand, path: "foo.yaml", - rule: parser.Rule{ - RecordingRule: &parser.RecordingRule{ - Record: parser.YamlNode{Value: "Foo"}, + entry: discovery.Entry{ + Rule: parser.Rule{ + RecordingRule: &parser.RecordingRule{ + Record: parser.YamlNode{Value: "Foo"}, + }, }, + State: discovery.Noop, }, match: config.Match{ Name: "Bar", @@ -121,17 +151,20 @@ func TestMatch(t *testing.T) { { cmd: config.LintCommand, path: "foo.yaml", - rule: parser.Rule{ - RecordingRule: &parser.RecordingRule{ - Labels: &parser.YamlMap{ - Items: []*parser.YamlKeyValue{ - { - Key: &parser.YamlNode{Value: "cluster"}, - Value: &parser.YamlNode{Value: "prod"}, + entry: discovery.Entry{ + Rule: parser.Rule{ + RecordingRule: &parser.RecordingRule{ + Labels: &parser.YamlMap{ + Items: []*parser.YamlKeyValue{ + { + Key: &parser.YamlNode{Value: "cluster"}, + Value: &parser.YamlNode{Value: "prod"}, + }, }, }, }, }, + State: discovery.Noop, }, match: config.Match{ Label: &config.MatchLabel{Key: "foo", Value: "bar"}, @@ -141,17 +174,20 @@ func TestMatch(t *testing.T) { { cmd: config.LintCommand, path: "foo.yaml", - rule: parser.Rule{ - RecordingRule: &parser.RecordingRule{ - Labels: &parser.YamlMap{ - Items: []*parser.YamlKeyValue{ - { - Key: &parser.YamlNode{Value: "cluster"}, - Value: &parser.YamlNode{Value: "prod"}, + entry: discovery.Entry{ + Rule: parser.Rule{ + RecordingRule: &parser.RecordingRule{ + Labels: &parser.YamlMap{ + Items: []*parser.YamlKeyValue{ + { + Key: &parser.YamlNode{Value: "cluster"}, + Value: &parser.YamlNode{Value: "prod"}, + }, }, }, }, }, + State: discovery.Noop, }, match: config.Match{ Annotation: &config.MatchAnnotation{Key: "foo", Value: "bar"}, @@ -161,17 +197,20 @@ func TestMatch(t *testing.T) { { cmd: config.LintCommand, path: "foo.yaml", - rule: parser.Rule{ - RecordingRule: &parser.RecordingRule{ - Labels: &parser.YamlMap{ - Items: []*parser.YamlKeyValue{ - { - Key: &parser.YamlNode{Value: "cluster"}, - Value: &parser.YamlNode{Value: "prod"}, + entry: discovery.Entry{ + Rule: parser.Rule{ + RecordingRule: &parser.RecordingRule{ + Labels: &parser.YamlMap{ + Items: []*parser.YamlKeyValue{ + { + Key: &parser.YamlNode{Value: "cluster"}, + Value: &parser.YamlNode{Value: "prod"}, + }, }, }, }, }, + State: discovery.Noop, }, match: config.Match{ Annotation: &config.MatchAnnotation{Key: "cluster", Value: "dev"}, @@ -181,17 +220,20 @@ func TestMatch(t *testing.T) { { cmd: config.LintCommand, path: "foo.yaml", - rule: parser.Rule{ - RecordingRule: &parser.RecordingRule{ - Labels: &parser.YamlMap{ - Items: []*parser.YamlKeyValue{ - { - Key: &parser.YamlNode{Value: "cluster"}, - Value: &parser.YamlNode{Value: "prod"}, + entry: discovery.Entry{ + Rule: parser.Rule{ + RecordingRule: &parser.RecordingRule{ + Labels: &parser.YamlMap{ + Items: []*parser.YamlKeyValue{ + { + Key: &parser.YamlNode{Value: "cluster"}, + Value: &parser.YamlNode{Value: "prod"}, + }, }, }, }, }, + State: discovery.Noop, }, match: config.Match{ Label: &config.MatchLabel{Key: "cluster", Value: "dev"}, @@ -201,17 +243,20 @@ func TestMatch(t *testing.T) { { cmd: config.LintCommand, path: "foo.yaml", - rule: parser.Rule{ - RecordingRule: &parser.RecordingRule{ - Labels: &parser.YamlMap{ - Items: []*parser.YamlKeyValue{ - { - Key: &parser.YamlNode{Value: "cluster"}, - Value: &parser.YamlNode{Value: "prod"}, + entry: discovery.Entry{ + Rule: parser.Rule{ + RecordingRule: &parser.RecordingRule{ + Labels: &parser.YamlMap{ + Items: []*parser.YamlKeyValue{ + { + Key: &parser.YamlNode{Value: "cluster"}, + Value: &parser.YamlNode{Value: "prod"}, + }, }, }, }, }, + State: discovery.Noop, }, match: config.Match{ Annotation: &config.MatchAnnotation{Key: "cluster", Value: "prod"}, @@ -221,17 +266,20 @@ func TestMatch(t *testing.T) { { cmd: config.LintCommand, path: "foo.yaml", - rule: parser.Rule{ - RecordingRule: &parser.RecordingRule{ - Labels: &parser.YamlMap{ - Items: []*parser.YamlKeyValue{ - { - Key: &parser.YamlNode{Value: "cluster"}, - Value: &parser.YamlNode{Value: "prod"}, + entry: discovery.Entry{ + Rule: parser.Rule{ + RecordingRule: &parser.RecordingRule{ + Labels: &parser.YamlMap{ + Items: []*parser.YamlKeyValue{ + { + Key: &parser.YamlNode{Value: "cluster"}, + Value: &parser.YamlNode{Value: "prod"}, + }, }, }, }, }, + State: discovery.Noop, }, match: config.Match{ Label: &config.MatchLabel{Key: "cluster", Value: "prod"}, @@ -241,8 +289,11 @@ func TestMatch(t *testing.T) { { cmd: config.LintCommand, path: "foo.yaml", - rule: parser.Rule{ - AlertingRule: &parser.AlertingRule{}, + entry: discovery.Entry{ + Rule: parser.Rule{ + AlertingRule: &parser.AlertingRule{}, + }, + State: discovery.Noop, }, match: config.Match{ Kind: "alerting", @@ -252,18 +303,23 @@ func TestMatch(t *testing.T) { { cmd: config.LintCommand, path: "foo.yaml", - rule: parser.Rule{ - AlertingRule: &parser.AlertingRule{}, + entry: discovery.Entry{ + Rule: parser.Rule{ + AlertingRule: &parser.AlertingRule{}, + }, + State: discovery.Noop, }, - match: config.Match{}, isMatch: true, }, { cmd: config.LintCommand, path: "foo.yaml", - rule: parser.Rule{ - AlertingRule: &parser.AlertingRule{}, + entry: discovery.Entry{ + Rule: parser.Rule{ + AlertingRule: &parser.AlertingRule{}, + }, + State: discovery.Noop, }, match: config.Match{ Kind: "recording", @@ -273,8 +329,11 @@ func TestMatch(t *testing.T) { { cmd: config.LintCommand, path: "foo.yaml", - rule: parser.Rule{ - RecordingRule: &parser.RecordingRule{}, + entry: discovery.Entry{ + Rule: parser.Rule{ + RecordingRule: &parser.RecordingRule{}, + }, + State: discovery.Noop, }, match: config.Match{ Kind: "recording", @@ -284,8 +343,11 @@ func TestMatch(t *testing.T) { { cmd: config.LintCommand, path: "foo.yaml", - rule: parser.Rule{ - RecordingRule: &parser.RecordingRule{}, + entry: discovery.Entry{ + Rule: parser.Rule{ + RecordingRule: &parser.RecordingRule{}, + }, + State: discovery.Noop, }, match: config.Match{ Kind: "alerting", @@ -295,17 +357,20 @@ func TestMatch(t *testing.T) { { cmd: config.LintCommand, path: "foo.yaml", - rule: parser.Rule{ - AlertingRule: &parser.AlertingRule{ - Annotations: &parser.YamlMap{ - Items: []*parser.YamlKeyValue{ - { - Key: &parser.YamlNode{Value: "cluster"}, - Value: &parser.YamlNode{Value: "prod"}, + entry: discovery.Entry{ + Rule: parser.Rule{ + AlertingRule: &parser.AlertingRule{ + Annotations: &parser.YamlMap{ + Items: []*parser.YamlKeyValue{ + { + Key: &parser.YamlNode{Value: "cluster"}, + Value: &parser.YamlNode{Value: "prod"}, + }, }, }, }, }, + State: discovery.Noop, }, match: config.Match{ Label: &config.MatchLabel{Key: "foo", Value: "bar"}, @@ -315,17 +380,20 @@ func TestMatch(t *testing.T) { { cmd: config.LintCommand, path: "foo.yaml", - rule: parser.Rule{ - AlertingRule: &parser.AlertingRule{ - Annotations: &parser.YamlMap{ - Items: []*parser.YamlKeyValue{ - { - Key: &parser.YamlNode{Value: "cluster"}, - Value: &parser.YamlNode{Value: "prod"}, + entry: discovery.Entry{ + Rule: parser.Rule{ + AlertingRule: &parser.AlertingRule{ + Annotations: &parser.YamlMap{ + Items: []*parser.YamlKeyValue{ + { + Key: &parser.YamlNode{Value: "cluster"}, + Value: &parser.YamlNode{Value: "prod"}, + }, }, }, }, }, + State: discovery.Noop, }, match: config.Match{ Annotation: &config.MatchAnnotation{Key: "foo", Value: "bar"}, @@ -335,17 +403,20 @@ func TestMatch(t *testing.T) { { cmd: config.LintCommand, path: "foo.yaml", - rule: parser.Rule{ - AlertingRule: &parser.AlertingRule{ - Annotations: &parser.YamlMap{ - Items: []*parser.YamlKeyValue{ - { - Key: &parser.YamlNode{Value: "cluster"}, - Value: &parser.YamlNode{Value: "prod"}, + entry: discovery.Entry{ + Rule: parser.Rule{ + AlertingRule: &parser.AlertingRule{ + Annotations: &parser.YamlMap{ + Items: []*parser.YamlKeyValue{ + { + Key: &parser.YamlNode{Value: "cluster"}, + Value: &parser.YamlNode{Value: "prod"}, + }, }, }, }, }, + State: discovery.Noop, }, match: config.Match{ Label: &config.MatchLabel{Key: "cluster", Value: "prod"}, @@ -355,17 +426,20 @@ func TestMatch(t *testing.T) { { cmd: config.LintCommand, path: "foo.yaml", - rule: parser.Rule{ - AlertingRule: &parser.AlertingRule{ - Annotations: &parser.YamlMap{ - Items: []*parser.YamlKeyValue{ - { - Key: &parser.YamlNode{Value: "cluster"}, - Value: &parser.YamlNode{Value: "prod"}, + entry: discovery.Entry{ + Rule: parser.Rule{ + AlertingRule: &parser.AlertingRule{ + Annotations: &parser.YamlMap{ + Items: []*parser.YamlKeyValue{ + { + Key: &parser.YamlNode{Value: "cluster"}, + Value: &parser.YamlNode{Value: "prod"}, + }, }, }, }, }, + State: discovery.Noop, }, match: config.Match{ Annotation: &config.MatchAnnotation{Key: "cluster", Value: "prod"}, @@ -375,7 +449,10 @@ func TestMatch(t *testing.T) { { cmd: config.LintCommand, path: "foo.yaml", - rule: parser.Rule{}, + entry: discovery.Entry{ + Rule: parser.Rule{}, + State: discovery.Noop, + }, match: config.Match{ Annotation: &config.MatchAnnotation{Key: "cluster", Value: "prod"}, }, @@ -384,7 +461,10 @@ func TestMatch(t *testing.T) { { cmd: config.LintCommand, path: "foo.yaml", - rule: parser.Rule{}, + entry: discovery.Entry{ + Rule: parser.Rule{}, + State: discovery.Noop, + }, match: config.Match{ Label: &config.MatchLabel{Key: "cluster", Value: "prod"}, }, @@ -393,7 +473,10 @@ func TestMatch(t *testing.T) { { cmd: config.LintCommand, path: "foo.yaml", - rule: parser.Rule{}, + entry: discovery.Entry{ + Rule: parser.Rule{}, + State: discovery.Noop, + }, match: config.Match{ Command: &config.LintCommand, }, @@ -402,7 +485,10 @@ func TestMatch(t *testing.T) { { cmd: config.LintCommand, path: "foo.yaml", - rule: parser.Rule{}, + entry: discovery.Entry{ + Rule: parser.Rule{}, + State: discovery.Noop, + }, match: config.Match{ Command: &config.WatchCommand, }, @@ -411,7 +497,10 @@ func TestMatch(t *testing.T) { { cmd: config.CICommand, path: "foo.yaml", - rule: parser.Rule{}, + entry: discovery.Entry{ + Rule: parser.Rule{}, + State: discovery.Noop, + }, match: config.Match{ Command: &config.CICommand, Path: "bar.yaml", @@ -422,8 +511,9 @@ func TestMatch(t *testing.T) { for i, tc := range testCases { t.Run(strconv.Itoa(i+1), func(t *testing.T) { + slog.SetDefault(slogt.New(t)) ctx := context.WithValue(context.Background(), config.CommandKey, tc.cmd) - isMatch := tc.match.IsMatch(ctx, tc.path, tc.rule) + isMatch := tc.match.IsMatch(ctx, tc.path, tc.entry) require.Equal(t, tc.isMatch, isMatch) }) } diff --git a/internal/discovery/git_branch.go b/internal/discovery/git_branch.go index 91b40ae8..979d5aa9 100644 --- a/internal/discovery/git_branch.go +++ b/internal/discovery/git_branch.go @@ -110,22 +110,24 @@ func (f GitBranchFinder) Find(allEntries []Entry) (entries []Entry, err error) { case me.hasBefore && me.hasAfter: switch { case me.isIdentical && !me.wasMoved: + me.after.State = Excluded + me.after.ModifiedLines = []int{} slog.Debug( "Rule content was not modified on HEAD, identical rule present before", slog.String("name", me.after.Rule.Name()), slog.String("lines", me.after.Rule.Lines.String()), ) - me.after.State = Excluded - me.after.ModifiedLines = []int{} case me.wasMoved: + me.after.State = Moved + me.after.ModifiedLines = git.CountLines(change.Body.After) slog.Debug( "Rule content was not modified on HEAD but the file was moved or renamed", slog.String("name", me.after.Rule.Name()), slog.String("lines", me.after.Rule.Lines.String()), ) - me.after.State = Moved - me.after.ModifiedLines = git.CountLines(change.Body.After) default: + me.after.State = Modified + me.after.ModifiedLines = commonLines(change.Body.ModifiedLines, me.after.ModifiedLines) slog.Debug( "Rule modified on HEAD branch", slog.String("name", me.after.Rule.Name()), @@ -134,8 +136,6 @@ func (f GitBranchFinder) Find(allEntries []Entry) (entries []Entry, err error) { slog.String("ruleLines", me.after.Rule.Lines.String()), slog.String("modifiedLines", output.FormatLineRangeString(me.after.ModifiedLines)), ) - me.after.State = Modified - me.after.ModifiedLines = commonLines(change.Body.ModifiedLines, me.after.ModifiedLines) } entries = append(entries, me.after) case me.hasBefore && !me.hasAfter && len(failedEntries) == 0: diff --git a/internal/reporter/github.go b/internal/reporter/github.go index b80545cd..79d900dc 100644 --- a/internal/reporter/github.go +++ b/internal/reporter/github.go @@ -176,7 +176,13 @@ func (gr GithubReporter) Create(ctx context.Context, dst any, p PendingComment) Side: github.String(side), } - slog.Debug("Creating a review comment", slog.String("body", comment.GetBody()), slog.String("commit", comment.GetCommitID())) + slog.Debug("Creating a pr comment", + slog.String("commit", comment.GetCommitID()), + slog.String("path", comment.GetPath()), + slog.Int("line", comment.GetLine()), + slog.String("side", comment.GetSide()), + slog.String("body", comment.GetBody()), + ) reqCtx, cancel := gr.reqContext(ctx) defer cancel() @@ -248,16 +254,21 @@ func (gr GithubReporter) createReview(ctx context.Context, summary Summary) erro reqCtx, cancel := gr.reqContext(ctx) defer cancel() + review := github.PullRequestReviewRequest{ + CommitID: github.String(gr.headCommit), + Body: github.String(formatGHReviewBody(gr.version, summary)), + Event: github.String("COMMENT"), + } + slog.Debug("Creating a review", + slog.String("commit", review.GetCommitID()), + slog.String("body", review.GetBody()), + ) _, resp, err := gr.client.PullRequests.CreateReview( reqCtx, gr.owner, gr.repo, gr.prNum, - &github.PullRequestReviewRequest{ - CommitID: github.String(gr.headCommit), - Body: github.String(formatGHReviewBody(gr.version, summary)), - Event: github.String("COMMENT"), - }, + &review, ) if err != nil { return err