Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Support to create new project #1146

Merged
merged 1 commit into from
Jan 17, 2022
Merged
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: 18 additions & 0 deletions extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,16 @@
{
"command": "gradle.hideStoppedDaemons",
"title": "Hide Stopped Daemons"
},
{
"command": "gradle.createProject",
"category": "Gradle",
"title": "Create a Gradle Java Project..."
},
{
"command": "gradle.createProjectAdvanced",
"category": "Gradle",
"title": "Create a Gradle Java Project... (Advanced)"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In long term, you can consider use a custom button to "switch to advanced mode" in the wizard. Then you only need one command as the only entry.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great. #1153 will track it.

}
],
"menus": {
Expand Down Expand Up @@ -466,6 +476,14 @@
{
"command": "gradle.findTask",
"when": "gradle:extensionActivated"
},
{
"command": "gradle.createProject",
"when": "gradle:extensionActivated"
},
{
"command": "gradle.createProjectAdvanced",
"when": "gradle:extensionActivated"
}
],
"view/title": [
Expand Down
7 changes: 5 additions & 2 deletions extension/src/commands/Commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ import {
RecentTasksTreeDataProvider,
} from "../views";
import { Command } from "./Command";
import { COMMAND_CREATE_PROJECT, COMMAND_CREATE_PROJECT_ADVANCED, CreateProjectCommand } from "./CreateProjectCommand";
import { HideStoppedDaemonsCommand, HIDE_STOPPED_DAEMONS } from "./HideStoppedDaemonsCommand";
import { ShowStoppedDaemonsCommand, SHOW_STOPPED_DAEMONS } from "./ShowStoppedDaemonsCommand";

Expand All @@ -99,10 +100,10 @@ export class Commands {
private gradleTasksTreeView: vscode.TreeView<vscode.TreeItem>
) {}

private registerCommand(commandId: string, command: Command): void {
private registerCommand(commandId: string, command: Command, params?: unknown[]): void {
this.context.subscriptions.push(
instrumentOperationAsVsCodeCommand(commandId, (...args: unknown[]) => {
return command.run(...args);
return command.run(...args, params || []);
})
);
}
Expand Down Expand Up @@ -180,5 +181,7 @@ export class Commands {
this.registerCommand(COMMAND_FIND_TASK, new FindTaskCommand(this.gradleTasksTreeView, this.gradleTaskProvider));
this.registerCommand(SHOW_STOPPED_DAEMONS, new ShowStoppedDaemonsCommand(this.gradleDaemonsTreeDataProvider));
this.registerCommand(HIDE_STOPPED_DAEMONS, new HideStoppedDaemonsCommand(this.gradleDaemonsTreeDataProvider));
this.registerCommand(COMMAND_CREATE_PROJECT, new CreateProjectCommand(this.client), [false]);
this.registerCommand(COMMAND_CREATE_PROJECT_ADVANCED, new CreateProjectCommand(this.client), [true]);
}
}
107 changes: 107 additions & 0 deletions extension/src/commands/CreateProjectCommand.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.

import * as path from "path";
import * as vscode from "vscode";
import { GradleClient } from "../client";
import { getRunTaskCommandCancellationKey } from "../client/CancellationKeys";
import { selectProjectTypeStep } from "../createProject/SelectProjectTypeStep";
import { selectScriptDSLStep } from "../createProject/SelectScriptDSLStep";
import { IProjectCreationMetadata, IProjectCreationStep, ProjectType, StepResult } from "../createProject/types";
import { Command } from "./Command";

export const COMMAND_CREATE_PROJECT = "gradle.createProject";
export const COMMAND_CREATE_PROJECT_ADVANCED = "gradle.createProjectAdvanced";

export class CreateProjectCommand extends Command {
constructor(private client: GradleClient) {
super();
}

async run(params: unknown[]): Promise<void> {
if (!params || params[0] === undefined) {
return;
}
const folders = vscode.workspace.workspaceFolders;
const targetFolderUri = await vscode.window.showOpenDialog({
defaultUri: folders && folders.length ? folders[0].uri : undefined,
title: "Select target Folder",
openLabel: "Select",
canSelectFiles: false,
canSelectFolders: true,
canSelectMany: false,
});
const isAdvanced = params[0] as boolean;
if (targetFolderUri) {
const metadata: IProjectCreationMetadata = {
isAdvanced: isAdvanced,
totalSteps: isAdvanced ? 5 : 2,
testFramework: undefined, // junit4
projectType: ProjectType.JAVA_APPLICATION,
targetFolder: targetFolderUri[0].fsPath,
projectName: path.basename(targetFolderUri[0].fsPath),
sourcePackageName: path.basename(targetFolderUri[0].fsPath),
steps: [],
nextStep: isAdvanced ? selectProjectTypeStep : selectScriptDSLStep,
};
const success = await this.runSteps(metadata);
if (success) {
await this.createProject(metadata);
const openInNewWindow = !(folders && folders.length);
vscode.commands.executeCommand(
"vscode.openFolder",
vscode.Uri.file(metadata.targetFolder),
openInNewWindow
);
}
}
return;
}

private async runSteps(metadata: IProjectCreationMetadata): Promise<boolean> {
let step: IProjectCreationStep | undefined = metadata.nextStep;
while (step !== undefined) {
const result = await step.run(metadata);
switch (result) {
case StepResult.NEXT:
step = metadata.nextStep;
break;
case StepResult.PREVIOUS:
if (metadata.steps.length === 0) {
return false;
}
step = metadata.steps.pop();
break;
case StepResult.STOP:
return false; // user cancellation
default:
throw new Error("invalid StepResult returned.");
}
}
return true;
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
private async createProject(metadata: IProjectCreationMetadata): Promise<void> {
const cancellationKey = getRunTaskCommandCancellationKey(metadata.targetFolder, "init");
const args: string[] = ["init"];
if (!metadata.projectType || !metadata.scriptDSL || !metadata.projectName || !metadata.sourcePackageName) {
return;
}
args.push("--dsl");
args.push(metadata.scriptDSL);
args.push("--type");
args.push(metadata.projectType);
if (metadata.testFramework) {
args.push("--test-framework");
args.push(metadata.testFramework);
}
args.push("--project-name");
args.push(metadata.projectName);
if (metadata.sourcePackageName) {
args.push("--package");
args.push(metadata.sourcePackageName);
}
await this.client.runBuild(metadata.targetFolder, cancellationKey, args);
}
}
77 changes: 77 additions & 0 deletions extension/src/createProject/SelectProjectTypeStep.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.

import * as vscode from "vscode";
import { selectScriptDSLStep } from "./SelectScriptDSLStep";
import { IProjectCreationMetadata, IProjectCreationStep, ProjectType, StepResult } from "./types";

export class SelectProjectTypeStep implements IProjectCreationStep {
public async run(metadata: IProjectCreationMetadata): Promise<StepResult> {
const disposables: vscode.Disposable[] = [];
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const selectProjectTypePromise = new Promise<StepResult>(async (resolve, _reject) => {
const pickBox = vscode.window.createQuickPick<vscode.QuickPickItem>();
pickBox.title = `Create Gradle project: Select project type (${metadata.steps.length + 1}/${
metadata.totalSteps
})`;
pickBox.placeholder = "Select project type ...";
pickBox.matchOnDescription = true;
pickBox.ignoreFocusOut = true;
pickBox.items = this.getProjectTypePickItems();
disposables.push(
pickBox.onDidAccept(async () => {
const selectedType = pickBox.selectedItems[0];
if (selectedType) {
switch (selectedType.label) {
case "application":
metadata.projectType = ProjectType.JAVA_APPLICATION;
break;
case "library":
metadata.projectType = ProjectType.JAVA_LIBRARY;
break;
case "Gradle plugin":
metadata.projectType = ProjectType.JAVA_GRADLE_PLUGIN;
metadata.totalSteps = 4; // when creating gradle plugin, we shouldn't specify test framework
break;
default:
resolve(StepResult.STOP);
}
metadata.steps.push(selectProjectTypeStep);
metadata.nextStep = selectScriptDSLStep;
resolve(StepResult.NEXT);
}
}),
pickBox.onDidHide(() => {
resolve(StepResult.STOP);
})
);
disposables.push(pickBox);
pickBox.show();
});

try {
return await selectProjectTypePromise;
} finally {
disposables.forEach((d) => d.dispose());
}
}

private getProjectTypePickItems(): vscode.QuickPickItem[] {
const result: vscode.QuickPickItem[] = [];
result.push({
label: "application",
description: "A command-line application implemented in Java",
});
result.push({
label: "library",
description: "A Java library",
});
result.push({
label: "Gradle plugin",
description: "A Gradle plugin implemented in Java",
});
return result;
}
}

export const selectProjectTypeStep = new SelectProjectTypeStep();
82 changes: 82 additions & 0 deletions extension/src/createProject/SelectScriptDSLStep.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.

import * as vscode from "vscode";
import { selectTestFrameworkStep } from "./SelectTestFrameworkStep";
import { specifyProjectNameStep } from "./SpecifyProjectNameStep";
import { IProjectCreationMetadata, IProjectCreationStep, ProjectType, StepResult } from "./types";

export class SelectScriptDSLStep implements IProjectCreationStep {
public async run(metadata: IProjectCreationMetadata): Promise<StepResult> {
const disposables: vscode.Disposable[] = [];
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const selectScriptDSLPromise = new Promise<StepResult>(async (resolve, _reject) => {
const pickBox = vscode.window.createQuickPick<vscode.QuickPickItem>();
pickBox.title = `Create Gradle project: Select script DSL (${metadata.steps.length + 1}/${
metadata.totalSteps
})`;
pickBox.placeholder = "Select build script DSL ...";
pickBox.matchOnDescription = true;
pickBox.ignoreFocusOut = true;
pickBox.items = this.getScriptDSLPickItems();
if (metadata.steps.length) {
pickBox.buttons = [vscode.QuickInputButtons.Back];
disposables.push(
pickBox.onDidTriggerButton((item) => {
if (item === vscode.QuickInputButtons.Back) {
resolve(StepResult.PREVIOUS);
}
})
);
}
disposables.push(
pickBox.onDidAccept(() => {
const selectedScriptDSL = pickBox.selectedItems[0];
if (selectedScriptDSL) {
switch (selectedScriptDSL.label) {
case "Groovy":
metadata.scriptDSL = "groovy";
break;
case "Kotlin":
metadata.scriptDSL = "kotlin";
break;
default:
resolve(StepResult.STOP);
}
metadata.steps.push(selectScriptDSLStep);
if (!metadata.isAdvanced || metadata.projectType === ProjectType.JAVA_GRADLE_PLUGIN) {
metadata.nextStep = specifyProjectNameStep;
} else {
metadata.nextStep = selectTestFrameworkStep;
}
resolve(StepResult.NEXT);
}
}),
pickBox.onDidHide(() => {
resolve(StepResult.STOP);
})
);
disposables.push(pickBox);
pickBox.show();
});

try {
return await selectScriptDSLPromise;
} finally {
disposables.forEach((d) => d.dispose());
}
}

private getScriptDSLPickItems(): vscode.QuickPickItem[] {
const result: vscode.QuickPickItem[] = [];
result.push({
label: "Groovy",
});
result.push({
label: "Kotlin",
});
return result;
}
}

export const selectScriptDSLStep = new SelectScriptDSLStep();
Loading