feat(run): Docker and Compose run targets (#1640)
CI / Changes (push) Successful in 1s
Language smoke / Language smoke (go) (push) Failing after 6s
Language smoke / Language smoke (kotlin) (push) Failing after 6s
Language smoke / Language smoke (java) (push) Failing after 7s
Language smoke / Language smoke (python) (push) Failing after 3s
Language smoke / Language smoke (typescript) (push) Failing after 5s
Language smoke / Language smoke (rust) (push) Failing after 5s
CI / Plugins (SDK, official, fixtures) (push) Successful in 3m9s
CI / Cargo deny (push) Successful in 52s
CI / Remote server (linux musl) (push) Successful in 5m57s
CI / E2E (push) Failing after 15m55s
CI / Frontend (push) Successful in 25m38s
CI / Rust (ubuntu-22.04) (push) Failing after 46m4s
CI / Rust (macos-latest) (push) Canceled after 0s
CI / Rust (windows-latest) (push) Canceled after 0s

A run target can be a Docker image or a Compose service: the configuration runs as a local docker run --rm / docker compose run --rm with the project bind-mounted, so the console, PTY, stdin, Stop and test parsers work unchanged. Only daemons on this machine are accepted; on Linux the container runs as the project folder's owner; Stop runs docker stop with the same docker CLI. Debugging, coverage and profiling stay on this machine. Refs #1083 (step A1).

Co-authored-by: andreabasile <[email protected]>
Цей коміт міститься в:
Andrea Basileтаandreabasile authored and GitHub committed 2026-11-06 07:34:00 +08:00
1 джерело a5d1b16e59
коміт 589cf81bae
21 files changed
+1301 -39

No files matched your search

+13 -1
Переглянути файл
@@ -6310,5 +6310,17 @@
"Composer dependencies are not installed": "未安装 Composer 依赖",
"Installed Composer packages differ from composer.lock": "已安装的 Composer 包与 composer.lock 不一致",
"Composer Install": "安装 Composer 依赖",
"Input for the program (pause to evaluate)": "程序输入(暂停后可计算)"
"Input for the program (pause to evaluate)": "程序输入(暂停后可计算)",
"Coverage and profiling are not supported in containers": "容器中不支持覆盖率和性能分析",
"'{name}' runs in a container on {where}. Run it, or choose “Local machine” under “Run on”.": "'{name}' 在 {where} 的容器中运行。请直接运行,或在“运行于”中选择“本地计算机”。",
"Docker connection": "Docker 连接",
"Only daemons on this machine can mount the project.": "只有本机上的守护进程才能挂载项目。",
"Relative to the project; empty uses the project's default file.": "相对于项目;留空则使用项目的默认文件。",
"Service": "服务",
"Container folder": "容器文件夹",
"Empty: where the service mounts the project.": "留空:使用服务挂载项目的位置。",
"The project is mounted here; paths and the working directory are mapped into it.": "项目挂载在此处;路径和工作目录会映射到其中。",
"Published ports": "发布的端口",
"Run as the image's user, not the project folder's owner (Linux)": "以镜像的用户运行,而不是项目文件夹的所有者(Linux)",
"Docker connections come from the Services tool window. Each run gets a new container, removed when it ends; debugging, coverage and profiling stay on this machine.": "Docker 连接来自“服务”工具窗口。每次运行都会使用一个新容器,运行结束后删除;调试、覆盖率和性能分析仍在本机进行。"
}
+3
Переглянути файл
@@ -95,6 +95,9 @@ const UNTRANSLATED = new Set<string>([
"Ruff",
"IntelliJ IDEA",
"PHPStan",
// Docker run target placeholder values
"compose.yaml",
"python:3.12",
// Go environment variables and placeholder values
"CGO",
"GOPROXY",
+33
Переглянути файл
@@ -42,7 +42,10 @@ export interface DeploymentSettingsValid {
exclude: string[];
}
export type RunTargetKindValid = "ssh" | "docker" | "compose";
export interface RunTargetValid {
kind: RunTargetKindValid;
id: string;
name: string;
sshConfig: string;
@@ -51,6 +54,15 @@ export interface RunTargetValid {
python: string;
node: string;
java: string;
/** Services tool window Docker connection id; empty = the CLI's daemon. */
dockerConnection: string;
image: string;
composeFiles: string[];
service: string;
containerRoot: string;
ports: string[];
runOptions: string;
imageUser: boolean;
}
export interface RemoteSettings {
@@ -91,6 +103,7 @@ export const DEFAULT_DEPLOYMENT: DeploymentSettingsValid = {
};
export const DEFAULT_RUN_TARGET: RunTargetValid = {
kind: "ssh",
id: "",
name: "",
sshConfig: "",
@@ -99,6 +112,14 @@ export const DEFAULT_RUN_TARGET: RunTargetValid = {
python: "",
node: "",
java: "",
dockerConnection: "",
image: "",
composeFiles: [],
service: "",
containerRoot: "",
ports: [],
runOptions: "",
imageUser: false,
};
export const DEFAULT_REMOTE: RemoteSettings = {
@@ -181,6 +202,7 @@ export function validateDeployment(raw: unknown): DeploymentSettingsValid {
export function validateRunTargets(raw: unknown): RunTargetValid[] {
const d = DEFAULT_RUN_TARGET;
return withIds(raw, "target", (o) => ({
kind: oneOf(o.kind, ["ssh", "docker", "compose"] as const, d.kind),
id: text(o.id, ""),
name: text(o.name, ""),
sshConfig: text(o.sshConfig, ""),
@@ -189,6 +211,14 @@ export function validateRunTargets(raw: unknown): RunTargetValid[] {
python: text(o.python, ""),
node: text(o.node, ""),
java: text(o.java, ""),
dockerConnection: text(o.dockerConnection, ""),
image: text(o.image, ""),
composeFiles: strings(o.composeFiles, []),
service: text(o.service, ""),
containerRoot: text(o.containerRoot, ""),
ports: strings(o.ports, []),
runOptions: text(o.runOptions, ""),
imageUser: bool(o.imageUser, d.imageUser),
}));
}
@@ -212,6 +242,9 @@ let seq = 0;
/** A fresh id for a new SSH configuration, server or target. */
export const newRemoteId = (prefix: string) => `${prefix}-${Date.now().toString(36)}-${++seq}`;
/** Whether `target` runs configurations in a container (Docker, Compose) rather than over SSH. */
export const inContainer = (target: Pick<RunTargetValid, "kind">) => target.kind !== "ssh";
/** Backend connection descriptor for deployment and folder browsing. */
export function deploymentConnection(server: DeploymentServerValid): { kind: "local" } | { kind: "sftp"; ssh: string } {
return server.kind === "local" ? { kind: "local" } : { kind: "sftp", ssh: server.sshConfig };