feat: add flint v2 Rust binary#139
Merged
zeitlinger merged 142 commits intomainfrom Apr 10, 2026
Merged
Conversation
Working binary that discovers tools from PATH via built-in registry, runs them in parallel against changed files (merge-base diff), and exits non-zero on failure. Replaces run-linters.sh for standard linters. Supported linters: shellcheck, shfmt, markdownlint, prettier, actionlint, hadolint, codespell, ec, golangci-lint, ruff, ruff-format, biome, biome-format. Flags: --fix (AUTOFIX env), --full, --from-ref, --to-ref, [linters...] Config: optional flint.toml with settings.base_branch and settings.exclude. Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
- Add CheckKind enum to registry to support special checks alongside template-based ones; restructure Check with explicit bin_name field - Add links check: lychee orchestration with diff-mode/full-mode logic, config-change fallback, check_all_local opt-in, and GitHub remap args (same-repo PR → local file paths; fork PR → raw.githubusercontent.com) - Add renovate-deps check: embeds renovate-deps.py via include_str! and runs it as a subprocess; tagged slow=true, supports --fix via AUTOFIX - Add ChecksConfig / LinksConfig / RenovateDepsConfig to config.rs - Parallel runner now captures and defers output; fix mode is serial Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
- Add textlint, cargo-clippy, cargo-fmt to built-in registry - Fix Project-scope checks to respect patterns: skip when no matching files present (prevents cargo-clippy running in non-Rust repos) - Add flint.toml for self-config (links, renovate-deps, excludes) - Wire mise lint/fix/native-lint tasks to build-then-run local binary - Add linting tools to [tools] so mise installs them for CI - Remove bash-backed lint tasks (scripts stay until M5) - Fix clippy and fmt issues caught by dogfooding Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
This was referenced Apr 2, 2026
Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
- Drop npm:textlint and npm:textlint-rule-terminology (mise npm isolation incompatible with textlint plugin architecture; see design doc) - Drop SUPER_LINTER_VERSION and setup:native-lint-tools (superseded by flint binary in M4) - Remove textlint from built-in registry - Add README link to FLINT-V2.md - Regenerate renovate-tracked-deps.json Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
Suppresses per-check output and prints only the summary line: flint: 2 checks failed (shellcheck, prettier) Enabled via --short or FLINT_SHORT=true. Native-lint task now uses --short by default since it is the target called by the CC pre-push hook. Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
In --short mode, partition failed checks by fixability and emit the exact command for fixable ones: `flint --fix prettier shfmt` instead of `fix: prettier, shfmt`. AI callers can execute the command directly without a reasoning step. Non-fixable checks remain under `review:`. Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
This reverts commit 27cde78.
Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
ec (editorconfig-checker) was running on all files including *.rs, *.py, *.go, *.sh, *.json etc. — types that already have dedicated formatters. Add exclude_patterns to the Check registry and set it on ec to defer to those formatters for the types they own. Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
Static exclude_patterns always skipped e.g. *.rs from ec even when cargo-fmt wasn't installed. Replace with excludes_if_active: a list of check names that, when active, cause their patterns to be excluded from ec's file list. ec falls back to checking those files when the dedicated formatter isn't present. Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
shfmt, golangci-lint, and markdownlint don't enforce line length so they don't conflict with ec's max_line_length check. Only exclude from ec when cargo-fmt, ruff-format, biome-format, or prettier are active. Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
--auto fixes all fixable checks, reports outcome, and exits 0 only if everything passed or was fixed. Non-fixable failures (and failed fix attempts) are surfaced under 'review:'. Intended for pre-push hooks and agentic pipelines that have write access. flint: fixed: prettier cargo-fmt | review: shellcheck Update native-lint to use --auto --fast so the CC hook auto-fixes rather than round-tripping through the agent. Docs updated with intended-use-by-context table. Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
Fixes a bug where --auto exiting 0 after fixing would let the push proceed with unfixed commits. Now exits 1 with 'commit before pushing' whenever fixes were applied, so the agent knows to stage and commit the changes first. Only exits 0 if everything was already clean. Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
… differs After replacing install_key with mise_tool, check_active started looking for npm:/pipx:/github: prefixed keys only. Repos (and e2e fixtures) that declare the tool under the bare name (markdownlint-cli2, biome, ruff, etc.) stopped matching. Accept bin_name as a fallback when mise_tool_name is set.
…an/sh Update shfmt e2e test fixtures to declare 'github:mvdan/sh' = 'v3.12.0' so resolve_bin_name returns the correct versioned binary name (shfmt_v3.12.0) that ubi installs. Also restore check_active fallback: when mise_tool_name differs from bin_name, also accept the bare bin_name key so repos declaring the tool under a bare name (markdownlint-cli2, biome, ruff etc.) continue to work.
Prevents one flaky platform (e.g. renovate-deps on macOS) from cancelling the other matrix legs before they complete.
canonicalize() on Windows returns \\?\C:\... verbatim paths. Git and other tools don't handle UNC CWDs correctly, causing git ls-files to return nothing and all e2e checks to silently skip. Strip the prefix back to a regular drive path while keeping the macOS /private fix.
On Windows, mise creates .cmd shim files that cannot be spawned directly via CreateProcessW — they require cmd.exe as the interpreter. Using cmd.exe /C handles both .cmd shims (npm tools: prettier, biome, etc.) and the versioned shfmt_v3.12.0.cmd shim. Applies only on Windows; Unix paths are unchanged. Also remove the temporary debug step from test.yml.
…empty result Windows e2e: strip \\?\ from canonical path before substitution (so tool output using long names matches <REPO> when repo.path() has 8.3 short names), then normalize backslashes to forward slashes so Unix snapshots match Windows tool output. macOS flakiness: renovate occasionally produces empty packageFiles on first run due to transient network issues. Retry up to 3 times with a 3s delay before accepting an empty result.
… normalize - Strip \r\n/\r so Windows tool output (CRLF) matches Unix snapshots - Normalize \ to / in both the output AND the repo path strings before substitution, so both shfmt (backslash paths) and lychee (file:// URIs with forward slashes) get <REPO> substituted correctly
… normalization - cmd.exe /C wrapping for renovate and lychee (same fix as runner.rs) - Strip //?/ UNC prefix that leaks through after backslash normalization (e.g. cargo-fmt outputs Diff in //?/C:/... → strip to Diff in C:/...) - Collapse file:///<REPO> → file://<REPO> to match Unix snapshots
- Extract spawn_command() into linters/mod.rs — single place for the cmd.exe /C wrapping; all three callers (runner, lychee, renovate_deps) now use it instead of duplicating the cfg(windows) block. - Add dunce crate; replace manual \\?\ stripping in main.rs and e2e.rs with dunce::canonicalize() which handles both macOS /private/ symlinks and Windows verbatim paths in one call. - Extract canonical_repo_path() and normalize_output() helpers in e2e.rs so all Windows path normalization (CRLF, \→/, //?/, file:///) is in one place.
…tnet fixtures PE detection: some tools (ktlint) are native PE binaries without .exe extension. cmd.exe can't resolve them and the mise shim also fails. Detect MZ magic bytes and execute such binaries directly by full path, falling back to cmd.exe /C for .cmd shims. dotnet-format fixtures: add .editorconfig with end_of_line = lf so dotnet uses LF on Windows, matching the Unix test snapshots.
spawn_command: detect self-executing JARs (#!/ magic + >1MB) and invoke via 'java -jar' instead of cmd.exe. Handles ktlint which ships as a Unix self-executing JAR — cmd.exe can't run it and the mise shim fails. dotnet-format fixtures: fix .editorconfig syntax (root=true, [*.cs] section) and add end_of_line=lf to prevent dotnet on Windows from suggesting CRLF-based whitespace fixes.
…et output Replace global \→/ with a regex that only normalizes backslashes flanked by path-component characters (alphanumeric, ., /, >, -). This preserves dotnet's \s whitespace notation in diagnostic strings like Insert '\s\s\s\s' while still normalizing actual path separators like <REPO>\script.sh.orig.
Replaces the flanking-char regex with a simpler approach: match the entire <REPO>path... sequence and replace all \ within it. This correctly handles multi-level paths (e.g. <REPO>\src\lib.rs) while leaving dotnet's \s\s\s\s whitespace notation untouched since it never appears inside a <REPO>-prefixed path.
Replace <REPO>-scoped regex with a character-level walk that converts every \ to / except when inside single quotes. This handles: - Relative paths: .github\workflows → .github/workflows (actionlint, renovate) - Cargo/rustc paths: --> src\lib.rs → --> src/lib.rs - Lychee: [.\README.md] → [./README.md] And correctly preserves: - dotnet whitespace notation: Insert '\s\s\s\s' (inside single quotes)
Member
Author
|
@martincostello finally passing with all platforms |
martincostello
approved these changes
Apr 10, 2026
This was referenced Apr 10, 2026
zeitlinger
pushed a commit
that referenced
this pull request
Apr 13, 2026
## flint v0.20.0 — Rust rewrite flint has been rewritten from scratch in Rust. The bash + Docker stack is replaced by a fast, cross-platform native binary with no container dependency. ### Highlights - **Native binary** — no Docker, no bash wrappers; runs anywhere mise can install a Rust crate - **Parallel linting** — all checks run concurrently - **Diff-aware** — only checks files changed since the merge base by default (`--full` for everything) - **`flint update`** — migrates obsolete `mise.toml` tool keys automatically (e.g. `ubi:` → `github:`, `npm:markdownlint-cli` → `npm:markdownlint-cli2`) - **`flint hook install`** — installs a pre-commit hook without any mise task knowledge - **New linters**: `gofmt`, `google-java-format`, `ktlint`, `dotnet-format`, `markdownlint-cli2`, `xmllint` (via `cargo:xmloxide`), `license-header` (pure-Rust, no binary) - **Windows support** — ktlint self-executing JAR handled via explicit `java -jar` invocation ### Migration See [AGENTS-V2.md](https://github.com/grafana/flint/blob/main/AGENTS-V2.md) and [README.md](https://github.com/grafana/flint/blob/main/README.md) for full setup instructions. Quick reference for existing consumers: ```toml [tools] # While installing from source (pre-crates.io release): "cargo:https://github.com/grafana/flint" = "branch:main" [env] FLINT_CONFIG_DIR = ".github/config" [tasks.lint] run = "flint run" [tasks."lint:fix"] run = "flint run --fix" ``` Remove: `lint:super-linter`, `lint:links`, `lint:renovate-deps`, `setup:native-lint-tools`, `setup:pre-commit-hook` tasks. Run `flint update` to auto-migrate any obsolete tool keys. > [!NOTE] > The changelog below includes entries from the legacy v1 bash era — see [README-V1.md](https://github.com/grafana/flint/blob/main/README-V1.md) for v1 docs. --- ## [0.20.0](flint-v0.19.0...flint-v0.20.0) (2026-04-13) ### Features * add flint v2 Rust binary ([#139](#139)) ([19f2b25](19f2b25)) * add native linting mode and version mapping infrastructure ([#93](#93)) ([24b06da](24b06da)) * add Renovate shareable preset for consuming repos ([#17](#17)) ([8a06590](8a06590)) * consolidate link checking and add autofix flags ([#7](#7)) ([086a5e9](086a5e9)) * flint update command, explicit JAR flag, v0.20.0 ([#146](#146)) ([b43bf52](b43bf52)) * handle line-number anchors and issue comments globally ([#56](#56)) ([cf751df](cf751df)) * **links:** add GitHub URL remaps for line-number and fragment anchors ([#28](#28)) ([5b59065](5b59065)) * **links:** auto-remap base-branch GitHub URLs to PR branch ([#18](#18)) ([dd6cc61](dd6cc61)) * **renovate:** support SHA-pinned URLs in Renovate preset ([#21](#21)) ([4fd1f28](4fd1f28)) * **super-linter:** default to slim image ([#24](#24)) ([c8eeab8](c8eeab8)) * support NATIVE env var for container-free linting ([#107](#107)) ([0a8193d](0a8193d)) ### Bug Fixes * activate mise environment in native lint mode ([#123](#123)) ([d0fec45](d0fec45)) * add 'mise run fix' hint to lint failure output ([#90](#90)) ([5b4ad5d](5b4ad5d)) * decouple version mapping generation from pinned super-linter version ([#112](#112)) ([5370e77](5370e77)) * **deps:** update rust crate crossterm to 0.29 ([#156](#156)) ([c59ae3e](c59ae3e)) * **deps:** update rust crate similar to v3 ([#160](#160)) ([684be4e](684be4e)) * **deps:** update rust crate toml to v1 ([#161](#161)) ([3aae614](3aae614)) * **deps:** update rust crate toml_edit to 0.25 ([#158](#158)) ([42d9efd](42d9efd)) * exclude GitHub compare links from lychee checks ([#10](#10)) ([e714608](e714608)) * fail native lint when enabled tools are missing ([#111](#111)) ([163bb6b](163bb6b)) * improve link checker reliability against GitHub rate limiting ([#95](#95)) ([7a5282d](7a5282d)) * include staged files in native lint file list ([#135](#135)) ([34412d6](34412d6)) * **links:** add regex anchors to remap patterns ([#19](#19)) ([2e17348](2e17348)) * native lint in worktrees, trust toml, use ec binary, drop isort ([#134](#134)) ([8594bba](8594bba)) * **release-please:** fix footer not appearing on release PRs ([#40](#40)) ([d7a55e4](d7a55e4)) * remap same-repo GitHub URLs to local file paths ([#100](#100)) ([b4feadd](b4feadd)) * **renovate-deps:** forward GITHUB_TOKEN as GITHUB_COM_TOKEN ([#132](#132)) ([4d6510b](4d6510b)) * replace broken release-please PR comment with docs ([#12](#12)) ([817b37d](817b37d)) * run shellcheck on .bats files in native mode ([#137](#137)) ([a4fd3f8](a4fd3f8)) * strip Scroll to Text Fragment anchors in link checks ([#86](#86)) ([b630cdf](b630cdf)) * tighten markdownlint config for native mode ([#106](#106)) ([6ef25b2](6ef25b2)) * use remap instead of exclude for issue comment anchors ([#58](#58)) ([656f355](656f355)) --- > [!IMPORTANT] > Close and reopen this PR to trigger CI checks. Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This was referenced Apr 16, 2026
Closed
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Introduces the
flintRust binary: a mise-native lint orchestrator that replaces the v1 bash task scripts.How it works: reads installed tools from
mise.toml, maps them to a built-in check registry, runs checks against changed files (merge-base diff) in parallel. Special checks (lychee links, renovate-deps) are implemented in Rust.File breakdown
282 files changed — the count is misleading without context:
tests/— e2e test fixtures (70 test cases × ~3-4 files each)src/— Rust sourceThe 23 linters covered by e2e tests: actionlint, biome, biome-format, cargo-clippy, cargo-fmt, codespell, dotnet-format, editorconfig-checker, gofmt, golangci-lint, google-java-format, hadolint, ktlint, license-header, lychee, markdownlint-cli2, prettier, renovate-deps, ruff, ruff-format, shellcheck, shfmt, plus general cases.
What's not in this PR
Deferred features:
flint hook install— installs a git pre-commit hook; replaces the per-repomise run setup:pre-commit-hooktask with something self-contained in the CLIcheck_task/fix_taskinflint.toml— allows a fast script (e.g. regex/Python) as the check with a slow canonical fixer (e.g. Gradle); motivating use case: javaagent'sStaticImportFormatter--config-pathtakes a directory, not a file; needs a directory-injection variant in the registry APILow-priority linters (no consuming repo needs them yet):
merge-conflict-markers— pure-Rust special checkdotenv-linter,go-mod-tidy,xmllintPost-merge:
tasks/lint/) — retire once consumer PRs are mergedgithub:grafana/flintregistration — cut after this PR merges; consumer repos switch from branch tracking to a pinned versionConsumer migration status
All 7 consumer PRs green — validated across Rust, Go, Java, Kotlin, Python, .NET, Shell, Dockerfile:
Test plan
flint listshows all registry entries with correct installed/missing statusRelease-As: 0.20.0