Skip to content
Open
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
18 changes: 14 additions & 4 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,27 @@
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"image": "mcr.microsoft.com/devcontainers/typescript-node:1-22-bookworm",
"containerEnv": {
"COREPACK_ENABLE_DOWNLOAD_PROMPT": "0"
"COREPACK_ENABLE_DOWNLOAD_PROMPT": "0",
"CLI_ARCH": "linux_amd64" // Set the default CLI_ARCH to linux_amd64, for cli download script
},
// Features to add to the dev container. More info: https://containers.dev/features.
"features": {
"ghcr.io/devcontainers/features/docker-in-docker:2": {},
"ghcr.io/devcontainers/features/git:1": {},
"ghcr.io/devcontainers/features/github-cli:1": {},
"ghcr.io/devcontainers/features/python:1": {
"version": "3.12"
},
"ghcr.io/devcontainers/features/azure-cli:1": {},
"ghcr.io/devcontainers-extra/features/act:1": {},
"ghcr.io/devcontainers-extra/features/actionlint:1": {}
},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": "sudo corepack enable yarn && sudo corepack install && yarn install",
"postCreateCommand": "sudo corepack enable yarn && sudo corepack install",
// Use 'postStartCommand' to run commands after the container is started.
"postStartCommand": "yarn -v",
"postStartCommand": "yarn install && yarn run build && yarn workspace databricks run package:cli:fetch",
// Configure tool-specific properties.
"customizations": {
"vscode": {
Expand All @@ -41,12 +46,17 @@
}
},
"extensions": [
"ms-python.python",
"ms-toolsai.jupyter",
"dbaeumer.vscode-eslint",
"connor4312.esbuild-problem-matchers",
"ms-vscode.extension-test-runner",
"amodio.tsl-problem-matcher",
"esbenp.prettier-vscode",
"Tobermory.es6-string-html"
"Tobermory.es6-string-html",
"github.vscode-github-actions",
"redhat.vscode-xml",
"redhat.vscode-yaml"
]
}
},
Expand Down
4 changes: 2 additions & 2 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
"dist": true // set this to false to include "dist" folder in search results
},
// Turn off tsc task auto detection since we have the necessary tasks as npm scripts
"typescript.tsc.autoDetect": "off",
"ts.tsc.autoDetect": "off",
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
}
}
22 changes: 9 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,32 +11,28 @@ This repository contains the source code for Databricks extensions for VSCode.

Currently, we have the following packages:

