diff --git a/cmd/pint/ci.go b/cmd/pint/ci.go index e181c3d4..469e42e7 100644 --- a/cmd/pint/ci.go +++ b/cmd/pint/ci.go @@ -27,32 +27,32 @@ var ( var ciCmd = &cli.Command{ Name: "ci", - Usage: "Lint CI changes", + Usage: "Run checks on all git changes.", Action: actionCI, Flags: []cli.Flag{ &cli.BoolFlag{ Name: requireOwnerFlag, Aliases: []string{"r"}, Value: false, - Usage: "Require all rules to have an owner set via comment", + Usage: "Require all rules to have an owner set via comment.", }, &cli.StringFlag{ Name: baseBranchFlag, Aliases: []string{"b"}, Value: "", - Usage: "Set base branch to use for PR checks (main, master, ...)", + Usage: "Set base branch to use for PR checks (main, master, ...).", }, &cli.StringFlag{ Name: failOnFlag, Aliases: []string{"w"}, Value: "bug", - Usage: "Exit with non-zero code if there are problems with given severity (or higher) detected", + Usage: "Exit with non-zero code if there are problems with given severity (or higher) detected.", }, &cli.BoolFlag{ Name: teamCityFlag, Aliases: []string{"t"}, Value: false, - Usage: "Report problems using TeamCity Service Messages", + Usage: "Print found problems using TeamCity Service Messages format.", }, }, } diff --git a/cmd/pint/config.go b/cmd/pint/config.go index d0f56c11..12ec04bd 100644 --- a/cmd/pint/config.go +++ b/cmd/pint/config.go @@ -11,7 +11,7 @@ import ( var configCmd = &cli.Command{ Name: "config", - Usage: "Parse and print used config", + Usage: "Parse and print used config.", Action: actionConfig, } diff --git a/cmd/pint/lint.go b/cmd/pint/lint.go index df2a7c10..c02311ae 100644 --- a/cmd/pint/lint.go +++ b/cmd/pint/lint.go @@ -20,32 +20,32 @@ var requireOwnerFlag = "require-owner" var lintCmd = &cli.Command{ Name: "lint", - Usage: "Lint specified files", + Usage: "Check specified files or directories (can be a glob).", Action: actionLint, Flags: []cli.Flag{ &cli.BoolFlag{ Name: requireOwnerFlag, Aliases: []string{"r"}, Value: false, - Usage: "Require all rules to have an owner set via comment", + Usage: "Require all rules to have an owner set via comment.", }, &cli.StringFlag{ Name: minSeverityFlag, Aliases: []string{"n"}, Value: "warning", - Usage: "Set minimum severity for reported problems", + Usage: "Set minimum severity for reported problems.", }, &cli.StringFlag{ Name: failOnFlag, Aliases: []string{"w"}, Value: "bug", - Usage: "Exit with non-zero code if there are problems with given severity (or higher) detected", + Usage: "Exit with non-zero code if there are problems with given severity (or higher) detected.", }, &cli.BoolFlag{ Name: teamCityFlag, Aliases: []string{"t"}, Value: false, - Usage: "Report problems using TeamCity Service Messages", + Usage: "Report problems using TeamCity Service Messages.", }, }, } diff --git a/cmd/pint/main.go b/cmd/pint/main.go index 676d765e..c2afc174 100644 --- a/cmd/pint/main.go +++ b/cmd/pint/main.go @@ -27,43 +27,43 @@ var ( func newApp() *cli.App { return &cli.App{ - Usage: "Prometheus rule linter", + Usage: "Prometheus rule linter/validator.", Flags: []cli.Flag{ &cli.PathFlag{ Name: configFlag, Aliases: []string{"c"}, Value: ".pint.hcl", - Usage: "Configuration file to use", + Usage: "Configuration file to use.", }, &cli.IntFlag{ Name: workersFlag, Aliases: []string{"w"}, Value: 10, - Usage: "Number of worker threads for running checks", + Usage: "Number of worker threads for running checks.", }, &cli.StringFlag{ Name: logLevelFlag, Aliases: []string{"l"}, Value: slog.LevelInfo.String(), - Usage: "Log level", + Usage: "Log level.", }, &cli.BoolFlag{ Name: noColorFlag, Aliases: []string{"n"}, Value: false, - Usage: "Disable output colouring", + Usage: "Disable output colouring.", }, &cli.StringSliceFlag{ Name: disabledFlag, Aliases: []string{"d"}, Value: cli.NewStringSlice(), - Usage: "List of checks to disable (example: promql/cost)", + Usage: "List of checks to disable (example: promql/cost).", }, &cli.BoolFlag{ Name: offlineFlag, Aliases: []string{"o"}, Value: false, - Usage: "Disable all check that send live queries to Prometheus servers", + Usage: "Disable all check that send live queries to Prometheus servers.", }, }, Commands: []*cli.Command{ diff --git a/cmd/pint/parse.go b/cmd/pint/parse.go index 6e127cda..3ad7c0c0 100644 --- a/cmd/pint/parse.go +++ b/cmd/pint/parse.go @@ -12,7 +12,7 @@ const levelStep = 2 var parseCmd = &cli.Command{ Name: "parse", - Usage: "Parse a query and print AST, use for debugging or understanding query details", + Usage: "Parse a query and print AST, use it for debugging or understanding query details.", Action: actionParse, } diff --git a/cmd/pint/tests/0041_watch.txt b/cmd/pint/tests/0041_watch.txt index cc14448c..1446b807 100644 --- a/cmd/pint/tests/0041_watch.txt +++ b/cmd/pint/tests/0041_watch.txt @@ -1,6 +1,6 @@ exec bash -x ./test.sh & -pint.ok --no-color -l debug watch --interval=5s --listen=127.0.0.1:6041 --pidfile=pint.pid rules +pint.ok --no-color -l debug watch --interval=5s --listen=127.0.0.1:6041 --pidfile=pint.pid glob rules ! stdout . stderr 'level=INFO msg="Pidfile created" path=pint.pid' diff --git a/cmd/pint/tests/0042_watch_metrics.txt b/cmd/pint/tests/0042_watch_metrics.txt index fc4f4ba3..fcb663ef 100644 --- a/cmd/pint/tests/0042_watch_metrics.txt +++ b/cmd/pint/tests/0042_watch_metrics.txt @@ -1,6 +1,6 @@ exec bash -x ./test.sh & -pint.ok watch --listen=127.0.0.1:6042 --pidfile=pint.pid rules +pint.ok watch --listen=127.0.0.1:6042 --pidfile=pint.pid glob rules cmp curl.txt metrics.txt -- test.sh -- diff --git a/cmd/pint/tests/0043_watch_cancel.txt b/cmd/pint/tests/0043_watch_cancel.txt index de5d85c0..85ffb547 100644 --- a/cmd/pint/tests/0043_watch_cancel.txt +++ b/cmd/pint/tests/0043_watch_cancel.txt @@ -3,7 +3,7 @@ http start github 127.0.0.1:7043 exec bash -x ./test.sh & -pint.ok --no-color watch --interval=1h --listen=127.0.0.1:6043 --pidfile=pint.pid rules +pint.ok --no-color watch --interval=1h --listen=127.0.0.1:6043 --pidfile=pint.pid glob rules ! stdout . stderr 'level=INFO msg="Shutting down"' stderr 'level=INFO msg="Waiting for all background tasks to finish"' diff --git a/cmd/pint/tests/0048_watch_limit.txt b/cmd/pint/tests/0048_watch_limit.txt index fd03fef0..c3588de0 100644 --- a/cmd/pint/tests/0048_watch_limit.txt +++ b/cmd/pint/tests/0048_watch_limit.txt @@ -1,6 +1,6 @@ exec bash -x ./test.sh & -pint.ok watch --listen=127.0.0.1:6048 --max-problems=2 --pidfile=pint.pid rules +pint.ok watch --listen=127.0.0.1:6048 --max-problems=2 --pidfile=pint.pid glob rules cmp curl.txt metrics.txt -- test.sh -- diff --git a/cmd/pint/tests/0049_watch_severity_warning.txt b/cmd/pint/tests/0049_watch_severity_warning.txt index 404476ac..caaa8d21 100644 --- a/cmd/pint/tests/0049_watch_severity_warning.txt +++ b/cmd/pint/tests/0049_watch_severity_warning.txt @@ -1,6 +1,6 @@ exec bash -x ./test.sh & -pint.ok watch --listen=127.0.0.1:6049 --min-severity=warning --pidfile=pint.pid rules +pint.ok watch --listen=127.0.0.1:6049 --min-severity=warning --pidfile=pint.pid glob rules cmp curl.txt metrics.txt -- test.sh -- diff --git a/cmd/pint/tests/0050_watch_severity_fatal.txt b/cmd/pint/tests/0050_watch_severity_fatal.txt index 5eaa5a3c..8516b9ab 100644 --- a/cmd/pint/tests/0050_watch_severity_fatal.txt +++ b/cmd/pint/tests/0050_watch_severity_fatal.txt @@ -1,6 +1,6 @@ exec bash -x ./test.sh & -pint.ok watch --listen=127.0.0.1:6050 --min-severity=fatal --pidfile=pint.pid rules +pint.ok watch --listen=127.0.0.1:6050 --min-severity=fatal --pidfile=pint.pid glob rules cmp curl.txt metrics.txt -- test.sh -- diff --git a/cmd/pint/tests/0051_watch_severity_invalid.txt b/cmd/pint/tests/0051_watch_severity_invalid.txt index 9720e375..4d50559b 100644 --- a/cmd/pint/tests/0051_watch_severity_invalid.txt +++ b/cmd/pint/tests/0051_watch_severity_invalid.txt @@ -1,4 +1,4 @@ -pint.error --no-color watch --min-severity=foo bar +pint.error --no-color watch --min-severity=foo glob bar ! stdout . cmp stderr stderr.txt diff --git a/cmd/pint/tests/0054_watch_metrics_prometheus.txt b/cmd/pint/tests/0054_watch_metrics_prometheus.txt index bb58eb1c..3c7c405d 100644 --- a/cmd/pint/tests/0054_watch_metrics_prometheus.txt +++ b/cmd/pint/tests/0054_watch_metrics_prometheus.txt @@ -4,7 +4,7 @@ http start prometheus 127.0.0.1:7054 exec bash -x ./test.sh & -pint.ok watch --listen=127.0.0.1:6054 --pidfile=pint.pid rules +pint.ok watch --listen=127.0.0.1:6054 --pidfile=pint.pid glob rules cmp curl.txt metrics.txt -- test.sh -- diff --git a/cmd/pint/tests/0057_watch_metrics_prometheus_ignore.txt b/cmd/pint/tests/0057_watch_metrics_prometheus_ignore.txt index 1d8fe214..c2c28dbf 100644 --- a/cmd/pint/tests/0057_watch_metrics_prometheus_ignore.txt +++ b/cmd/pint/tests/0057_watch_metrics_prometheus_ignore.txt @@ -4,7 +4,7 @@ http start prometheus 127.0.0.1:7057 exec bash -x ./test.sh & -pint.ok watch --listen=127.0.0.1:6057 --pidfile=pint.pid rules +pint.ok watch --listen=127.0.0.1:6057 --pidfile=pint.pid glob rules cmp curl.txt metrics.txt -- test.sh -- diff --git a/cmd/pint/tests/0064_watch_no_path.txt b/cmd/pint/tests/0064_watch_no_path.txt index 07e2decb..d56f30af 100644 --- a/cmd/pint/tests/0064_watch_no_path.txt +++ b/cmd/pint/tests/0064_watch_no_path.txt @@ -1,4 +1,4 @@ -pint.error --no-color watch --listen=127.0.0.1:6064 +pint.error --no-color watch --listen=127.0.0.1:6064 glob ! stdout . cmp stderr stderr.txt diff --git a/cmd/pint/version.go b/cmd/pint/version.go index 72303263..0b3fb20f 100644 --- a/cmd/pint/version.go +++ b/cmd/pint/version.go @@ -8,7 +8,7 @@ import ( var versionCmd = &cli.Command{ Name: "version", - Usage: "Print version and exit", + Usage: "Print version and exit.", Action: actionVersion, } diff --git a/cmd/pint/watch.go b/cmd/pint/watch.go index 2865c304..414ea0e1 100644 --- a/cmd/pint/watch.go +++ b/cmd/pint/watch.go @@ -38,38 +38,44 @@ const ( ) var watchCmd = &cli.Command{ - Name: "watch", - Usage: "Continuously lint specified files", - Action: actionWatch, + Name: "watch", + Usage: "Run in the foreground and continuesly check specified rules.", + Subcommands: []*cli.Command{ + { + Name: "glob", + Usage: "Check a list of files or directories (can be a glob).", + Action: actionWatch, + }, + }, Flags: []cli.Flag{ &cli.DurationFlag{ Name: intervalFlag, Aliases: []string{"i"}, Value: time.Minute * 10, - Usage: "How often to run all checks", + Usage: "How often to run all checks.", }, &cli.StringFlag{ Name: listenFlag, Aliases: []string{"s"}, Value: ":8080", - Usage: "Listen address for HTTP web server exposing metrics", + Usage: "Listen address for HTTP web server exposing metrics.", }, &cli.StringFlag{ Name: pidfileFlag, Aliases: []string{"p"}, - Usage: "Write pid file to this path", + Usage: "Write pid file to this path.", }, &cli.IntFlag{ Name: maxProblemsFlag, Aliases: []string{"m"}, Value: 0, - Usage: "Maximum number of problems to report on metrics, 0 - no limit", + Usage: "Maximum number of problems to report on metrics, 0 - no limit.", }, &cli.StringFlag{ Name: minSeverityFlag, Aliases: []string{"n"}, Value: strings.ToLower(checks.Bug.String()), - Usage: "Set minimum severity for problems reported via metrics", + Usage: "Set minimum severity for problems reported via metrics.", }, }, } @@ -257,7 +263,6 @@ func newProblemCollector(cfg config.Config, paths []string, minSeverity checks.S func (c *problemCollector) scan(ctx context.Context, workers int, isOffline bool, gen *config.PrometheusGenerator) error { slog.Info("Finding all rules to check", slog.Any("paths", c.paths)) - // nolint: contextcheck entries, err := discovery.NewGlobFinder(c.paths, git.NewPathFilter(nil, nil, c.cfg.Parser.CompileRelaxed())).Find() if err != nil { return err diff --git a/docs/index.md b/docs/index.md index 2813bb80..40e51221 100644 --- a/docs/index.md +++ b/docs/index.md @@ -120,7 +120,9 @@ it will pass `workdir` option to `pint lint`, which means that all files inside ### Ad-hoc -Lint specified files and report any found issue. +Check specified files and report any found issue. +You can pass directory paths and use [glob](https://pkg.go.dev/path/filepath#Match) +patterns as arguments to select files for checking. You can lint selected files: @@ -140,14 +142,68 @@ or both: pint lint path/to/dir file.yml path/file.yml path/dir ``` +Using glob patterns: + +```shell +pint lint path/*.yml path/*.yaml +``` + ### Watch mode -Run pint as a daemon in watch mode: +Run pint as a daemon in watch mode where it continuously checks +all rules found in selected files and exposes metrics about +found problems. + +#### Manually selecting files and directories + +You can tell it to continuously test specific files or directories: + +```shell +pint watch glob $GLOB_1 $GLOB_2 ... $GLOB_N +``` + +Example: + +```shell +pint watch glob /etc/prometheus/rules-*.yml /etc/prometheus/rules.d +``` + +If provide a config file for pint with some Prometheus server definitions +then pint will also run "online" checks for it to, for example, ensure all +time series used inside your alerting rules are still present. +Example config: + +```json +prometheus "local" { + uri = "http://localhost:9090" +} +``` + +#### Getting list of files to check from Prometheus + +You can also point pint directly at a Prometheus server from the config file. +This will make pint query Prometheus API to get the current value of `rule_files` +Prometheus config option and then run checks on all matching files. +This way if you test your rules against a running Prometheus instance then you don't +need to manually specify any paths or directories. + +Usage: ```shell -pint watch rules.yml +pint watch rule_files $prometheus ``` +Where `$prometheus` is the name of `prometheus` configuration block from pint +config file. + +Example: + +```shell +pint watch rule_files local +``` + +#### Accessing watch mode metrics + By default it will start a HTTP server on port `8080` and run all checks every 10 minutes. This can be customised by passing extra flags to the `watch` command. Run `pint watch -h` to see all available flags.