How to await a build task in a VS Code extension?
Asked Answered
S

3

8
let result = await vscode.commands.executeCommand('workbench.action.tasks.build');

resolves immediately.

How can I await a build task with VS Code API?

Simla answered 25/4, 2020 at 16:30 Comment(0)
S
9

I figured it out! Tasks cannot be awaited from vscode.tasks.executeTask, but we can await vscode.tasks.onDidEndTask and check if ended task is our task.

async function executeBuildTask(task: vscode.Task) {
    const execution = await vscode.tasks.executeTask(task);

    return new Promise<void>(resolve => {
        let disposable = vscode.tasks.onDidEndTask(e => {
            if (e.execution.task.group === vscode.TaskGroup.Build) {
                disposable.dispose();
                resolve();
            }
        });
    });
}

async function getBuildTasks() {
    return new Promise<vscode.Task[]>(resolve => {
        vscode.tasks.fetchTasks().then((tasks) => {
            resolve(tasks.filter((task) => task.group === vscode.TaskGroup.Build));
        });
    });
}

export function activate(context: vscode.ExtensionContext) {
    context.subscriptions.push(vscode.commands.registerCommand('extension.helloWorld', async () => {
        const buildTasks = await getBuildTasks();
        await executeBuildTask(buildTasks[0]);
    }));
}

Note that currently there is a bug #96643, which prevents us from doing a comparison of vscode.Task objects: if (e.execution.task === execution.task) { ... }

Simla answered 9/5, 2020 at 20:18 Comment(1)
A simple if (e.execution === execution) should work now.Hussein
R
2

I think this depends on how the main command is executed in the extension.ts

Being new to JS/TS, I may be wrong here, but just trying to help:

make sure the vscode.command.registerCommand is not asyncronous, like below:

    context.subscriptions.push(vscode.commands.registerCommand('extension.openSettings', () => {
        return vscode.commands.executeCommand("workbench.action.openSettings", "settingsName");
    }));

This would be compared to something async, like below:

    context.subscriptions.push(vscode.commands.registerCommand('extension.removeHost', async (hostID) => {

        const bigipHosts: Array<string> | undefined = vscode.workspace.getConfiguration().get('extension.hosts');

        const newHosts = Hosts?.filter( item => item != hostID.label)

        await vscode.workspace.getConfiguration().update('f5-fast.hosts', newBigipHosts, vscode.ConfigurationTarget.Global);
        hostsTreeProvider.refresh();
    }));
Raynell answered 5/5, 2020 at 16:51 Comment(1)
Hi @Benji, thanks for posting and welcome to SO! Please ignore my previous (now deleted) comment. Unfortunately vscode.commands.executeCommand and vscode.commands.executeTask still resolve immediately, but I figured out a way to wait for a task to end (see answer below). Thank you!Simla
D
0

vscode.tasks.onDidEndTaskProcess to also get the exit status

If you only want to run the next task if the previous worked out, you can also check the exit status with onDidEndTaskProcess as in:

export async function activate(context: vscode.ExtensionContext) {
  async function runTask(): Promise<number|undefined> {
    // Define your command in a task.
    const quotingStyle: vscode.ShellQuoting = vscode.ShellQuoting.Strong
    let myTaskCommand: vscode.ShellQuotedString = {
      value: '/usr/bin/ls,
      quoting: quotingStyle,
    }
    const args = ['.']
    let myTaskArgs: vscode.ShellQuotedString[] = args.map((arg) => {
      return { value: arg, quoting: quotingStyle }
    })
    let myTaskOptions: vscode.ShellExecutionOptions = {
      cwd: '/usr/lib',
    }
    let shellExec: vscode.ShellExecution = new vscode.ShellExecution(
      myTaskCommand,
      myTaskArgs,
      myTaskOptions
    )
    const taskName = 'build'
    let myTask: vscode.Task = new vscode.Task(
      { type: "shell", group: "build", label: taskName },
      vscode.TaskScope.Workspace,
      taskName,
      "makefile",
      shellExec
    )
    myTask.presentationOptions.clear = true
    myTask.presentationOptions.showReuseMessage = true

    // Run the command.
    const execution = await vscode.tasks.executeTask(myTask)
    return new Promise(resolve => {
      const disposable = vscode.tasks.onDidEndTaskProcess(e => {
        if (e.execution === execution) {
          disposable.dispose()
          resolve(e.exitCode)
        }
      })
    })
  }

  context.subscriptions.push(
    vscode.commands.registerCommand('myextid.helloWorld', async function () {
      const exitCode = await runTask()
      if (exitCode === 0) {
        // Do something else.
      }
    })
  )
}

Related: How to detect failure of task execution from a vscode extension?

Tested on vscode 1.91.1, Ubuntu 24.04.

Delatorre answered 1/8, 2024 at 17:31 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.