@@ -2237,3 +2237,146 @@ def test_format_leading_comma_default(runner: CliRunner, tmp_path: Path):
22372237 assert result .exit_code == 0
22382238 finally :
22392239 del os .environ ["SQLMESH__FORMAT__LEADING_COMMA" ]
2240+
2241+
2242+ def _create_local_only_project (path : Path , project : str ) -> None :
2243+ path .mkdir (parents = True , exist_ok = True )
2244+ create_example_project (path , template = ProjectTemplate .EMPTY )
2245+ config_path = path / "config.yaml"
2246+ existing = config_path .read_text (encoding = "utf-8" )
2247+ config_path .write_text (f"project: { project } \n \n " + existing , encoding = "utf-8" )
2248+
2249+ (path / "models" / "example.sql" ).write_text (
2250+ f"MODEL(name { project } .example, dialect 'duckdb'); SELECT 1 AS col\n " ,
2251+ encoding = "utf-8" ,
2252+ )
2253+
2254+
2255+ def _patch_state_access (mocker ):
2256+ return mocker .patch (
2257+ "sqlmesh.core.state_sync.db.facade.EngineAdapterStateSync.get_versions" ,
2258+ side_effect = RuntimeError ("state should not be accessed" ),
2259+ )
2260+
2261+
2262+ def _setup_local_only_project (tmp_path , mocker ):
2263+ _create_local_only_project (tmp_path , "cli_test" )
2264+ return _patch_state_access (mocker )
2265+
2266+
2267+ def test_format_runs_without_state (runner : CliRunner , tmp_path : Path , mocker ):
2268+ mock = _setup_local_only_project (tmp_path , mocker )
2269+ result = runner .invoke (cli , ["--paths" , str (tmp_path ), "format" ])
2270+ assert result .exit_code == 0 , f"Format failed: { result .output } \n Exception: { result .exception } "
2271+ mock .assert_not_called ()
2272+
2273+
2274+ def test_format_runs_without_state_multi_repo_partial (runner : CliRunner , copy_to_temp_path , mocker ):
2275+ """Format one repo of a multi-repo project whose upstream models live only in prod state."""
2276+ repo_2 = copy_to_temp_path ("examples/multi" )[0 ] / "repo_2"
2277+ mock = _patch_state_access (mocker )
2278+
2279+ result = runner .invoke (cli , ["--gateway" , "memory" , "--paths" , str (repo_2 ), "format" ])
2280+ assert result .exit_code == 0 , f"Format failed: { result .output } \n Exception: { result .exception } "
2281+ mock .assert_not_called ()
2282+
2283+
2284+ def test_lint_still_loads_state (runner : CliRunner , tmp_path : Path , mocker ):
2285+ """Guard that `lint` explicitly passes `load_state=True` and still reaches state sync."""
2286+ mock = _setup_local_only_project (tmp_path , mocker )
2287+ init_spy = mocker .spy (Context , "__init__" )
2288+
2289+ runner .invoke (cli , ["--paths" , str (tmp_path ), "lint" ])
2290+
2291+ assert init_spy .called , "Context was never constructed"
2292+ for call in init_spy .call_args_list :
2293+ assert "load_state" in call .kwargs , (
2294+ "CLI didn't pass load_state= explicitly; missing kwarg defaults to True silently"
2295+ )
2296+ assert call .kwargs ["load_state" ] is True , (
2297+ f"Context was constructed with load_state={ call .kwargs ['load_state' ]} for `lint`"
2298+ )
2299+ assert mock .called , "state-sync was never accessed during `lint`"
2300+
2301+
2302+ @pytest .mark .parametrize ("command" , ["format" ])
2303+ def test_local_only_commands_skip_state_multiple_paths (
2304+ runner : CliRunner , tmp_path : Path , mocker , command : str
2305+ ):
2306+ project_a = tmp_path / "a"
2307+ project_b = tmp_path / "b"
2308+ _create_local_only_project (project_a , "proj_a" )
2309+ _create_local_only_project (project_b , "proj_b" )
2310+ mock = _patch_state_access (mocker )
2311+
2312+ result = runner .invoke (cli , ["--paths" , str (project_a ), "--paths" , str (project_b ), command ])
2313+ assert result .exit_code == 0 , (
2314+ f"{ command } failed: { result .output } \n Exception: { result .exception } "
2315+ )
2316+ mock .assert_not_called ()
2317+
2318+
2319+ def test_plan_still_loads_state (runner : CliRunner , tmp_path : Path , mocker ):
2320+ """Guard that `plan` explicitly passes `load_state=True` and still reaches state sync."""
2321+ mock = _setup_local_only_project (tmp_path , mocker )
2322+ init_spy = mocker .spy (Context , "__init__" )
2323+
2324+ runner .invoke (cli , ["--paths" , str (tmp_path ), "plan" ], input = "n\n " )
2325+
2326+ assert init_spy .called , "Context was never constructed"
2327+ for call in init_spy .call_args_list :
2328+ assert "load_state" in call .kwargs , (
2329+ "CLI didn't pass load_state= explicitly; missing kwarg defaults to True silently"
2330+ )
2331+ assert call .kwargs ["load_state" ] is True , (
2332+ f"Context was constructed with load_state={ call .kwargs ['load_state' ]} for `plan`"
2333+ )
2334+ assert mock .called , "state-sync was never accessed during `plan`"
2335+
2336+
2337+ def test_format_does_not_open_state_connection (
2338+ runner : CliRunner , tmp_path : Path , mocker , monkeypatch
2339+ ):
2340+ """Format must not open a configured remote Postgres state connection when CI secrets are unset."""
2341+ pytest .importorskip ("psycopg2" )
2342+
2343+ for var in ("PG_HOST" , "PG_USER" , "PG_PASSWORD" , "PG_DATABASE" ):
2344+ monkeypatch .delenv (var , raising = False )
2345+
2346+ create_example_project (tmp_path , template = ProjectTemplate .EMPTY )
2347+ (tmp_path / "config.yaml" ).write_text (
2348+ """project: cli_test
2349+
2350+ gateways:
2351+ prod:
2352+ state_connection:
2353+ type: postgres
2354+ host: "{{ env_var('PG_HOST', 'postgres.internal.example.com') }}"
2355+ port: 5432
2356+ user: "{{ env_var('PG_USER') }}"
2357+ password: "{{ env_var('PG_PASSWORD') }}"
2358+ database: "{{ env_var('PG_DATABASE', 'sqlmesh_state') }}"
2359+ connection:
2360+ type: duckdb
2361+ database: "warehouse.db"
2362+
2363+ default_gateway: prod
2364+
2365+ model_defaults:
2366+ dialect: duckdb
2367+ """ ,
2368+ encoding = "utf-8" ,
2369+ )
2370+ (tmp_path / "models" / "example.sql" ).write_text (
2371+ "MODEL(name local.example, dialect 'duckdb'); SELECT 1 AS col\n " ,
2372+ encoding = "utf-8" ,
2373+ )
2374+
2375+ mock = mocker .patch (
2376+ "sqlmesh.core.state_sync.db.facade.EngineAdapterStateSync.get_versions" ,
2377+ side_effect = RuntimeError ("state should not be accessed" ),
2378+ )
2379+
2380+ result = runner .invoke (cli , ["--paths" , str (tmp_path ), "format" ])
2381+ assert result .exit_code == 0 , f"Format failed: { result .output } \n Exception: { result .exception } "
2382+ mock .assert_not_called ()
0 commit comments