Skip to content

Commit 31f90d0

Browse files
authored
chore(vscode): better handling no sqlmesh (#4739)
1 parent a1b5903 commit 31f90d0

File tree

5 files changed

+111
-11
lines changed

5 files changed

+111
-11
lines changed

vscode/extension/src/utilities/errors.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { traceInfo } from './common/log'
99
export type ErrorType =
1010
| ErrorTypeGeneric
1111
| { type: 'not_signed_in' }
12+
| { type: 'sqlmesh_not_found' }
1213
| { type: 'sqlmesh_lsp_not_found' }
1314
// tcloud_bin_not_found is used when the tcloud executable is not found. This is likely to happen if the user
1415
// opens a project that has a `tcloud.yaml` file but doesn't have tcloud installed.
@@ -85,6 +86,8 @@ export async function handleError(
8586
return
8687
case 'not_signed_in':
8788
return handleNotSignedInError(authProvider)
89+
case 'sqlmesh_not_found':
90+
return handleSqlmeshNotFoundError()
8891
case 'sqlmesh_lsp_not_found':
8992
return handleSqlmeshLspNotFoundError()
9093
case 'sqlmesh_lsp_dependencies_missing':
@@ -118,6 +121,14 @@ const handleNotSignedInError = async (
118121
}
119122
}
120123

124+
/**
125+
* Handles the case where the sqlmesh executable is not found.
126+
*/
127+
const handleSqlmeshNotFoundError = async (): Promise<void> => {
128+
traceInfo('handleSqlmeshNotFoundError')
129+
await window.showErrorMessage('SQLMesh not found, please check installation')
130+
}
131+
121132
/**
122133
* Handles the case where the sqlmesh_lsp is not found.
123134
*/

vscode/extension/src/utilities/sqlmesh/sqlmesh.ts

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,12 @@ export const sqlmeshExec = async (): Promise<
287287
args: [],
288288
})
289289
} else {
290+
const exists = await doesExecutableExist(sqlmesh)
291+
if (!exists) {
292+
return err({
293+
type: 'sqlmesh_not_found',
294+
})
295+
}
290296
return ok({
291297
bin: sqlmesh,
292298
workspacePath,
@@ -384,22 +390,28 @@ export const sqlmeshLspExec = async (): Promise<
384390
type: 'not_signed_in',
385391
})
386392
}
393+
const exists = await doesExecutableExist(sqlmeshLSP)
394+
if (!exists) {
395+
return err({
396+
type: 'sqlmesh_lsp_not_found',
397+
})
398+
}
387399
const ensured = await ensureSqlmeshEnterpriseInstalled()
388400
if (isErr(ensured)) {
389401
return ensured
390402
}
391403
}
392-
const ensuredDependencies = await ensureSqlmeshLspDependenciesInstalled()
393-
if (isErr(ensuredDependencies)) {
394-
return ensuredDependencies
395-
}
396404
const binPath = path.join(interpreterDetails.binPath!, sqlmeshLSP)
397405
traceLog(`Bin path: ${binPath}`)
398406
if (!fs.existsSync(binPath)) {
399407
return err({
400408
type: 'sqlmesh_lsp_not_found',
401409
})
402410
}
411+
const ensuredDependencies = await ensureSqlmeshLspDependenciesInstalled()
412+
if (isErr(ensuredDependencies)) {
413+
return ensuredDependencies
414+
}
403415
return ok({
404416
bin: binPath,
405417
workspacePath,
@@ -411,6 +423,12 @@ export const sqlmeshLspExec = async (): Promise<
411423
args: [],
412424
})
413425
} else {
426+
const exists = await doesExecutableExist(sqlmeshLSP)
427+
if (!exists) {
428+
return err({
429+
type: 'sqlmesh_lsp_not_found',
430+
})
431+
}
414432
return ok({
415433
bin: sqlmeshLSP,
416434
workspacePath,
@@ -419,3 +437,18 @@ export const sqlmeshLspExec = async (): Promise<
419437
})
420438
}
421439
}
440+
441+
async function doesExecutableExist(executable: string): Promise<boolean> {
442+
const command = process.platform === 'win32' ? 'where.exe' : 'which'
443+
traceLog(`Checking if ${executable} exists with ${command}`)
444+
try {
445+
const result = await execAsync(command, [executable])
446+
traceLog(`Checked if ${executable} exists with ${command}, with result ${result.exitCode}`)
447+
const exists = result.exitCode === 0
448+
traceLog(`Checked if ${executable} exists with ${command}, with result ${exists}`)
449+
return exists
450+
} catch {
451+
traceLog(`Checked if ${executable} exists with ${command}, errored, returning false`)
452+
return false
453+
}
454+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import os from 'os'
44
import path from 'path'
55
import {
66
createVirtualEnvironment,
7+
openLineageView,
78
pipInstall,
89
REPO_ROOT,
910
startVSCode,
@@ -72,3 +73,41 @@ test('missing LSP dependencies shows install prompt', async ({}, testInfo) => {
7273
await fs.remove(tempDir)
7374
}
7475
})
76+
77+
test('lineage, no sqlmesh found', async ({}) => {
78+
const tempDir = await fs.mkdtemp(
79+
path.join(os.tmpdir(), 'vscode-test-tcloud-'),
80+
)
81+
const pythonEnvDir = path.join(tempDir, '.venv')
82+
const pythonDetails = await createVirtualEnvironment(pythonEnvDir)
83+
84+
try {
85+
// Copy sushi project
86+
await fs.copy(SUSHI_SOURCE_PATH, tempDir)
87+
88+
// Configure VS Code settings to use our Python environment
89+
const settings = {
90+
'python.defaultInterpreterPath': pythonDetails.pythonPath,
91+
'sqlmesh.environmentPath': pythonEnvDir,
92+
}
93+
await fs.ensureDir(path.join(tempDir, '.vscode'))
94+
await fs.writeJson(
95+
path.join(tempDir, '.vscode', 'settings.json'),
96+
settings,
97+
{ spaces: 2 },
98+
)
99+
100+
const { window, close } = await startVSCode(tempDir)
101+
102+
// Open lineage view
103+
await openLineageView(window)
104+
105+
// Assert shows that sqlmesh is not installed
106+
await window.waitForSelector('text=SQLMesh LSP not found')
107+
108+
await close()
109+
} finally {
110+
// Clean up
111+
await fs.remove(tempDir)
112+
}
113+
})

vscode/extension/tests/lineage.spec.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,14 @@ import { test, expect, Page } from '@playwright/test'
22
import path from 'path'
33
import fs from 'fs-extra'
44
import os from 'os'
5-
import { startVSCode, SUSHI_SOURCE_PATH } from './utils'
5+
import { openLineageView, startVSCode, SUSHI_SOURCE_PATH } from './utils'
66
import { writeFileSync } from 'fs'
77

88
/**
99
* Helper function to launch VS Code and test lineage with given project path config
1010
*/
1111
async function testLineageWithProjectPath(window: Page): Promise<void> {
12-
// Trigger lineage command
13-
await window.keyboard.press(
14-
process.platform === 'darwin' ? 'Meta+Shift+P' : 'Control+Shift+P',
15-
)
16-
await window.keyboard.type('Lineage: Focus On View')
17-
await window.keyboard.press('Enter')
12+
await openLineageView(window)
1813

1914
// Wait for "Loaded SQLMesh context" text to appear
2015
const loadedContextText = window.locator('text=Loaded SQLMesh context')

vscode/extension/tests/utils.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,3 +137,25 @@ export const pipInstall = async (
137137
throw new Error(`Failed to install package: ${stderr}`)
138138
}
139139
}
140+
141+
/**
142+
* Open the lineage view in the given window.
143+
*/
144+
export const openLineageView = async (window: Page): Promise<void> => {
145+
await window.keyboard.press(
146+
process.platform === 'darwin' ? 'Meta+Shift+P' : 'Control+Shift+P',
147+
)
148+
await window.keyboard.type('Lineage: Focus On View')
149+
await window.keyboard.press('Enter')
150+
}
151+
152+
/**
153+
* Restart the SQLMesh servers
154+
*/
155+
export const restartSqlmeshServers = async (window: Page): Promise<void> => {
156+
await window.keyboard.press(
157+
process.platform === 'darwin' ? 'Meta+Shift+P' : 'Control+Shift+P',
158+
)
159+
await window.keyboard.type('Restart SQLMesh servers')
160+
await window.keyboard.press('Enter')
161+
}

0 commit comments

Comments
 (0)