diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 8ac475241..4f805b355 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -1,6 +1,7 @@
name: Build & Publish
on:
push:
+ branches: [master]
pull_request:
branches: [master]
release:
@@ -15,7 +16,7 @@ jobs:
- name: Use Java 8
uses: actions/setup-java@v1
with:
- java-version: '8'
+ java-version: "8"
architecture: x64
- name: Use Node 12.16.2
uses: actions/setup-node@v1
@@ -34,7 +35,7 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_SONARCLOUD_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
- JAVA_HOME: ''
+ JAVA_HOME: ""
- name: Upload lib
uses: actions/upload-artifact@v2
with:
@@ -45,12 +46,12 @@ jobs:
# lib generated in the previous step for a better real-world test.
test-extension:
needs: [build-and-analyse]
- name: 'Test Java ${{ matrix.java-version }} - Node ${{ matrix.node-version }} - ${{ matrix.os }}'
+ name: "Test Java ${{ matrix.java-version }} - Node ${{ matrix.node-version }} - ${{ matrix.os }}"
runs-on: ${{ matrix.os }}
strategy:
matrix:
node-version: [12.16.2]
- java-version: ['8', '11']
+ java-version: ["8", "11"]
os: [ubuntu-latest, windows-latest]
# os: [ubuntu-latest, windows-latest, macos-latest]
steps:
@@ -70,7 +71,7 @@ jobs:
arguments: extension:build
wrapper-cache-enabled: false
env:
- NODE_OPTIONS: '--max-old-space-size=4096'
+ NODE_OPTIONS: "--max-old-space-size=4096"
- name: Download lib
uses: actions/download-artifact@v2
with:
@@ -112,8 +113,8 @@ jobs:
arguments: testVsCode
wrapper-cache-enabled: false
env:
- DISPLAY: ':99.0'
- CI: 'true'
+ DISPLAY: ":99.0"
+ CI: "true"
- name: Stop Gradle daemon for root project
uses: eskatos/gradle-command-action@v1
with:
diff --git a/README.md b/README.md
index 367f9c485..f6b5ac72c 100644
--- a/README.md
+++ b/README.md
@@ -34,7 +34,7 @@ A Gradle build can have one or more projects. Projects are listed in a flat list
When you expand a project, tasks are listed in a tree, grouped by the task group. You can toggle the display of the tasks by clicking on the `Show Flat List`/`Show Tree` button in the treeview header.
-
+
Run tasks
@@ -47,7 +47,7 @@ Tasks can be run via:
A running task will be shown with an animated "spinner" icon in the treeviews, along with `Cancel Task` & `Restart Task` buttons. The `Cancel Task` button will gracefully cancel the task. The `Restart Task` button will first cancel the task, then restart it.
-
+
A task will be run a vscode terminal where you can view the task output.
@@ -60,6 +60,23 @@ Tasks run via the `Run a Gradle Build` command are not reflected in any of the t
+
+Control task terminal behaviour
+
+`"gradle.reuseTerminals": "task"` (default):
+
+
+
+`"gradle.reuseTerminals": "all"`:
+
+
+
+`"gradle.reuseTerminals": "off"`:
+
+
+
+
+
Debug JavaExec tasks
This extension provides an experimental feature to debug [JavaExec](https://docs.gradle.org/current/dsl/org.gradle.api.tasks.JavaExec.html) tasks. Before using this feature you need to install the [Debugger for Java](https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-debug) and [Language Support for Java](https://marketplace.visualstudio.com/items?itemName=redhat.java) extensions.
@@ -153,12 +170,13 @@ The extension uses the Gradle wrapper to list daemons, and is quite a slow proce
This extension contributes the following settings:
-- `gradle.autoDetect`: Automatically detect Gradle tasks
-- `gradle.focusTaskInExplorer`: Focus the task in the explorer when running a task
+- `gradle.autoDetect`: Automatically detect Gradle tasks ("on" or "off")
+- `gradle.focusTaskInExplorer`: Focus the task in the explorer when running a task (boolean)
- `gradle.nestedProjects`: Process nested projects (boolean or an array of directories)
+- `gradle.reuseTerminals`: Reuse task terminals ("task" [default], "all", or "off")
- `gradle.javaDebug`: Debug JavaExec tasks (see below for usage)
-- `gradle.debug`: Show extra debug info in the output panel
-- `gradle.disableConfirmations`: Disable the warning confirm messages when performing batch actions (eg clear tasks, stop daemons etc)
+- `gradle.debug`: Show extra debug info in the output panel (boolean)
+- `gradle.disableConfirmations`: Disable the warning confirm messages when performing batch actions (eg clear tasks, stop daemons etc) (boolean)
## Gradle & Java Settings
@@ -166,7 +184,7 @@ Set Gradle & Java options with standard environment variables or standard Gradle
### Example Environment Variables
-- `JAVE_HOME`
+- `JAVA_HOME`
- `GRADLE_USER_HOME`
_Note, the VS Code settings take precedence over the environment variables._
diff --git a/extension/package.json b/extension/package.json
index 659621bfe..d1a3baef3 100644
--- a/extension/package.json
+++ b/extension/package.json
@@ -592,6 +592,16 @@
"default": false,
"description": "Discover Gradle projects in nested sub-directories"
},
+ "gradle.reuseTerminals": {
+ "enum": [
+ "task",
+ "off",
+ "all"
+ ],
+ "default": "task",
+ "scope": "window",
+ "description": "Reuse task terminals behaviour"
+ },
"gradle.debug": {
"type": "boolean",
"default": false,
diff --git a/extension/src/async/index.ts b/extension/src/async/index.ts
deleted file mode 100644
index 3d438d3b7..000000000
--- a/extension/src/async/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from './Deferred';
diff --git a/extension/src/client/GradleClient.ts b/extension/src/client/GradleClient.ts
index e6504f0a0..6ebc707fa 100644
--- a/extension/src/client/GradleClient.ts
+++ b/extension/src/client/GradleClient.ts
@@ -26,10 +26,10 @@ import {
import { GradleClient as GrpcClient } from '../proto/gradle_grpc_pb';
import { logger, LoggerStream, LogVerbosity, Logger } from '../logger';
-import { EventWaiter } from '../events';
+import { EventWaiter } from '../util';
import { GradleServer } from '../server';
import { ProgressHandler } from '../progress';
-import { getGradleConfig, getConfigJavaDebug } from '../config';
+import { getGradleConfig, getConfigJavaDebug } from '../util';
import { removeCancellingTask, restartQueuedTask } from '../tasks/taskUtil';
import {
COMMAND_REFRESH_DAEMON_STATUS,
diff --git a/extension/src/commands/ClearAllPinnedTasksCommand.ts b/extension/src/commands/ClearAllPinnedTasksCommand.ts
index 50a96219b..b3817fe14 100644
--- a/extension/src/commands/ClearAllPinnedTasksCommand.ts
+++ b/extension/src/commands/ClearAllPinnedTasksCommand.ts
@@ -1,4 +1,4 @@
-import { confirmModal } from '../input';
+import { confirmModal } from '../util/input';
import { PinnedTasksStore } from '../stores';
import { Command } from './Command';
diff --git a/extension/src/commands/ClearAllRecentTasksCommand.ts b/extension/src/commands/ClearAllRecentTasksCommand.ts
index aedd49a42..f6554939e 100644
--- a/extension/src/commands/ClearAllRecentTasksCommand.ts
+++ b/extension/src/commands/ClearAllRecentTasksCommand.ts
@@ -1,4 +1,4 @@
-import { confirmModal } from '../input';
+import { confirmModal } from '../util/input';
import { RecentTasksStore } from '../stores';
import { Command } from './Command';
diff --git a/extension/src/commands/CloseAllTaskTerminalsCommand.ts b/extension/src/commands/CloseAllTaskTerminalsCommand.ts
index e828712b9..2ca199630 100644
--- a/extension/src/commands/CloseAllTaskTerminalsCommand.ts
+++ b/extension/src/commands/CloseAllTaskTerminalsCommand.ts
@@ -1,4 +1,4 @@
-import { confirmModal } from '../input';
+import { confirmModal } from '../util/input';
import { TaskTerminalsStore } from '../stores';
import { Command } from './Command';
diff --git a/extension/src/commands/PinTaskWithArgsCommand.ts b/extension/src/commands/PinTaskWithArgsCommand.ts
index 4fac13bc5..0c93e6fc3 100644
--- a/extension/src/commands/PinTaskWithArgsCommand.ts
+++ b/extension/src/commands/PinTaskWithArgsCommand.ts
@@ -1,6 +1,6 @@
import { GradleTaskTreeItem, PinnedTasksTreeDataProvider } from '../views';
import { GradleTaskDefinition } from '../tasks';
-import { getTaskArgs } from '../input';
+import { getTaskArgs } from '../util/input';
import { Command } from './Command';
export const COMMAND_PIN_TASK_WITH_ARGS = 'gradle.pinTaskWithArgs';
diff --git a/extension/src/commands/RunBuildCommand.ts b/extension/src/commands/RunBuildCommand.ts
index d248ce837..e47a75dc1 100644
--- a/extension/src/commands/RunBuildCommand.ts
+++ b/extension/src/commands/RunBuildCommand.ts
@@ -1,6 +1,6 @@
import * as vscode from 'vscode';
import { parseArgsStringToArgv } from 'string-argv';
-import { getGradleCommand, getRootProjectFolder } from '../input';
+import { getGradleCommand, getRootProjectFolder } from '../util/input';
import { GradleRunnerTerminal } from '../terminal';
import { getRunBuildCancellationKey } from '../client/CancellationKeys';
import { Command } from './Command';
diff --git a/extension/src/commands/StopDaemonCommand.ts b/extension/src/commands/StopDaemonCommand.ts
index 7da8d2c6f..96b139a7d 100644
--- a/extension/src/commands/StopDaemonCommand.ts
+++ b/extension/src/commands/StopDaemonCommand.ts
@@ -1,5 +1,5 @@
import { GradleDaemonTreeItem } from '../views';
-import { confirmModal } from '../input';
+import { confirmModal } from '../util/input';
import { logger } from '../logger';
import { Command } from './Command';
import { GradleClient } from '../client';
diff --git a/extension/src/commands/StopDaemonsCommand.ts b/extension/src/commands/StopDaemonsCommand.ts
index 958b8d33f..3d039cf37 100644
--- a/extension/src/commands/StopDaemonsCommand.ts
+++ b/extension/src/commands/StopDaemonsCommand.ts
@@ -1,5 +1,5 @@
import * as vscode from 'vscode';
-import { confirmModal } from '../input';
+import { confirmModal } from '../util/input';
import { StopDaemonsReply } from '../proto/gradle_pb';
import { logger } from '../logger';
import { Command } from './Command';
diff --git a/extension/src/decorators/index.ts b/extension/src/decorators/index.ts
deleted file mode 100644
index b7a1cf14d..000000000
--- a/extension/src/decorators/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from './decorators';
diff --git a/extension/src/events/index.ts b/extension/src/events/index.ts
deleted file mode 100644
index 7353629c5..000000000
--- a/extension/src/events/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from './EventWaiter';
diff --git a/extension/src/extension/Extension.ts b/extension/src/extension/Extension.ts
index 570d74d8c..49fbb4f48 100644
--- a/extension/src/extension/Extension.ts
+++ b/extension/src/extension/Extension.ts
@@ -4,10 +4,7 @@ import { Api } from '../api';
import { GradleClient } from '../client';
import { GradleServer } from '../server';
import { Icons } from '../icons';
-import {
- getConfigFocusTaskInExplorer,
- getConfigIsDebugEnabled,
-} from '../config';
+import { getConfigFocusTaskInExplorer, getConfigIsDebugEnabled } from '../util';
import {
GradleDaemonsTreeDataProvider,
PinnedTasksTreeDataProvider,
@@ -32,7 +29,7 @@ import {
RECENT_TASKS_VIEW,
} from '../views/constants';
import { focusTaskInGradleTasksTree } from '../views/viewUtil';
-import { FileWatcher } from '../watcher';
+import { FileWatcher } from '../util';
import { COMMAND_RENDER_TASK, COMMAND_REFRESH } from '../commands';
import { Commands } from '../commands/Commands';
@@ -263,16 +260,16 @@ export class Extension {
event.affectsConfiguration('java.import.gradle.java.home')
) {
await this.restartServer();
- }
- if (
+ } else if (
event.affectsConfiguration('gradle.javaDebug') ||
event.affectsConfiguration('gradle.nestedProjects')
) {
this.rootProjectsStore.clear();
await this.refresh();
await this.activate();
- }
- if (event.affectsConfiguration('gradle.debug')) {
+ } else if (event.affectsConfiguration('gradle.reuseTerminals')) {
+ await this.refresh();
+ } else if (event.affectsConfiguration('gradle.debug')) {
const debug = getConfigIsDebugEnabled();
Logger.setLogVerbosity(
debug ? LogVerbosity.DEBUG : LogVerbosity.INFO
diff --git a/extension/src/rootProject/RootProject.ts b/extension/src/rootProject/RootProject.ts
index 568f02654..66a064799 100644
--- a/extension/src/rootProject/RootProject.ts
+++ b/extension/src/rootProject/RootProject.ts
@@ -1,6 +1,6 @@
import * as vscode from 'vscode';
import { Environment } from '../proto/gradle_pb';
-import { JavaDebug } from '../config';
+import { JavaDebug } from '../util';
export class RootProject {
private environment?: Environment;
diff --git a/extension/src/rootProject/index.ts b/extension/src/rootProject/index.ts
new file mode 100644
index 000000000..69e5c08e6
--- /dev/null
+++ b/extension/src/rootProject/index.ts
@@ -0,0 +1 @@
+export * from './RootProject';
diff --git a/extension/src/server/serverUtil.ts b/extension/src/server/serverUtil.ts
index d7b307716..35cec43e4 100644
--- a/extension/src/server/serverUtil.ts
+++ b/extension/src/server/serverUtil.ts
@@ -1,4 +1,4 @@
-import { getConfigGradleJavaHome } from '../config';
+import { getConfigGradleJavaHome } from '../util';
export function getGradleServerCommand(): string {
const platform = process.platform;
diff --git a/extension/src/stores/EventedStore.ts b/extension/src/stores/EventedStore.ts
index a0ebaf2dd..ad9b803d6 100644
--- a/extension/src/stores/EventedStore.ts
+++ b/extension/src/stores/EventedStore.ts
@@ -1,5 +1,5 @@
import * as vscode from 'vscode';
-import { debounce } from '../decorators';
+import { debounce } from '../util';
export abstract class EventedStore implements vscode.Disposable {
private readonly _onDidChange: vscode.EventEmitter = new vscode.EventEmitter<
diff --git a/extension/src/stores/RootProjectsStore.ts b/extension/src/stores/RootProjectsStore.ts
index fea69c113..782fac224 100644
--- a/extension/src/stores/RootProjectsStore.ts
+++ b/extension/src/stores/RootProjectsStore.ts
@@ -1,6 +1,6 @@
import * as vscode from 'vscode';
import * as path from 'path';
-import { getNestedProjectsConfig, getConfigJavaDebug } from '../config';
+import { getNestedProjectsConfig, getConfigJavaDebug } from '../util';
import { StoreMap } from '.';
import { isGradleRootProject } from '../util';
import { RootProject } from '../rootProject/RootProject';
diff --git a/extension/src/tasks/GradleTaskProvider.ts b/extension/src/tasks/GradleTaskProvider.ts
index a5df07467..135c4d440 100644
--- a/extension/src/tasks/GradleTaskProvider.ts
+++ b/extension/src/tasks/GradleTaskProvider.ts
@@ -1,12 +1,12 @@
import * as vscode from 'vscode';
-import { EventWaiter } from '../events';
+import { EventWaiter } from '../util';
import { GradleTaskDefinition } from '.';
import { logger } from '../logger';
import { createTaskFromDefinition, loadTasksForProjectRoots } from './taskUtil';
import { TaskId } from '../stores/types';
import { RootProjectsStore, TaskTerminalsStore } from '../stores';
import { RootProject } from '../rootProject/RootProject';
-import { getConfigJavaDebug } from '../config';
+import { getConfigJavaDebug, getConfigReuseTerminals } from '../util';
import { GradleClient } from '../client';
export class GradleTaskProvider
@@ -64,11 +64,13 @@ export class GradleTaskProvider
vscode.Uri.file(gradleTaskDefinition.projectFolder),
javaDebug
);
+ const reuseTerminals = getConfigReuseTerminals();
return createTaskFromDefinition(
this.taskTerminalsStore,
gradleTaskDefinition,
rootProject,
- this.client
+ this.client,
+ reuseTerminals
);
}
diff --git a/extension/src/tasks/taskUtil.ts b/extension/src/tasks/taskUtil.ts
index 5c370588a..9c947e371 100644
--- a/extension/src/tasks/taskUtil.ts
+++ b/extension/src/tasks/taskUtil.ts
@@ -5,7 +5,12 @@ import { TaskArgs } from '../stores/types';
import { GradleTaskDefinition } from '.';
import { GradleRunnerTerminal } from '../terminal';
import { logger } from '../logger';
-import { getGradleConfig, getConfigIsAutoDetectionEnabled } from '../config';
+import {
+ getGradleConfig,
+ getConfigIsAutoDetectionEnabled,
+ getConfigReuseTerminals,
+ ReuseTerminalsValue,
+} from '../util';
import {
getJavaLanguageSupportExtension,
getJavaDebuggerExtension,
@@ -13,8 +18,8 @@ import {
JAVA_DEBUGGER_EXTENSION_ID,
isJavaDebuggerExtensionActivated,
isJavaLanguageSupportExtensionActivated,
-} from '../compat';
-import { getTaskArgs } from '../input';
+} from '../util/compat';
+import { getTaskArgs } from '../util/input';
import { COMMAND_RENDER_TASK } from '../commands';
import { RootProject } from '../rootProject/RootProject';
import { getRunTaskCommandCancellationKey } from '../client/CancellationKeys';
@@ -151,11 +156,55 @@ export function buildTaskName(definition: GradleTaskDefinition): string {
return `${definition.script}${argsLabel}`;
}
+function disposePreviousTerminals(
+ definition: GradleTaskDefinition,
+ taskTerminalsStore: TaskTerminalsStore,
+ reuseTerminals: ReuseTerminalsValue
+): void {
+ if (reuseTerminals === 'task') {
+ const previousTerminals = taskTerminalsStore.get(
+ definition.id + definition.args
+ );
+ if (previousTerminals) {
+ for (const previousTerminal of previousTerminals.values()) {
+ previousTerminal.dispose();
+ }
+ previousTerminals.clear();
+ }
+ } else if (reuseTerminals === 'all') {
+ const store = taskTerminalsStore.getData();
+ for (const taskTerminals of store.values()) {
+ for (const previousTerminal of taskTerminals.values()) {
+ previousTerminal.dispose();
+ }
+ taskTerminals.clear();
+ }
+ }
+}
+
+function handleTaskStart(
+ definition: GradleTaskDefinition,
+ taskTerminalsStore: TaskTerminalsStore,
+ reuseTerminals: ReuseTerminalsValue
+): void {
+ disposePreviousTerminals(definition, taskTerminalsStore, reuseTerminals);
+ const disposable = vscode.window.onDidOpenTerminal(
+ (openedTerminal: vscode.Terminal) => {
+ disposable.dispose();
+ taskTerminalsStore.addEntry(
+ definition.id + definition.args,
+ openedTerminal
+ );
+ }
+ );
+}
+
export function createTaskFromDefinition(
taskTerminalsStore: TaskTerminalsStore,
definition: Required,
rootProject: RootProject,
- client: GradleClient
+ client: GradleClient,
+ reuseTerminals: ReuseTerminalsValue
): vscode.Task {
const args = [definition.script]
.concat(parseArgsStringToArgv(definition.args.trim()))
@@ -165,6 +214,7 @@ export function createTaskFromDefinition(
rootProject.getProjectUri().fsPath,
definition.script
);
+
const terminal = new GradleRunnerTerminal(
rootProject,
args,
@@ -178,15 +228,7 @@ export function createTaskFromDefinition(
'gradle',
new vscode.CustomExecution(
async (): Promise => {
- const disposable = vscode.window.onDidOpenTerminal(
- (openedTerminal: vscode.Terminal) => {
- disposable.dispose();
- taskTerminalsStore.addEntry(
- definition.id + definition.args,
- openedTerminal
- );
- }
- );
+ handleTaskStart(definition, taskTerminalsStore, reuseTerminals);
return terminal;
}
),
@@ -209,6 +251,7 @@ function createVSCodeTaskFromGradleTask(
gradleTask: GradleTask,
rootProject: RootProject,
client: GradleClient,
+ reuseTerminals: ReuseTerminalsValue,
args = '',
javaDebug = false
): vscode.Task {
@@ -236,7 +279,8 @@ function createVSCodeTaskFromGradleTask(
taskTerminalsStore,
definition,
rootProject,
- client
+ client,
+ reuseTerminals
);
}
@@ -246,6 +290,7 @@ export function getVSCodeTasksFromGradleProject(
gradleProject: GradleProject,
client: GradleClient
): vscode.Task[] {
+ const reuseTerminals = getConfigReuseTerminals();
let projects: Array = [gradleProject];
const vsCodeTasks: vscode.Task[] = [];
while (projects.length) {
@@ -257,7 +302,8 @@ export function getVSCodeTasksFromGradleProject(
taskTerminalsStore,
gradleTask,
rootProject,
- client
+ client,
+ reuseTerminals
)
);
}
@@ -391,10 +437,12 @@ export function cloneTask(
javaDebug,
};
const rootProject = rootProjectsStore.get(definition.projectFolder);
+ const reuseTerminals = getConfigReuseTerminals();
return createTaskFromDefinition(
taskTerminalsStore,
definition,
rootProject!,
- client
+ client,
+ reuseTerminals
);
}
diff --git a/extension/src/terminal/GradleRunnerTerminal.ts b/extension/src/terminal/GradleRunnerTerminal.ts
index c2a5eaff9..e095d6ef2 100644
--- a/extension/src/terminal/GradleRunnerTerminal.ts
+++ b/extension/src/terminal/GradleRunnerTerminal.ts
@@ -15,7 +15,7 @@ const NL = '\n';
const CR = '\r';
const nlRegExp = new RegExp(`${NL}([^${CR}]|$)`, 'g');
-export class GradleRunnerTerminal {
+export class GradleRunnerTerminal implements vscode.Pseudoterminal {
private readonly writeEmitter = new vscode.EventEmitter();
private stdOutLoggerStream: LoggerStream | undefined;
private readonly closeEmitter = new vscode.EventEmitter();
diff --git a/extension/src/test/integration/gradle/extension.test.ts b/extension/src/test/integration/gradle/extension.test.ts
index fe7e5d8c8..1ba356462 100644
--- a/extension/src/test/integration/gradle/extension.test.ts
+++ b/extension/src/test/integration/gradle/extension.test.ts
@@ -15,8 +15,23 @@ const fixturePath = vscode.Uri.file(
path.resolve(__dirname, '../../../../test-fixtures', fixtureName)
);
+const executeAndWaitForTask = (task: vscode.Task): Promise => {
+ return new Promise(async (resolve) => {
+ const disposable = vscode.tasks.onDidEndTaskProcess((e) => {
+ if (e.execution.task === task) {
+ disposable.dispose();
+ resolve();
+ }
+ });
+ try {
+ await vscode.tasks.executeTask(task);
+ } catch (e) {
+ console.error('There was an error starting the task:', e.message);
+ }
+ });
+};
+
describe(getSuiteName('Extension'), () => {
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
let extension: vscode.Extension | undefined;
before(() => {
@@ -72,19 +87,7 @@ describe(getSuiteName('Extension'), () => {
extension!.exports.getLogger(),
'appendLine'
);
- await new Promise(async (resolve) => {
- const disposable = vscode.tasks.onDidEndTaskProcess((e) => {
- if (e.execution.task === task) {
- disposable.dispose();
- resolve();
- }
- });
- try {
- await vscode.tasks.executeTask(task);
- } catch (e) {
- console.error('There was an error starting the task:', e.message);
- }
- });
+ await executeAndWaitForTask(task);
assert.ok(loggerAppendSpy.calledWith(sinon.match('Hello, World!')));
assert.ok(
loggerAppendLineSpy.calledWith(sinon.match('Completed build: hello'))
@@ -104,7 +107,6 @@ describe(getSuiteName('Extension'), () => {
assert.ok(task);
const spy = sinon.spy(extension.exports.getLogger(), 'append');
await new Promise(async (resolve) => {
- // eslint-disable-next-line sonarjs/no-identical-functions
const endDisposable = vscode.tasks.onDidEndTaskProcess((e) => {
if (e.execution.task.definition.script === task.definition.script) {
endDisposable.dispose();
@@ -151,4 +153,55 @@ describe(getSuiteName('Extension'), () => {
assert.ok(hasMessage);
});
});
+
+ describe('Reuse terminals config', () => {
+ const resetConfig = async (): Promise =>
+ await vscode.workspace
+ .getConfiguration('gradle')
+ .update('reuseTerminals', 'off');
+
+ const executeAndWaitForTasks = async (): Promise => {
+ const tasks = await vscode.tasks.fetchTasks({ type: 'gradle' });
+ const byeTask = tasks.find(({ name }) => name === 'bye');
+ assert.ok(byeTask);
+ const helloTask = tasks.find(({ name }) => name === 'hello');
+ assert.ok(helloTask);
+ await executeAndWaitForTask(byeTask);
+ await executeAndWaitForTask(byeTask);
+ await executeAndWaitForTask(helloTask);
+ };
+
+ before(async () => await resetConfig());
+ after(async () => await resetConfig());
+
+ beforeEach(() => {
+ vscode.window.terminals.forEach((terminal) => {
+ terminal.dispose();
+ });
+ });
+
+ it('should generate a new terminal for every task run with reuseTerminals: "off"', async () => {
+ await vscode.workspace
+ .getConfiguration('gradle')
+ .update('reuseTerminals', 'off');
+ await executeAndWaitForTasks();
+ assert.strictEqual(vscode.window.terminals.length, 3);
+ });
+
+ it('should generate 1 terminal per task with reuseTerminals: "task"', async () => {
+ await vscode.workspace
+ .getConfiguration('gradle')
+ .update('reuseTerminals', 'task');
+ await executeAndWaitForTasks();
+ assert.strictEqual(vscode.window.terminals.length, 2);
+ });
+
+ it('should generate 1 terminal for all tasks with reuseTerminals: "all"', async () => {
+ await vscode.workspace
+ .getConfiguration('gradle')
+ .update('reuseTerminals', 'all');
+ await executeAndWaitForTasks();
+ assert.strictEqual(vscode.window.terminals.length, 1);
+ });
+ });
});
diff --git a/extension/src/async/Deferred.ts b/extension/src/util/Deferred.ts
similarity index 100%
rename from extension/src/async/Deferred.ts
rename to extension/src/util/Deferred.ts
diff --git a/extension/src/events/EventWaiter.ts b/extension/src/util/EventWaiter.ts
similarity index 100%
rename from extension/src/events/EventWaiter.ts
rename to extension/src/util/EventWaiter.ts
diff --git a/extension/src/watcher/FileWatcher.ts b/extension/src/util/FileWatcher.ts
similarity index 100%
rename from extension/src/watcher/FileWatcher.ts
rename to extension/src/util/FileWatcher.ts
diff --git a/extension/src/compat.ts b/extension/src/util/compat.ts
similarity index 100%
rename from extension/src/compat.ts
rename to extension/src/util/compat.ts
diff --git a/extension/src/config.ts b/extension/src/util/config.ts
similarity index 90%
rename from extension/src/config.ts
rename to extension/src/util/config.ts
index a1ac16da6..b71e7d1db 100644
--- a/extension/src/config.ts
+++ b/extension/src/util/config.ts
@@ -1,6 +1,6 @@
import * as vscode from 'vscode';
-import { GradleConfig } from './proto/gradle_pb';
-import { RootProject } from './rootProject/RootProject';
+import { GradleConfig } from '../proto/gradle_pb';
+import { RootProject } from '../rootProject/RootProject';
type AutoDetect = 'on' | 'off';
@@ -60,6 +60,14 @@ export function getConfigIsDebugEnabled(): boolean {
.get('debug', false);
}
+export type ReuseTerminalsValue = 'task' | 'off' | 'all';
+
+export function getConfigReuseTerminals(): ReuseTerminalsValue {
+ return vscode.workspace
+ .getConfiguration('gradle')
+ .get('reuseTerminals', 'task');
+}
+
export function getDisableConfirmations(): boolean {
return vscode.workspace
.getConfiguration('gradle')
diff --git a/extension/src/decorators/decorators.ts b/extension/src/util/decorators.ts
similarity index 100%
rename from extension/src/decorators/decorators.ts
rename to extension/src/util/decorators.ts
diff --git a/extension/src/util.ts b/extension/src/util/index.ts
similarity index 87%
rename from extension/src/util.ts
rename to extension/src/util/index.ts
index 0cd876d09..86447c939 100644
--- a/extension/src/util.ts
+++ b/extension/src/util/index.ts
@@ -2,7 +2,7 @@ import * as vscode from 'vscode';
import * as net from 'net';
import * as path from 'path';
import * as fs from 'fs';
-import { RootProject } from './rootProject/RootProject';
+import { RootProject } from '../rootProject';
export const isTest = (): boolean =>
process.env.VSCODE_TEST?.toLowerCase() === 'true';
@@ -64,3 +64,11 @@ export function isWorkspaceFolder(
): value is vscode.WorkspaceFolder {
return value && typeof value !== 'number';
}
+
+export * from './compat';
+export * from './config';
+export * from './decorators';
+export * from './Deferred';
+export * from './EventWaiter';
+export * from './input';
+export * from './FileWatcher';
diff --git a/extension/src/input/index.ts b/extension/src/util/input.ts
similarity index 97%
rename from extension/src/input/index.ts
rename to extension/src/util/input.ts
index 07b24b645..234a4deed 100644
--- a/extension/src/input/index.ts
+++ b/extension/src/util/input.ts
@@ -1,6 +1,6 @@
import * as vscode from 'vscode';
import { TaskArgs } from '../stores/types';
-import { getDisableConfirmations } from '../config';
+import { getDisableConfirmations } from '../util';
import { RootProject } from '../rootProject/RootProject';
import { RootProjectsStore } from '../stores';
diff --git a/extension/src/views/gradleDaemons/GradleDaemonsTreeDataProvider.ts b/extension/src/views/gradleDaemons/GradleDaemonsTreeDataProvider.ts
index 736b02310..dbd52d60e 100644
--- a/extension/src/views/gradleDaemons/GradleDaemonsTreeDataProvider.ts
+++ b/extension/src/views/gradleDaemons/GradleDaemonsTreeDataProvider.ts
@@ -1,6 +1,6 @@
import * as vscode from 'vscode';
import { GradleDaemonTreeItem } from '.';
-import { Deferred } from '../../async';
+import { Deferred } from '../../util';
import { RootProjectsStore } from '../../stores';
import { GradleClient } from '../../client';
diff --git a/extension/src/views/gradleTasks/GradleTaskTreeItem.ts b/extension/src/views/gradleTasks/GradleTaskTreeItem.ts
index 269ffc1c5..622ed54f1 100644
--- a/extension/src/views/gradleTasks/GradleTaskTreeItem.ts
+++ b/extension/src/views/gradleTasks/GradleTaskTreeItem.ts
@@ -1,5 +1,5 @@
import * as vscode from 'vscode';
-import { JavaDebug } from '../../config';
+import { JavaDebug } from '../../util';
import { Icons } from '../../icons';
import { TASK_STATE_RUNNING_REGEX } from '../constants';
import { getTreeItemState } from '../viewUtil';
diff --git a/extension/src/views/recentTasks/RecentTaskTreeItem.ts b/extension/src/views/recentTasks/RecentTaskTreeItem.ts
index d86c828ac..cc5ce1ab5 100644
--- a/extension/src/views/recentTasks/RecentTaskTreeItem.ts
+++ b/extension/src/views/recentTasks/RecentTaskTreeItem.ts
@@ -1,6 +1,6 @@
import * as vscode from 'vscode';
import { GradleTaskTreeItem } from '..';
-import { JavaDebug } from '../../config';
+import { JavaDebug } from '../../util';
import { Icons } from '../../icons';
import { TaskTerminalsStore } from '../../stores';
import { GradleTaskDefinition } from '../../tasks';
diff --git a/extension/src/views/viewUtil.ts b/extension/src/views/viewUtil.ts
index dd6a015a6..8eefe1af7 100644
--- a/extension/src/views/viewUtil.ts
+++ b/extension/src/views/viewUtil.ts
@@ -8,7 +8,7 @@ import {
} from './constants';
import { GradleTaskDefinition } from '../tasks';
import { logger } from '../logger';
-import { JavaDebug } from '../config';
+import { JavaDebug } from '../util';
import { TaskArgs } from '../stores/types';
import { isTaskCancelling, isTaskRunning } from '../tasks/taskUtil';
import {
diff --git a/extension/src/watcher/index.ts b/extension/src/watcher/index.ts
deleted file mode 100644
index 78f81077c..000000000
--- a/extension/src/watcher/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from './FileWatcher';
diff --git a/extension/test-fixtures/gradle-groovy-custom-build-file/my-custom-build.gradle b/extension/test-fixtures/gradle-groovy-custom-build-file/my-custom-build.gradle
index 700664759..ac3836ba3 100644
--- a/extension/test-fixtures/gradle-groovy-custom-build-file/my-custom-build.gradle
+++ b/extension/test-fixtures/gradle-groovy-custom-build-file/my-custom-build.gradle
@@ -11,6 +11,12 @@ tasks.register("hello") {
}
}
+tasks.register("bye") {
+ doLast {
+ println 'Goodbye cruel world'
+ }
+}
+
tasks.register("helloProjectProperty") {
doLast {
println 'Hello, Project Property!' + customProp
diff --git a/extension/test-fixtures/gradle-groovy-default-build-file/build.gradle b/extension/test-fixtures/gradle-groovy-default-build-file/build.gradle
index bb84c6d31..69c80d02b 100644
--- a/extension/test-fixtures/gradle-groovy-default-build-file/build.gradle
+++ b/extension/test-fixtures/gradle-groovy-default-build-file/build.gradle
@@ -11,6 +11,12 @@ tasks.register("hello") {
}
}
+tasks.register("bye") {
+ doLast {
+ println 'Goodbye cruel world'
+ }
+}
+
tasks.register("helloProjectProperty") {
doLast {
println 'Hello, Project Property!' + customProp
diff --git a/extension/test-fixtures/gradle-kotlin-default-build-file/build.gradle.kts b/extension/test-fixtures/gradle-kotlin-default-build-file/build.gradle.kts
index 0a8bb57fa..9f2bd031e 100644
--- a/extension/test-fixtures/gradle-kotlin-default-build-file/build.gradle.kts
+++ b/extension/test-fixtures/gradle-kotlin-default-build-file/build.gradle.kts
@@ -11,6 +11,12 @@ tasks.register("hello") {
}
}
+tasks.register("bye") {
+ doLast {
+ println("Goodbye cruel world")
+ }
+}
+
tasks.register("helloKotlinDefault") {
doLast {
println("Hello, helloKotlinDefault!")
diff --git a/images/reuse-terminals-all.gif b/images/reuse-terminals-all.gif
new file mode 100644
index 000000000..c57764c15
Binary files /dev/null and b/images/reuse-terminals-all.gif differ
diff --git a/images/reuse-terminals-off.gif b/images/reuse-terminals-off.gif
new file mode 100644
index 000000000..ce28d170d
Binary files /dev/null and b/images/reuse-terminals-off.gif differ
diff --git a/images/reuse-terminals-task.gif b/images/reuse-terminals-task.gif
new file mode 100644
index 000000000..4c250a553
Binary files /dev/null and b/images/reuse-terminals-task.gif differ
diff --git a/npm-package/.eslintignore b/npm-package/.eslintignore
index d5f19d89b..21a841fe4 100644
--- a/npm-package/.eslintignore
+++ b/npm-package/.eslintignore
@@ -1,2 +1,6 @@
node_modules
package-lock.json
+**/*.ts
+**/*.js
+!/*.ts
+/*.d.ts
diff --git a/npm-package/build.gradle b/npm-package/build.gradle
index 9319de1c7..d86e0256a 100644
--- a/npm-package/build.gradle
+++ b/npm-package/build.gradle
@@ -106,6 +106,15 @@ task copyClientTypes(type: Copy) {
into 'lib/client'
}
+task copyUtilTypes(type: Copy) {
+ dependsOn ':extension:buildProd'
+ group 'copy'
+ description 'Copies util'
+ from file("../extension/dist/util")
+ include "*.d.ts"
+ into 'lib/util'
+}
+
task copyTasksTypes(type: Copy) {
dependsOn ':extension:buildProd'
group 'copy'
@@ -152,7 +161,8 @@ task copyPublicApi(type: Copy) {
copyLoggerTypes,
copyRootProjectTypes,
copyApiTypes,
- copyIconTypes
+ copyIconTypes,
+ copyUtilTypes
group 'copy'
description 'Copies publc API types'
from file("../extension/dist")