Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions sqlmesh/core/config/loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ def load_config_from_paths(
"SQLMesh project config could not be found. Point the cli to the project path with `sqlmesh -p`. If you haven't set up the SQLMesh project, run `sqlmesh init`."
)

yaml_config_path: t.Optional[Path] = None
for path in [*project_paths, *personal_paths]:
if not path.exists():
continue
Expand All @@ -107,8 +108,9 @@ def load_config_from_paths(
if extension in ("yml", "yaml"):
if config_name != "config" and not python_config:
raise ConfigError(
"YAML configs do not support multiple configs. Use Python instead."
"YAML configs do not support multiple configs. Use Python instead.",
)
yaml_config_path = path.resolve()
non_python_configs.append(load_config_from_yaml(path))
elif extension == "py":
try:
Expand Down Expand Up @@ -149,7 +151,8 @@ def load_config_from_paths(
except ValidationError as e:
raise ConfigError(
validation_error_message(e, "Invalid project config:")
+ "\n\nVerify your config.yaml and environment variables."
+ "\n\nVerify your config.yaml and environment variables.",
location=yaml_config_path,
)

no_dialect_err_msg = "Default model SQL dialect is a required configuration parameter. Set it in the `model_defaults` `dialect` key in your config file."
Expand Down
12 changes: 8 additions & 4 deletions sqlmesh/lsp/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -767,7 +767,7 @@ def completion(
get_sql_completions(None, URI(params.text_document.uri))
return None

def _get_diagnostics_for_uri(self, uri: URI) -> t.Tuple[t.List[types.Diagnostic], int]:
def _get_diagnostics_for_uri(self, uri: URI) -> t.Tuple[t.List[types.Diagnostic], str]:
"""Get diagnostics for a specific URI, returning (diagnostics, result_id).

Since we no longer track version numbers, we always return 0 as the result_id.
Expand All @@ -776,12 +776,16 @@ def _get_diagnostics_for_uri(self, uri: URI) -> t.Tuple[t.List[types.Diagnostic]
try:
context = self._context_get_or_load(uri)
diagnostics = context.lint_model(uri)
return LSPContext.diagnostics_to_lsp_diagnostics(diagnostics), 0
return LSPContext.diagnostics_to_lsp_diagnostics(
diagnostics
), self.context_state.version_id
except ConfigError as config_error:
diagnostic, error = context_error_to_diagnostic(config_error, uri_filter=uri)
if diagnostic:
return [diagnostic[1]], 0
return [], 0
location, diag = diagnostic
if location == uri.value:
return [diag], self.context_state.version_id
return [], self.context_state.version_id

def _context_get_or_load(self, document_uri: t.Optional[URI] = None) -> LSPContext:
state = self.context_state
Expand Down
3 changes: 2 additions & 1 deletion vscode/extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@
"ts-loader": "^9.5.2",
"typescript": "^5.8.3",
"typescript-eslint": "^8.35.1",
"vitest": "^3.2.4"
"vitest": "^3.2.4",
"yaml": "^2.8.0"
}
}
66 changes: 65 additions & 1 deletion vscode/extension/tests/broken_project.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,15 @@ import { test, expect } from './fixtures'
import fs from 'fs-extra'
import os from 'os'
import path from 'path'
import { openLineageView, saveFile, SUSHI_SOURCE_PATH } from './utils'
import {
openLineageView,
runCommand,
saveFile,
SUSHI_SOURCE_PATH,
} from './utils'
import { createPythonInterpreterSettingsSpecifier } from './utils_code_server'
import { execAsync } from '../src/utilities/exec'
import yaml from 'yaml'

test('bad project, double model', async ({ page, sharedCodeServer }) => {
const tempDir = await fs.mkdtemp(
Expand Down Expand Up @@ -253,3 +260,60 @@ test('bad project, double model, check lineage', async ({

await page.waitForTimeout(500)
})

const setup = async (tempDir: string) => {
// Run the sqlmesh CLI from the root of the repo using the local path
const sqlmeshCliPath = path.resolve(__dirname, '../../../.venv/bin/sqlmesh')
const result = await execAsync(sqlmeshCliPath, ['init', 'duckdb'], {
cwd: tempDir,
})
expect(result.exitCode).toBe(0)
}

test.describe('Bad config.py/config.yaml file issues', () => {
test('sqlmesh init, then corrupted config.yaml, bad parameters', async ({
page,
sharedCodeServer,
}) => {
const tempDir = await fs.mkdtemp(
path.join(os.tmpdir(), 'vscode-test-tcloud-'),
)
await setup(tempDir)
await createPythonInterpreterSettingsSpecifier(tempDir)

const configYamlPath = path.join(tempDir, 'config.yaml')
// Write an invalid YAML to config.yaml
const config = {
gateway: 'test',
}
// Write config to the yaml file
await fs.writeFile(configYamlPath, yaml.stringify(config))

await page.goto(
`http://127.0.0.1:${sharedCodeServer.codeServerPort}/?folder=${tempDir}`,
)
await page.waitForLoadState('networkidle')

// Open full_model.sql model
await page
.getByRole('treeitem', { name: 'models', exact: true })
.locator('a')
.click()
await page
.getByRole('treeitem', { name: 'full_model.sql', exact: true })
.locator('a')
.click()

// Wait for the error to appear
await page.waitForSelector('text=Error creating context')

// Open the problems view
await runCommand(page, 'View: Focus Problems')

// Asser that the error is present in the problems view
await page
.getByText('Invalid project config:', { exact: true })
.first()
.isVisible({ timeout: 5_000 })
})
})
Loading