From b1b2865926395270ef37bc0ade3761acbb0a11ec Mon Sep 17 00:00:00 2001 From: msalain Date: Wed, 29 May 2024 10:43:30 -0700 Subject: [PATCH 01/12] added log for start of static web app command --- src/commands/createStaticWebApp/createStaticWebApp.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/commands/createStaticWebApp/createStaticWebApp.ts b/src/commands/createStaticWebApp/createStaticWebApp.ts index b0888de07..8339899eb 100644 --- a/src/commands/createStaticWebApp/createStaticWebApp.ts +++ b/src/commands/createStaticWebApp/createStaticWebApp.ts @@ -50,6 +50,7 @@ function isSubscription(item?: SubscriptionTreeItemBase): item is SubscriptionTr let isVerifyingWorkspace: boolean = false; export async function createStaticWebApp(context: IActionContext & Partial & Partial, node?: SubscriptionTreeItemBase): Promise { + console.log("STARTING STATIC WEB APP LOG"); if (isVerifyingWorkspace) { throw new VerifyingWorkspaceError(context); } From 08c4d5fe019e0e29f7a63ef3133cdb5c4948e12b Mon Sep 17 00:00:00 2001 From: alain-zhiyanov Date: Fri, 7 Jun 2024 14:00:02 -0700 Subject: [PATCH 02/12] added functionality clone and start SWA --- .../createStaticWebApp/createStaticWebApp.ts | 133 +++++++++++++----- 1 file changed, 97 insertions(+), 36 deletions(-) diff --git a/src/commands/createStaticWebApp/createStaticWebApp.ts b/src/commands/createStaticWebApp/createStaticWebApp.ts index 8339899eb..c00ebc0d1 100644 --- a/src/commands/createStaticWebApp/createStaticWebApp.ts +++ b/src/commands/createStaticWebApp/createStaticWebApp.ts @@ -7,7 +7,10 @@ import { StaticSiteARMResource, WebSiteManagementClient } from '@azure/arm-appse import { LocationListStep, ResourceGroupCreateStep, ResourceGroupListStep, SubscriptionTreeItemBase, VerifyProvidersStep } from '@microsoft/vscode-azext-azureutils'; import { AzExtFsExtra, AzureWizard, AzureWizardExecuteStep, AzureWizardPromptStep, ExecuteActivityContext, IActionContext, ICreateChildImplContext, nonNullProp } from '@microsoft/vscode-azext-utils'; import { AppResource } from '@microsoft/vscode-azext-utils/hostapi'; -import { ProgressLocation, ProgressOptions, Uri, window, workspace } from 'vscode'; +import { exec } from 'child_process'; +import { homedir } from 'os'; +import { join } from 'path'; +import { ExtensionContext, ProgressLocation, ProgressOptions, Uri, WorkspaceFolder, window, workspace } from 'vscode'; import { Utils } from 'vscode-uri'; import { StaticWebAppResolver } from '../../StaticWebAppResolver'; import { DetectorResults, NodeDetector } from '../../detectors/node/NodeDetector'; @@ -20,7 +23,7 @@ import { getGitHubAccessToken } from '../../utils/gitHubUtils'; import { gitPull } from '../../utils/gitUtils'; import { localize } from '../../utils/localize'; import { telemetryUtils } from '../../utils/telemetryUtils'; -import { getSingleRootFsPath, getSubFolders, showNoWorkspacePrompt, tryGetWorkspaceFolder } from '../../utils/workspaceUtils'; +import { getSingleRootFsPath, getSubFolders, showNoWorkspacePrompt } from '../../utils/workspaceUtils'; import { RemoteShortnameStep } from '../createRepo/RemoteShortnameStep'; import { RepoCreateStep } from '../createRepo/RepoCreateStep'; import { RepoNameStep } from '../createRepo/RepoNameStep'; @@ -49,26 +52,105 @@ function isSubscription(item?: SubscriptionTreeItemBase): item is SubscriptionTr } let isVerifyingWorkspace: boolean = false; -export async function createStaticWebApp(context: IActionContext & Partial & Partial, node?: SubscriptionTreeItemBase): Promise { +export async function createStaticWebApp(context: IActionContext & Partial & ExtensionContext & Partial, node?: SubscriptionTreeItemBase): Promise { console.log("STARTING STATIC WEB APP LOG"); + if (isVerifyingWorkspace) { throw new VerifyingWorkspaceError(context); } + const progressOptions: ProgressOptions = { location: ProgressLocation.Window, title: localize('verifyingWorkspace', 'Verifying workspace...') }; isVerifyingWorkspace = true; - try { - if (!isSubscription(node)) { - node = await ext.rgApi.appResourceTree.showTreeItemPicker(SubscriptionTreeItemBase.contextValue, context); + + + if (!isSubscription(node)) { + node = await ext.rgApi.appResourceTree.showTreeItemPicker(SubscriptionTreeItemBase.contextValue, context); + } + //folder is manually set below + //const folder = await tryGetWorkspaceFolder(context); + + + // ---- this used to be below the if (folder) + const client: WebSiteManagementClient = await createWebSiteClient([context, node.subscription]); + const wizardContext: IStaticWebAppWizardContext = { + accessToken: await getGitHubAccessToken(), + client, + ...context, + ...node.subscription, + ...(await createActivityContext()) + }; + + const title: string = localize('createStaticApp', 'Create Static Web App'); + const promptSteps: AzureWizardPromptStep[] = []; + const executeSteps: AzureWizardExecuteStep[] = []; + + + if (!context.advancedCreation) { + wizardContext.sku = SkuListStep.getSkus()[0]; + executeSteps.push(new ResourceGroupCreateStep()); + } else { + promptSteps.push(new ResourceGroupListStep()); + } + + promptSteps.push(new StaticWebAppNameStep(), new SkuListStep()); + const hasRemote: boolean = !!wizardContext.repoHtmlUrl; + // ---- + + const wizard: AzureWizard = new AzureWizard(wizardContext, { + title, + promptSteps, + executeSteps, + showLoadingPrompt: true + }); + + wizardContext.telemetry.properties.gotRemote = String(hasRemote); + wizardContext.uri = wizardContext.uri || getSingleRootFsPath(); + + //this prompt is new. it allows us to get the name early + await wizard.prompt(); + + + //cloning template --- + + const repoUrl = 'https://github.com/alain-zhiyanov/template-swa-la'; + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access + const folderName: string = wizardContext.newStaticWebAppName || 'default_folder_name'; + const homeDir = homedir(); + const clonePath = join(homeDir, folderName); + const command = `git clone ${repoUrl} "${clonePath}"`; + exec(command, (error, stdout, stderr) => { + if (error) { + console.error(`Error: ${error.message}`); + return; } + if (stderr) { + console.error(`Stderr: ${stderr}`); + return; + } + console.log(`Repo cloned to folder: ${clonePath}`); + }); + // --- + + try { + + const clonePathUri: Uri = Uri.file(clonePath); await window.withProgress(progressOptions, async () => { - const folder = await tryGetWorkspaceFolder(context); + const folder: WorkspaceFolder = { + uri: clonePathUri, + name: "myUri", + index: 0 + } + + + if (folder) { + await telemetryUtils.runWithDurationTelemetry(context, 'tryGetFrameworks', async () => { const detector = new NodeDetector(); @@ -99,6 +181,8 @@ export async function createStaticWebApp(context: IActionContext & Partial[] = []; - const executeSteps: AzureWizardExecuteStep[] = []; - - if (!context.advancedCreation) { - wizardContext.sku = SkuListStep.getSkus()[0]; - executeSteps.push(new ResourceGroupCreateStep()); - } else { - promptSteps.push(new ResourceGroupListStep()); - } - promptSteps.push(new StaticWebAppNameStep(), new SkuListStep()); - const hasRemote: boolean = !!wizardContext.repoHtmlUrl; // if the local project doesn't have a GitHub remote, we will create it for them + // this used to be right below website management client, maybe doesn't even need to be ran? if (!hasRemote) { promptSteps.push(new GitHubOrgListStep(), new RepoNameStep(), new RepoPrivacyStep(), new RemoteShortnameStep()); + executeSteps.push(new RepoCreateStep()); } @@ -158,15 +223,9 @@ export async function createStaticWebApp(context: IActionContext & Partial = new AzureWizard(wizardContext, { - title, - promptSteps, - executeSteps, - showLoadingPrompt: true - }); - wizardContext.telemetry.properties.gotRemote = String(hasRemote); - wizardContext.uri = wizardContext.uri || getSingleRootFsPath(); + + wizardContext.telemetry.properties.numberOfWorkspaces = !workspace.workspaceFolders ? String(0) : String(workspace.workspaceFolders.length); await wizard.prompt(); @@ -177,6 +236,7 @@ export async function createStaticWebApp(context: IActionContext & Partial { return await createStaticWebApp({ ...context, advancedCreation: true }, node); } From f7662ed5e220299f50a1beb7c5023ec12d68609e Mon Sep 17 00:00:00 2001 From: alain-zhiyanov Date: Tue, 11 Jun 2024 14:59:46 -0700 Subject: [PATCH 03/12] changing createstaticwebapp flow (broken at staticwebappcreatestep) --- .../createStaticWebApp/createStaticWebApp.ts | 67 +++++++++++++++++-- 1 file changed, 60 insertions(+), 7 deletions(-) diff --git a/src/commands/createStaticWebApp/createStaticWebApp.ts b/src/commands/createStaticWebApp/createStaticWebApp.ts index c00ebc0d1..d6efdf89b 100644 --- a/src/commands/createStaticWebApp/createStaticWebApp.ts +++ b/src/commands/createStaticWebApp/createStaticWebApp.ts @@ -7,7 +7,6 @@ import { StaticSiteARMResource, WebSiteManagementClient } from '@azure/arm-appse import { LocationListStep, ResourceGroupCreateStep, ResourceGroupListStep, SubscriptionTreeItemBase, VerifyProvidersStep } from '@microsoft/vscode-azext-azureutils'; import { AzExtFsExtra, AzureWizard, AzureWizardExecuteStep, AzureWizardPromptStep, ExecuteActivityContext, IActionContext, ICreateChildImplContext, nonNullProp } from '@microsoft/vscode-azext-utils'; import { AppResource } from '@microsoft/vscode-azext-utils/hostapi'; -import { exec } from 'child_process'; import { homedir } from 'os'; import { join } from 'path'; import { ExtensionContext, ProgressLocation, ProgressOptions, Uri, WorkspaceFolder, window, workspace } from 'vscode'; @@ -41,6 +40,7 @@ import { StaticWebAppNameStep } from './StaticWebAppNameStep'; import { setGitWorkspaceContexts } from './setWorkspaceContexts'; import { tryGetApiLocations } from './tryGetApiLocations'; + function isSubscription(item?: SubscriptionTreeItemBase): item is SubscriptionTreeItemBase { try { // Accessing item.subscription throws an error for some workspace items @@ -98,7 +98,7 @@ export async function createStaticWebApp(context: IActionContext & Partial = new AzureWizard(wizardContext, { @@ -108,7 +108,6 @@ export async function createStaticWebApp(context: IActionContext & Partial { if (error) { console.error(`Error: ${error.message}`); @@ -134,11 +176,13 @@ export async function createStaticWebApp(context: IActionContext & Partial { const folder: WorkspaceFolder = { @@ -191,6 +235,12 @@ export async function createStaticWebApp(context: IActionContext & Partial { return await createStaticWebApp({ ...context, advancedCreation: true }, node); } + + + From e11f13c4dbff7ed583238a776713aaf6b6eda95b Mon Sep 17 00:00:00 2001 From: alain-zhiyanov Date: Wed, 12 Jun 2024 11:18:14 -0700 Subject: [PATCH 04/12] flow changed to support create and clone from template --- .../StaticWebAppCreateStep.ts | 12 ++++ .../createStaticWebApp/createStaticWebApp.ts | 61 +++++-------------- 2 files changed, 26 insertions(+), 47 deletions(-) diff --git a/src/commands/createStaticWebApp/StaticWebAppCreateStep.ts b/src/commands/createStaticWebApp/StaticWebAppCreateStep.ts index 79298572e..d3ab9ba3b 100644 --- a/src/commands/createStaticWebApp/StaticWebAppCreateStep.ts +++ b/src/commands/createStaticWebApp/StaticWebAppCreateStep.ts @@ -7,15 +7,27 @@ import { StaticSiteARMResource } from "@azure/arm-appservice"; import { LocationListStep } from "@microsoft/vscode-azext-azureutils"; import { AzureWizardExecuteStep, nonNullProp, nonNullValueAndProp } from "@microsoft/vscode-azext-utils"; import { AppResource } from "@microsoft/vscode-azext-utils/hostapi"; +import { Octokit } from "@octokit/rest"; import { Progress } from "vscode"; import { ext } from "../../extensionVariables"; import { localize } from "../../utils/localize"; +import { createOctokitClient } from "../github/createOctokitClient"; import { IStaticWebAppWizardContext } from "./IStaticWebAppWizardContext"; export class StaticWebAppCreateStep extends AzureWizardExecuteStep { public priority: number = 250; public async execute(context: IStaticWebAppWizardContext, progress: Progress<{ message?: string | undefined; increment?: number | undefined }>): Promise { + context.branchData = {name : "main"}; + + const octokitClient: Octokit = await createOctokitClient(context); + + const owner = "alain-zhiyanov"; + const repo = context.newStaticWebAppName || 'def'; + + const { data } = await octokitClient.repos.get({ owner, repo }); + context.repoHtmlUrl = data.html_url; + const newName: string = nonNullProp(context, 'newStaticWebAppName'); const branchData = nonNullProp(context, 'branchData'); const siteEnvelope: StaticSiteARMResource = { diff --git a/src/commands/createStaticWebApp/createStaticWebApp.ts b/src/commands/createStaticWebApp/createStaticWebApp.ts index d6efdf89b..3286ccdcb 100644 --- a/src/commands/createStaticWebApp/createStaticWebApp.ts +++ b/src/commands/createStaticWebApp/createStaticWebApp.ts @@ -7,9 +7,10 @@ import { StaticSiteARMResource, WebSiteManagementClient } from '@azure/arm-appse import { LocationListStep, ResourceGroupCreateStep, ResourceGroupListStep, SubscriptionTreeItemBase, VerifyProvidersStep } from '@microsoft/vscode-azext-azureutils'; import { AzExtFsExtra, AzureWizard, AzureWizardExecuteStep, AzureWizardPromptStep, ExecuteActivityContext, IActionContext, ICreateChildImplContext, nonNullProp } from '@microsoft/vscode-azext-utils'; import { AppResource } from '@microsoft/vscode-azext-utils/hostapi'; +import { Octokit } from '@octokit/rest'; import { homedir } from 'os'; import { join } from 'path'; -import { ExtensionContext, ProgressLocation, ProgressOptions, Uri, WorkspaceFolder, window, workspace } from 'vscode'; +import { ProgressLocation, ProgressOptions, Uri, WorkspaceFolder, window, workspace } from 'vscode'; import { Utils } from 'vscode-uri'; import { StaticWebAppResolver } from '../../StaticWebAppResolver'; import { DetectorResults, NodeDetector } from '../../detectors/node/NodeDetector'; @@ -18,15 +19,17 @@ import { VerifyingWorkspaceError } from '../../errors'; import { ext } from '../../extensionVariables'; import { createActivityContext } from '../../utils/activityUtils'; import { createWebSiteClient } from '../../utils/azureClients'; +import { cpUtils } from '../../utils/cpUtils'; import { getGitHubAccessToken } from '../../utils/gitHubUtils'; import { gitPull } from '../../utils/gitUtils'; import { localize } from '../../utils/localize'; import { telemetryUtils } from '../../utils/telemetryUtils'; -import { getSingleRootFsPath, getSubFolders, showNoWorkspacePrompt } from '../../utils/workspaceUtils'; +import { getSingleRootFsPath, getSubFolders, showNoWorkspacePrompt, tryGetWorkspaceFolder } from '../../utils/workspaceUtils'; import { RemoteShortnameStep } from '../createRepo/RemoteShortnameStep'; import { RepoCreateStep } from '../createRepo/RepoCreateStep'; import { RepoNameStep } from '../createRepo/RepoNameStep'; import { RepoPrivacyStep } from '../createRepo/RepoPrivacyStep'; +import { createOctokitClient } from '../github/createOctokitClient'; import { showSwaCreated } from '../showSwaCreated'; import { ApiLocationStep } from './ApiLocationStep'; import { AppLocationStep } from './AppLocationStep'; @@ -52,7 +55,7 @@ function isSubscription(item?: SubscriptionTreeItemBase): item is SubscriptionTr } let isVerifyingWorkspace: boolean = false; -export async function createStaticWebApp(context: IActionContext & Partial & ExtensionContext & Partial, node?: SubscriptionTreeItemBase): Promise { +export async function createStaticWebApp(context: IActionContext & Partial & Partial, node?: SubscriptionTreeItemBase): Promise { console.log("STARTING STATIC WEB APP LOG"); if (isVerifyingWorkspace) { @@ -114,7 +117,7 @@ export async function createStaticWebApp(context: IActionContext & Partial { - if (error) { - console.error(`Error: ${error.message}`); - return; - } - if (stderr) { - console.error(`Stderr: ${stderr}`); - return; - } - console.log(`Repo cloned to folder: ${clonePath}`); - }); - */ - // --- - + await tryGetWorkspaceFolder(context); try { @@ -291,7 +254,7 @@ export async function createStaticWebApp(context: IActionContext & Partial { + return new Promise(resolve => setTimeout(resolve, ms)); + } + From 687a1cef57932d4d467d5c0361eab17d939ae82b Mon Sep 17 00:00:00 2001 From: alain-zhiyanov Date: Wed, 12 Jun 2024 14:25:19 -0700 Subject: [PATCH 05/12] dynamically get branch --- .../createStaticWebApp/StaticWebAppCreateStep.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/commands/createStaticWebApp/StaticWebAppCreateStep.ts b/src/commands/createStaticWebApp/StaticWebAppCreateStep.ts index d3ab9ba3b..964a0dbd1 100644 --- a/src/commands/createStaticWebApp/StaticWebAppCreateStep.ts +++ b/src/commands/createStaticWebApp/StaticWebAppCreateStep.ts @@ -18,7 +18,6 @@ export class StaticWebAppCreateStep extends AzureWizardExecuteStep): Promise { - context.branchData = {name : "main"}; const octokitClient: Octokit = await createOctokitClient(context); @@ -28,6 +27,20 @@ export class StaticWebAppCreateStep extends AzureWizardExecuteStep branch.name === 'main'); + + if (defaultBranch) { + context.branchData = { name: defaultBranch.name }; + + } else { + context.branchData = {name: branches[0].name }; + } + const newName: string = nonNullProp(context, 'newStaticWebAppName'); const branchData = nonNullProp(context, 'branchData'); const siteEnvelope: StaticSiteARMResource = { From c7ed4501c6fdd30b94e05f91e287c86e7f35da15 Mon Sep 17 00:00:00 2001 From: alain-zhiyanov Date: Fri, 21 Jun 2024 14:03:32 -0700 Subject: [PATCH 06/12] changing repo to private & create repo in new dir --- .../createStaticWebApp/createStaticWebApp.ts | 50 +++++++++++-------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/src/commands/createStaticWebApp/createStaticWebApp.ts b/src/commands/createStaticWebApp/createStaticWebApp.ts index 3286ccdcb..2161d0abf 100644 --- a/src/commands/createStaticWebApp/createStaticWebApp.ts +++ b/src/commands/createStaticWebApp/createStaticWebApp.ts @@ -3,17 +3,18 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { StaticSiteARMResource, WebSiteManagementClient } from '@azure/arm-appservice'; +import type { StaticSiteARMResource, WebSiteManagementClient } from '@azure/arm-appservice'; import { LocationListStep, ResourceGroupCreateStep, ResourceGroupListStep, SubscriptionTreeItemBase, VerifyProvidersStep } from '@microsoft/vscode-azext-azureutils'; -import { AzExtFsExtra, AzureWizard, AzureWizardExecuteStep, AzureWizardPromptStep, ExecuteActivityContext, IActionContext, ICreateChildImplContext, nonNullProp } from '@microsoft/vscode-azext-utils'; -import { AppResource } from '@microsoft/vscode-azext-utils/hostapi'; -import { Octokit } from '@octokit/rest'; -import { homedir } from 'os'; -import { join } from 'path'; -import { ProgressLocation, ProgressOptions, Uri, WorkspaceFolder, window, workspace } from 'vscode'; +import { AzExtFsExtra, AzureWizard, nonNullProp, type AzureWizardExecuteStep, type AzureWizardPromptStep, type ExecuteActivityContext, type IActionContext, type ICreateChildImplContext } from '@microsoft/vscode-azext-utils'; +import type { AppResource } from '@microsoft/vscode-azext-utils/hostapi'; +import type { Octokit } from '@octokit/rest'; +import { promises as fs } from 'node:fs'; // Import the promises API from fs +import { homedir } from 'node:os'; +import { join } from 'node:path'; +import { ProgressLocation, Uri, window, workspace, type ProgressOptions, type WorkspaceFolder } from 'vscode'; import { Utils } from 'vscode-uri'; import { StaticWebAppResolver } from '../../StaticWebAppResolver'; -import { DetectorResults, NodeDetector } from '../../detectors/node/NodeDetector'; +import { NodeDetector, type DetectorResults } from '../../detectors/node/NodeDetector'; import { NodeConstants } from '../../detectors/node/nodeConstants'; import { VerifyingWorkspaceError } from '../../errors'; import { ext } from '../../extensionVariables'; @@ -35,7 +36,7 @@ import { ApiLocationStep } from './ApiLocationStep'; import { AppLocationStep } from './AppLocationStep'; import { BuildPresetListStep } from './BuildPresetListStep'; import { GitHubOrgListStep } from './GitHubOrgListStep'; -import { IStaticWebAppWizardContext } from './IStaticWebAppWizardContext'; +import type { IStaticWebAppWizardContext } from './IStaticWebAppWizardContext'; import { OutputLocationStep } from './OutputLocationStep'; import { SkuListStep } from './SkuListStep'; import { StaticWebAppCreateStep } from './StaticWebAppCreateStep'; @@ -44,6 +45,7 @@ import { setGitWorkspaceContexts } from './setWorkspaceContexts'; import { tryGetApiLocations } from './tryGetApiLocations'; + function isSubscription(item?: SubscriptionTreeItemBase): item is SubscriptionTreeItemBase { try { // Accessing item.subscription throws an error for some workspace items @@ -54,7 +56,7 @@ function isSubscription(item?: SubscriptionTreeItemBase): item is SubscriptionTr } } -let isVerifyingWorkspace: boolean = false; +let isVerifyingWorkspace = false; export async function createStaticWebApp(context: IActionContext & Partial & Partial, node?: SubscriptionTreeItemBase): Promise { console.log("STARTING STATIC WEB APP LOG"); @@ -119,27 +121,33 @@ export async function createStaticWebApp(context: IActionContext & Partial { return await createStaticWebApp({ ...context, advancedCreation: true }, node); @@ -283,3 +291,5 @@ function sleep(ms: number): Promise { + + From 9600e2028034383cf01d7f0356bd62513463e45d Mon Sep 17 00:00:00 2001 From: alain-zhiyanov Date: Wed, 3 Jul 2024 10:17:25 -0700 Subject: [PATCH 07/12] added link API call and logicApp command parameter (broken) --- .../IStaticWebAppWizardContext.ts | 5 +++ .../StaticWebAppCreateStep.ts | 41 ++++++++++++++++--- .../createStaticWebApp/createStaticWebApp.ts | 27 ++++++++---- src/commands/registerCommands.ts | 3 +- 4 files changed, 61 insertions(+), 15 deletions(-) diff --git a/src/commands/createStaticWebApp/IStaticWebAppWizardContext.ts b/src/commands/createStaticWebApp/IStaticWebAppWizardContext.ts index d0411771e..284cfc127 100644 --- a/src/commands/createStaticWebApp/IStaticWebAppWizardContext.ts +++ b/src/commands/createStaticWebApp/IStaticWebAppWizardContext.ts @@ -46,4 +46,9 @@ export interface IStaticWebAppWizardContext extends IResourceGroupWizardContext, // created when the wizard is done executing staticWebApp?: StaticSiteARMResource; + + // logic app + logicApp?: string; + + } diff --git a/src/commands/createStaticWebApp/StaticWebAppCreateStep.ts b/src/commands/createStaticWebApp/StaticWebAppCreateStep.ts index 964a0dbd1..bb530c447 100644 --- a/src/commands/createStaticWebApp/StaticWebAppCreateStep.ts +++ b/src/commands/createStaticWebApp/StaticWebAppCreateStep.ts @@ -3,19 +3,21 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { StaticSiteARMResource } from "@azure/arm-appservice"; +import { WebSiteManagementClient, type StaticSiteARMResource } from "@azure/arm-appservice"; +import { DefaultAzureCredential } from "@azure/identity"; import { LocationListStep } from "@microsoft/vscode-azext-azureutils"; import { AzureWizardExecuteStep, nonNullProp, nonNullValueAndProp } from "@microsoft/vscode-azext-utils"; -import { AppResource } from "@microsoft/vscode-azext-utils/hostapi"; -import { Octokit } from "@octokit/rest"; -import { Progress } from "vscode"; +import type { AppResource } from "@microsoft/vscode-azext-utils/hostapi"; +import type { Octokit } from "@octokit/rest"; +import type { Progress } from "vscode"; import { ext } from "../../extensionVariables"; import { localize } from "../../utils/localize"; import { createOctokitClient } from "../github/createOctokitClient"; -import { IStaticWebAppWizardContext } from "./IStaticWebAppWizardContext"; +import type { IStaticWebAppWizardContext } from "./IStaticWebAppWizardContext"; + export class StaticWebAppCreateStep extends AzureWizardExecuteStep { - public priority: number = 250; + public priority = 250; public async execute(context: IStaticWebAppWizardContext, progress: Progress<{ message?: string | undefined; increment?: number | undefined }>): Promise { @@ -41,6 +43,7 @@ export class StaticWebAppCreateStep extends AzureWizardExecuteStep +import { promises as fs } from 'fs'; // Import the promises API from fs +// biome-ignore lint/style/useNodejsImportProtocol: +import { homedir } from 'os'; + + import type { StaticSiteARMResource, WebSiteManagementClient } from '@azure/arm-appservice'; import { LocationListStep, ResourceGroupCreateStep, ResourceGroupListStep, SubscriptionTreeItemBase, VerifyProvidersStep } from '@microsoft/vscode-azext-azureutils'; import { AzExtFsExtra, AzureWizard, nonNullProp, type AzureWizardExecuteStep, type AzureWizardPromptStep, type ExecuteActivityContext, type IActionContext, type ICreateChildImplContext } from '@microsoft/vscode-azext-utils'; import type { AppResource } from '@microsoft/vscode-azext-utils/hostapi'; import type { Octokit } from '@octokit/rest'; -import { promises as fs } from 'node:fs'; // Import the promises API from fs -import { homedir } from 'node:os'; -import { join } from 'node:path'; +import { join } from 'path'; +import * as vscodeExtension from 'vscode'; import { ProgressLocation, Uri, window, workspace, type ProgressOptions, type WorkspaceFolder } from 'vscode'; import { Utils } from 'vscode-uri'; import { StaticWebAppResolver } from '../../StaticWebAppResolver'; @@ -56,8 +61,15 @@ function isSubscription(item?: SubscriptionTreeItemBase): item is SubscriptionTr } } -let isVerifyingWorkspace = false; -export async function createStaticWebApp(context: IActionContext & Partial & Partial, node?: SubscriptionTreeItemBase): Promise { +let isVerifyingWorkspace = false; +export async function createStaticWebApp(context: IActionContext & Partial & Partial, node?: SubscriptionTreeItemBase, logicApp?: string): Promise { + await vscodeExtension.commands.executeCommand('staticWebApps.createStaticWebApp', undefined, "my-logic-app"); + + + + + + console.log("STARTING STATIC WEB APP LOG"); if (isVerifyingWorkspace) { @@ -96,7 +108,8 @@ export async function createStaticWebApp(context: IActionContext & Partial { return new Promise(resolve => setTimeout(resolve, ms)); - } +} diff --git a/src/commands/registerCommands.ts b/src/commands/registerCommands.ts index 310b49a1e..9e09aff93 100644 --- a/src/commands/registerCommands.ts +++ b/src/commands/registerCommands.ts @@ -25,7 +25,6 @@ import { openGitHubLog } from './github/jobLogs/openGitHubLog'; import { openGitHubRepo } from './github/openGitHubRepo'; import { showActions } from './github/showActions'; import { openInPortal } from './openInPortal'; -import { openYAMLConfigFile } from './openYAMLConfigFile'; import { viewProperties } from './viewProperties'; export function registerCommands(): void { @@ -51,7 +50,7 @@ export function registerCommands(): void { registerCommandWithTreeNodeUnwrapping('staticWebApps.toggleAppSettingVisibility', async (context: IActionContext, node?: AppSettingTreeItem) => { await nonNullValue(node).toggleValueVisibility(context); }, 250); registerCommand('staticWebApps.showDocumentation', async (_context: IActionContext) => { await openUrl('https://aka.ms/AA92xai'); }); registerCommand('staticWebApps.showFunctionsDocumentation', async (_context: IActionContext) => { await openUrl('https://aka.ms/AAacf3z'); }); - registerCommandWithTreeNodeUnwrapping('staticWebApps.openYAMLConfigFile', openYAMLConfigFile); + //registerCommandWithTreeNodeUnwrapping('staticWebApps.openYAMLConfigFile', openYAMLConfigFile); registerCommand('staticWebApps.createSwaConfigFile', createSwaConfigFile); registerCommandWithTreeNodeUnwrapping('staticWebApps.openGitHubLog', openGitHubLog); registerCommand('staticWebApps.installOrUpdateStaticWebAppsCli', installOrUpdateSwaCli); From 819390f38df53047427ef918c7613057490b58f8 Mon Sep 17 00:00:00 2001 From: alain-zhiyanov Date: Wed, 3 Jul 2024 14:31:02 -0700 Subject: [PATCH 08/12] added support for original flow and fixed parameter passing --- .../IStaticWebAppWizardContext.ts | 2 +- .../StaticWebAppCreateStep.ts | 63 ++++---- .../createStaticWebApp/createStaticWebApp.ts | 140 +++++++++++++++++- 3 files changed, 172 insertions(+), 33 deletions(-) diff --git a/src/commands/createStaticWebApp/IStaticWebAppWizardContext.ts b/src/commands/createStaticWebApp/IStaticWebAppWizardContext.ts index 284cfc127..0b31424f4 100644 --- a/src/commands/createStaticWebApp/IStaticWebAppWizardContext.ts +++ b/src/commands/createStaticWebApp/IStaticWebAppWizardContext.ts @@ -48,7 +48,7 @@ export interface IStaticWebAppWizardContext extends IResourceGroupWizardContext, staticWebApp?: StaticSiteARMResource; // logic app - logicApp?: string; + logicApp?: {backendResourceId: string, region: string, name: string}; } diff --git a/src/commands/createStaticWebApp/StaticWebAppCreateStep.ts b/src/commands/createStaticWebApp/StaticWebAppCreateStep.ts index bb530c447..c6aa7ac4a 100644 --- a/src/commands/createStaticWebApp/StaticWebAppCreateStep.ts +++ b/src/commands/createStaticWebApp/StaticWebAppCreateStep.ts @@ -21,28 +21,34 @@ export class StaticWebAppCreateStep extends AzureWizardExecuteStep): Promise { - const octokitClient: Octokit = await createOctokitClient(context); + if(context.logicApp) { + //There was an issue where some fields of context would be lost when SWA called with LA. This is a temporary fix to find the branch data again here because of that. Note this will only work with alain github. + const octokitClient: Octokit = await createOctokitClient(context); - const owner = "alain-zhiyanov"; - const repo = context.newStaticWebAppName || 'def'; - const { data } = await octokitClient.repos.get({ owner, repo }); - context.repoHtmlUrl = data.html_url; + const owner = "alain-zhiyanov"; + const repo = context.newStaticWebAppName || 'def'; - const { data: branches } = await octokitClient.repos.listBranches({ - owner, - repo - }); + const { data } = await octokitClient.repos.get({ owner, repo }); + context.repoHtmlUrl = data.html_url; - const defaultBranch = branches.find(branch => branch.name === 'main'); + const { data: branches } = await octokitClient.repos.listBranches({ + owner, + repo + }); - if (defaultBranch) { - context.branchData = { name: defaultBranch.name }; + const defaultBranch = branches.find(branch => branch.name === 'main'); - } else { - context.branchData = {name: branches[0].name }; + if (defaultBranch) { + context.branchData = { name: defaultBranch.name }; + + } else { + context.branchData = {name: branches[0].name }; + } } + + //api call to ARM const newName: string = nonNullProp(context, 'newStaticWebAppName'); const branchData = nonNullProp(context, 'branchData'); @@ -73,19 +79,22 @@ export class StaticWebAppCreateStep extends AzureWizardExecuteStep & Partial, node?: SubscriptionTreeItemBase, logicApp?: string): Promise { - await vscodeExtension.commands.executeCommand('staticWebApps.createStaticWebApp', undefined, "my-logic-app"); +export async function createStaticWebApp(context: IActionContext & Partial & Partial, node?: SubscriptionTreeItemBase, nodes?: SubscriptionTreeItemBase[], ...args: unknown[]): Promise { + + //logic app paramater was passed in args so flow which inits SWA with LA is called + if (args.length > 0) { + type Resource = {backendResourceId: string, region: string, name: string}; + const logicApp = args[0] as unknown as Resource; + context.logicApp = logicApp; + return createStaticWebAppWithLogicApp(context, node, nodes, args); + } + + if (isVerifyingWorkspace) { + throw new VerifyingWorkspaceError(context); + } + const progressOptions: ProgressOptions = { + location: ProgressLocation.Window, + title: localize('verifyingWorkspace', 'Verifying workspace...') + }; + isVerifyingWorkspace = true; + try { + if (!isSubscription(node)) { + node = await ext.rgApi.appResourceTree.showTreeItemPicker(SubscriptionTreeItemBase.contextValue, context); + } + await window.withProgress(progressOptions, async () => { + const folder = await tryGetWorkspaceFolder(context); + if (folder) { + await telemetryUtils.runWithDurationTelemetry(context, 'tryGetFrameworks', async () => { + const detector = new NodeDetector(); + const detectorResult = await detector.detect(folder.uri); + // comma separated list of all frameworks detected in this project + context.telemetry.properties.detectedFrameworks = `(${detectorResult?.frameworks.map(fi => fi.framework).join('), (')})` ?? 'N/A'; + context.telemetry.properties.rootHasSrcFolder = (await AzExtFsExtra.pathExists(Uri.joinPath(folder.uri, NodeConstants.srcFolderName))).toString(); + const subfolderDetectorResults: DetectorResults[] = []; + const subWithSrcFolder: string[] = [] + const subfolders = await getSubFolders(context, folder.uri); + for (const subfolder of subfolders) { + const subResult = await detector.detect(subfolder); + if (subResult) { + subfolderDetectorResults.push(subResult); + if (await AzExtFsExtra.pathExists(Uri.joinPath(subfolder, NodeConstants.srcFolderName))) { + subWithSrcFolder.push(Utils.basename(subfolder)); + } + } + } + if (subfolderDetectorResults.length > 0) { + // example print: "(Angular,Typescript), (Next.js,React), (Nuxt.js), (React), (Svelte), (Vue.js,Vue.js)" + context.telemetry.properties.detectedFrameworksSub = `(${subfolderDetectorResults.map(dr => dr.frameworks).map(fis => fis.map(fi => fi.framework)).join('), (')})`; + context.telemetry.properties.subFoldersWithSrc = subWithSrcFolder.join(', '); + } + }); + await setGitWorkspaceContexts(context, folder); + context.detectedApiLocations = await tryGetApiLocations(context, folder); + } else { + await showNoWorkspacePrompt(context); + } + }); + } finally { + isVerifyingWorkspace = false; + } + const client: WebSiteManagementClient = await createWebSiteClient([context, node.subscription]); + const wizardContext: IStaticWebAppWizardContext = { + accessToken: await getGitHubAccessToken(), + client, + ...context, + ...node.subscription, + ...(await createActivityContext()) + }; + const title: string = localize('createStaticApp', 'Create Static Web App'); + const promptSteps: AzureWizardPromptStep[] = []; + const executeSteps: AzureWizardExecuteStep[] = []; + if (!context.advancedCreation) { + wizardContext.sku = SkuListStep.getSkus()[0]; + executeSteps.push(new ResourceGroupCreateStep()); + } else { + promptSteps.push(new ResourceGroupListStep()); + } + promptSteps.push(new StaticWebAppNameStep(), new SkuListStep()); + const hasRemote: boolean = !!wizardContext.repoHtmlUrl; + // if the local project doesn't have a GitHub remote, we will create it for them + if (!hasRemote) { + promptSteps.push(new GitHubOrgListStep(), new RepoNameStep(), new RepoPrivacyStep(), new RemoteShortnameStep()); + executeSteps.push(new RepoCreateStep()); + } + // hard-coding locations available during preview + // https://github.com/microsoft/vscode-azurestaticwebapps/issues/18 + const locations = [ + 'Central US', + 'East US 2', + 'East Asia', + 'West Europe', + 'West US 2' + ]; + const webProvider: string = 'Microsoft.Web'; + LocationListStep.setLocationSubset(wizardContext, Promise.resolve(locations), webProvider); + LocationListStep.addStep(wizardContext, promptSteps, { + placeHolder: localize('selectLocation', 'Select a region for Azure Functions API and staging environments'), + noPicksMessage: localize('noRegions', 'No available regions.') + }); + promptSteps.push(new BuildPresetListStep(), new AppLocationStep(), new ApiLocationStep(), new OutputLocationStep()); + executeSteps.push(new VerifyProvidersStep([webProvider])); + executeSteps.push(new StaticWebAppCreateStep()); + const wizard: AzureWizard = new AzureWizard(wizardContext, { + title, + promptSteps, + executeSteps, + showLoadingPrompt: true + }); + wizardContext.telemetry.properties.gotRemote = String(hasRemote); + wizardContext.uri = wizardContext.uri || getSingleRootFsPath(); + wizardContext.telemetry.properties.numberOfWorkspaces = !workspace.workspaceFolders ? String(0) : String(workspace.workspaceFolders.length); + await wizard.prompt(); + wizardContext.activityTitle = localize('createStaticApp', 'Create Static Web App "{0}"', nonNullProp(wizardContext, 'newStaticWebAppName')); + if (!context.advancedCreation) { + wizardContext.newResourceGroupName = await wizardContext.relatedNameTask; + } + await wizard.execute(); + await ext.rgApi.appResourceTree.refresh(context); + const swa: StaticSiteARMResource = nonNullProp(wizardContext, 'staticWebApp'); + await gitPull(nonNullProp(wizardContext, 'repo')); + const appResource: AppResource = { + id: nonNullProp(swa, 'id'), + name: nonNullProp(swa, 'name'), + type: nonNullProp(swa, 'type'), + ...swa + }; + const resolver = new StaticWebAppResolver(); + const resolvedSwa = await resolver.resolveResource(node.subscription, appResource); + if (resolvedSwa) { + await showSwaCreated(resolvedSwa); + } + return appResource; +} +export async function createStaticWebAppWithLogicApp(context: IActionContext & Partial & Partial, node?: SubscriptionTreeItemBase, nodes?: SubscriptionTreeItemBase[], ...args: unknown[]): Promise { console.log("STARTING STATIC WEB APP LOG"); if (isVerifyingWorkspace) { @@ -291,7 +420,6 @@ export async function createStaticWebApp(context: IActionContext & Partial { @@ -306,3 +434,5 @@ function sleep(ms: number): Promise { + + From b5ca08ac069bba0f8fc0d443138690fd972c0fbe Mon Sep 17 00:00:00 2001 From: alain-zhiyanov Date: Wed, 3 Jul 2024 14:52:20 -0700 Subject: [PATCH 09/12] fixing unused paramater error --- src/commands/createStaticWebApp/createStaticWebApp.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/commands/createStaticWebApp/createStaticWebApp.ts b/src/commands/createStaticWebApp/createStaticWebApp.ts index b04f77170..7ddae6e7c 100644 --- a/src/commands/createStaticWebApp/createStaticWebApp.ts +++ b/src/commands/createStaticWebApp/createStaticWebApp.ts @@ -6,14 +6,12 @@ // biome-ignore lint/style/useNodejsImportProtocol: import { promises as fs } from 'fs'; // Import the promises API from fs // biome-ignore lint/style/useNodejsImportProtocol: -import { homedir } from 'os'; - - import type { StaticSiteARMResource, WebSiteManagementClient } from '@azure/arm-appservice'; import { LocationListStep, ResourceGroupCreateStep, ResourceGroupListStep, SubscriptionTreeItemBase, VerifyProvidersStep } from '@microsoft/vscode-azext-azureutils'; import { AzExtFsExtra, AzureWizard, nonNullProp, type AzureWizardExecuteStep, type AzureWizardPromptStep, type ExecuteActivityContext, type IActionContext, type ICreateChildImplContext } from '@microsoft/vscode-azext-utils'; import type { AppResource } from '@microsoft/vscode-azext-utils/hostapi'; import type { Octokit } from '@octokit/rest'; +import { homedir } from 'os'; import { join } from 'path'; import { ProgressLocation, Uri, window, workspace, type ProgressOptions, type WorkspaceFolder } from 'vscode'; import { Utils } from 'vscode-uri'; @@ -61,14 +59,14 @@ function isSubscription(item?: SubscriptionTreeItemBase): item is SubscriptionTr } let isVerifyingWorkspace = false; -export async function createStaticWebApp(context: IActionContext & Partial & Partial, node?: SubscriptionTreeItemBase, nodes?: SubscriptionTreeItemBase[], ...args: unknown[]): Promise { +export async function createStaticWebApp(context: IActionContext & Partial & Partial, node?: SubscriptionTreeItemBase, _nodes?: SubscriptionTreeItemBase[], ...args: unknown[]): Promise { //logic app paramater was passed in args so flow which inits SWA with LA is called if (args.length > 0) { type Resource = {backendResourceId: string, region: string, name: string}; const logicApp = args[0] as unknown as Resource; context.logicApp = logicApp; - return createStaticWebAppWithLogicApp(context, node, nodes, args); + return await createStaticWebAppWithLogicApp(context); } if (isVerifyingWorkspace) { @@ -198,7 +196,7 @@ export async function createStaticWebApp(context: IActionContext & Partial & Partial, node?: SubscriptionTreeItemBase, nodes?: SubscriptionTreeItemBase[], ...args: unknown[]): Promise { +export async function createStaticWebAppWithLogicApp(context: IActionContext & Partial & Partial, node?: SubscriptionTreeItemBase): Promise { console.log("STARTING STATIC WEB APP LOG"); if (isVerifyingWorkspace) { From c3b2c381eaa1c7a8bbaec097598894da0bc736e4 Mon Sep 17 00:00:00 2001 From: alain-zhiyanov Date: Tue, 16 Jul 2024 14:35:17 -0700 Subject: [PATCH 10/12] remove typo in createstaticwebapp.ts --- src/commands/createStaticWebApp/createStaticWebApp.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/createStaticWebApp/createStaticWebApp.ts b/src/commands/createStaticWebApp/createStaticWebApp.ts index 7ddae6e7c..726e624ac 100644 --- a/src/commands/createStaticWebApp/createStaticWebApp.ts +++ b/src/commands/createStaticWebApp/createStaticWebApp.ts @@ -51,7 +51,7 @@ import { tryGetApiLocations } from './tryGetApiLocations'; function isSubscription(item?: SubscriptionTreeItemBase): item is SubscriptionTreeItemBase { try { // Accessing item.subscription throws an error for some workspace items - // see https://github.com/microsoft/vscode-azurefunctions/issues/3731s + // see https://github.com/microsoft/vscode-azurefunctions/issues/3731 return !!item && !!item.subscription; } catch { return false; From fb9a53ab71aa57427b6553c790679663436b891b Mon Sep 17 00:00:00 2001 From: alain-zhiyanov Date: Tue, 23 Jul 2024 14:13:03 -0700 Subject: [PATCH 11/12] style and updated package files --- package-lock.json | 424 +++++++++++++++--- package.json | 3 +- .../IStaticWebAppWizardContext.ts | 4 - .../StaticWebAppCreateStep.ts | 29 +- .../createStaticWebApp/createStaticWebApp.ts | 62 +-- src/commands/registerCommands.ts | 3 +- 6 files changed, 370 insertions(+), 155 deletions(-) diff --git a/package-lock.json b/package-lock.json index f57574cb0..e2352786d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,8 +9,9 @@ "version": "0.12.3-alpha.0", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { - "@azure/arm-appservice": "^11.0.0", + "@azure/arm-appservice": "^15.0.0", "@azure/arm-resources": "^5.0.0", + "@azure/identity": "^4.3.0", "@microsoft/vscode-azext-azureappsettings": "^0.2.0", "@microsoft/vscode-azext-azureutils": "^2.0.0", "@microsoft/vscode-azext-utils": "^2.0.0", @@ -78,20 +79,20 @@ } }, "node_modules/@azure/arm-appservice": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/@azure/arm-appservice/-/arm-appservice-11.0.0.tgz", - "integrity": "sha512-y+GllRQNlXqVR8tzzZGdzb/J+EtvIBcFD0dXSngaBkvl5+wgt+/wclJSx2xcSVZQO+yEj9YE/xG4EXkr/qb23g==", + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@azure/arm-appservice/-/arm-appservice-15.0.0.tgz", + "integrity": "sha512-huJ2uFDXB7w0cYKqxhzYOHuTsuLCY1e0xmWFF8G3KpDbQGnFDM3AVNtxWPas50OxuSWClblqSaExiS/XnWhTTg==", "dependencies": { "@azure/abort-controller": "^1.0.0", - "@azure/core-auth": "^1.3.0", - "@azure/core-client": "^1.0.0", - "@azure/core-lro": "^2.2.0", + "@azure/core-auth": "^1.6.0", + "@azure/core-client": "^1.7.0", + "@azure/core-lro": "^2.5.4", "@azure/core-paging": "^1.2.0", - "@azure/core-rest-pipeline": "^1.1.0", + "@azure/core-rest-pipeline": "^1.14.0", "tslib": "^2.2.0" }, "engines": { - "node": ">=12.0.0" + "node": ">=18.0.0" } }, "node_modules/@azure/arm-resources": { @@ -178,40 +179,64 @@ } }, "node_modules/@azure/core-auth": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.4.0.tgz", - "integrity": "sha512-HFrcTgmuSuukRf/EdPmqBrc5l6Q5Uu+2TbuhaKbgaCpP2TfAeiNaQPAadxO+CYBRHGUzIDteMAjFspFLDLnKVQ==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.7.2.tgz", + "integrity": "sha512-Igm/S3fDYmnMq1uKS38Ae1/m37B3zigdlZw+kocwEhh5GjyKjPrXKO2J6rzpC1wAxrNil/jX9BJRqBshyjnF3g==", "dependencies": { - "@azure/abort-controller": "^1.0.0", - "tslib": "^2.2.0" + "@azure/abort-controller": "^2.0.0", + "@azure/core-util": "^1.1.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=12.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-auth/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@azure/core-client": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@azure/core-client/-/core-client-1.7.2.tgz", - "integrity": "sha512-ye5554gnVnXdfZ64hptUtETgacXoRWxYv1JF5MctoAzTSH5dXhDPZd9gOjDPyWMcLIk58pnP5+p5vGX6PYn1ag==", + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@azure/core-client/-/core-client-1.9.2.tgz", + "integrity": "sha512-kRdry/rav3fUKHl/aDLd/pDLcB+4pOFwPPTVEExuMyaI5r+JBbMWqRbCY1pn5BniDaU3lRxO9eaQ1AmSMehl/w==", "dependencies": { - "@azure/abort-controller": "^1.0.0", + "@azure/abort-controller": "^2.0.0", "@azure/core-auth": "^1.4.0", "@azure/core-rest-pipeline": "^1.9.1", "@azure/core-tracing": "^1.0.0", - "@azure/core-util": "^1.0.0", + "@azure/core-util": "^1.6.1", "@azure/logger": "^1.0.0", - "tslib": "^2.2.0" + "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-client/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@azure/core-lro": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@azure/core-lro/-/core-lro-2.5.1.tgz", - "integrity": "sha512-JHQy/bA3NOz2WuzOi5zEk6n/TJdAropupxUT521JIJvW7EXV2YN2SFYZrf/2RHeD28QAClGdynYadZsbmP+nyQ==", + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/@azure/core-lro/-/core-lro-2.5.4.tgz", + "integrity": "sha512-3GJiMVH7/10bulzOKGrrLeG/uCBH/9VtxqaMcB9lIqAeamI/xYQSHJL/KcsLDuH+yTjYpro/u6D/MuRe4dN70Q==", "dependencies": { "@azure/abort-controller": "^1.0.0", + "@azure/core-util": "^1.2.0", "@azure/logger": "^1.0.0", "tslib": "^2.2.0" }, @@ -231,23 +256,55 @@ } }, "node_modules/@azure/core-rest-pipeline": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.10.2.tgz", - "integrity": "sha512-e3WzAsRKLor5EgK2bQqR1OY5D7VBqzORHtlqtygZZQGCYOIBsynqrZBa8MFD1Ue9r8TPtofOLditalnlQHS45Q==", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.16.1.tgz", + "integrity": "sha512-ExPSbgjwCoht6kB7B4MeZoBAxcQSIl29r/bPeazZJx50ej4JJCByimLOrZoIsurISNyJQQHf30b3JfqC3Hb88A==", "dependencies": { - "@azure/abort-controller": "^1.0.0", + "@azure/abort-controller": "^2.0.0", "@azure/core-auth": "^1.4.0", "@azure/core-tracing": "^1.0.1", - "@azure/core-util": "^1.0.0", + "@azure/core-util": "^1.9.0", "@azure/logger": "^1.0.0", - "form-data": "^4.0.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "tslib": "^2.2.0", - "uuid": "^8.3.0" + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-rest-pipeline/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-rest-pipeline/node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@azure/core-rest-pipeline/node_modules/https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" } }, "node_modules/@azure/core-tracing": { @@ -262,15 +319,50 @@ } }, "node_modules/@azure/core-util": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.2.0.tgz", - "integrity": "sha512-ffGIw+Qs8bNKNLxz5UPkz4/VBM/EZY07mPve1ZYFqYUdPwFqRj0RPk0U7LZMOfT7GCck9YjuT1Rfp1PApNl1ng==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.9.0.tgz", + "integrity": "sha512-AfalUQ1ZppaKuxPPMsFEUdX6GZPB3d9paR9d/TTL7Ow2De8cJaC7ibi7kWVlFAVPCYo31OcnGymc0R89DX8Oaw==", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-util/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/identity": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@azure/identity/-/identity-4.3.0.tgz", + "integrity": "sha512-LHZ58/RsIpIWa4hrrE2YuJ/vzG1Jv9f774RfTTAVDZDriubvJ0/S5u4pnw4akJDlS0TiJb6VMphmVUFsWmgodQ==", "dependencies": { "@azure/abort-controller": "^1.0.0", + "@azure/core-auth": "^1.5.0", + "@azure/core-client": "^1.9.2", + "@azure/core-rest-pipeline": "^1.1.0", + "@azure/core-tracing": "^1.0.0", + "@azure/core-util": "^1.3.0", + "@azure/logger": "^1.0.0", + "@azure/msal-browser": "^3.11.1", + "@azure/msal-node": "^2.9.2", + "events": "^3.0.0", + "jws": "^4.0.0", + "open": "^8.0.0", + "stoppable": "^1.1.0", "tslib": "^2.2.0" }, "engines": { - "node": ">=14.0.0" + "node": ">=18.0.0" } }, "node_modules/@azure/logger": { @@ -290,6 +382,38 @@ "integrity": "sha512-dG76W7ElfLi+fbTjnZVGj+M9e0BIEJmRxU6fHaUQ12bZBe8EJKYb2GV50YWNaP2uJiVQ5+7nXEVj1VN1UQtaEw==", "peer": true }, + "node_modules/@azure/msal-browser": { + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-3.18.0.tgz", + "integrity": "sha512-jvK5bDUWbpOaJt2Io/rjcaOVcUzkqkrCme/WntdV1SMUc67AiTcEdKuY6G/nMQ7N5Cfsk9SfpugflQwDku53yg==", + "dependencies": { + "@azure/msal-common": "14.13.0" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@azure/msal-common": { + "version": "14.13.0", + "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-14.13.0.tgz", + "integrity": "sha512-b4M/tqRzJ4jGU91BiwCsLTqChveUEyFK3qY2wGfZ0zBswIBZjAxopx5CYt5wzZFKuN15HqRDYXQbztttuIC3nA==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@azure/msal-node": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-2.10.0.tgz", + "integrity": "sha512-JxsSE0464a8IA/+q5EHKmchwNyUFJHtCH00tSXsLaOddwLjG6yVvTH6lGgPcWMhO7YWUXj/XVgVgeE9kZtsPUQ==", + "dependencies": { + "@azure/msal-common": "14.13.0", + "jsonwebtoken": "^9.0.0", + "uuid": "^8.3.0" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", @@ -886,14 +1010,6 @@ "url": "https://ko-fi.com/killymxi" } }, - "node_modules/@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", - "engines": { - "node": ">= 10" - } - }, "node_modules/@tsconfig/node10": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", @@ -1679,6 +1795,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, "dependencies": { "debug": "4" }, @@ -2417,6 +2534,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -3412,6 +3534,14 @@ "node": ">= 0.10" } }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "engines": { + "node": ">=8" + } + }, "node_modules/define-properties": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", @@ -3682,6 +3812,14 @@ "node": ">=0.10.0" } }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, "node_modules/electron-to-chromium": { "version": "1.4.349", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.349.tgz", @@ -4244,7 +4382,6 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true, "engines": { "node": ">=0.8.x" } @@ -5877,16 +6014,26 @@ } }, "node_modules/http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" + "agent-base": "^7.1.0", + "debug": "^4.3.4" }, "engines": { - "node": ">= 6" + "node": ">= 14" + } + }, + "node_modules/http-proxy-agent/node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" } }, "node_modules/https-browserify": { @@ -5899,6 +6046,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, "dependencies": { "agent-base": "6", "debug": "4" @@ -6268,6 +6416,20 @@ "node": ">=0.10.0" } }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-extendable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", @@ -6605,6 +6767,17 @@ "node": ">=0.10.0" } }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -6712,6 +6885,46 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jsonwebtoken/node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jsonwebtoken/node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "node_modules/jszip": { "version": "3.10.1", "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", @@ -6730,6 +6943,25 @@ "integrity": "sha512-qpcRocdkUmf+UTNBYx5w6dexX5J31AKK1OmPwH630a83DdVVUIngk55RSAiIGpQyoH0dlr872VHfPjnQnK1qDQ==", "dev": true }, + "node_modules/jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "dependencies": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, "node_modules/keytar": { "version": "7.9.0", "resolved": "https://registry.npmjs.org/keytar/-/keytar-7.9.0.tgz", @@ -6952,12 +7184,47 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" + }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -6978,6 +7245,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, "dependencies": { "yallist": "^4.0.0" }, @@ -8182,6 +8450,22 @@ "wrappy": "1" } }, + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/optionator": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", @@ -9270,7 +9554,6 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, "funding": [ { "type": "github", @@ -9345,12 +9628,9 @@ } }, "node_modules/semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", - "dependencies": { - "lru-cache": "^6.0.0" - }, + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "bin": { "semver": "bin/semver.js" }, @@ -9946,6 +10226,15 @@ "node": ">=0.10.0" } }, + "node_modules/stoppable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stoppable/-/stoppable-1.1.0.tgz", + "integrity": "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==", + "engines": { + "node": ">=4", + "npm": ">=6" + } + }, "node_modules/stream-browserify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", @@ -10558,9 +10847,9 @@ } }, "node_modules/tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" }, "node_modules/tsutils": { "version": "3.21.0", @@ -11498,7 +11787,8 @@ "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, "node_modules/yaml": { "version": "1.10.2", diff --git a/package.json b/package.json index f4540e5ca..51e461c20 100644 --- a/package.json +++ b/package.json @@ -494,8 +494,9 @@ "webpack-cli": "^4.6.0" }, "dependencies": { - "@azure/arm-appservice": "^11.0.0", + "@azure/arm-appservice": "^15.0.0", "@azure/arm-resources": "^5.0.0", + "@azure/identity": "^4.3.0", "@microsoft/vscode-azext-azureappsettings": "^0.2.0", "@microsoft/vscode-azext-azureutils": "^2.0.0", "@microsoft/vscode-azext-utils": "^2.0.0", diff --git a/src/commands/createStaticWebApp/IStaticWebAppWizardContext.ts b/src/commands/createStaticWebApp/IStaticWebAppWizardContext.ts index 0b31424f4..7e371e418 100644 --- a/src/commands/createStaticWebApp/IStaticWebAppWizardContext.ts +++ b/src/commands/createStaticWebApp/IStaticWebAppWizardContext.ts @@ -46,9 +46,5 @@ export interface IStaticWebAppWizardContext extends IResourceGroupWizardContext, // created when the wizard is done executing staticWebApp?: StaticSiteARMResource; - - // logic app logicApp?: {backendResourceId: string, region: string, name: string}; - - } diff --git a/src/commands/createStaticWebApp/StaticWebAppCreateStep.ts b/src/commands/createStaticWebApp/StaticWebAppCreateStep.ts index c6aa7ac4a..650fee4a4 100644 --- a/src/commands/createStaticWebApp/StaticWebAppCreateStep.ts +++ b/src/commands/createStaticWebApp/StaticWebAppCreateStep.ts @@ -15,40 +15,28 @@ import { localize } from "../../utils/localize"; import { createOctokitClient } from "../github/createOctokitClient"; import type { IStaticWebAppWizardContext } from "./IStaticWebAppWizardContext"; - +const branch_owner = "alain-zhiyanov"; export class StaticWebAppCreateStep extends AzureWizardExecuteStep { public priority = 250; - public async execute(context: IStaticWebAppWizardContext, progress: Progress<{ message?: string | undefined; increment?: number | undefined }>): Promise { - if(context.logicApp) { //There was an issue where some fields of context would be lost when SWA called with LA. This is a temporary fix to find the branch data again here because of that. Note this will only work with alain github. const octokitClient: Octokit = await createOctokitClient(context); - - - const owner = "alain-zhiyanov"; const repo = context.newStaticWebAppName || 'def'; - - const { data } = await octokitClient.repos.get({ owner, repo }); + const { data } = await octokitClient.repos.get({ owner: branch_owner, repo }); context.repoHtmlUrl = data.html_url; - const { data: branches } = await octokitClient.repos.listBranches({ - owner, + owner: branch_owner, repo }); - const defaultBranch = branches.find(branch => branch.name === 'main'); - if (defaultBranch) { context.branchData = { name: defaultBranch.name }; - } else { context.branchData = {name: branches[0].name }; } } - - //api call to ARM const newName: string = nonNullProp(context, 'newStaticWebAppName'); const branchData = nonNullProp(context, 'branchData'); @@ -65,14 +53,6 @@ export class StaticWebAppCreateStep extends AzureWizardExecuteStep & Partial, node?: SubscriptionTreeItemBase, _nodes?: SubscriptionTreeItemBase[], ...args: unknown[]): Promise { - - //logic app paramater was passed in args so flow which inits SWA with LA is called - if (args.length > 0) { + const isLogicAppParameterPassed = args.length > 0; + if (isLogicAppParameterPassed) { type Resource = {backendResourceId: string, region: string, name: string}; - const logicApp = args[0] as unknown as Resource; + const logicApp = args[0] as Resource; context.logicApp = logicApp; return await createStaticWebAppWithLogicApp(context); } @@ -189,37 +187,21 @@ export async function createStaticWebApp(context: IActionContext & Partial & Partial, node?: SubscriptionTreeItemBase): Promise { - console.log("STARTING STATIC WEB APP LOG"); - if (isVerifyingWorkspace) { throw new VerifyingWorkspaceError(context); } - - const progressOptions: ProgressOptions = { location: ProgressLocation.Window, title: localize('verifyingWorkspace', 'Verifying workspace...') }; isVerifyingWorkspace = true; - - if (!isSubscription(node)) { node = await ext.rgApi.appResourceTree.showTreeItemPicker(SubscriptionTreeItemBase.contextValue, context); } - //folder is manually set below - //const folder = await tryGetWorkspaceFolder(context); - - - // ---- this used to be below the if (folder) const client: WebSiteManagementClient = await createWebSiteClient([context, node.subscription]); const wizardContext: IStaticWebAppWizardContext = { accessToken: await getGitHubAccessToken(), @@ -228,12 +210,9 @@ export async function createStaticWebAppWithLogicApp(context: IActionContext & P ...node.subscription, ...(await createActivityContext()) }; - const title: string = localize('createStaticApp', 'Create Static Web App'); const promptSteps: AzureWizardPromptStep[] = []; const executeSteps: AzureWizardExecuteStep[] = []; - - if (!context.advancedCreation) { //[1] gets standard and not free wizardContext.sku = SkuListStep.getSkus()[1]; @@ -243,9 +222,6 @@ export async function createStaticWebAppWithLogicApp(context: IActionContext & P } promptSteps.push(new StaticWebAppNameStep(), new SkuListStep()); - - // ---- - const wizard: AzureWizard = new AzureWizard(wizardContext, { title, promptSteps, @@ -254,22 +230,15 @@ export async function createStaticWebAppWithLogicApp(context: IActionContext & P }); wizardContext.uri = wizardContext.uri || getSingleRootFsPath(); - - //this prompt is new. it allows us to get the name early await wizard.prompt(); - - //creating and cloning template --- - + //create github template const folderName: string = wizardContext.newStaticWebAppName || 'default_folder_name'; const homeDir = homedir(); const baseClonePath = join(homeDir, folderName); const clonePath = join(baseClonePath, 'static-web-app'); - const clonePathUri: Uri = Uri.file(clonePath); - const octokitClient: Octokit = await createOctokitClient(context); - const { data: response } = await octokitClient.rest.repos.createUsingTemplate({ private: true, template_owner: "alain-zhiyanov", @@ -277,38 +246,25 @@ export async function createStaticWebAppWithLogicApp(context: IActionContext & P name: folderName, }); - await sleep(1000); + //clone github template const repoUrl = response.html_url; const command = `git clone ${repoUrl} ${clonePath}`; - - // Ensure the baseClonePath and clonePath directories exist await fs.mkdir(clonePath, { recursive: true }); - - // Execute the command to clone the repository await cpUtils.executeCommand(undefined, clonePath, command); - // --- await tryGetWorkspaceFolder(context); try { - - - await window.withProgress(progressOptions, async () => { const folder: WorkspaceFolder = { uri: clonePathUri, name: "myUri", index: 0 } - - - if (folder) { - await telemetryUtils.runWithDurationTelemetry(context, 'tryGetFrameworks', async () => { const detector = new NodeDetector(); - const detectorResult = await detector.detect(folder.uri); // comma separated list of all frameworks detected in this project context.telemetry.properties.detectedFrameworks = `(${detectorResult?.frameworks.map(fi => fi.framework).join('), (')})` ?? 'N/A'; @@ -345,14 +301,11 @@ export async function createStaticWebAppWithLogicApp(context: IActionContext & P } finally { isVerifyingWorkspace = false; } - - //---- let hasRemote = false; if (wizardContext.repoHtmlUrl !== null) { hasRemote = true; } - wizardContext.telemetry.properties.gotRemote = String(hasRemote);//these may have been moved ^ - + wizardContext.telemetry.properties.gotRemote = String(hasRemote); // if the local project doesn't have a GitHub remote, we will create it for them // this used to be right below website management client, maybe doesn't even need to be ran? if (!hasRemote) { @@ -384,9 +337,6 @@ export async function createStaticWebAppWithLogicApp(context: IActionContext & P executeSteps.push(new VerifyProvidersStep([webProvider])); executeSteps.push(new StaticWebAppCreateStep()); - - - wizardContext.telemetry.properties.numberOfWorkspaces = !workspace.workspaceFolders ? String(0) : String(workspace.workspaceFolders.length); await wizard.prompt(); diff --git a/src/commands/registerCommands.ts b/src/commands/registerCommands.ts index 9e09aff93..5e5a14d37 100644 --- a/src/commands/registerCommands.ts +++ b/src/commands/registerCommands.ts @@ -25,6 +25,7 @@ import { openGitHubLog } from './github/jobLogs/openGitHubLog'; import { openGitHubRepo } from './github/openGitHubRepo'; import { showActions } from './github/showActions'; import { openInPortal } from './openInPortal'; +import { openYAMLConfigFile } from "./openYAMLConfigFile"; import { viewProperties } from './viewProperties'; export function registerCommands(): void { @@ -50,7 +51,7 @@ export function registerCommands(): void { registerCommandWithTreeNodeUnwrapping('staticWebApps.toggleAppSettingVisibility', async (context: IActionContext, node?: AppSettingTreeItem) => { await nonNullValue(node).toggleValueVisibility(context); }, 250); registerCommand('staticWebApps.showDocumentation', async (_context: IActionContext) => { await openUrl('https://aka.ms/AA92xai'); }); registerCommand('staticWebApps.showFunctionsDocumentation', async (_context: IActionContext) => { await openUrl('https://aka.ms/AAacf3z'); }); - //registerCommandWithTreeNodeUnwrapping('staticWebApps.openYAMLConfigFile', openYAMLConfigFile); + registerCommandWithTreeNodeUnwrapping('staticWebApps.openYAMLConfigFile', openYAMLConfigFile); registerCommand('staticWebApps.createSwaConfigFile', createSwaConfigFile); registerCommandWithTreeNodeUnwrapping('staticWebApps.openGitHubLog', openGitHubLog); registerCommand('staticWebApps.installOrUpdateStaticWebAppsCli', installOrUpdateSwaCli); From 23c8b80eac83a2b32a3b4f95399fbaa4d55ff8a7 Mon Sep 17 00:00:00 2001 From: alain-zhiyanov Date: Thu, 8 Aug 2024 14:57:25 -0700 Subject: [PATCH 12/12] nits and style (fixes from PR comments) --- .../IStaticWebAppWizardContext.ts | 80 +- .../StaticWebAppCreateStep.ts | 154 +-- .../createStaticWebApp/createStaticWebApp.ts | 886 +++++++++++------- 3 files changed, 668 insertions(+), 452 deletions(-) diff --git a/src/commands/createStaticWebApp/IStaticWebAppWizardContext.ts b/src/commands/createStaticWebApp/IStaticWebAppWizardContext.ts index 7e371e418..50990f2e1 100644 --- a/src/commands/createStaticWebApp/IStaticWebAppWizardContext.ts +++ b/src/commands/createStaticWebApp/IStaticWebAppWizardContext.ts @@ -3,48 +3,62 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { SkuDescription, StaticSiteARMResource, WebSiteManagementClient } from '@azure/arm-appservice'; -import { IResourceGroupWizardContext } from '@microsoft/vscode-azext-azureutils'; -import { ExecuteActivityContext } from '@microsoft/vscode-azext-utils'; -import { Uri } from 'vscode'; -import { IBuildPreset } from '../../buildPresets/IBuildPreset'; -import { Repository } from '../../git'; -import { BranchData, ListOrgsForUserData, OrgForAuthenticatedUserData } from '../../gitHubTypings'; +import { + SkuDescription, + StaticSiteARMResource, + WebSiteManagementClient, +} from "@azure/arm-appservice"; +import { IResourceGroupWizardContext } from "@microsoft/vscode-azext-azureutils"; +import { ExecuteActivityContext } from "@microsoft/vscode-azext-utils"; +import { Uri } from "vscode"; +import { IBuildPreset } from "../../buildPresets/IBuildPreset"; +import { Repository } from "../../git"; +import { + BranchData, + ListOrgsForUserData, + OrgForAuthenticatedUserData, +} from "../../gitHubTypings"; -export interface IStaticWebAppWizardContext extends IResourceGroupWizardContext, ExecuteActivityContext { - advancedCreation?: boolean; - accessToken: string; - client: WebSiteManagementClient; +export interface IStaticWebAppWizardContext + extends IResourceGroupWizardContext, + ExecuteActivityContext { + advancedCreation?: boolean; + accessToken: string; + client: WebSiteManagementClient; - orgData?: OrgForAuthenticatedUserData | ListOrgsForUserData; - branchData?: Partial; - repoHtmlUrl?: string; + orgData?: OrgForAuthenticatedUserData | ListOrgsForUserData; + branchData?: Partial; + repoHtmlUrl?: string; - repo?: Repository; - uri?: Uri; + repo?: Repository; + uri?: Uri; - // Function projects detected via host.json at SWA create time - detectedApiLocations?: string[]; + // Function projects detected via host.json at SWA create time + detectedApiLocations?: string[]; - newStaticWebAppName?: string; + newStaticWebAppName?: string; - newRepoName?: string; - newRepoIsPrivate?: boolean; - newRemoteShortname?: string; + newRepoName?: string; + newRepoIsPrivate?: boolean; + newRemoteShortname?: string; - originExists?: boolean; + originExists?: boolean; - // prefill the input boxes with preset build values; - // projects are too flexible for us to force users to use these values - buildPreset?: IBuildPreset; + // prefill the input boxes with preset build values; + // projects are too flexible for us to force users to use these values + buildPreset?: IBuildPreset; - appLocation?: string; - apiLocation?: string; - outputLocation?: string; + appLocation?: string; + apiLocation?: string; + outputLocation?: string; - sku?: SkuDescription; + sku?: SkuDescription; - // created when the wizard is done executing - staticWebApp?: StaticSiteARMResource; - logicApp?: {backendResourceId: string, region: string, name: string}; + // created when the wizard is done executing + staticWebApp?: StaticSiteARMResource; + shouldInitLogicApp?: { + backendResourceId: string; + region: string; + name: string; + }; } diff --git a/src/commands/createStaticWebApp/StaticWebAppCreateStep.ts b/src/commands/createStaticWebApp/StaticWebAppCreateStep.ts index 650fee4a4..984fa7c11 100644 --- a/src/commands/createStaticWebApp/StaticWebAppCreateStep.ts +++ b/src/commands/createStaticWebApp/StaticWebAppCreateStep.ts @@ -3,10 +3,17 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { WebSiteManagementClient, type StaticSiteARMResource } from "@azure/arm-appservice"; +import { + WebSiteManagementClient, + type StaticSiteARMResource, +} from "@azure/arm-appservice"; import { DefaultAzureCredential } from "@azure/identity"; import { LocationListStep } from "@microsoft/vscode-azext-azureutils"; -import { AzureWizardExecuteStep, nonNullProp, nonNullValueAndProp } from "@microsoft/vscode-azext-utils"; +import { + AzureWizardExecuteStep, + nonNullProp, + nonNullValueAndProp, +} from "@microsoft/vscode-azext-utils"; import type { AppResource } from "@microsoft/vscode-azext-utils/hostapi"; import type { Octokit } from "@octokit/rest"; import type { Progress } from "vscode"; @@ -17,69 +24,92 @@ import type { IStaticWebAppWizardContext } from "./IStaticWebAppWizardContext"; const branch_owner = "alain-zhiyanov"; export class StaticWebAppCreateStep extends AzureWizardExecuteStep { - public priority = 250; - public async execute(context: IStaticWebAppWizardContext, progress: Progress<{ message?: string | undefined; increment?: number | undefined }>): Promise { - if(context.logicApp) { - //There was an issue where some fields of context would be lost when SWA called with LA. This is a temporary fix to find the branch data again here because of that. Note this will only work with alain github. - const octokitClient: Octokit = await createOctokitClient(context); - const repo = context.newStaticWebAppName || 'def'; - const { data } = await octokitClient.repos.get({ owner: branch_owner, repo }); - context.repoHtmlUrl = data.html_url; - const { data: branches } = await octokitClient.repos.listBranches({ - owner: branch_owner, - repo - }); - const defaultBranch = branches.find(branch => branch.name === 'main'); - if (defaultBranch) { - context.branchData = { name: defaultBranch.name }; - } else { - context.branchData = {name: branches[0].name }; - } - } - - //api call to ARM - const newName: string = nonNullProp(context, 'newStaticWebAppName'); - const branchData = nonNullProp(context, 'branchData'); - const siteEnvelope: StaticSiteARMResource = { - repositoryUrl: context.repoHtmlUrl, - branch: branchData.name, - repositoryToken: context.accessToken, - // The SDK hasn't updated to reflect the outputLocation property and platform will continue supporting appArtifactLocation, but will update as soon as available - buildProperties: { - appLocation: context.appLocation, - apiLocation: context.apiLocation, - appArtifactLocation: context.outputLocation - }, - sku: context.sku, - location: (await LocationListStep.getLocation(context)).name - }; - const creatingSwa: string = localize('creatingSwa', 'Creating new static web app "{0}"...', newName); - progress.report({ message: creatingSwa }); - ext.outputChannel.appendLog(creatingSwa); - context.staticWebApp = await context.client.staticSites.beginCreateOrUpdateStaticSiteAndWait(nonNullValueAndProp(context.resourceGroup, 'name'), newName, siteEnvelope); - context.activityResult = context.staticWebApp as AppResource; + public priority = 250; + public async execute( + context: IStaticWebAppWizardContext, + progress: Progress<{ + message?: string | undefined; + increment?: number | undefined; + }> + ): Promise { + if (context.shouldInitLogicApp) { + //There was an issue where some fields of context would be lost when SWA called with LA. This is a temporary fix to find the branch data again here because of that. Note this will only work with alain github. + const octokitClient: Octokit = await createOctokitClient(context); + const repo = context.newStaticWebAppName || "def"; + const { data } = await octokitClient.repos.get({ + owner: branch_owner, + repo, + }); + context.repoHtmlUrl = data.html_url; + const { data: branches } = await octokitClient.repos.listBranches({ + owner: branch_owner, + repo, + }); + const defaultBranch = branches.find((branch) => branch.name === "main"); + if (defaultBranch) { + context.branchData = { name: defaultBranch.name }; + } else { + context.branchData = { name: branches[0].name }; + } + } - if (context.logicApp) { - //link backends only if SWA called with LA - const staticSiteLinkedBackendEnvelope = { - backendResourceId: context.logicApp.backendResourceId, - region: context.logicApp.region - }; - const credential = new DefaultAzureCredential(); - const client = new WebSiteManagementClient(credential, context.subscriptionId); + //api call to ARM + const newName: string = nonNullProp(context, "newStaticWebAppName"); + const branchData = nonNullProp(context, "branchData"); + const siteEnvelope: StaticSiteARMResource = { + repositoryUrl: context.repoHtmlUrl, + branch: branchData.name, + repositoryToken: context.accessToken, + // The SDK hasn't updated to reflect the outputLocation property and platform will continue supporting appArtifactLocation, but will update as soon as available + buildProperties: { + appLocation: context.appLocation, + apiLocation: context.apiLocation, + appArtifactLocation: context.outputLocation, + }, + sku: context.sku, + location: (await LocationListStep.getLocation(context)).name, + }; + const creatingSwa: string = localize( + "creatingSwa", + 'Creating new static web app "{0}"...', + newName + ); + progress.report({ message: creatingSwa }); + ext.outputChannel.appendLog(creatingSwa); + context.staticWebApp = + await context.client.staticSites.beginCreateOrUpdateStaticSiteAndWait( + nonNullValueAndProp(context.resourceGroup, "name"), + newName, + siteEnvelope + ); + context.activityResult = context.staticWebApp as AppResource; - try{ - const result = await client.staticSites.beginLinkBackendAndWait( - nonNullValueAndProp(context.resourceGroup, 'name'), nonNullValueAndProp(context.staticWebApp, "name"), context.logicApp.name, staticSiteLinkedBackendEnvelope); - console.log(result); - } catch(error) { - console.log(error); - } - } - } + if (context.shouldInitLogicApp) { + const staticSiteLinkedBackendEnvelope = { + backendResourceId: context.shouldInitLogicApp.backendResourceId, + region: context.shouldInitLogicApp.region, + }; + const credential = new DefaultAzureCredential(); + const client = new WebSiteManagementClient( + credential, + context.subscriptionId + ); - public shouldExecute(_wizardContext: IStaticWebAppWizardContext): boolean { - return true; + try { + const result = await client.staticSites.beginLinkBackendAndWait( + nonNullValueAndProp(context.resourceGroup, "name"), + nonNullValueAndProp(context.staticWebApp, "name"), + context.shouldInitLogicApp.name, + staticSiteLinkedBackendEnvelope + ); + console.log(result); + } catch (error) { + console.log(error); + } } + } + public shouldExecute(_wizardContext: IStaticWebAppWizardContext): boolean { + return true; + } } diff --git a/src/commands/createStaticWebApp/createStaticWebApp.ts b/src/commands/createStaticWebApp/createStaticWebApp.ts index 70c107e42..d09969ed8 100644 --- a/src/commands/createStaticWebApp/createStaticWebApp.ts +++ b/src/commands/createStaticWebApp/createStaticWebApp.ts @@ -4,383 +4,555 @@ *--------------------------------------------------------------------------------------------*/ // biome-ignore lint/style/useNodejsImportProtocol: -import { promises as fs } from 'fs'; // Import the promises API from fs +import { promises as fs } from "fs"; // Import the promises API from fs // biome-ignore lint/style/useNodejsImportProtocol: -import type { StaticSiteARMResource, WebSiteManagementClient } from '@azure/arm-appservice'; -import { LocationListStep, ResourceGroupCreateStep, ResourceGroupListStep, SubscriptionTreeItemBase, VerifyProvidersStep } from '@microsoft/vscode-azext-azureutils'; -import { AzExtFsExtra, AzureWizard, nonNullProp, type AzureWizardExecuteStep, type AzureWizardPromptStep, type ExecuteActivityContext, type IActionContext, type ICreateChildImplContext } from '@microsoft/vscode-azext-utils'; -import type { AppResource } from '@microsoft/vscode-azext-utils/hostapi'; -import type { Octokit } from '@octokit/rest'; -import { homedir } from 'os'; -import { join } from 'path'; -import { ProgressLocation, Uri, window, workspace, type ProgressOptions, type WorkspaceFolder } from 'vscode'; -import { Utils } from 'vscode-uri'; -import { StaticWebAppResolver } from '../../StaticWebAppResolver'; -import { NodeDetector, type DetectorResults } from '../../detectors/node/NodeDetector'; -import { NodeConstants } from '../../detectors/node/nodeConstants'; -import { VerifyingWorkspaceError } from '../../errors'; -import { ext } from '../../extensionVariables'; -import { createActivityContext } from '../../utils/activityUtils'; -import { createWebSiteClient } from '../../utils/azureClients'; -import { cpUtils } from '../../utils/cpUtils'; -import { getGitHubAccessToken } from '../../utils/gitHubUtils'; -import { gitPull } from '../../utils/gitUtils'; -import { localize } from '../../utils/localize'; -import { telemetryUtils } from '../../utils/telemetryUtils'; -import { getSingleRootFsPath, getSubFolders, showNoWorkspacePrompt, tryGetWorkspaceFolder } from '../../utils/workspaceUtils'; -import { RemoteShortnameStep } from '../createRepo/RemoteShortnameStep'; -import { RepoCreateStep } from '../createRepo/RepoCreateStep'; -import { RepoNameStep } from '../createRepo/RepoNameStep'; -import { RepoPrivacyStep } from '../createRepo/RepoPrivacyStep'; -import { createOctokitClient } from '../github/createOctokitClient'; -import { showSwaCreated } from '../showSwaCreated'; -import { ApiLocationStep } from './ApiLocationStep'; -import { AppLocationStep } from './AppLocationStep'; -import { BuildPresetListStep } from './BuildPresetListStep'; -import { GitHubOrgListStep } from './GitHubOrgListStep'; -import type { IStaticWebAppWizardContext } from './IStaticWebAppWizardContext'; -import { OutputLocationStep } from './OutputLocationStep'; -import { SkuListStep } from './SkuListStep'; -import { StaticWebAppCreateStep } from './StaticWebAppCreateStep'; -import { StaticWebAppNameStep } from './StaticWebAppNameStep'; -import { setGitWorkspaceContexts } from './setWorkspaceContexts'; -import { tryGetApiLocations } from './tryGetApiLocations'; - - -function isSubscription(item?: SubscriptionTreeItemBase): item is SubscriptionTreeItemBase { - try { - // Accessing item.subscription throws an error for some workspace items - // see https://github.com/microsoft/vscode-azurefunctions/issues/3731 - return !!item && !!item.subscription; - } catch { - return false; - } +import type { + StaticSiteARMResource, + WebSiteManagementClient, +} from "@azure/arm-appservice"; +import { + LocationListStep, + ResourceGroupCreateStep, + ResourceGroupListStep, + SubscriptionTreeItemBase, + VerifyProvidersStep, +} from "@microsoft/vscode-azext-azureutils"; +import { + AzExtFsExtra, + AzureWizard, + nonNullProp, + type AzureWizardExecuteStep, + type AzureWizardPromptStep, + type ExecuteActivityContext, + type IActionContext, + type ICreateChildImplContext, +} from "@microsoft/vscode-azext-utils"; +import type { AppResource } from "@microsoft/vscode-azext-utils/hostapi"; +import type { Octokit } from "@octokit/rest"; +import { homedir } from "os"; +import { join } from "path"; +import { + ProgressLocation, + Uri, + window, + workspace, + type ProgressOptions, + type WorkspaceFolder, +} from "vscode"; +import { Utils } from "vscode-uri"; +import { StaticWebAppResolver } from "../../StaticWebAppResolver"; +import { + NodeDetector, + type DetectorResults, +} from "../../detectors/node/NodeDetector"; +import { NodeConstants } from "../../detectors/node/nodeConstants"; +import { VerifyingWorkspaceError } from "../../errors"; +import { ext } from "../../extensionVariables"; +import { createActivityContext } from "../../utils/activityUtils"; +import { createWebSiteClient } from "../../utils/azureClients"; +import { cpUtils } from "../../utils/cpUtils"; +import { getGitHubAccessToken } from "../../utils/gitHubUtils"; +import { gitPull } from "../../utils/gitUtils"; +import { localize } from "../../utils/localize"; +import { telemetryUtils } from "../../utils/telemetryUtils"; +import { + getSingleRootFsPath, + getSubFolders, + showNoWorkspacePrompt, + tryGetWorkspaceFolder, +} from "../../utils/workspaceUtils"; +import { RemoteShortnameStep } from "../createRepo/RemoteShortnameStep"; +import { RepoCreateStep } from "../createRepo/RepoCreateStep"; +import { RepoNameStep } from "../createRepo/RepoNameStep"; +import { RepoPrivacyStep } from "../createRepo/RepoPrivacyStep"; +import { createOctokitClient } from "../github/createOctokitClient"; +import { showSwaCreated } from "../showSwaCreated"; +import { ApiLocationStep } from "./ApiLocationStep"; +import { AppLocationStep } from "./AppLocationStep"; +import { BuildPresetListStep } from "./BuildPresetListStep"; +import { GitHubOrgListStep } from "./GitHubOrgListStep"; +import type { IStaticWebAppWizardContext } from "./IStaticWebAppWizardContext"; +import { OutputLocationStep } from "./OutputLocationStep"; +import { SkuListStep } from "./SkuListStep"; +import { StaticWebAppCreateStep } from "./StaticWebAppCreateStep"; +import { StaticWebAppNameStep } from "./StaticWebAppNameStep"; +import { setGitWorkspaceContexts } from "./setWorkspaceContexts"; +import { tryGetApiLocations } from "./tryGetApiLocations"; + +function isSubscription( + item?: SubscriptionTreeItemBase +): item is SubscriptionTreeItemBase { + try { + // Accessing item.subscription throws an error for some workspace items + // see https://github.com/microsoft/vscode-azurefunctions/issues/3731 + return !!item && !!item.subscription; + } catch { + return false; + } } let isVerifyingWorkspace = false; -export async function createStaticWebApp(context: IActionContext & Partial & Partial, node?: SubscriptionTreeItemBase, _nodes?: SubscriptionTreeItemBase[], ...args: unknown[]): Promise { - const isLogicAppParameterPassed = args.length > 0; - if (isLogicAppParameterPassed) { - type Resource = {backendResourceId: string, region: string, name: string}; - const logicApp = args[0] as Resource; - context.logicApp = logicApp; - return await createStaticWebAppWithLogicApp(context); - } - - if (isVerifyingWorkspace) { - throw new VerifyingWorkspaceError(context); +export async function createStaticWebApp( + context: IActionContext & + Partial & + Partial, + node?: SubscriptionTreeItemBase, + _nodes?: SubscriptionTreeItemBase[], + ...args: unknown[] +): Promise { + const isLogicAppParameterPassed = args.length > 0; + if (isLogicAppParameterPassed) { + type Resource = { backendResourceId: string; region: string; name: string }; + const logicApp = args[0] as Resource; + context.shouldInitLogicApp = logicApp; + return await createStaticWebAppWithLogicApp(context); + } + + if (isVerifyingWorkspace) { + throw new VerifyingWorkspaceError(context); + } + const progressOptions: ProgressOptions = { + location: ProgressLocation.Window, + title: localize("verifyingWorkspace", "Verifying workspace..."), + }; + isVerifyingWorkspace = true; + try { + if (!isSubscription(node)) { + node = + await ext.rgApi.appResourceTree.showTreeItemPicker( + SubscriptionTreeItemBase.contextValue, + context + ); } - const progressOptions: ProgressOptions = { - location: ProgressLocation.Window, - title: localize('verifyingWorkspace', 'Verifying workspace...') - }; - isVerifyingWorkspace = true; - try { - if (!isSubscription(node)) { - node = await ext.rgApi.appResourceTree.showTreeItemPicker(SubscriptionTreeItemBase.contextValue, context); - } - await window.withProgress(progressOptions, async () => { - const folder = await tryGetWorkspaceFolder(context); - if (folder) { - await telemetryUtils.runWithDurationTelemetry(context, 'tryGetFrameworks', async () => { - const detector = new NodeDetector(); - const detectorResult = await detector.detect(folder.uri); - // comma separated list of all frameworks detected in this project - context.telemetry.properties.detectedFrameworks = `(${detectorResult?.frameworks.map(fi => fi.framework).join('), (')})` ?? 'N/A'; - context.telemetry.properties.rootHasSrcFolder = (await AzExtFsExtra.pathExists(Uri.joinPath(folder.uri, NodeConstants.srcFolderName))).toString(); - const subfolderDetectorResults: DetectorResults[] = []; - const subWithSrcFolder: string[] = [] - const subfolders = await getSubFolders(context, folder.uri); - for (const subfolder of subfolders) { - const subResult = await detector.detect(subfolder); - if (subResult) { - subfolderDetectorResults.push(subResult); - if (await AzExtFsExtra.pathExists(Uri.joinPath(subfolder, NodeConstants.srcFolderName))) { - subWithSrcFolder.push(Utils.basename(subfolder)); - } - } - } - if (subfolderDetectorResults.length > 0) { - // example print: "(Angular,Typescript), (Next.js,React), (Nuxt.js), (React), (Svelte), (Vue.js,Vue.js)" - context.telemetry.properties.detectedFrameworksSub = `(${subfolderDetectorResults.map(dr => dr.frameworks).map(fis => fis.map(fi => fi.framework)).join('), (')})`; - context.telemetry.properties.subFoldersWithSrc = subWithSrcFolder.join(', '); - } - }); - await setGitWorkspaceContexts(context, folder); - context.detectedApiLocations = await tryGetApiLocations(context, folder); - } else { - await showNoWorkspacePrompt(context); + await window.withProgress(progressOptions, async () => { + const folder = await tryGetWorkspaceFolder(context); + if (folder) { + await telemetryUtils.runWithDurationTelemetry( + context, + "tryGetFrameworks", + async () => { + const detector = new NodeDetector(); + + const detectorResult = await detector.detect(folder.uri); + // comma separated list of all frameworks detected in this project + context.telemetry.properties.detectedFrameworks = + `(${detectorResult?.frameworks + .map((fi) => fi.framework) + .join("), (")})` ?? "N/A"; + context.telemetry.properties.rootHasSrcFolder = ( + await AzExtFsExtra.pathExists( + Uri.joinPath(folder.uri, NodeConstants.srcFolderName) + ) + ).toString(); + const subfolderDetectorResults: DetectorResults[] = []; + const subWithSrcFolder: string[] = []; + const subfolders = await getSubFolders(context, folder.uri); + for (const subfolder of subfolders) { + const subResult = await detector.detect(subfolder); + if (subResult) { + subfolderDetectorResults.push(subResult); + if ( + await AzExtFsExtra.pathExists( + Uri.joinPath(subfolder, NodeConstants.srcFolderName) + ) + ) { + subWithSrcFolder.push(Utils.basename(subfolder)); + } + } } - }); - } finally { - isVerifyingWorkspace = false; - } - const client: WebSiteManagementClient = await createWebSiteClient([context, node.subscription]); - const wizardContext: IStaticWebAppWizardContext = { - accessToken: await getGitHubAccessToken(), - client, - ...context, - ...node.subscription, - ...(await createActivityContext()) - }; - const title: string = localize('createStaticApp', 'Create Static Web App'); - const promptSteps: AzureWizardPromptStep[] = []; - const executeSteps: AzureWizardExecuteStep[] = []; - if (!context.advancedCreation) { - wizardContext.sku = SkuListStep.getSkus()[0]; - executeSteps.push(new ResourceGroupCreateStep()); - } else { - promptSteps.push(new ResourceGroupListStep()); - } - promptSteps.push(new StaticWebAppNameStep(), new SkuListStep()); - const hasRemote: boolean = !!wizardContext.repoHtmlUrl; - // if the local project doesn't have a GitHub remote, we will create it for them - if (!hasRemote) { - promptSteps.push(new GitHubOrgListStep(), new RepoNameStep(), new RepoPrivacyStep(), new RemoteShortnameStep()); - executeSteps.push(new RepoCreateStep()); - } - // hard-coding locations available during preview - // https://github.com/microsoft/vscode-azurestaticwebapps/issues/18 - const locations = [ - 'Central US', - 'East US 2', - 'East Asia', - 'West Europe', - 'West US 2' - ]; - const webProvider: string = 'Microsoft.Web'; - LocationListStep.setLocationSubset(wizardContext, Promise.resolve(locations), webProvider); - LocationListStep.addStep(wizardContext, promptSteps, { - placeHolder: localize('selectLocation', 'Select a region for Azure Functions API and staging environments'), - noPicksMessage: localize('noRegions', 'No available regions.') - }); - promptSteps.push(new BuildPresetListStep(), new AppLocationStep(), new ApiLocationStep(), new OutputLocationStep()); - executeSteps.push(new VerifyProvidersStep([webProvider])); - executeSteps.push(new StaticWebAppCreateStep()); - const wizard: AzureWizard = new AzureWizard(wizardContext, { - title, - promptSteps, - executeSteps, - showLoadingPrompt: true + if (subfolderDetectorResults.length > 0) { + // example print: "(Angular,Typescript), (Next.js,React), (Nuxt.js), (React), (Svelte), (Vue.js,Vue.js)" + context.telemetry.properties.detectedFrameworksSub = `(${subfolderDetectorResults + .map((dr) => dr.frameworks) + .map((fis) => fis.map((fi) => fi.framework)) + .join("), (")})`; + context.telemetry.properties.subFoldersWithSrc = + subWithSrcFolder.join(", "); + } + } + ); + await setGitWorkspaceContexts(context, folder); + context.detectedApiLocations = await tryGetApiLocations( + context, + folder + ); + } else { + await showNoWorkspacePrompt(context); + } }); - wizardContext.telemetry.properties.gotRemote = String(hasRemote); - wizardContext.uri = wizardContext.uri || getSingleRootFsPath(); - wizardContext.telemetry.properties.numberOfWorkspaces = !workspace.workspaceFolders ? String(0) : String(workspace.workspaceFolders.length); - await wizard.prompt(); - wizardContext.activityTitle = localize('createStaticApp', 'Create Static Web App "{0}"', nonNullProp(wizardContext, 'newStaticWebAppName')); - if (!context.advancedCreation) { - wizardContext.newResourceGroupName = await wizardContext.relatedNameTask; + } finally { + isVerifyingWorkspace = false; + } + const client: WebSiteManagementClient = await createWebSiteClient([ + context, + node.subscription, + ]); + const wizardContext: IStaticWebAppWizardContext = { + accessToken: await getGitHubAccessToken(), + client, + ...context, + ...node.subscription, + ...(await createActivityContext()), + }; + const title: string = localize("createStaticApp", "Create Static Web App"); + const promptSteps: AzureWizardPromptStep< + IStaticWebAppWizardContext & ExecuteActivityContext + >[] = []; + const executeSteps: AzureWizardExecuteStep[] = []; + if (!context.advancedCreation) { + wizardContext.sku = SkuListStep.getSkus()[0]; + executeSteps.push(new ResourceGroupCreateStep()); + } else { + promptSteps.push(new ResourceGroupListStep()); + } + promptSteps.push(new StaticWebAppNameStep(), new SkuListStep()); + const hasRemote: boolean = !!wizardContext.repoHtmlUrl; + // if the local project doesn't have a GitHub remote, we will create it for them + if (!hasRemote) { + promptSteps.push( + new GitHubOrgListStep(), + new RepoNameStep(), + new RepoPrivacyStep(), + new RemoteShortnameStep() + ); + executeSteps.push(new RepoCreateStep()); + } + // hard-coding locations available during preview + // https://github.com/microsoft/vscode-azurestaticwebapps/issues/18 + const locations = [ + "Central US", + "East US 2", + "East Asia", + "West Europe", + "West US 2", + ]; + const webProvider: string = "Microsoft.Web"; + LocationListStep.setLocationSubset( + wizardContext, + Promise.resolve(locations), + webProvider + ); + LocationListStep.addStep(wizardContext, promptSteps, { + placeHolder: localize( + "selectLocation", + "Select a region for Azure Functions API and staging environments" + ), + noPicksMessage: localize("noRegions", "No available regions."), + }); + promptSteps.push( + new BuildPresetListStep(), + new AppLocationStep(), + new ApiLocationStep(), + new OutputLocationStep() + ); + executeSteps.push(new VerifyProvidersStep([webProvider])); + executeSteps.push(new StaticWebAppCreateStep()); + const wizard: AzureWizard = new AzureWizard( + wizardContext, + { + title, + promptSteps, + executeSteps, + showLoadingPrompt: true, } - await wizard.execute(); - await ext.rgApi.appResourceTree.refresh(context); - const swa: StaticSiteARMResource = nonNullProp(wizardContext, 'staticWebApp'); - await gitPull(nonNullProp(wizardContext, 'repo')); - const appResource: AppResource = { - id: nonNullProp(swa, 'id'), - name: nonNullProp(swa, 'name'), - type: nonNullProp(swa, 'type'), - ...swa - }; - const resolver = new StaticWebAppResolver(); - const resolvedSwa = await resolver.resolveResource(node.subscription, appResource); - if (resolvedSwa) { - await showSwaCreated(resolvedSwa); - } - return appResource; + ); + wizardContext.telemetry.properties.gotRemote = String(hasRemote); + wizardContext.uri = wizardContext.uri || getSingleRootFsPath(); + wizardContext.telemetry.properties.numberOfWorkspaces = + !workspace.workspaceFolders + ? String(0) + : String(workspace.workspaceFolders.length); + await wizard.prompt(); + wizardContext.activityTitle = localize( + "createStaticApp", + 'Create Static Web App "{0}"', + nonNullProp(wizardContext, "newStaticWebAppName") + ); + if (!context.advancedCreation) { + wizardContext.newResourceGroupName = await wizardContext.relatedNameTask; + } + await wizard.execute(); + await ext.rgApi.appResourceTree.refresh(context); + const swa: StaticSiteARMResource = nonNullProp(wizardContext, "staticWebApp"); + await gitPull(nonNullProp(wizardContext, "repo")); + const appResource: AppResource = { + id: nonNullProp(swa, "id"), + name: nonNullProp(swa, "name"), + type: nonNullProp(swa, "type"), + ...swa, + }; + const resolver = new StaticWebAppResolver(); + const resolvedSwa = await resolver.resolveResource( + node.subscription, + appResource + ); + if (resolvedSwa) { + await showSwaCreated(resolvedSwa); + } + return appResource; } -export async function createStaticWebAppWithLogicApp(context: IActionContext & Partial & Partial, node?: SubscriptionTreeItemBase): Promise { - if (isVerifyingWorkspace) { - throw new VerifyingWorkspaceError(context); +export async function createStaticWebAppWithLogicApp( + context: IActionContext & + Partial & + Partial, + node?: SubscriptionTreeItemBase +): Promise { + if (isVerifyingWorkspace) { + throw new VerifyingWorkspaceError(context); + } + const progressOptions: ProgressOptions = { + location: ProgressLocation.Window, + title: localize("verifyingWorkspace", "Verifying workspace..."), + }; + + isVerifyingWorkspace = true; + if (!isSubscription(node)) { + node = + await ext.rgApi.appResourceTree.showTreeItemPicker( + SubscriptionTreeItemBase.contextValue, + context + ); + } + const client: WebSiteManagementClient = await createWebSiteClient([ + context, + node.subscription, + ]); + const wizardContext: IStaticWebAppWizardContext = { + accessToken: await getGitHubAccessToken(), + client, + ...context, + ...node.subscription, + ...(await createActivityContext()), + }; + const title: string = localize("createStaticApp", "Create Static Web App"); + const promptSteps: AzureWizardPromptStep< + IStaticWebAppWizardContext & ExecuteActivityContext + >[] = []; + const executeSteps: AzureWizardExecuteStep[] = []; + if (!context.advancedCreation) { + //[1] gets standard and not free + wizardContext.sku = SkuListStep.getSkus()[1]; + executeSteps.push(new ResourceGroupCreateStep()); + } else { + promptSteps.push(new ResourceGroupListStep()); + } + + promptSteps.push(new StaticWebAppNameStep(), new SkuListStep()); + const wizard: AzureWizard = new AzureWizard( + wizardContext, + { + title, + promptSteps, + executeSteps, + showLoadingPrompt: true, } - const progressOptions: ProgressOptions = { - location: ProgressLocation.Window, - title: localize('verifyingWorkspace', 'Verifying workspace...') - }; - - isVerifyingWorkspace = true; - if (!isSubscription(node)) { - node = await ext.rgApi.appResourceTree.showTreeItemPicker(SubscriptionTreeItemBase.contextValue, context); + ); + + wizardContext.uri = wizardContext.uri || getSingleRootFsPath(); + await wizard.prompt(); + + //create github template (TODO 7: Make this a function) + const folderName: string = getFolderName(wizardContext); + const homeDir = homedir(); + const clonePath = getClonePath(homeDir, folderName); + const clonePathUri: Uri = Uri.file(clonePath); + const octokitClient: Octokit = await createOctokitClient(context); + const { data: response } = await octokitClient.rest.repos.createUsingTemplate( + { + private: true, + template_owner: "alain-zhiyanov", + template_repo: "template-swa-la", + name: folderName, } - const client: WebSiteManagementClient = await createWebSiteClient([context, node.subscription]); - const wizardContext: IStaticWebAppWizardContext = { - accessToken: await getGitHubAccessToken(), - client, - ...context, - ...node.subscription, - ...(await createActivityContext()) - }; - const title: string = localize('createStaticApp', 'Create Static Web App'); - const promptSteps: AzureWizardPromptStep[] = []; - const executeSteps: AzureWizardExecuteStep[] = []; - if (!context.advancedCreation) { - //[1] gets standard and not free - wizardContext.sku = SkuListStep.getSkus()[1]; - executeSteps.push(new ResourceGroupCreateStep()); - } else { - promptSteps.push(new ResourceGroupListStep()); - } - - promptSteps.push(new StaticWebAppNameStep(), new SkuListStep()); - const wizard: AzureWizard = new AzureWizard(wizardContext, { - title, - promptSteps, - executeSteps, - showLoadingPrompt: true - }); - - wizardContext.uri = wizardContext.uri || getSingleRootFsPath(); - await wizard.prompt(); - - //create github template - const folderName: string = wizardContext.newStaticWebAppName || 'default_folder_name'; - const homeDir = homedir(); - const baseClonePath = join(homeDir, folderName); - const clonePath = join(baseClonePath, 'static-web-app'); - const clonePathUri: Uri = Uri.file(clonePath); - const octokitClient: Octokit = await createOctokitClient(context); - const { data: response } = await octokitClient.rest.repos.createUsingTemplate({ - private: true, - template_owner: "alain-zhiyanov", - template_repo: "template-swa-la", - name: folderName, - - }); - await sleep(1000); - - //clone github template - const repoUrl = response.html_url; - const command = `git clone ${repoUrl} ${clonePath}`; - await fs.mkdir(clonePath, { recursive: true }); - await cpUtils.executeCommand(undefined, clonePath, command); - - await tryGetWorkspaceFolder(context); - try { - await window.withProgress(progressOptions, async () => { - const folder: WorkspaceFolder = { - uri: clonePathUri, - name: "myUri", - index: 0 + ); + await sleep(1000); + + //clone github template + const repoUrl = response.html_url; + const command = `git clone ${repoUrl} ${clonePath}`; + await fs.mkdir(clonePath, { recursive: true }); + await cpUtils.executeCommand(undefined, clonePath, command); + + await tryGetWorkspaceFolder(context); + try { + await window.withProgress(progressOptions, async () => { + const folder: WorkspaceFolder = { + uri: clonePathUri, + name: "myUri", + index: 0, + }; + if (folder) { + await telemetryUtils.runWithDurationTelemetry( + context, + "tryGetFrameworks", + async () => { + const detector = new NodeDetector(); + const detectorResult = await detector.detect(folder.uri); + // comma separated list of all frameworks detected in this project + context.telemetry.properties.detectedFrameworks = + `(${detectorResult?.frameworks + .map((fi) => fi.framework) + .join("), (")})` ?? "N/A"; + context.telemetry.properties.rootHasSrcFolder = ( + await AzExtFsExtra.pathExists( + Uri.joinPath(folder.uri, NodeConstants.srcFolderName) + ) + ).toString(); + + const subfolderDetectorResults: DetectorResults[] = []; + const subWithSrcFolder: string[] = []; + const subfolders = await getSubFolders(context, folder.uri); + for (const subfolder of subfolders) { + const subResult = await detector.detect(subfolder); + if (subResult) { + subfolderDetectorResults.push(subResult); + if ( + await AzExtFsExtra.pathExists( + Uri.joinPath(subfolder, NodeConstants.srcFolderName) + ) + ) { + subWithSrcFolder.push(Utils.basename(subfolder)); + } + } } - if (folder) { - await telemetryUtils.runWithDurationTelemetry(context, 'tryGetFrameworks', async () => { - const detector = new NodeDetector(); - const detectorResult = await detector.detect(folder.uri); - // comma separated list of all frameworks detected in this project - context.telemetry.properties.detectedFrameworks = `(${detectorResult?.frameworks.map(fi => fi.framework).join('), (')})` ?? 'N/A'; - context.telemetry.properties.rootHasSrcFolder = (await AzExtFsExtra.pathExists(Uri.joinPath(folder.uri, NodeConstants.srcFolderName))).toString(); - - const subfolderDetectorResults: DetectorResults[] = []; - const subWithSrcFolder: string[] = [] - const subfolders = await getSubFolders(context, folder.uri); - for (const subfolder of subfolders) { - const subResult = await detector.detect(subfolder); - if (subResult) { - subfolderDetectorResults.push(subResult); - if (await AzExtFsExtra.pathExists(Uri.joinPath(subfolder, NodeConstants.srcFolderName))) { - subWithSrcFolder.push(Utils.basename(subfolder)); - } - } - } - - if (subfolderDetectorResults.length > 0) { - // example print: "(Angular,Typescript), (Next.js,React), (Nuxt.js), (React), (Svelte), (Vue.js,Vue.js)" - context.telemetry.properties.detectedFrameworksSub = `(${subfolderDetectorResults.map(dr => dr.frameworks).map(fis => fis.map(fi => fi.framework)).join('), (')})`; - context.telemetry.properties.subFoldersWithSrc = subWithSrcFolder.join(', '); - } - }); - - await setGitWorkspaceContexts(context, folder); - context.detectedApiLocations = await tryGetApiLocations(context, folder); - - - } else { - await showNoWorkspacePrompt(context); - } - }); - } finally { - isVerifyingWorkspace = false; - } - let hasRemote = false; - if (wizardContext.repoHtmlUrl !== null) { - hasRemote = true; - } - wizardContext.telemetry.properties.gotRemote = String(hasRemote); - // if the local project doesn't have a GitHub remote, we will create it for them - // this used to be right below website management client, maybe doesn't even need to be ran? - if (!hasRemote) { - promptSteps.push(new GitHubOrgListStep(), new RepoNameStep(), new RepoPrivacyStep(), new RemoteShortnameStep()); - - executeSteps.push(new RepoCreateStep()); - } - // hard-coding locations available during preview - // https://github.com/microsoft/vscode-azurestaticwebapps/issues/18 - const locations = [ - 'Central US', - 'East US 2', - 'East Asia', - 'West Europe', - 'West US 2' - ]; - - const webProvider: string = 'Microsoft.Web'; - - LocationListStep.setLocationSubset(wizardContext, Promise.resolve(locations), webProvider); - LocationListStep.addStep(wizardContext, promptSteps, { - placeHolder: localize('selectLocation', 'Select a region for Azure Functions API and staging environments'), - noPicksMessage: localize('noRegions', 'No available regions.') + if (subfolderDetectorResults.length > 0) { + // example print: "(Angular,Typescript), (Next.js,React), (Nuxt.js), (React), (Svelte), (Vue.js,Vue.js)" + context.telemetry.properties.detectedFrameworksSub = `(${subfolderDetectorResults + .map((dr) => dr.frameworks) + .map((fis) => fis.map((fi) => fi.framework)) + .join("), (")})`; + context.telemetry.properties.subFoldersWithSrc = + subWithSrcFolder.join(", "); + } + } + ); + + await setGitWorkspaceContexts(context, folder); + context.detectedApiLocations = await tryGetApiLocations( + context, + folder + ); + } else { + await showNoWorkspacePrompt(context); + } }); + } finally { + isVerifyingWorkspace = false; + } + let hasRemote = false; + if (wizardContext.repoHtmlUrl !== null) { + hasRemote = true; + } + wizardContext.telemetry.properties.gotRemote = String(hasRemote); + // if the local project doesn't have a GitHub remote, we will create it for them + // this used to be right below website management client, maybe doesn't even need to be ran? + if (!hasRemote) { + promptSteps.push( + new GitHubOrgListStep(), + new RepoNameStep(), + new RepoPrivacyStep(), + new RemoteShortnameStep() + ); + + executeSteps.push(new RepoCreateStep()); + } + + // hard-coding locations available during preview + // https://github.com/microsoft/vscode-azurestaticwebapps/issues/18 + const locations = [ + "Central US", + "East US 2", + "East Asia", + "West Europe", + "West US 2", + ]; + + const webProvider: string = "Microsoft.Web"; + + LocationListStep.setLocationSubset( + wizardContext, + Promise.resolve(locations), + webProvider + ); + LocationListStep.addStep(wizardContext, promptSteps, { + placeHolder: localize( + "selectLocation", + "Select a region for Azure Functions API and staging environments" + ), + noPicksMessage: localize("noRegions", "No available regions."), + }); + + promptSteps.push( + new BuildPresetListStep(), + new AppLocationStep(), + new ApiLocationStep(), + new OutputLocationStep() + ); + + executeSteps.push(new VerifyProvidersStep([webProvider])); + executeSteps.push(new StaticWebAppCreateStep()); + + wizardContext.telemetry.properties.numberOfWorkspaces = + !workspace.workspaceFolders + ? String(0) + : String(workspace.workspaceFolders.length); + + await wizard.prompt(); + + wizardContext.activityTitle = localize( + "createStaticApp", + 'Create Static Web App "{0}"', + nonNullProp(wizardContext, "newStaticWebAppName") + ); + + if (!context.advancedCreation) { + wizardContext.newResourceGroupName = await wizardContext.relatedNameTask; + } + + await wizard.execute(); + + await ext.rgApi.appResourceTree.refresh(context); + const swa: StaticSiteARMResource = nonNullProp(wizardContext, "staticWebApp"); + await gitPull(nonNullProp(context, "repo")); + + const appResource: AppResource = { + id: nonNullProp(swa, "id"), + name: nonNullProp(swa, "name"), + type: nonNullProp(swa, "type"), + ...swa, + }; + + const resolver = new StaticWebAppResolver(); + const resolvedSwa = await resolver.resolveResource( + node.subscription, + appResource + ); + if (resolvedSwa) { + await showSwaCreated(resolvedSwa); + } + + return appResource; +} - promptSteps.push(new BuildPresetListStep(), new AppLocationStep(), new ApiLocationStep(), new OutputLocationStep()); - - executeSteps.push(new VerifyProvidersStep([webProvider])); - executeSteps.push(new StaticWebAppCreateStep()); - - wizardContext.telemetry.properties.numberOfWorkspaces = !workspace.workspaceFolders ? String(0) : String(workspace.workspaceFolders.length); - - await wizard.prompt(); - - wizardContext.activityTitle = localize('createStaticApp', 'Create Static Web App "{0}"', nonNullProp(wizardContext, 'newStaticWebAppName')); - - if (!context.advancedCreation) { - wizardContext.newResourceGroupName = await wizardContext.relatedNameTask; - } - - - await wizard.execute(); - - await ext.rgApi.appResourceTree.refresh(context); - const swa: StaticSiteARMResource = nonNullProp(wizardContext, 'staticWebApp'); - await gitPull(nonNullProp(context, 'repo')); - - const appResource: AppResource = { - id: nonNullProp(swa, 'id'), - name: nonNullProp(swa, 'name'), - type: nonNullProp(swa, 'type'), - ...swa - }; - - const resolver = new StaticWebAppResolver(); - const resolvedSwa = await resolver.resolveResource(node.subscription, appResource); - if (resolvedSwa) { - await showSwaCreated(resolvedSwa); - } +function getClonePath(homeDir: string, folderName: string) { + const baseClonePath = join(homeDir, folderName); + const clonePath = join(baseClonePath, "static-web-app"); + return clonePath; +} - return appResource; +function getFolderName(wizardContext: IStaticWebAppWizardContext): string { + return wizardContext.newStaticWebAppName || "default_folder_name"; } -export async function createStaticWebAppAdvanced(context: IActionContext, node?: SubscriptionTreeItemBase): Promise { - return await createStaticWebApp({ ...context, advancedCreation: true }, node); +export async function createStaticWebAppAdvanced( + context: IActionContext, + node?: SubscriptionTreeItemBase +): Promise { + return await createStaticWebApp({ ...context, advancedCreation: true }, node); } function sleep(ms: number): Promise { - return new Promise(resolve => setTimeout(resolve, ms)); + return new Promise((resolve) => setTimeout(resolve, ms)); } - - - - - - -