Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

fix(core): cycle depedencies batch 1 #11619

Merged
merged 14 commits into from
May 17, 2024
3 changes: 1 addition & 2 deletions packages/cli/src/commands/models/provision.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import { CLICommand, CLIContext, InputsWithProjectPath } from "@microsoft/teamsfx-api";
import { CoreQuestionNames } from "@microsoft/teamsfx-core";
import { newResourceGroupOption } from "@microsoft/teamsfx-core/build/question/other";
import { CoreQuestionNames, newResourceGroupOption } from "@microsoft/teamsfx-core";
import { getFxCore } from "../../activate";
import { commands } from "../../resource";
import { TelemetryEvent } from "../../telemetry/cliTelemetryEvents";
Expand Down
5 changes: 2 additions & 3 deletions packages/fx-core/resource/package.nls.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"core.addApi.confirm":"Teams Toolkit will modify files in your \"%s\" folder based on the new OpenAPI document you provided. To avoid losing unexpected changes, back up your files or use git for change tracking before proceeding.",
"core.addApi.confirm": "Teams Toolkit will modify files in your \"%s\" folder based on the new OpenAPI document you provided. To avoid losing unexpected changes, back up your files or use git for change tracking before proceeding.",
"core.addApi.continue": "Add",
"core.provision.provision": "Provision",
"core.provision.learnMore": "More info",
Expand Down Expand Up @@ -529,7 +529,6 @@
"core.common.OutlookDesktopClientName": "Outlook desktop client id",
"core.common.OutlookWebClientName1": "Outlook web access client id 1",
"core.common.OutlookWebClientName2": "Outlook web access client id 2",
"core.common.OutlookMobileClientName": "Outlook mobile client id",
"core.common.CancelledMessage": "Operation is canceled.",
"core.common.SwaggerNotSupported": "Swagger 2.0 is not supported. Convert it to OpenAPI 3.0 first.",
"core.common.SpecVersionNotSupported": "OpenAPI version %s is not supported. Use version 3.0.x.",
Expand Down Expand Up @@ -888,4 +887,4 @@
"driver.oauth.confirm.update": "The following parameters will be updated:\n%s\nDo you want to continue?",
"driver.oauth.log.successUpdateOauth": "OAuth registration updated successfully!",
"driver.oauth.info.update": "OAuth registration updated successfully! The following parameters have been updated:\n%s"
}
}
75 changes: 75 additions & 0 deletions packages/fx-core/src/common/azureUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import {
AzureAccountProvider,
FxError,
OptionItem,
Result,
SubscriptionInfo,
SystemError,
UserError,
UserInteraction,
err,
ok,
} from "@microsoft/teamsfx-api";
import { getDefaultString, getLocalizedString } from "./localizeUtils";

