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

add draft info languages #80

Merged
merged 21 commits into from
Jan 9, 2023
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"properties": {
"aks.draft.releaseTag": {
"type": "string",
"default": "v0.0.25",
"default": "v0.0.27",
"title": "Draft repository release tag",
"description": "Release tag for the stable Draft tool release."
}
Expand Down Expand Up @@ -152,6 +152,7 @@
"watch-tests": "tsc -p . -w --outDir out",
"pretest": "npm run compile-tests && npm run compile && npm run lint",
"lint": "eslint src --ext ts",
"format": "prettier --write .",
"test": "node ./out/test/runTest.js"
},
"devDependencies": {
Expand Down
4 changes: 4 additions & 0 deletions src/commands/runDraftTool/helper/draftCommandBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,3 +116,7 @@ export function buildUpdateCommand(
): string {
return `update -a ${host} -s ${certificate} -d ${destination}`;
}

export function buildInfoCommand(): string {
return `info`;
}
62 changes: 62 additions & 0 deletions src/commands/runDraftTool/helper/languages.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,70 @@
import {Errorable, failed, Succeeded} from '../../../utils/errorable';
import {buildInfoCommand} from './draftCommandBuilder';
import {ensureDraftBinary, runDraftCommand} from './runDraftHelper';

/**
* The respresentation of a Draft language for use in this extension.
*/
export interface DraftLanguage {
name: string;
id: string;
versions: string[];
}

/**
* The full return of the draft info command.
*/
interface DraftInfo {
supportedLanguages: DraftInfoLanguage[];
supportedDeployTypes: string[];
}
/**
* The respresentation of a Draft language as returned by the draft info command.
*/
interface DraftInfoLanguage {
name: string;
displayName: string;
variableExampleValues: DraftInfoExampleValues;
}
interface DraftInfoExampleValues {
// eslint-disable-next-line @typescript-eslint/naming-convention
VERSION: string[]; // All caps since it comes from draft builder variable conventions
}
export async function getDraftLanguages(): Promise<Errorable<DraftLanguage[]>> {
const ensureDraftResult = await ensureDraftBinary();
if (failed<null>(ensureDraftResult)) {
return {
succeeded: false,
error: ensureDraftResult.error
};
}

const [result, err] = await runDraftCommand(buildInfoCommand());
if (err) {
return {
succeeded: false,
error: err
};
}
const resultJSON = JSON.parse(result);
const draftInfo = resultJSON as DraftInfo;

const infoLanguages: DraftLanguage[] = draftInfo.supportedLanguages.map(
(infoLanguage: DraftInfoLanguage): DraftLanguage => {
const language: DraftLanguage = {
name: infoLanguage.displayName,
id: infoLanguage.name,
versions: infoLanguage.variableExampleValues.VERSION
};
return language;
}
);

return {
succeeded: true,
result: infoLanguages
};
}
export const draftLanguages: DraftLanguage[] = [
{id: 'clojure', name: 'Clojure', versions: ['8-jdk-alpine']},
{id: 'csharp', name: 'C#', versions: ['6.0', '5.0', '4.0', '3.1']},
Expand Down
18 changes: 12 additions & 6 deletions src/commands/runDraftTool/helper/runDraftHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,17 @@ function checkIfDraftBinaryExist(destinationFile: string): boolean {
return fs.existsSync(destinationFile);
}

export async function downloadDraftBinary() {
export async function ensureDraftBinary(): Promise<Errorable<null>> {
// 0. Get latest release tag.
// 1: check if file already exist.
// 2: if not Download latest.
const latestReleaseTag = await getLatestDraftReleaseTag();

if (!latestReleaseTag) {
return;
return {
succeeded: false,
error: `failed to get latest release tag`
};
}

const draftBinaryFile = getBinaryFileName();
Expand All @@ -47,7 +50,7 @@ export async function downloadDraftBinary() {
}

if (checkIfDraftBinaryExist(destinationFile)) {
return {succeeded: true};
return {succeeded: true, result: null};
}

const draftDownloadUrl = `https://github.com/Azure/draft/releases/download/${latestReleaseTag}/${draftBinaryFile}`;
Expand All @@ -59,19 +62,22 @@ export async function downloadDraftBinary() {
if (failed(downloadResult)) {
return {
succeeded: false,
error: [`Failed to download draft binary: ${downloadResult.error[0]}`]
error: `Failed to download draft binary: ${downloadResult.error} from ${draftDownloadUrl}`
};
}
//If linux check -- make chmod 0755
fs.chmodSync(destinationFile, '0755');
return succeeded(downloadResult);
return {
succeeded: true,
result: null
};
}

function getBinaryFileName() {
let architecture = os.arch();
let operatingSystem = os.platform().toLocaleLowerCase();

if (architecture === 'x64') {
if (architecture === 'x64' || architecture === 'ia32') {
Tatsinnit marked this conversation as resolved.
Show resolved Hide resolved
Tatsinnit marked this conversation as resolved.
Show resolved Hide resolved
architecture = 'amd64';
}
let draftBinaryFile = `draft-${operatingSystem}-${architecture}`;
Expand Down
26 changes: 10 additions & 16 deletions src/commands/runDraftTool/runDraftDeployment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {Context} from './model/context';
import * as vscode from 'vscode';
import {State, StateApi} from '../../utils/state';
import {longRunning} from '../../utils/host';
import {downloadDraftBinary, runDraftCommand} from './helper/runDraftHelper';
import {ensureDraftBinary, runDraftCommand} from './helper/runDraftHelper';
import {
AzureWizard,
AzureWizardExecuteStep,
Expand All @@ -23,7 +23,7 @@ import {
getHelm,
getKubectl
} from '../../utils/kubernetes';
import {failed, getAysncResult} from '../../utils/errorable';
import {failed, getAsyncResult} from '../../utils/errorable';
import {
RegistryItem,
RepositoryItem,
Expand All @@ -43,6 +43,7 @@ import {
import {image} from '../../utils/acr';
import {CompletedSteps} from './model/guidedExperience';
import {sort} from '../../utils/sort';
import {getAsyncOptions} from '../../utils/quickPick';

const title = 'Draft a Kubernetes Deployment and Service';

Expand Down Expand Up @@ -93,7 +94,7 @@ export async function runDraftDeployment(

// Ensure Draft Binary
const downloadResult = await longRunning(`Downloading Draft.`, () =>
downloadDraftBinary()
ensureDraftBinary()
Tatsinnit marked this conversation as resolved.
Show resolved Hide resolved
);
if (!downloadResult) {
vscode.window.showErrorMessage('Failed to download Draft');
Expand Down Expand Up @@ -224,7 +225,7 @@ class PromptNamespace extends AzureWizardPromptStep<WizardContext> {
}

public async prompt(wizardContext: WizardContext): Promise<void> {
const namespaces = getAysncResult(this.k8s.listNamespaces());
const namespaces = getAsyncResult(this.k8s.listNamespaces());
const newOption = 'New Namespace';
const getOptions = async (): Promise<vscode.QuickPickItem[]> => {
const namespaceOptions: vscode.QuickPickItem[] = (
Expand Down Expand Up @@ -325,7 +326,7 @@ class PromptAcrSubscription extends AzureWizardPromptStep<WizardContext> {
}

public async prompt(wizardContext: WizardContext): Promise<void> {
const subs = getAysncResult(this.az.listSubscriptions());
const subs = getAsyncResult(this.az.listSubscriptions());
const subToItem = (sub: SubscriptionItem) => ({
label: sub.subscription.displayName || '',
description: sub.subscription.subscriptionId || ''
Expand Down Expand Up @@ -365,7 +366,7 @@ class PromptAcrResourceGroup extends AzureWizardPromptStep<WizardContext> {
throw Error('ACR Subscription is undefined');
}

const rgs = getAysncResult(
const rgs = getAsyncResult(
this.az.listResourceGroups(wizardContext.acrSubscription)
);
const rgToItem = (rg: ResourceGroupItem) => ({
Expand Down Expand Up @@ -402,7 +403,7 @@ class PromptAcrRegistry extends AzureWizardPromptStep<WizardContext> {
throw Error('ACR Resource Group is undefined');
}

const registries = getAysncResult(
const registries = getAsyncResult(
this.az.listContainerRegistries(
wizardContext.acrSubscription,
wizardContext.acrResourceGroup
Expand Down Expand Up @@ -444,7 +445,7 @@ class PromptAcrRepository extends AzureWizardPromptStep<WizardContext> {
throw Error('ACR Registry is undefined');
}

const repositories = getAysncResult(
const repositories = getAsyncResult(
this.az.listRegistryRepositories(
wizardContext.acrSubscription,
wizardContext.acrRegistry
Expand Down Expand Up @@ -489,7 +490,7 @@ class PromptAcrTag extends AzureWizardPromptStep<WizardContext> {
throw Error('ACR Repository is undefined');
}

const tags = getAysncResult(
const tags = getAsyncResult(
this.az.listRepositoryTags(
wizardContext.acrSubscription,
wizardContext.acrRegistry,
Expand Down Expand Up @@ -793,10 +794,3 @@ function getOutputPath(wizardContext: WizardContext): string {
return path.join(base, 'manifests');
}
}

async function getAsyncOptions<T>(
arr: Promise<T[]>,
callbackfn: (a: T) => vscode.QuickPickItem
): Promise<vscode.QuickPickItem[]> {
return (await arr).map(callbackfn);
}
19 changes: 12 additions & 7 deletions src/commands/runDraftTool/runDraftDockerfile.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import {longRunning} from '../../utils/host';
import {Context} from './model/context';
import * as vscode from 'vscode';
import {downloadDraftBinary, runDraftCommand} from './helper/runDraftHelper';
import {DraftLanguage, draftLanguages} from './helper/languages';
import {ensureDraftBinary, runDraftCommand} from './helper/runDraftHelper';
import {
DraftLanguage,
draftLanguages,
getDraftLanguages
} from './helper/languages';
import {
AzureWizard,
AzureWizardExecuteStep,
Expand All @@ -19,6 +23,8 @@ import {State, StateApi} from '../../utils/state';
import {ignoreFocusOut} from './helper/commonPrompts';
import {CompletedSteps} from './model/guidedExperience';
import {ValidatePort} from '../../utils/validation';
import {getAsyncResult} from '../../utils/errorable';
import {getAsyncOptions} from '../../utils/quickPick';

const title = 'Draft a Dockerfile from source code';

Expand All @@ -41,7 +47,7 @@ export async function runDraftDockerfile(

// Ensure Draft Binary
const downloadResult = await longRunning(`Downloading Draft.`, () =>
downloadDraftBinary()
ensureDraftBinary()
);
if (!downloadResult) {
vscode.window.showErrorMessage('Failed to download Draft');
Expand Down Expand Up @@ -109,17 +115,16 @@ class PromptSourceCodeFolder extends AzureWizardPromptStep<WizardContext> {
class PromptLanguage extends AzureWizardPromptStep<WizardContext> {
public async prompt(wizardContext: WizardContext): Promise<void> {
const languageToItem = (lang: DraftLanguage) => ({label: lang.name});
const languageOptions: vscode.QuickPickItem[] =
draftLanguages.map(languageToItem);
const draftLanguages = getAsyncResult(getDraftLanguages());
const languagePick = await wizardContext.ui.showQuickPick(
languageOptions,
getAsyncOptions(draftLanguages, languageToItem),
{
ignoreFocusOut,
stepName: 'Programming Language',
placeHolder: 'Select the programming language'
}
);
const language = draftLanguages.find(
const language = (await draftLanguages).find(
(lang) => languageToItem(lang).label === languagePick.label
);
if (language === undefined) {
Expand Down
39 changes: 39 additions & 0 deletions src/test/suite/utils/languages.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import {ESLint} from 'eslint';
import {
DraftLanguage,
getDraftLanguages
} from '../../../commands/runDraftTool/helper/languages';
import * as assert from 'assert';
import {
Errorable,
failed,
getAsyncResult,
Succeeded
} from '../../../utils/errorable';
import {before} from 'mocha';
import {ensureDraftBinary} from '../../../commands/runDraftTool/helper/runDraftHelper';

suite('Languages Test Suite', () => {
before(async function () {
this.timeout(5000);
const draftBinaryResult = await ensureDraftBinary();
if (failed(draftBinaryResult)) {
throw draftBinaryResult.error;
}
});

test('languages are retrieve from draft info without error', async () => {
const languages = await getAsyncResult(getDraftLanguages());

assert.doesNotThrow(getDraftLanguages);
assert(languages.length > 0);
});

test('each retrieved language contains a version', async () => {
const languages = await getAsyncResult(getDraftLanguages());

languages.forEach((lang: DraftLanguage) => {
assert(lang.versions.length > 0);
});
});
});
2 changes: 1 addition & 1 deletion src/utils/errorable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export function failed<T>(e: Errorable<T>): e is Failed {
return !e.succeeded;
}

export async function getAysncResult<T>(e: Promise<Errorable<T>>): Promise<T> {
export async function getAsyncResult<T>(e: Promise<Errorable<T>>): Promise<T> {
const awaited = await e;
if (failed(awaited)) {
throw Error(awaited.error);
Expand Down
8 changes: 8 additions & 0 deletions src/utils/quickPick.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import * as vscode from 'vscode';

export async function getAsyncOptions<T>(
arr: Promise<T[]>,
callbackfn: (a: T) => vscode.QuickPickItem
): Promise<vscode.QuickPickItem[]> {
return (await arr).map(callbackfn);
}