forked from golang/vscode-go
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
src/goTaskProvider: add default go task provider
This new provider provides the execution for tasks with type = "go". The task runs the `go` command and runs the build or test command, along with optional 'args'. The provider provides the default task definitions including - go build <current package> - go test <current package> - go build ./... - go test ./... VS Code offers users to create custom task configurations from the default task definition this provide provides. By default a Go task runs from the workspace root folder with the tools execution environment unless options "cwd"/"env" are configured. Users who need to work with a module in a nested directory have to either set up `go.work` in the workspace root folder, or create custom task configurations that set options "cwd" property. Fixes golang#194 Change-Id: I3ee54af6e1b37031a60fdcb511fd1d961687314e Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/467697 Reviewed-by: Suzy Mueller <[email protected]> TryBot-Result: kokoro <[email protected]> Run-TryBot: Hyang-Ah Hana Kim <[email protected]>
- Loading branch information
Showing
6 changed files
with
370 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
/*--------------------------------------------------------- | ||
* Copyright 2023 The Go Authors. All rights reserved. | ||
* Licensed under the MIT License. See LICENSE in the project root for license information. | ||
*--------------------------------------------------------*/ | ||
|
||
import * as vscode from 'vscode'; | ||
import { getGoConfig } from './config'; | ||
import { toolExecutionEnvironment } from './goEnv'; | ||
import { getBinPath } from './util'; | ||
|
||
const TASK_TYPE = 'go'; | ||
type GoCommand = 'build' | 'test'; // TODO(hyangah): run, install? | ||
|
||
interface GoTaskDefinition extends vscode.TaskDefinition { | ||
label?: string; | ||
|
||
command: GoCommand; | ||
args?: string[]; | ||
|
||
options?: vscode.ProcessExecutionOptions; | ||
// TODO(hyangah): plumb go.testFlags and go.buildFlags | ||
} | ||
|
||
type Workspace = Pick<typeof vscode.workspace, 'workspaceFolders' | 'getWorkspaceFolder'>; | ||
|
||
// GoTaskProvider provides default tasks | ||
// - build/test the current package | ||
// - build/test all packages in the current workspace | ||
// This default task provider can be disabled by `go.tasks.provideDefault`. | ||
// | ||
// Note that these tasks run from the workspace root folder. If the workspace root | ||
// folder and the package to test are not in the same module nor in the same workspace | ||
// defined by a go.work file, the build/test task will fail because the tested package | ||
// is not visible from the workspace root folder. | ||
export class GoTaskProvider implements vscode.TaskProvider { | ||
private constructor(private workspace: Workspace) {} | ||
|
||
static setup(ctx: vscode.ExtensionContext, workspace: Workspace): GoTaskProvider | undefined { | ||
if (workspace.workspaceFolders && workspace.workspaceFolders.length > 0) { | ||
const provider = new GoTaskProvider(workspace); | ||
ctx.subscriptions.push(vscode.tasks.registerTaskProvider('go', provider)); | ||
return provider; | ||
} | ||
return undefined; | ||
} | ||
|
||
// provides the default tasks. | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
provideTasks(_: vscode.CancellationToken): vscode.ProviderResult<vscode.Task[]> { | ||
const folders = this.workspace.workspaceFolders; | ||
if (!folders || !folders.length) { | ||
// zero workspace folder setup. | ||
// In zero-workspace folder setup, vscode.TaskScope.Workspace doesn't seem to work. | ||
// The task API does not implement vscode.TaskScope.Global yet. | ||
// Once Global scope is supported, we can consider to add tasks like `go build ${fileDirname}`. | ||
return undefined; | ||
} | ||
|
||
const opened = vscode.window.activeTextEditor?.document?.uri; | ||
const goCfg = getGoConfig(opened); | ||
if (!goCfg.get('tasks.provideDefault')) { | ||
return undefined; | ||
} | ||
|
||
// Explicitly specify the workspace folder directory based on the current open file. | ||
// Behavior of tasks constructed with vscode.TaskScope.Workspace as scope | ||
// is not well-defined when handling multiple folder workspace. | ||
const folder = (opened && this.workspace.getWorkspaceFolder(opened)) || folders[0]; | ||
return [ | ||
// all tasks run from the chosen workspace root folder. | ||
buildGoTask(folder, { | ||
type: TASK_TYPE, | ||
label: 'build package', | ||
command: 'build', | ||
args: ['${fileDirname}'] | ||
}), | ||
buildGoTask(folder, { type: TASK_TYPE, label: 'test package', command: 'test', args: ['${fileDirname}'] }), | ||
buildGoTask(folder, { type: TASK_TYPE, label: 'build workspace', command: 'build', args: ['./...'] }), | ||
buildGoTask(folder, { type: TASK_TYPE, label: 'test workspace', command: 'test', args: ['./...'] }) | ||
]; | ||
} | ||
|
||
// fill an incomplete task definition ('tasks.json') whose type is "go". | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
resolveTask(_task: vscode.Task, _: vscode.CancellationToken): vscode.ProviderResult<vscode.Task> { | ||
// vscode calls resolveTask for every 'go' type task in tasks.json. | ||
const def = _task.definition; | ||
if (def && def.type === TASK_TYPE) { | ||
if (!def.command) { | ||
def.command = 'build'; | ||
} | ||
return buildGoTask(_task.scope ?? vscode.TaskScope.Workspace, def as GoTaskDefinition); | ||
} | ||
return undefined; | ||
} | ||
} | ||
|
||
function buildGoTask(scope: vscode.WorkspaceFolder | vscode.TaskScope, definition: GoTaskDefinition): vscode.Task { | ||
const cwd = definition.options?.cwd ?? (isWorkspaceFolder(scope) ? scope.uri.fsPath : undefined); | ||
const task = new vscode.Task( | ||
definition, | ||
scope, | ||
definition.label ?? defaultTaskName(definition), | ||
TASK_TYPE, | ||
new vscode.ProcessExecution(getBinPath('go'), [definition.command, ...(definition.args ?? [])], { | ||
cwd, | ||
env: mergedToolExecutionEnv(scope, definition.options?.env) | ||
}), | ||
['$go'] | ||
); | ||
|
||
task.group = taskGroup(definition.command); | ||
task.detail = defaultTaskDetail(definition, cwd); | ||
task.runOptions = { reevaluateOnRerun: true }; | ||
task.isBackground = false; | ||
task.presentationOptions.clear = true; | ||
task.presentationOptions.echo = true; | ||
task.presentationOptions.showReuseMessage = true; | ||
task.presentationOptions.panel = vscode.TaskPanelKind.Dedicated; | ||
return task; | ||
} | ||
|
||
function defaultTaskName({ command, args }: GoTaskDefinition): string { | ||
return `go ${command} ${(args ?? []).join(' ')}`; | ||
} | ||
|
||
function defaultTaskDetail(def: GoTaskDefinition, cwd: string | undefined): string { | ||
const cd = cwd ? `cd ${cwd}; ` : ''; | ||
return `${cd}${defaultTaskName(def)}`; | ||
} | ||
|
||
function taskGroup(command: GoCommand): vscode.TaskGroup | undefined { | ||
switch (command) { | ||
case 'build': | ||
return vscode.TaskGroup.Build; | ||
case 'test': | ||
return vscode.TaskGroup.Test; | ||
default: | ||
return undefined; | ||
} | ||
} | ||
|
||
function isWorkspaceFolder(scope: vscode.WorkspaceFolder | vscode.TaskScope): scope is vscode.WorkspaceFolder { | ||
return typeof scope !== 'number' && 'uri' in scope; | ||
} | ||
|
||
function mergedToolExecutionEnv( | ||
scope: vscode.WorkspaceFolder | vscode.TaskScope, | ||
toAdd: { [key: string]: string } = {} | ||
): { [key: string]: string } { | ||
const env = toolExecutionEnvironment(isWorkspaceFolder(scope) ? scope.uri : undefined, /* addProcessEnv: */ false); | ||
Object.keys(env).forEach((key) => { | ||
if (env[key] === undefined) { | ||
env[key] = ''; | ||
} | ||
}); // unset | ||
return Object.assign(env, toAdd); | ||
} |
Oops, something went wrong.