Skip to content

Commit

Permalink
Use v4 of the MicroProfile starter api (#59)
Browse files Browse the repository at this point in the history
* Update to use v4 mp starter api

* move project generation to starter api helper

* Update wording in error messages

Signed-off-by: Ryan Zegray <[email protected]>
  • Loading branch information
rzgry committed Jun 23, 2020
1 parent ee6ddd3 commit b3f1590
Show file tree
Hide file tree
Showing 8 changed files with 151 additions and 74 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
# Change Log
All notable changes to the MicroProfile Starter extension will be documented below.

## 0.2.5
- MicroProfile 3.3
- Support for generating a WildFly project
- Better support for selecting a JavaSE version
- Use version 4 of the MicroProfile Starter API

## 0.2.4
- Use version 3 of the MicroProfile Starter API when generating a project
- Update dependencies
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# VS Code MicroProfile Starter Extension

[![Marketplace Version](https://vsmarketplacebadge.apphb.com/version/MicroProfile-Community.mp-starter-vscode-ext.svg "Current Release")](https://marketplace.visualstudio.com/items?itemName=MicroProfile-Community.mp-starter-vscode-ext)
[![Marketplace Installs](https://vsmarketplacebadge.apphb.com/installs-short/MicroProfile-Community.mp-starter-vscode-ext.svg "Installs")](https://marketplace.visualstudio.com/items?itemName=MicroProfile-Community.mp-starter-vscode-ext)
[![Build Status](https://travis-ci.org/MicroShed/mp-starter-vscode-ext.svg?branch=master)](https://travis-ci.org/MicroShed/mp-starter-vscode-ext)

The MicroProfile Starter extension provides support for generating a MicroProfile Maven project with examples based on the Eclipse MicroProfile Starter project (https://start.microprofile.io/) by the MicroProfile community. You will be able to generate a project by choosing a MicroProfile version, server and specifications, such as CDI, Config, Health, Metrics, and more. The code for this extension is hosted under the MicroShed organization on GitHub.
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "mp-starter-vscode-ext",
"displayName": "MicroProfile Starter",
"description": "Generate Java Microservice Maven projects using Eclipse MicroProfile",
"version": "0.2.4",
"version": "0.2.5",
"publisher": "MicroProfile-Community",
"preview": true,
"license": "Apache-2.0",
Expand Down
104 changes: 44 additions & 60 deletions src/commands/generateProject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,12 @@ import * as vscode from "vscode";
import * as util from "../util/util";
import * as prompts from "../util/vscodePrompts";
import * as path from "path";
import fetch from "node-fetch";
import { MP_STARTER_API_ROOT, OPEN_NEW_PROJECT_OPTIONS, EXTENSION_USER_AGENT } from "../constants";
import { OPEN_NEW_PROJECT_OPTIONS, ERRORS } from "../constants";
import * as mpStarterApi from "../util/mpStarterApi";

export async function generateProject(): Promise<void> {
try {
const mpSupportResponse = await fetch(`${MP_STARTER_API_ROOT}/supportMatrix`, {
method: "GET",
headers: {
"User-Agent": EXTENSION_USER_AGENT,
},
});
if (mpSupportResponse.status >= 400 && mpSupportResponse.status < 600) {
throw new Error(`Bad response ${mpSupportResponse.status}: ${mpSupportResponse.statusText}`);
}

const mpSupportMatrix = await mpSupportResponse.json();

const mpSupportMatrix = await mpStarterApi.getSupportMatrix();
// mpConfigurations is a map of mp version -> mp configuration
const mpConfigurations = mpSupportMatrix.configs;
const allMpVersions = Object.keys(mpConfigurations);
Expand All @@ -44,18 +33,20 @@ export async function generateProject(): Promise<void> {
return;
}

const javaSEVersion = await prompts.askForJavaSEVersion(mpVersion, mpServer);
// gets support information about which JavaSE versions / microprofile specs are supported by the
// users selected mp server / mp version combination
const { javaSEVersions, mpSpecs } = await mpStarterApi.getSupportedJavaAndSpecs(
mpServer,
mpVersion
);

const javaSEVersion = await prompts.askForJavaSEVersion(javaSEVersions);
if (javaSEVersion === undefined) {
return;
}

// ask user to pick a list of mp specifications to use for the given version of mp they selected
const allSupportedSpecs = mpConfigurations[mpVersion].specs;
const specDescriptions = mpSupportMatrix.descriptions;
const mpSpecifications = await prompts.askForMPSpecifications(
allSupportedSpecs,
specDescriptions
);
const mpSpecifications = await prompts.askForMPSpecifications(mpSpecs, specDescriptions);
if (mpSpecifications === undefined) {
return;
}
Expand All @@ -67,7 +58,7 @@ export async function generateProject(): Promise<void> {

const targetDirString = targetFolder.fsPath;

const requestPayload = {
const projectOptions = {
groupId: groupId,
artifactId: artifactId,
mpVersion: mpVersion,
Expand All @@ -80,61 +71,54 @@ export async function generateProject(): Promise<void> {
// location to download the zip file
const zipPath = path.join(targetDirString, zipName);

const requestOptions = {
url: `${MP_STARTER_API_ROOT}/project`,
method: "POST",
headers: {
"Content-Type": "application/json",
"User-Agent": EXTENSION_USER_AGENT,
},
body: JSON.stringify(requestPayload),
};

// show a progress bar as the zip file is being downloaded
await vscode.window.withProgress(
{
location: vscode.ProgressLocation.Notification,
title: "Generating the MicroProfile Starter project...",
cancellable: false,
},
() => util.downloadFile(requestOptions, zipPath)
() => mpStarterApi.downloadMPStarterProjectZip(projectOptions, zipPath)
);

const targetDirFolder = path.join(targetDirString, artifactId);

try {
const targetDirFolder = path.join(targetDirString, artifactId);
await util.unzipFile(zipPath, targetDirString, targetDirFolder);
try {
await util.deleteFile(zipPath);
} catch (e) {
console.error(e);
vscode.window.showErrorMessage(`Failed to delete file ${zipName}`);
}

// open the unzipped folder in a new VS Code window
const uriPath = vscode.Uri.file(targetDirFolder);
// prompt user whether they want to add project to current workspace or open in a new window
const selection = await vscode.window.showInformationMessage(
"MicroProfile Starter project generated. Would you like to add your project to the current workspace or open it in a new window?",
...[
OPEN_NEW_PROJECT_OPTIONS.ADD_CURRENT_WORKSPACE,
OPEN_NEW_PROJECT_OPTIONS.OPEN_NEW_WINDOW,
]
);
if (selection === OPEN_NEW_PROJECT_OPTIONS.ADD_CURRENT_WORKSPACE) {
vscode.workspace.updateWorkspaceFolders(0, 0, { uri: uriPath });
} else if (selection === OPEN_NEW_PROJECT_OPTIONS.OPEN_NEW_WINDOW) {
await vscode.commands.executeCommand("vscode.openFolder", uriPath, true);
}
} catch (err) {
console.error(err);
vscode.window.showErrorMessage("Failed to extract the MicroProfile Starter project.");
} catch (e) {
console.error(e);
const err = new Error("Unable to extract MicroProfile Starter project");
err.name = ERRORS.EXTRACT_PROJECT_ERROR;
throw err;
}

// if failed to delete the zip, no need to error out but show a warning to users
try {
await util.deleteFile(zipPath);
} catch (e) {
console.error(e);
vscode.window.showErrorMessage(`Failed to delete file ${zipName}`);
}

const uriPath = vscode.Uri.file(targetDirFolder);
// prompt user whether they want to add project to current workspace or open in a new window
const selection = await vscode.window.showInformationMessage(
"MicroProfile Starter project generated. Add your project to the current workspace or open it in a new window?",
...[OPEN_NEW_PROJECT_OPTIONS.ADD_CURRENT_WORKSPACE, OPEN_NEW_PROJECT_OPTIONS.OPEN_NEW_WINDOW]
);
if (selection === OPEN_NEW_PROJECT_OPTIONS.ADD_CURRENT_WORKSPACE) {
vscode.workspace.updateWorkspaceFolders(0, 0, { uri: uriPath });
} else if (selection === OPEN_NEW_PROJECT_OPTIONS.OPEN_NEW_WINDOW) {
await vscode.commands.executeCommand("vscode.openFolder", uriPath, true);
}
} catch (e) {
console.error(e);
if (e.name === "FetchError") {
if (e.name === ERRORS.FETCH_ERROR) {
vscode.window.showErrorMessage(
"Failed to connect to the MicroProfile Starter. Please check your network connection and try again."
);
} else if (e.name === ERRORS.EXTRACT_PROJECT_ERROR) {
vscode.window.showErrorMessage("Failed to extract the MicroProfile Starter project");
} else {
vscode.window.showErrorMessage("Failed to generate a MicroProfile Starter project");
}
Expand Down
10 changes: 8 additions & 2 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export const MP_STARTER_API_ROOT = "https://start.microprofile.io/api/3";
export const MP_STARTER_API_ROOT = "https://start.microprofile.io/api/4";

export const MP_VERSION_LABELS: Record<string, string> = {
MP33: "Version 3.3",
MP32: "Version 3.2",
MP30: "Version 3.0",
MP22: "Version 2.2",
Expand All @@ -17,7 +18,7 @@ export const MP_SERVER_LABELS: Record<string, string> = {
PAYARA_MICRO: "Payara Micro",
THORNTAIL_V2: "Thorntail Version 2",
KUMULUZEE: "KumuluzEE",
TOMEE: "Apache TomEE 8.00-M2",
TOMEE: "Apache TomEE 8.00-M3",
WILDFLY: "WildFly",
WILDFLY_SWARM: "WildFly Swarm",
QUARKUS: "Quarkus",
Expand All @@ -34,3 +35,8 @@ export const CONFIRM_OPTIONS = {
YES: "Yes",
NO: "No",
};

export const ERRORS = {
FETCH_ERROR: "FetchError",
EXTRACT_PROJECT_ERROR: "ExtractProjectError",
};
89 changes: 89 additions & 0 deletions src/util/mpStarterApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { MP_STARTER_API_ROOT, EXTENSION_USER_AGENT } from "../constants";
import fetch from "node-fetch";
import * as util from "../util/util";

interface MPVersionSupport {
supportedServers: string[];
specs: string[];
}

interface SupportMatrix {
configs: Record<string, MPVersionSupport>;
descriptions: Record<string, string>;
}

export async function getSupportMatrix(): Promise<SupportMatrix> {
const mpSupportResponse = await fetch(`${MP_STARTER_API_ROOT}/supportMatrix`, {
method: "GET",
headers: {
"User-Agent": EXTENSION_USER_AGENT,
},
});
if (mpSupportResponse.status >= 400 && mpSupportResponse.status < 600) {
throw new Error(`Bad response ${mpSupportResponse.status}: ${mpSupportResponse.statusText}`);
}

return mpSupportResponse.json();
}

interface SupportDetails {
mpVersion: string;
mpSpecs: string[];
javaSEVersions: string[];
}

export async function getSupportedJavaAndSpecs(
serverName: string,
microprofileVersion: string
): Promise<SupportDetails> {
const serverSupportResponse = await fetch(`${MP_STARTER_API_ROOT}/supportMatrix/servers`, {
method: "GET",
headers: {
"User-Agent": EXTENSION_USER_AGENT,
},
});
if (serverSupportResponse.status >= 400 && serverSupportResponse.status < 600) {
throw new Error(
`Bad response ${serverSupportResponse.status}: ${serverSupportResponse.statusText}`
);
}

const supportJSON = await serverSupportResponse.json();
const serverInformation = supportJSON.configs[serverName];

const supportDetails: SupportDetails | undefined = serverInformation.find(
(supportRecord: SupportDetails) => supportRecord.mpVersion === microprofileVersion
);

if (supportDetails === undefined) {
throw new Error("Unable to find supported MicroProfile specifications and Java versions");
}

return supportDetails;
}

interface StarterProjectOptions {
groupId: string;
artifactId: string;
mpVersion: string;
supportedServer: string;
javaSEVersion: string;
selectedSpecs: string[];
}

export async function downloadMPStarterProjectZip(
options: StarterProjectOptions,
downloadLocation: string
): Promise<void> {
const requestOptions = {
url: `${MP_STARTER_API_ROOT}/project`,
method: "POST",
headers: {
"Content-Type": "application/json",
"User-Agent": EXTENSION_USER_AGENT,
},
body: JSON.stringify(options),
};

await util.downloadFile(requestOptions, downloadLocation);
}
11 changes: 1 addition & 10 deletions src/util/vscodePrompts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,8 @@ export async function askForArtifactID(): Promise<string | undefined> {
}

export async function askForJavaSEVersion(
mpVersion: string,
mpServer: string
supportedJavaSEVersions: string[]
): Promise<string | undefined> {
const MP32_JAVA_11_SUPPORTED = ["LIBERTY", "PAYARA_MICRO", "HELIDON", "THORNTAIL_V2", "WILDFLY"];

let supportedJavaSEVersions = ["SE8"];

if (mpVersion === "MP32" && MP32_JAVA_11_SUPPORTED.includes(mpServer)) {
supportedJavaSEVersions = ["SE8", "SE11"];
}

return await vscode.window.showQuickPick(supportedJavaSEVersions, {
ignoreFocusOut: true,
placeHolder: "Select a Java SE version.",
Expand Down

0 comments on commit b3f1590

Please sign in to comment.