Skip to content

Commit c469dc0

Browse files
author
evieira
committed
add lint --local option
Signed-off-by: evieira <t01etvi@tryg.dk>
1 parent 1bef6a8 commit c469dc0

4 files changed

Lines changed: 43 additions & 1 deletion

File tree

docs/guides/linter.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,14 @@ Error: Linter detected errors in the code. Please fix them before proceeding.
126126

127127
Use `sqlmesh lint --help` for more information.
128128

129+
You can pass `--local` to run lint without loading state from the configured state connection:
130+
131+
``` bash
132+
$ sqlmesh lint --local
133+
```
134+
135+
This can make linting faster in repositories where all referenced models are loaded from local files. In multi-repository setups, or when linting only a subset of projects, `--local` may cause additional linting errors because SQLMesh will not resolve references or schemas from models that exist only in remote state.
136+
129137

130138
## Applying linting rules
131139

@@ -258,4 +266,4 @@ You may specify that a rule's violation should not error and only log a warning
258266
)
259267
```
260268

261-
SQLMesh will raise an error if the same rule is included in more than one of the `rules`, `warn_rules`, and `ignored_rules` keys since they should be mutually exclusive.
269+
SQLMesh will raise an error if the same rule is included in more than one of the `rules`, `warn_rules`, and `ignored_rules` keys since they should be mutually exclusive.

docs/reference/cli.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,9 @@ Usage: sqlmesh lint [OPTIONS]
650650
651651
Options:
652652
--model TEXT A model to lint. Multiple models can be linted. If no models are specified, every model will be linted.
653+
--local Lint using only locally loaded project files without loading state.
653654
--help Show this message and exit.
654655
655656
```
657+
658+
`--local` skips loading state from the configured state connection. In multi-repository setups, or when linting only a subset of projects, this may cause additional linting errors because SQLMesh will not resolve references or schemas from models that exist only in remote state.

sqlmesh/cli/main.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ def cli(
118118
load = True
119119
# Local-only gating must hold for any number of --paths, so it stays outside the block below.
120120
load_state = ctx.invoked_subcommand not in LOCAL_ONLY_COMMANDS
121+
if ctx.invoked_subcommand == "lint" and "--local" in sys.argv:
122+
load_state = False
121123

122124
if len(paths) == 1:
123125
path = os.path.abspath(paths[0])
@@ -1194,12 +1196,18 @@ def environments(obj: Context) -> None:
11941196
multiple=True,
11951197
help="A model to lint. Multiple models can be linted. If no models are specified, every model will be linted.",
11961198
)
1199+
@click.option(
1200+
"--local",
1201+
is_flag=True,
1202+
help="Lint using only locally loaded project files without loading state.",
1203+
)
11971204
@click.pass_obj
11981205
@error_handler
11991206
@cli_analytics
12001207
def lint(
12011208
obj: Context,
12021209
models: t.Iterator[str],
1210+
local: bool,
12031211
) -> None:
12041212
"""Run the linter for the target model(s)."""
12051213
obj.lint_models(models)

tests/cli/test_cli.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2305,6 +2305,29 @@ def test_lint_still_loads_state(runner: CliRunner, tmp_path: Path, mocker):
23052305
assert mock.called, "state-sync was never accessed during `lint`"
23062306

23072307

2308+
def test_lint_local_runs_without_state(
2309+
runner: CliRunner, tmp_path: Path, mocker, monkeypatch
2310+
):
2311+
mock = _setup_local_only_project(tmp_path, mocker)
2312+
init_spy = mocker.spy(Context, "__init__")
2313+
monkeypatch.setattr(
2314+
"sys.argv", ["sqlmesh", "--paths", str(tmp_path), "lint", "--local"]
2315+
)
2316+
2317+
result = runner.invoke(cli, ["--paths", str(tmp_path), "lint", "--local"])
2318+
2319+
assert result.exit_code == 0, f"Lint failed: {result.output}\nException: {result.exception}"
2320+
assert init_spy.called, "Context was never constructed"
2321+
for call in init_spy.call_args_list:
2322+
assert "load_state" in call.kwargs, (
2323+
"CLI didn't pass load_state= explicitly; missing kwarg defaults to True silently"
2324+
)
2325+
assert call.kwargs["load_state"] is False, (
2326+
f"Context was constructed with load_state={call.kwargs['load_state']} for `lint --local`"
2327+
)
2328+
mock.assert_not_called()
2329+
2330+
23082331
@pytest.mark.parametrize("command", ["format"])
23092332
def test_local_only_commands_skip_state_multiple_paths(
23102333
runner: CliRunner, tmp_path: Path, mocker, command: str

0 commit comments

Comments
 (0)