export async function askSubscription(
azureAccountProvider: AzureAccountProvider,
ui: UserInteraction,
activeSubscriptionId?: string
): Promise<Result<SubscriptionInfo, FxError>> {
const subscriptions: SubscriptionInfo[] = await azureAccountProvider.listSubscriptions();

Check warning on line 23 in packages/fx-core/src/common/azureUtils.ts

View check run for this annotation

Codecov / codecov/patch

packages/fx-core/src/common/azureUtils.ts#L23

Added line #L23 was not covered by tests

if (subscriptions.length === 0) {
return err(

Check warning on line 26 in packages/fx-core/src/common/azureUtils.ts

View check run for this annotation

Codecov / codecov/patch

packages/fx-core/src/common/azureUtils.ts#L26

Added line #L26 was not covered by tests
new UserError(
"Core",
"NoSubscriptionFound",
getDefaultString("error.NoSubscriptionFound"),
getLocalizedString("error.NoSubscriptionFound")
)
);
}
let resultSub = subscriptions.find((sub) => sub.subscriptionId === activeSubscriptionId);

Check warning on line 35 in packages/fx-core/src/common/azureUtils.ts

View check run for this annotation

Codecov / codecov/patch

packages/fx-core/src/common/azureUtils.ts#L35

Added line #L35 was not covered by tests
if (activeSubscriptionId === undefined || resultSub === undefined) {
let selectedSub: SubscriptionInfo | undefined = undefined;

Check warning on line 37 in packages/fx-core/src/common/azureUtils.ts

View check run for this annotation

Codecov / codecov/patch

packages/fx-core/src/common/azureUtils.ts#L37

Added line #L37 was not covered by tests
if (subscriptions.length === 1) {
selectedSub = subscriptions[0];

Check warning on line 39 in packages/fx-core/src/common/azureUtils.ts

View check run for this annotation

Codecov / codecov/patch

packages/fx-core/src/common/azureUtils.ts#L39

Added line #L39 was not covered by tests
} else {
const options: OptionItem[] = subscriptions.map((sub) => {
return {

Check warning on line 42 in packages/fx-core/src/common/azureUtils.ts

View check run for this annotation

Codecov / codecov/patch

packages/fx-core/src/common/azureUtils.ts#L41-L42

Added lines #L41 - L42 were not covered by tests
id: sub.subscriptionId,
label: sub.subscriptionName,
data: sub.tenantId,
} as OptionItem;
});
const askRes = await ui.selectOption({

Check warning on line 48 in packages/fx-core/src/common/azureUtils.ts

View check run for this annotation

Codecov / codecov/patch

packages/fx-core/src/common/azureUtils.ts#L48

Added line #L48 was not covered by tests
name: "subscription",
title: "Select a subscription",
options: options,
returnObject: true,
});
if (askRes.isErr()) return err(askRes.error);
const subItem = askRes.value.result as OptionItem;
selectedSub = {

Check warning on line 56 in packages/fx-core/src/common/azureUtils.ts

View check run for this annotation

Codecov / codecov/patch

packages/fx-core/src/common/azureUtils.ts#L55-L56

Added lines #L55 - L56 were not covered by tests
subscriptionId: subItem.id,
subscriptionName: subItem.label,
tenantId: subItem.data as string,
};
}
if (selectedSub === undefined) {
return err(

Check warning on line 63 in packages/fx-core/src/common/azureUtils.ts

View check run for this annotation

Codecov / codecov/patch

packages/fx-core/src/common/azureUtils.ts#L63

Added line #L63 was not covered by tests
new SystemError(
"Core",
"NoSubscriptionFound",
getDefaultString("error.NoSubscriptionFound"),
getLocalizedString("error.NoSubscriptionFound")
)
);
}
resultSub = selectedSub;

Check warning on line 72 in packages/fx-core/src/common/azureUtils.ts

View check run for this annotation

Codecov / codecov/patch

packages/fx-core/src/common/azureUtils.ts#L72

Added line #L72 was not covered by tests
}
return ok(resultSub);

Check warning on line 74 in packages/fx-core/src/common/azureUtils.ts

View check run for this annotation

Codecov / codecov/patch

packages/fx-core/src/common/azureUtils.ts#L74

Added line #L74 was not covered by tests
}
34 changes: 34 additions & 0 deletions packages/fx-core/src/common/constants.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import { getLocalizedString } from "./localizeUtils";

export class ConstantString {
static readonly UTF8Encoding = "utf-8";
static readonly DeploymentResourceType = "Microsoft.Resources/deployments";
Expand Down Expand Up @@ -55,3 +57,35 @@
static readonly CopilotAuth = "API_COPILOT_PLUGIN_AUTH";
static readonly CustomizeGpt = "TEAMSFX_DECLARATIVE_COPILOT";
}

export function getAllowedAppMaps(): Record<string, string> {
return {

Check warning on line 62 in packages/fx-core/src/common/constants.ts

View check run for this annotation

Codecov / codecov/patch

packages/fx-core/src/common/constants.ts#L62

Added line #L62 was not covered by tests
[TeamsClientId.MobileDesktop]: getLocalizedString("core.common.TeamsMobileDesktopClientName"),
[TeamsClientId.Web]: getLocalizedString("core.common.TeamsWebClientName"),
[OfficeClientId.Desktop]: getLocalizedString("core.common.OfficeDesktopClientName"),
[OfficeClientId.Web1]: getLocalizedString("core.common.OfficeWebClientName1"),
[OfficeClientId.Web2]: getLocalizedString("core.common.OfficeWebClientName2"),
[OutlookClientId.Desktop]: getLocalizedString("core.common.OutlookDesktopClientName"),
[OutlookClientId.Web1]: getLocalizedString("core.common.OutlookWebClientName1"),
[OutlookClientId.Web2]: getLocalizedString("core.common.OutlookWebClientName2"),
};
}

