diff --git a/.github/agents/knowledge/architecture.md b/.github/agents/knowledge/architecture.md index a3ad6db..dd3e230 100644 --- a/.github/agents/knowledge/architecture.md +++ b/.github/agents/knowledge/architecture.md @@ -48,7 +48,11 @@ A check is expanded to all matching files when: - it was not active at the merge base, meaning its tool was newly added to `mise.toml` - its resolved tool version changed in `mise.toml` +- the pinned `github:grafana/flint` version changed in `mise.toml`; this expands + every active check because the runner/orchestrator changed - its registered `.linter_config(...)` file changed under `FLINT_CONFIG_DIR` +- another supported baseline config changed, such as `.editorconfig` for + `editorconfig-checker` - `flint.toml` changed under `[settings]` - `flint.toml` changed the check-specific section for a special check @@ -57,3 +61,8 @@ Explicit `--full` bypasses this selection because every check is already using the all-files list. Config-change triggers use the raw git change list before `settings.exclude` is applied, so excluded config paths still expand the affected check. + +For linters where flint passes a config file explicitly, the registered +flint-managed file is authoritative. Known alternate upstream config files are +hard failures for active checks, including section-based configs like +`pyproject.toml` only when the relevant tool section exists. diff --git a/.github/agents/knowledge/linters.md b/.github/agents/knowledge/linters.md index ff90b75..6deb5e5 100644 --- a/.github/agents/knowledge/linters.md +++ b/.github/agents/knowledge/linters.md @@ -66,6 +66,13 @@ Check::file("rumdl", "rumdl check {FILE}", &["*.md"]) Look up the tool's `--help` or man page for the config flag name and expected argument type before adding `.linter_config`. +When a tool supports other config filenames, register them with +`.unsupported_configs(...)` so flint fails loudly instead of letting the tool +auto-discover a config that flint does not baseline or inject. Use +`.baseline_configs(...)` for config-like files that should force an all-files +run when changed, even if they are not passed via `.linter_config(...)`; for +example, `editorconfig-checker` treats `.editorconfig` as a baseline config. + For checks that need custom logic (not a simple command template), add a module under `src/linters/` and use `CheckKind::Special`. diff --git a/docs/cli.md b/docs/cli.md index d5cf544..b62dc3a 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -48,8 +48,12 @@ A check runs against all matching files when: - the check is newly active because its tool was added to `mise.toml` - the check's tool version changed in `mise.toml` +- the pinned `github:grafana/flint` version changed in `mise.toml`, which + expands all active checks - the check's flint-managed config file changed, such as `.shellcheckrc` or `.yamllint.yml` in `FLINT_CONFIG_DIR` +- another supported baseline config for the check changed, such as + `.editorconfig` for `editorconfig-checker` - `flint.toml` changed under `[settings]` - `flint.toml` changed the check-specific config for a special check, such as `[checks.links]` or `[checks.renovate-deps]` @@ -60,6 +64,12 @@ have changed. Config-file triggers are detected from the raw git change list, so they still apply when the config path itself is excluded from ordinary lint file selection. +Flint intentionally supports one canonical config filename per linter when it +passes config paths explicitly. If an active linter has a known alternate +upstream config file, Flint fails before running the linter instead of silently +ignoring or partially auto-discovering that config. Move the config to the +Flint-managed filename under `FLINT_CONFIG_DIR`, or remove the alternate file. + **`--short` output** — failed checks partitioned by fixability, fixable ones expressed as the exact command to run: diff --git a/src/main.rs b/src/main.rs index e417cc7..e8bdaec 100644 --- a/src/main.rs +++ b/src/main.rs @@ -251,6 +251,20 @@ async fn run( out }; + if let Some((check, config)) = active.iter().find_map(|check| { + unsupported_config(check, project_root, config_dir).map(|config| (*check, config)) + }) { + let canonical = check + .linter_config + .map(|(file, _)| format!("FLINT_CONFIG_DIR/{file}")) + .unwrap_or_else(|| "the flint-managed config".to_string()); + eprintln!( + "flint: unsupported {name} config file found: {config}\n Flint only supports {canonical} for {name}. Move the config to the supported location or remove the alternate file.", + name = check.name + ); + std::process::exit(1); + } + if args.verbose { let names: Vec<&str> = active.iter().map(|c| c.name).collect(); if names.is_empty() { @@ -566,6 +580,10 @@ fn baseline_check_names( let changed = changed_rel_paths(file_list, project_root); let previous_tools = registry::read_mise_tools_at_ref(project_root, merge_base); + if registry::flint_version_changed(&previous_tools, current_tools) { + return active.iter().map(|check| check.name.to_string()).collect(); + } + let flint_config = config_rel_path(project_root, config_dir, "flint.toml"); let flint_config_changed = changed.contains(&flint_config); let flint_toml = @@ -581,14 +599,26 @@ fn baseline_check_names( || (matches!(check.kind, CheckKind::Special(_)) && change.check_changed(check.name)) }) - || check.linter_config.is_some_and(|(file, _)| { - changed.contains(&config_rel_path(project_root, config_dir, file)) + || check.baseline_configs.iter().any(|config| { + changed.contains(&config_file_rel_path(project_root, config_dir, config)) }) }) .map(|check| check.name.to_string()) .collect() } +fn unsupported_config( + check: ®istry::Check, + project_root: &Path, + config_dir: &Path, +) -> Option { + check + .unsupported_configs + .iter() + .find(|config| config_present(project_root, config_dir, config)) + .map(|config| config_file_rel_path(project_root, config_dir, config)) +} + struct FlintTomlChange { current: toml::Value, previous: toml::Value, @@ -623,6 +653,30 @@ fn read_toml_file(path: &Path) -> toml::Value { .unwrap_or(toml::Value::Table(Default::default())) } +fn config_present(project_root: &Path, config_dir: &Path, config: ®istry::ConfigFile) -> bool { + let path = config_file_abs_path(project_root, config_dir, config); + match config.presence { + registry::ConfigMatch::Exists => path.exists(), + registry::ConfigMatch::TomlSection(section) => { + toml_section(&read_toml_file(&path), section).is_some() + } + registry::ConfigMatch::IniSection(section) => ini_section_exists(&path, section), + } +} + +fn ini_section_exists(path: &Path, section: &str) -> bool { + let Ok(content) = std::fs::read_to_string(path) else { + return false; + }; + content.lines().any(|line| { + let trimmed = line.trim(); + trimmed + .strip_prefix('[') + .and_then(|rest| rest.strip_suffix(']')) + .is_some_and(|name| name.trim() == section) + }) +} + fn read_toml_at_ref(project_root: &Path, git_ref: &str, rel_path: &str) -> toml::Value { let spec = format!("{git_ref}:{rel_path}"); std::process::Command::new("git") @@ -668,6 +722,34 @@ fn config_rel_path(project_root: &Path, config_dir: &Path, file: &str) -> String .unwrap_or_else(|_| normalize_path(&PathBuf::from(file))) } +fn config_file_abs_path( + project_root: &Path, + config_dir: &Path, + config: ®istry::ConfigFile, +) -> PathBuf { + match config.base { + registry::ConfigBase::ProjectRoot => project_root.join(config.path), + registry::ConfigBase::ConfigDir => { + if config_dir.is_absolute() { + config_dir.join(config.path) + } else { + project_root.join(config_dir).join(config.path) + } + } + } +} + +fn config_file_rel_path( + project_root: &Path, + config_dir: &Path, + config: ®istry::ConfigFile, +) -> String { + let path = config_file_abs_path(project_root, config_dir, config); + path.strip_prefix(project_root) + .map(normalize_path) + .unwrap_or_else(|_| normalize_path(&PathBuf::from(config.path))) +} + fn normalize_path(path: &Path) -> String { path.components() .map(|component| component.as_os_str().to_string_lossy()) diff --git a/src/registry/checks.rs b/src/registry/checks.rs index 732518c..5ba2478 100644 --- a/src/registry/checks.rs +++ b/src/registry/checks.rs @@ -1,6 +1,69 @@ -use super::types::{Check, SpecialKind}; +use super::types::{Check, ConfigFile, SpecialKind}; use crate::linters::renovate_deps::RENOVATE_CONFIG_PATTERNS; +const TOOL_RUMDL: &[&str] = &["tool", "rumdl"]; +const TOOL_CODESPELL: &[&str] = &["tool", "codespell"]; +const TOOL_RUFF: &[&str] = &["tool", "ruff"]; + +const SHELLCHECK_BASELINE_CONFIGS: &[ConfigFile] = &[ConfigFile::config_dir(".shellcheckrc")]; +const SHELLCHECK_UNSUPPORTED_CONFIGS: &[ConfigFile] = &[ + ConfigFile::config_dir("shellcheckrc"), + ConfigFile::project("shellcheckrc"), +]; +const RUMDL_BASELINE_CONFIGS: &[ConfigFile] = &[ConfigFile::config_dir(".rumdl.toml")]; +const RUMDL_UNSUPPORTED_CONFIGS: &[ConfigFile] = &[ + ConfigFile::config_dir("rumdl.toml"), + ConfigFile::project("rumdl.toml"), + ConfigFile::project(".config/rumdl.toml"), + ConfigFile::project_toml_section("pyproject.toml", TOOL_RUMDL), +]; +const YAMLLINT_BASELINE_CONFIGS: &[ConfigFile] = &[ConfigFile::config_dir(".yamllint.yml")]; +const YAMLLINT_UNSUPPORTED_CONFIGS: &[ConfigFile] = &[ + ConfigFile::config_dir(".yamllint"), + ConfigFile::config_dir(".yamllint.yaml"), + ConfigFile::project(".yamllint"), + ConfigFile::project(".yamllint.yaml"), +]; +const ACTIONLINT_BASELINE_CONFIGS: &[ConfigFile] = &[ConfigFile::config_dir("actionlint.yml")]; +const ACTIONLINT_UNSUPPORTED_CONFIGS: &[ConfigFile] = &[ + ConfigFile::config_dir("actionlint.yaml"), + ConfigFile::project(".github/actionlint.yaml"), + ConfigFile::project(".github/actionlint.yml"), +]; +const HADOLINT_BASELINE_CONFIGS: &[ConfigFile] = &[ConfigFile::config_dir(".hadolint.yaml")]; +const HADOLINT_UNSUPPORTED_CONFIGS: &[ConfigFile] = &[ + ConfigFile::config_dir(".hadolint.yml"), + ConfigFile::project(".hadolint.yml"), +]; +const CODESPELL_BASELINE_CONFIGS: &[ConfigFile] = &[ConfigFile::config_dir(".codespellrc")]; +const CODESPELL_UNSUPPORTED_CONFIGS: &[ConfigFile] = &[ + ConfigFile::project_ini_section("setup.cfg", "codespell"), + ConfigFile::project_toml_section("pyproject.toml", TOOL_CODESPELL), +]; +const EDITORCONFIG_CHECKER_BASELINE_CONFIGS: &[ConfigFile] = &[ + ConfigFile::config_dir(".editorconfig-checker.json"), + ConfigFile::project(".editorconfig"), +]; +const EDITORCONFIG_CHECKER_UNSUPPORTED_CONFIGS: &[ConfigFile] = &[ + ConfigFile::config_dir(".ecrc"), + ConfigFile::project(".ecrc"), +]; +const GOLANGCI_LINT_BASELINE_CONFIGS: &[ConfigFile] = &[ConfigFile::config_dir(".golangci.yml")]; +const GOLANGCI_LINT_UNSUPPORTED_CONFIGS: &[ConfigFile] = &[ + ConfigFile::config_dir(".golangci.yaml"), + ConfigFile::config_dir(".golangci.toml"), + ConfigFile::config_dir(".golangci.json"), + ConfigFile::project(".golangci.yaml"), + ConfigFile::project(".golangci.toml"), + ConfigFile::project(".golangci.json"), +]; +const RUFF_BASELINE_CONFIGS: &[ConfigFile] = &[ConfigFile::config_dir("ruff.toml")]; +const RUFF_UNSUPPORTED_CONFIGS: &[ConfigFile] = &[ + ConfigFile::config_dir(".ruff.toml"), + ConfigFile::project(".ruff.toml"), + ConfigFile::project_toml_section("pyproject.toml", TOOL_RUFF), +]; + /// Built-in linter registry. /// /// # Naming convention @@ -20,6 +83,8 @@ fn check_shellcheck() -> Check { &["*.sh", "*.bash", "*.bats"], ) .linter_config(".shellcheckrc", "--rcfile") + .baseline_configs(SHELLCHECK_BASELINE_CONFIGS) + .unsupported_configs(SHELLCHECK_UNSUPPORTED_CONFIGS) .desc("Lint shell scripts for common mistakes") .style() } @@ -36,6 +101,8 @@ fn check_rumdl() -> Check { Check::file("rumdl", "rumdl check {FILE}", &["*.md"]) .fix("rumdl check --fix {FILE}") .linter_config(".rumdl.toml", "--config") + .baseline_configs(RUMDL_BASELINE_CONFIGS) + .unsupported_configs(RUMDL_UNSUPPORTED_CONFIGS) .formatter() .desc("Lint Markdown files for style and consistency") .mise_tool("rumdl") @@ -45,6 +112,8 @@ fn check_yaml_lint() -> Check { Check::files("yaml-lint", "yaml-lint {FILES}", &["*.yml", "*.yaml"]) .fix("yaml-lint --fix {FILES}") .linter_config(".yamllint.yml", "-c") + .baseline_configs(YAMLLINT_BASELINE_CONFIGS) + .unsupported_configs(YAMLLINT_UNSUPPORTED_CONFIGS) .formatter() .desc("Lint YAML files for style and consistency") .mise_tool("cargo:yaml-lint") @@ -57,6 +126,8 @@ fn check_actionlint() -> Check { &[".github/workflows/*.yml", ".github/workflows/*.yaml"], ) .linter_config("actionlint.yml", "-config-file") + .baseline_configs(ACTIONLINT_BASELINE_CONFIGS) + .unsupported_configs(ACTIONLINT_UNSUPPORTED_CONFIGS) .desc("Lint GitHub Actions workflow files") .style() } @@ -68,6 +139,8 @@ fn check_hadolint() -> Check { &["Dockerfile", "Dockerfile.*", "*.dockerfile"], ) .linter_config(".hadolint.yaml", "--config") + .baseline_configs(HADOLINT_BASELINE_CONFIGS) + .unsupported_configs(HADOLINT_UNSUPPORTED_CONFIGS) .desc("Lint Dockerfiles") .style() } @@ -82,6 +155,8 @@ fn check_codespell() -> Check { Check::files("codespell", "codespell {FILES}", &["*"]) .fix("codespell --write-changes {FILES}") .linter_config(".codespellrc", "--config") + .baseline_configs(CODESPELL_BASELINE_CONFIGS) + .unsupported_configs(CODESPELL_UNSUPPORTED_CONFIGS) .desc("Check for common spelling mistakes") .mise_tool("pipx:codespell") } @@ -95,6 +170,8 @@ fn check_editorconfig_checker() -> Check { .mise_tool("editorconfig-checker") .defer_to_formatters() .linter_config(".editorconfig-checker.json", "-config") + .baseline_configs(EDITORCONFIG_CHECKER_BASELINE_CONFIGS) + .unsupported_configs(EDITORCONFIG_CHECKER_UNSUPPORTED_CONFIGS) .desc("Check files comply with EditorConfig settings") } @@ -105,6 +182,8 @@ fn check_golangci_lint() -> Check { &["*.go"], ) .linter_config(".golangci.yml", "--config") + .baseline_configs(GOLANGCI_LINT_BASELINE_CONFIGS) + .unsupported_configs(GOLANGCI_LINT_UNSUPPORTED_CONFIGS) .desc("Lint Go code; uses --new-from-rev to scope analysis to changed code") .lang() } @@ -113,6 +192,8 @@ fn check_ruff() -> Check { Check::file("ruff", "ruff check {FILE}", &["*.py"]) .fix("ruff check --fix {FILE}") .linter_config("ruff.toml", "--config") + .baseline_configs(RUFF_BASELINE_CONFIGS) + .unsupported_configs(RUFF_UNSUPPORTED_CONFIGS) .desc("Lint Python code") .mise_tool("pipx:ruff") .lang() @@ -123,6 +204,8 @@ fn check_ruff_format() -> Check { .bin("ruff") .fix("ruff format {FILE}") .linter_config("ruff.toml", "--config") + .baseline_configs(RUFF_BASELINE_CONFIGS) + .unsupported_configs(RUFF_UNSUPPORTED_CONFIGS) .formatter() .desc("Format Python code") .mise_tool("pipx:ruff") diff --git a/src/registry/mise.rs b/src/registry/mise.rs index 37e6e5c..06091e0 100644 --- a/src/registry/mise.rs +++ b/src/registry/mise.rs @@ -100,6 +100,15 @@ pub fn tool_version_changed( previous.is_some() && current.is_some() && previous != current } +pub fn flint_version_changed( + previous_tools: &HashMap, + current_tools: &HashMap, +) -> bool { + let previous = previous_tools.get("github:grafana/flint"); + let current = current_tools.get("github:grafana/flint"); + previous.is_some() && current.is_some() && previous != current +} + fn declared_tool_version<'a>( check: &Check, mise_tools: &'a HashMap, diff --git a/src/registry/mod.rs b/src/registry/mod.rs index fdda651..089b048 100644 --- a/src/registry/mod.rs +++ b/src/registry/mod.rs @@ -5,10 +5,16 @@ mod resolve; mod types; pub use checks::builtin; -pub use mise::{check_active, read_mise_tools, read_mise_tools_at_ref, tool_version_changed}; +pub use mise::{ + check_active, flint_version_changed, read_mise_tools, read_mise_tools_at_ref, + tool_version_changed, +}; pub use obsolete::{OBSOLETE_KEYS, find_obsolete_key, find_unsupported_key}; pub use resolve::binary_on_path; -pub use types::{Category, Check, CheckKind, FixBehavior, RunPolicy, Scope, SpecialKind}; +pub use types::{ + Category, Check, CheckKind, ConfigBase, ConfigFile, ConfigMatch, FixBehavior, RunPolicy, Scope, + SpecialKind, +}; /// Returns the set of `mise.toml` tool keys that name language runtimes/SDKs /// (e.g. `rust`, `go`, `dotnet`). Derived from registry checks marked diff --git a/src/registry/types.rs b/src/registry/types.rs index c9b83f8..683e8b1 100644 --- a/src/registry/types.rs +++ b/src/registry/types.rs @@ -89,6 +89,12 @@ pub struct Check { /// When set, look for `(filename, flag)` in config_dir: if the file exists, inject /// `flag ` into the command right after the binary name. pub linter_config: Option<(&'static str, &'static str)>, + /// Config-like files that affect this check's results and should trigger + /// a one-time all-files baseline run when changed. + pub baseline_configs: &'static [ConfigFile], + /// Known upstream config locations that flint does not support for this + /// check. Their presence is a hard failure to avoid silent config drift. + pub unsupported_configs: &'static [ConfigFile], /// This check is a formatter — it owns certain file types for formatting purposes. pub is_formatter: bool, /// Skip files owned by active formatters (used by ec to avoid double-checking). @@ -196,6 +202,8 @@ impl Check { patterns, excludes_if_active: &[], linter_config: None, + baseline_configs: &[], + unsupported_configs: &[], is_formatter: false, defers_to_formatters: false, activate_unconditionally: false, @@ -226,6 +234,8 @@ impl Check { patterns: &[], excludes_if_active: &[], linter_config: None, + baseline_configs: &[], + unsupported_configs: &[], is_formatter: false, defers_to_formatters: false, activate_unconditionally: false, @@ -391,4 +401,71 @@ impl Check { self.linter_config = Some((file, flag)); self } + + pub fn baseline_configs(mut self, files: &'static [ConfigFile]) -> Self { + self.baseline_configs = files; + self + } + + pub fn unsupported_configs(mut self, files: &'static [ConfigFile]) -> Self { + self.unsupported_configs = files; + self + } +} + +#[derive(Debug, Clone, Copy)] +pub enum ConfigBase { + ProjectRoot, + ConfigDir, +} + +#[derive(Debug, Clone, Copy)] +pub enum ConfigMatch { + Exists, + TomlSection(&'static [&'static str]), + IniSection(&'static str), +} + +#[derive(Debug, Clone, Copy)] +pub struct ConfigFile { + pub base: ConfigBase, + pub path: &'static str, + pub presence: ConfigMatch, +} + +impl ConfigFile { + pub const fn project(path: &'static str) -> Self { + Self { + base: ConfigBase::ProjectRoot, + path, + presence: ConfigMatch::Exists, + } + } + + pub const fn config_dir(path: &'static str) -> Self { + Self { + base: ConfigBase::ConfigDir, + path, + presence: ConfigMatch::Exists, + } + } + + pub const fn project_toml_section( + path: &'static str, + section: &'static [&'static str], + ) -> Self { + Self { + base: ConfigBase::ProjectRoot, + path, + presence: ConfigMatch::TomlSection(section), + } + } + + pub const fn project_ini_section(path: &'static str, section: &'static str) -> Self { + Self { + base: ConfigBase::ProjectRoot, + path, + presence: ConfigMatch::IniSection(section), + } + } } diff --git a/src/runner.rs b/src/runner.rs index cf75357..2e41288 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -723,6 +723,8 @@ mod tests { patterns, excludes_if_active: &[], linter_config: None, + baseline_configs: &[], + unsupported_configs: &[], is_formatter: false, defers_to_formatters: false, activate_unconditionally: false, diff --git a/tests/cases/general/baseline-editorconfig-change/changes/.editorconfig b/tests/cases/general/baseline-editorconfig-change/changes/.editorconfig new file mode 100644 index 0000000..9da00de --- /dev/null +++ b/tests/cases/general/baseline-editorconfig-change/changes/.editorconfig @@ -0,0 +1,8 @@ +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/tests/cases/general/baseline-editorconfig-change/files/.editorconfig b/tests/cases/general/baseline-editorconfig-change/files/.editorconfig new file mode 100644 index 0000000..a0c37f4 --- /dev/null +++ b/tests/cases/general/baseline-editorconfig-change/files/.editorconfig @@ -0,0 +1,8 @@ +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +trim_trailing_whitespace = false +insert_final_newline = true diff --git a/tests/cases/general/baseline-editorconfig-change/files/hello.txt b/tests/cases/general/baseline-editorconfig-change/files/hello.txt new file mode 100644 index 0000000..5d1cd3a --- /dev/null +++ b/tests/cases/general/baseline-editorconfig-change/files/hello.txt @@ -0,0 +1,2 @@ +hello +world diff --git a/tests/cases/general/baseline-editorconfig-change/files/mise.toml b/tests/cases/general/baseline-editorconfig-change/files/mise.toml new file mode 100644 index 0000000..972b254 --- /dev/null +++ b/tests/cases/general/baseline-editorconfig-change/files/mise.toml @@ -0,0 +1,2 @@ +[tools] +editorconfig-checker = "latest" diff --git a/tests/cases/general/baseline-editorconfig-change/test.toml b/tests/cases/general/baseline-editorconfig-change/test.toml new file mode 100644 index 0000000..f40df89 --- /dev/null +++ b/tests/cases/general/baseline-editorconfig-change/test.toml @@ -0,0 +1,13 @@ +[expected] +args = "run editorconfig-checker" +exit = 1 +stderr = ''' +[editorconfig-checker] +hello.txt: + 2: Trailing whitespace + +1 errors found + +flint: 1 check failed (editorconfig-checker) +💡 Try `flint run --fix` to auto-fix lint issues, then re-run `flint run` to verify. +''' diff --git a/tests/cases/general/baseline-flint-upgrade/changes/mise.toml b/tests/cases/general/baseline-flint-upgrade/changes/mise.toml new file mode 100644 index 0000000..f1438f4 --- /dev/null +++ b/tests/cases/general/baseline-flint-upgrade/changes/mise.toml @@ -0,0 +1,3 @@ +[tools] +shellcheck = "0.11.0" +"github:grafana/flint" = "0.20.3" diff --git a/tests/cases/general/baseline-flint-upgrade/files/bad.sh b/tests/cases/general/baseline-flint-upgrade/files/bad.sh new file mode 100644 index 0000000..706457d --- /dev/null +++ b/tests/cases/general/baseline-flint-upgrade/files/bad.sh @@ -0,0 +1,2 @@ +#!/bin/bash +echo $1 diff --git a/tests/cases/general/baseline-flint-upgrade/files/mise.toml b/tests/cases/general/baseline-flint-upgrade/files/mise.toml new file mode 100644 index 0000000..0040b48 --- /dev/null +++ b/tests/cases/general/baseline-flint-upgrade/files/mise.toml @@ -0,0 +1,3 @@ +[tools] +shellcheck = "0.11.0" +"github:grafana/flint" = "0.20.2" diff --git a/tests/cases/general/baseline-flint-upgrade/test.toml b/tests/cases/general/baseline-flint-upgrade/test.toml new file mode 100644 index 0000000..6ee2c8d --- /dev/null +++ b/tests/cases/general/baseline-flint-upgrade/test.toml @@ -0,0 +1,19 @@ +[expected] +args = "run shellcheck" +exit = 1 +stderr = ''' +[shellcheck] + +In /bad.sh line 2: +echo $1 + ^-- SC2086 (info): Double quote to prevent globbing and word splitting. + +Did you mean: +echo "$1" + +For more information: + https://www.shellcheck.net/wiki/SC2086 -- Double quote to prevent globbing ... + +flint: 1 check failed (shellcheck) +💡 Try `flint run --fix` to auto-fix lint issues, then re-run `flint run` to verify. +''' diff --git a/tests/cases/general/unsupported-alternate-config/files/good.sh b/tests/cases/general/unsupported-alternate-config/files/good.sh new file mode 100644 index 0000000..ccc95ec --- /dev/null +++ b/tests/cases/general/unsupported-alternate-config/files/good.sh @@ -0,0 +1,2 @@ +#!/bin/bash +echo "$1" diff --git a/tests/cases/general/unsupported-alternate-config/files/mise.toml b/tests/cases/general/unsupported-alternate-config/files/mise.toml new file mode 100644 index 0000000..d725983 --- /dev/null +++ b/tests/cases/general/unsupported-alternate-config/files/mise.toml @@ -0,0 +1,2 @@ +[tools] +shellcheck = "latest" diff --git a/tests/cases/general/unsupported-alternate-config/files/shellcheckrc b/tests/cases/general/unsupported-alternate-config/files/shellcheckrc new file mode 100644 index 0000000..5de1df3 --- /dev/null +++ b/tests/cases/general/unsupported-alternate-config/files/shellcheckrc @@ -0,0 +1 @@ +disable=SC2086 diff --git a/tests/cases/general/unsupported-alternate-config/test.toml b/tests/cases/general/unsupported-alternate-config/test.toml new file mode 100644 index 0000000..9ad8db1 --- /dev/null +++ b/tests/cases/general/unsupported-alternate-config/test.toml @@ -0,0 +1,7 @@ +[expected] +args = "run shellcheck" +exit = 1 +stderr = ''' +flint: unsupported shellcheck config file found: shellcheckrc + Flint only supports FLINT_CONFIG_DIR/.shellcheckrc for shellcheck. Move the config to the supported location or remove the alternate file. +'''