Skip to content
This repository was archived by the owner on Jul 9, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jest.mock('../../../src/utils/auth', () => ({

const state = {
projectId: 'test',
publishTypes: [{ name: 'azureFunctionsPublish', description: 'Publish bot to Azure Functions (Preview)' }],
publishTypes: [{ name: 'azurePublish', description: 'Publish bot to Azure (Preview)' }],
};

describe('Publish Target', () => {
Expand All @@ -31,9 +31,7 @@ describe('Publish Target', () => {
setPublishTargets: setPublishTargetsMock,
getPublishTargetTypes: () => {},
});
set(publishTypesState(state.projectId), [
{ name: 'azureFunctionsPublish', description: 'Publish bot to Azure Functions (Preview)' },
]);
set(publishTypesState(state.projectId), [{ name: 'azurePublish', description: 'Publish bot to Azure (Preview)' }]);
};
it('should add new publish profile', () => {
const { getByTestId, getByText } = renderWithRecoilAndCustomDispatchers(
Expand Down
45 changes: 44 additions & 1 deletion Composer/packages/lib/shared/src/skillsUtils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,5 +101,48 @@ export const isSkillHostUpdateRequired = (skillHostEndpoint?: string) => {
return !skillHostEndpoint || isLocalhostUrl(skillHostEndpoint);
};

/**
* Returns true if the runtime key is adaptive; false otherwise.
* Example adaptive runtime keys: 'adaptive-runtime-dotnet-webapp' or 'adaptive-runtime-node-functions'
* Example older adaptive runtime keys: 'csharp-azurewebapp-v2'
Copy link
Contributor

Choose a reason for hiding this comment

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

FWIW, this was used for a pretty brief period of time during the early stages of the runtimes. Only people running preview bits would have projects with the csharp-azurewebapp-v2 value.

*/
export const isUsingAdaptiveRuntimeKey = (runtimeKey?: string): boolean =>
runtimeKey === 'csharp-azurewebapp-v2' || !!runtimeKey?.startsWith('adaptive-runtime-');

/**
* Returns true if the runtime.key exists and is adaptive; false otherwise.
* Example adaptive runtime keys: 'adaptive-runtime-dotnet-webapp' or 'adaptive-runtime-node-functions'
* Example older adaptive runtime keys: 'csharp-azurewebapp-v2'
*/
export const isUsingAdaptiveRuntime = (runtime?: DialogSetting['runtime']): boolean =>
runtime?.key === 'csharp-azurewebapp-v2' || !!runtime?.key?.startsWith('adaptive-runtime-');
isUsingAdaptiveRuntimeKey(runtime?.key);

/**
* Parses the runtime key
* Example adaptive runtime keys: 'adaptive-runtime-dotnet-webapp' or 'adaptive-runtime-node-functions'
* Example older adaptive runtime keys: 'csharp-azurewebapp-v2'
* @returns If the runtime is adaptive and the parsed runtime language and type
* @default { isUsingAdaptiveRuntime: false, runtimeLanguage: 'dotnet', runtimeType: 'webapp'}
*/
export const parseRuntimeKey = (
runtimeKey?: string
): { isUsingAdaptiveRuntime: boolean; runtimeLanguage?: string; runtimeType?: string } => {
const isAdaptive = isUsingAdaptiveRuntimeKey(runtimeKey);

if (runtimeKey && isAdaptive) {
const parts = runtimeKey?.split('-');
if (parts.length === 4) {
return {
isUsingAdaptiveRuntime: isAdaptive,
runtimeLanguage: parts[2],
runtimeType: parts[3],
};
}
}

return {
isUsingAdaptiveRuntime: isAdaptive,
runtimeLanguage: 'dotnet',
runtimeType: 'webapp',
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,7 @@ export const AzureProvisionDialog: React.FC = () => {
const { accessToken } = getTokenFromCache();

setToken(accessToken);

// decode token
const decoded = decodeToken(accessToken);
if (decoded) {
Expand Down
47 changes: 23 additions & 24 deletions extensions/azurePublish/src/node/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
PublishResponse,
PublishResult,
} from '@botframework-composer/types';
import { isUsingAdaptiveRuntime } from '@bfc/shared';
import { isUsingAdaptiveRuntime, parseRuntimeKey } from '@bfc/shared';

import { authConfig, ResourcesItem } from '../types';

Expand Down Expand Up @@ -88,7 +88,6 @@ export default async (composer: IExtensionRegistration): Promise<void> => {
private historyFilePath: string;
private publishHistories: Record<string, Record<string, PublishResult[]>>; // use botId profileName as key
private provisionHistories: Record<string, Record<string, ProcessStatus>>;
private mode: string;
public schema: JSONSchema7;
public instructions: string;
public name: string;
Expand All @@ -97,14 +96,13 @@ export default async (composer: IExtensionRegistration): Promise<void> => {
public hasView = true;
public bundleId = 'publish'; /** host custom UI */

constructor(mode: string, name: string, description: string, bundleId: string) {
constructor(name: string, description: string, bundleId: string) {
this.publishHistories = {};
this.provisionHistories = {};
this.historyFilePath = path.resolve(__dirname, '../../publishHistory.txt');
if (PERSIST_HISTORY) {
this.loadHistoryFromFile();
}
this.mode = mode || 'azurewebapp';
this.schema = schema;
this.instructions = instructions;
this.name = name;
Expand All @@ -119,6 +117,12 @@ export default async (composer: IExtensionRegistration): Promise<void> => {
/* These methods generate all the necessary paths to various files */
/*******************************************************************************************************************************/

private getRuntimeTemplateMode = (runtimeKey?: string): string => {
// The "mode" is kept the same for backward compatibility with original folder names
const { runtimeType } = parseRuntimeKey(runtimeKey);
return runtimeType === 'functions' ? 'azurefunctions' : 'azurewebapp';
};

// path to working folder containing all the assets
private getRuntimeFolder = (key: string) => {
return path.resolve(this.baseRuntimeFolder, `${key}`);
Expand Down Expand Up @@ -189,19 +193,21 @@ export default async (composer: IExtensionRegistration): Promise<void> => {
// point to the declarative assets (possibly in remote storage)
const botFiles = project.getProject().files;

const mode = this.getRuntimeTemplateMode(runtime?.key);

// include both pre-release and release identifiers here
// TODO: eventually we can clean this up when the "old" runtime is deprecated
// (old runtime support is the else block below)
if (isUsingAdaptiveRuntime(runtime)) {
const buildFolder = this.getProjectFolder(resourcekey, this.mode);
const buildFolder = this.getProjectFolder(resourcekey, mode);

// clean up from any previous deploys
await this.cleanup(resourcekey);

// copy bot and runtime into projFolder
await copy(srcTemplate, buildFolder);
} else {
const botFolder = this.getBotFolder(resourcekey, this.mode);
const botFolder = this.getBotFolder(resourcekey, mode);
const runtimeFolder = this.getRuntimeFolder(resourcekey);

// clean up from any previous deploys
Expand All @@ -228,7 +234,7 @@ export default async (composer: IExtensionRegistration): Promise<void> => {
}

// save manifest
runtime.setSkillManifest(runtimeFolder, project.fileStorage, manifestPath, project.fileStorage, this.mode);
runtime.setSkillManifest(runtimeFolder, project.fileStorage, manifestPath, project.fileStorage, mode);

// copy bot and runtime into projFolder
await copy(srcTemplate, runtimeFolder);
Expand Down Expand Up @@ -276,6 +282,9 @@ export default async (composer: IExtensionRegistration): Promise<void> => {
customizeConfiguration: DeployResources
) => {
const { subscriptionID, accessToken, name, environment, hostname, luisResource, abs } = customizeConfiguration;

const mode = this.getRuntimeTemplateMode(runtime?.key);

// Create the BotProjectDeploy object, which is used to carry out the deploy action.
const azDeployer = new BotProjectDeploy({
logger: (msg: any, ...args: any[]) => {
Expand All @@ -285,7 +294,7 @@ export default async (composer: IExtensionRegistration): Promise<void> => {
}
},
accessToken: accessToken,
projPath: this.getProjectFolder(resourcekey, this.mode),
projPath: this.getProjectFolder(resourcekey, mode),
runtime: runtime,
});

Expand Down Expand Up @@ -639,6 +648,8 @@ export default async (composer: IExtensionRegistration): Promise<void> => {
getResources = async (project: IBotProject, user): Promise<ResourcesItem[]> => {
const recommendedResources: ResourcesItem[] = [];

const { runtimeType } = parseRuntimeKey(project.settings?.runtime?.key);

// add in the ALWAYS REQUIRED options

// Always need an app registration (app id and password)
Expand All @@ -648,14 +659,14 @@ export default async (composer: IExtensionRegistration): Promise<void> => {
});

// always need hosting compute - either web app or functions
if (this.mode === 'azurewebapp') {
if (runtimeType === 'functions') {
recommendedResources.push({
...AzureResourceDefinitions[AzureResourceTypes.WEBAPP],
...AzureResourceDefinitions[AzureResourceTypes.AZUREFUNCTIONS],
required: true,
});
} else {
recommendedResources.push({
...AzureResourceDefinitions[AzureResourceTypes.AZUREFUNCTIONS],
...AzureResourceDefinitions[AzureResourceTypes.WEBAPP],
required: true,
});
}
Expand Down Expand Up @@ -773,19 +784,7 @@ export default async (composer: IExtensionRegistration): Promise<void> => {
};
}

const azurePublish = new AzurePublisher(
'azurewebapp',
'azurePublish',
'Publish bot to Azure Web App (Preview)',
'azurePublish'
);
const azureFunctionsPublish = new AzurePublisher(
'azurefunctions',
'azureFunctionsPublish',
'Publish bot to Azure Functions (Preview)',
'azureFunctionsPublish'
);
const azurePublish = new AzurePublisher('azurePublish', 'Publish bot to Azure (Preview)', 'azurePublish');

await composer.addPublishMethod(azurePublish);
await composer.addPublishMethod(azureFunctionsPublish);
};