diff --git a/cli/cli.go b/cli/cli.go index bf6ff04b..243a8439 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -37,6 +37,8 @@ type Format struct { CpuProfile string `optional:"" help:"The file into which a cpu profile will be written."` + Ci bool `help:"Runs treefmt in a CI mode, enabling --no-cache, --fail-on-change and adjusting some other settings best suited to a CI use case."` + formatters map[string]*format.Formatter globalExcludes []glob.Glob diff --git a/cli/format.go b/cli/format.go index 1aaa0e59..dc1d6732 100644 --- a/cli/format.go +++ b/cli/format.go @@ -34,6 +34,37 @@ func (f *Format) Run() (err error) { // set log level and other options f.configureLogging() + // ci mode + if f.Ci { + f.NoCache = true + f.FailOnChange = true + + // ensure INFO level + if f.Verbosity < 1 { + f.Verbosity = 1 + } + // reconfigure logging + f.configureLogging() + + log.Info("ci mode enabled") + + startAfter := time.Now(). + // truncate to second precision + Truncate(time.Second). + // add one second + Add(1 * time.Second). + // a little extra to ensure we don't start until the next second + Add(10 * time.Millisecond) + + log.Debugf("waiting until %v before continuing", startAfter) + + // Wait until we tick over into the next second before processing to ensure our EPOCH level modtime comparisons + // for change detection are accurate. + // This can fail in CI between checkout and running treefmt if everything happens too quickly. + // For humans, the second level precision should not be a problem as they are unlikely to run treefmt in sub-second succession. + <-time.After(time.Until(startAfter)) + } + // cpu profiling if f.CpuProfile != "" { cpuProfile, err := os.Create(f.CpuProfile) diff --git a/docs/usage.md b/docs/usage.md index 2e09bd2c..c9f4fbeb 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -31,6 +31,7 @@ Flags: . --stdin Format the context passed in via stdin. --cpu-profile=STRING The file into which a cpu profile will be written. + --ci Runs treefmt in a CI mode, enabling --no-cache, --fail-on-change and adjusting some other settings best suited to a CI use case. ``` ## Arguments @@ -112,13 +113,22 @@ Format the context passed in via stdin. The file into which a cpu profile will be written. +### `--ci` + +Runs treefmt in a CI mode which does the following: + +- ensures `INFO` level logging at a minimum +- enables `--no-cache` and `--fail-on-change` +- introduces a small startup delay so we do not start processing until the second after the process started, thereby + ensuring the accuracy of our change detection based on second-level `modtime`. + ### `-V, --version` Print version. ## CI integration -Typically, you would use `treefmt` in CI with the `--fail-on-change` and `--no-cache flags`. +Typically, you would use `treefmt` in CI with the `--ci` flag. You can configure a `treefmt` job in a GitHub pipeline for Ubuntu with `nix-shell` like this: @@ -141,5 +151,5 @@ jobs: name: nix-community authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" - name: treefmt - run: nix-shell -p treefmt --run "treefmt --fail-on-change --no-cache" + run: nix-shell -p treefmt --run "treefmt --ci" ```