const AzurePortalUrl = "https://portal.azure.com";
export function getResourceGroupInPortal(
subscriptionId?: string,
tenantId?: string,
resourceGroupName?: string
): string | undefined {
if (subscriptionId && tenantId && resourceGroupName) {
return `${AzurePortalUrl}/#@${tenantId}/resource/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}`;
} else {
return undefined;
}
}

export const AuthSvcScopes = ["https://api.spaces.skype.com/Region.ReadWrite"];
export const GraphScopes = ["Application.ReadWrite.All", "TeamsAppInstallation.ReadForUser"];
export const GraphReadUserScopes = ["https://graph.microsoft.com/User.ReadBasic.All"];
export const SPFxScopes = (tenant: string) => [`${tenant}/Sites.FullControl.All`];
export const AzureScopes = ["https://management.core.windows.net/user_impersonation"];
2 changes: 1 addition & 1 deletion packages/fx-core/src/common/globalState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import * as fs from "fs-extra";
import crypto from "crypto";
import { ConfigFolderName, ProductName } from "@microsoft/teamsfx-api";
import properLock from "proper-lockfile";
import { waitSeconds } from "./tools";
import { waitSeconds } from "./utils";

const GlobalStateFileName = "state.json";

Expand Down
2 changes: 1 addition & 1 deletion packages/fx-core/src/common/local/taskDefinition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import { FolderName, npmInstallCommand } from "./constants";
import path from "path";
import { isWindows } from "../deps-checker/util/system";
import { ProgrammingLanguage } from "../../question/create";
import { ProgrammingLanguage } from "../../question/constants";