- [databricks-vscode](https://github.com/databricks/databricks-vscode/tree/main/packages/databricks-vscode)
The VSCode extension for Databricks published to the VSCode marketplace.
- [databricks-vscode-types](https://github.com/databricks/databricks-vscode/tree/main/packages/databricks-vscode-types)
Type definition of the public API of the VSCode extension.
- [databricks-vscode](https://github.com/databricks/databricks-vscode/tree/main/packages/databricks-vscode)
The VSCode extension for Databricks published to the VSCode marketplace.
- [databricks-vscode-types](https://github.com/databricks/databricks-vscode/tree/main/packages/databricks-vscode-types)
Type definition of the public API of the VSCode extension.

### Getting Started

Prepare yarn:
Start the [devcontainer](.devcontainer/devcontainer.json) or use the system of your choice with Node.js 22+ installed and prepare yarn:

```
```sh
npm install -g yarn@2
yarn install
```

Prepare Databricks JavaScript SDK:

```
yarn run install:sdk
yarn run build
```

Prepare Databricks CLI:

```
```sh
yarn workspace databricks run package:cli:fetch
```

Then open the [code workspace](https://code.visualstudio.com/docs/editing/workspaces/workspaces).
After that you are ready to build and test the `databricks-vscode` extension.

### Found an issue?
Expand Down
8 changes: 6 additions & 2 deletions packages/databricks-vscode/.vscode/extensions.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"ms-python.python",
"ms-toolsai.jupyter",
"dbaeumer.vscode-eslint",
"amodio.tsl-problem-matcher",
"esbenp.prettier-vscode",
"Tobermory.es6-string-html"
"Tobermory.es6-string-html",
"redhat.vscode-xml",
"redhat.vscode-yaml"
]
}
}
110 changes: 110 additions & 0 deletions packages/databricks-vscode/src/language/EnvironmentCommands.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import assert from "assert";
import {Uri} from "vscode";
import {Environment} from "./MsPythonExtensionApi";
import {environmentName} from "../utils/environmentUtils";

function makeEnvironment(overrides: Partial<Environment> = {}): Environment {
return {
id: "env-1",
path: "/usr/bin/python3",
executable: {
uri: Uri.file("/usr/bin/python3"),
bitness: "64-bit",
sysPrefix: "/usr",
},
environment: {
type: "VirtualEnvironment",
name: "test-venv",
folderUri: Uri.file("/home/user/test-venv"),
workspaceFolder: undefined,
},
version: {
major: 3,
minor: 10,
micro: 0,
release: {level: "final", serial: 0},
sysVersion: "3.10.0",
},
tools: [],
...overrides,
};
}

function makeGlobalEnvironment(): Environment {
return makeEnvironment({
id: "global-python",
path: "/usr/bin/python3",
environment: undefined,
});
}

describe(__filename, () => {
it("should use path as name for global environments", () => {
const env = makeGlobalEnvironment();
const name = environmentName(env);
assert.strictEqual(name, "3.10.0 /usr/bin/python3");
});

it("should use environment name for virtual environments", () => {
const env = makeEnvironment();
const name = environmentName(env);
assert.strictEqual(name, "3.10.0 test-venv");
});

it("should handle environments without version", () => {
const env = makeGlobalEnvironment();
(env as any).version = undefined;
const name = environmentName(env);
assert.strictEqual(name, "/usr/bin/python3");
});

it("should identify global environment as having no environment property", () => {
const globalEnv = makeGlobalEnvironment();
assert.strictEqual(globalEnv.environment, undefined);
assert.ok(globalEnv.version);
assert.ok(globalEnv.executable.uri);
});

it("should identify virtual environment as having an environment property", () => {
const venvEnv = makeEnvironment();
assert.ok(venvEnv.environment);
assert.strictEqual(venvEnv.environment!.type, "VirtualEnvironment");
assert.strictEqual(venvEnv.environment!.name, "test-venv");
});

it("should distinguish global from non-global by environment field", () => {
const globalEnv = makeGlobalEnvironment();
const venvEnv = makeEnvironment();
assert.strictEqual(!globalEnv.environment, true);
assert.strictEqual(!venvEnv.environment, false);
});

it("should create pick item with 'Global' description for global environments", () => {
const env = makeGlobalEnvironment();
const isGlobal = !env.environment;
const item = {
label: environmentName(env),
description: isGlobal ? "Global" : env.environment?.type,
detail: env.path,
path: env.path,
isGlobal,
};
assert.strictEqual(item.description, "Global");
assert.strictEqual(item.isGlobal, true);
assert.strictEqual(item.path, "/usr/bin/python3");
});

it("should create pick item with env type for virtual environments", () => {
const env = makeEnvironment();
const isGlobal = !env.environment;
const item = {
label: environmentName(env),
description: isGlobal ? "Global" : env.environment?.type,
detail: env.path,
path: env.path,
isGlobal,
};
assert.strictEqual(item.description, "VirtualEnvironment");
assert.strictEqual(item.isGlobal, false);
});
});
94 changes: 93 additions & 1 deletion packages/databricks-vscode/src/language/EnvironmentCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,22 @@ export class EnvironmentCommands {
if (environments.length > 0) {
await this.showEnvironmentsQuickPick(environments);
} else {
await this.pythonExtension.createPythonEnvironment();
const createNewLabel = "$(add) Create new environment";
const useExistingLabel = "$(globe) Use existing Python";
const selectedPick = await window.showQuickPick(
[
{label: createNewLabel, alwaysShow: true},
{label: useExistingLabel, alwaysShow: true},
],
{title: "Select Python Environment"}
);
if (selectedPick) {
if (selectedPick.label === createNewLabel) {
await this.pythonExtension.createPythonEnvironment();
} else if (selectedPick.label === useExistingLabel) {
await this.showPythonInterpreterQuickPick();
}
}
}
}

Expand All @@ -93,10 +108,12 @@ export class EnvironmentCommands {
})
);
const createNewLabel = "$(add) Create new environment";
const useExistingLabel = "$(globe) Use existing Python";
const usePythonExtensionLabel =
"$(gear) Use Python Extension to setup environments";
const staticPicks: QuickPickItem[] = [
{label: createNewLabel, alwaysShow: true},
{label: useExistingLabel, alwaysShow: true},
{label: usePythonExtensionLabel, alwaysShow: true},
];
const selectedPick = await window.showQuickPick(
Expand All @@ -106,6 +123,8 @@ export class EnvironmentCommands {
if (selectedPick) {
if (selectedPick.label === createNewLabel) {
await this.pythonExtension.createPythonEnvironment();
} else if (selectedPick.label === useExistingLabel) {
await this.showPythonInterpreterQuickPick();
} else if (selectedPick.label === usePythonExtensionLabel) {
await this.pythonExtension.selectPythonInterpreter();
} else if (selectedPick.path) {
Expand All @@ -116,6 +135,79 @@ export class EnvironmentCommands {
}
}

private async showPythonInterpreterQuickPick() {
const environments =
await this.pythonExtension.getAllKnownEnvironments();
if (environments.length === 0) {
window.showInformationMessage(
"No Python interpreters found. Install Python or create a virtual environment."
);
return;
}

type EnvPickItem = QuickPickItem & {
path: string;
isGlobal: boolean;
};
const items: EnvPickItem[] = environments.map((env) => {
const isGlobal = !env.environment;
return {
label: environmentName(env),
description: isGlobal ? "Global" : env.environment?.type,
detail: env.path,
path: env.path,
isGlobal,
};
});

const activeEnvPath =
this.pythonExtension.api.environments.getActiveEnvironmentPath();

const quickPick = window.createQuickPick<EnvPickItem>();
quickPick.title = "Select Python Interpreter";
quickPick.items = items;
quickPick.canSelectMany = false;

if (activeEnvPath) {
const currentItem = items.find(
(item) => item.path === activeEnvPath.path
);
if (currentItem) {
quickPick.activeItems = [currentItem];
}
}

quickPick.show();

return new Promise<void>((resolve) => {
quickPick.onDidAccept(async () => {
const selected = quickPick.selectedItems[0];
quickPick.dispose();
if (selected) {
if (selected.isGlobal) {
const confirm = await window.showWarningMessage(
"You selected a global Python interpreter. Installing packages like databricks-connect into a global Python may affect other applications. Consider using a virtual environment instead.",
{modal: true},
"Use Global Python"
);
if (confirm !== "Use Global Python") {
resolve();
return;
}
}
await this.pythonExtension.api.environments.updateActiveEnvironmentPath(
selected.path
);
}
resolve();
});
quickPick.onDidHide(() => {
quickPick.dispose();
resolve();
});
});
}

async reinstallDBConnect(cluster?: Cluster) {
const state = await this.featureManager.isEnabled(
"environment.dependencies"
Expand Down
Loading
Loading