export interface ITaskDefinition {
name: string;
Expand Down
10 changes: 5 additions & 5 deletions packages/fx-core/src/common/m365/launchHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@

import { err, FxError, LogProvider, M365TokenProvider, ok, Result } from "@microsoft/teamsfx-api";

import { hooks } from "@feathersjs/hooks";
import { CoreSource } from "../../core/error";
import { AppStudioScopes } from "../tools";
import { ErrorContextMW } from "../../core/globalVars";
import { assembleError } from "../../error/common";
import { HubTypes } from "../../question/constants";
import { NotExtendedToM365Error } from "./errors";
import { PackageService } from "./packageService";
import { serviceEndpoint, serviceScope } from "./serviceConstant";
import { assembleError } from "../../error/common";
import { HubTypes } from "../../question/other";
import { ErrorContextMW } from "../../core/globalVars";
import { hooks } from "@feathersjs/hooks";
import { AppStudioScopes } from "../../component/driver/teamsApp/constants";

export class LaunchHelper {
private readonly m365TokenProvider: M365TokenProvider;
Expand Down
14 changes: 6 additions & 8 deletions packages/fx-core/src/common/m365/packageService.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,25 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import { hooks } from "@feathersjs/hooks";
import { LogProvider, SystemError, UserError } from "@microsoft/teamsfx-api";
import AdmZip from "adm-zip";
import FormData from "form-data";
import fs from "fs-extra";

import { LogProvider, SystemError, UserError } from "@microsoft/teamsfx-api";

import { waitSeconds } from "../tools";
import { NotExtendedToM365Error } from "./errors";
import { serviceEndpoint } from "./serviceConstant";
import { ErrorContextMW, TOOLS } from "../../core/globalVars";
import { assembleError } from "../../error/common";
import { ErrorCategory } from "../../error/types";
import { ErrorContextMW, TOOLS } from "../../core/globalVars";
import { hooks } from "@feathersjs/hooks";
import {
Component,
TelemetryEvent,
TelemetryProperty,
sendTelemetryErrorEvent,
sendTelemetryEvent,
} from "../telemetry";
import { waitSeconds } from "../utils";
import { WrappedAxiosClient } from "../wrappedAxiosClient";
import { NotExtendedToM365Error } from "./errors";
import { serviceEndpoint } from "./serviceConstant";

const M365ErrorSource = "M365";
const M365ErrorComponent = "PackageService";
Expand Down
10 changes: 0 additions & 10 deletions packages/fx-core/src/common/projectSettingsHelperV3.ts

This file was deleted.

53 changes: 53 additions & 0 deletions packages/fx-core/src/common/requestUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import axios, { AxiosResponse, CancelToken } from "axios";

export async function sendRequestWithRetry<T>(
requestFn: () => Promise<AxiosResponse<T>>,
tryLimits: number
): Promise<AxiosResponse<T>> {
// !status means network error, see https://github.com/axios/axios/issues/383
const canTry = (status: number | undefined) => !status || (status >= 500 && status < 600);

let status: number | undefined;
let error: Error;

for (let i = 0; i < tryLimits && canTry(status); i++) {
try {
const res = await requestFn();
if (res.status === 200 || res.status === 201) {
return res;
} else {
error = new Error(`HTTP Request failed: ${JSON.stringify(res)}`);
}
status = res.status;
} catch (e: any) {
error = e;
status = e?.response?.status;
}
}

error ??= new Error(`RequestWithRetry got bad tryLimits: ${tryLimits}`);
throw error;
}
export async function sendRequestWithTimeout<T>(
requestFn: (cancelToken: CancelToken) => Promise<AxiosResponse<T>>,
timeoutInMs: number,
tryLimits = 1
): Promise<AxiosResponse<T>> {
const source = axios.CancelToken.source();
const timeout = setTimeout(() => {
source.cancel();
}, timeoutInMs);
try {
const res = await sendRequestWithRetry(() => requestFn(source.token), tryLimits);
clearTimeout(timeout);
return res;
} catch (err: unknown) {
if (axios.isCancel(err)) {
throw new Error("Request timeout");
}
throw err;
}
}
11 changes: 8 additions & 3 deletions packages/fx-core/src/common/samples.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@
// Licensed under the MIT license.

import axios from "axios";

import { hooks } from "@feathersjs/hooks";

import { SampleUrlInfo, sendRequestWithTimeout } from "../component/generator/utils";
import { ErrorContextMW } from "../core/globalVars";
import { AccessGithubError } from "../error/common";
import { FeatureFlagName } from "./constants";
import { sendRequestWithTimeout } from "./requestUtils";

const packageJson = require("../../package.json");

Expand All @@ -19,6 +17,13 @@ export const SampleConfigTag = "v2.5.0";
// prerelease tag is always using a branch.
export const SampleConfigBranchForPrerelease = "main";

export type SampleUrlInfo = {
owner: string;
repository: string;
ref: string;
dir: string;
};

export interface SampleConfig {
id: string;
onboardDate: Date;
Expand Down
42 changes: 42 additions & 0 deletions packages/fx-core/src/common/stringUtils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import { FailedToParseResourceIdError } from "../core/error";
import * as Handlebars from "handlebars";
import * as uuid from "uuid";
import * as crypto from "crypto";

const MIN_ENTROPY = 4;
const SECRET_REPLACE = "<REDACTED:secret>";
const USER_REPLACE = "<REDACTED:user>";
Expand Down Expand Up @@ -132,3 +137,40 @@
}
return stdout;
}

export function convertToAlphanumericOnly(appName: string): string {
return appName.replace(/[^\da-zA-Z]/g, "");
}

Handlebars.registerHelper("contains", (value, array) => {
array = array instanceof Array ? array : [array];
return array.indexOf(value) > -1 ? this : "";
});
Handlebars.registerHelper("notContains", (value, array) => {
array = array instanceof Array ? array : [array];
return array.indexOf(value) == -1 ? this : "";
});
Handlebars.registerHelper("equals", (value, target) => {
return value === target ? this : "";
});

export function getResourceGroupNameFromResourceId(resourceId: string): string {
const result = parseFromResourceId(/\/resourceGroups\/([^\/]*)\//i, resourceId);
if (!result) {
throw FailedToParseResourceIdError("resource group name", resourceId);

Check warning on line 160 in packages/fx-core/src/common/stringUtils.ts

View check run for this annotation

Codecov / codecov/patch

packages/fx-core/src/common/stringUtils.ts#L160

Added line #L160 was not covered by tests
}
return result;
}

export function parseFromResourceId(pattern: RegExp, resourceId: string): string {
const result = resourceId.match(pattern);
return result ? result[1].trim() : "";
}

export function getUuid(): string {
return uuid.v4();
}

export function getHashedEnv(envName: string): string {
return crypto.createHash("sha256").update(envName).digest("hex");
}
Loading
Loading