in Composer/packages/server/src/services/project.ts [624:784]
public static async createProjectAsync(req: Request, jobId: string) {
const {
templateId,
templateVersion,
name,
description,
storageId,
location,
preserveRoot,
templateDir,
eTag,
alias,
locale,
schemaUrl,
runtimeType,
runtimeLanguage,
isLocalGenerator,
isRoot: creatingRootBot = true,
} = req.body;
// get user from request
const user = await ExtensionContext.getUserFromRequest(req);
const createFromPva = !!templateDir;
// populate template if none was passed
if (templateId === '') {
// TODO: Replace with default template once one is determined
throw Error('empty templateID passed');
}
// test for required dependencies
if (runtimeType === 'functions') {
if (!(await isFunctionsRuntimeInstalled())) {
BackgroundProcessManager.updateProcess(jobId, 500, formatMessage('Azure Functions runtime not installed.'));
TelemetryService.trackEvent('CreateNewBotProjectFailed', {
reason: 'Azure Functions runtime not installed.',
template: templateId,
status: 500,
});
return;
}
}
// location to store the bot project
const locationRef = getLocationRef(location, storageId, name);
try {
await BotProjectService.cleanProject(locationRef);
// Update status for polling
BackgroundProcessManager.updateProcess(jobId, 202, formatMessage('Getting template'));
const newProjRef = createFromPva
? await getNewProjRef(templateDir, templateId, locationRef, user, locale)
: await AssetService.manager.copyRemoteProjectTemplateToV2(
templateId,
templateVersion,
name,
locationRef,
jobId,
runtimeType,
runtimeLanguage,
null,
user,
isLocalGenerator
);
BackgroundProcessManager.updateProcess(jobId, 202, formatMessage('Bot files created'));
const botsToProcess: { storageId: string; path: string; name: string }[] = [];
// The outcome of our creation might be > 1 bot! We need to determine how many bots we find in this folder.
// is this a single bot?
if (await StorageService.checkIsBotFolder(newProjRef.storageId, newProjRef.path, user)) {
botsToProcess.push({ ...newProjRef, name });
} else {
// or multiple bots?
const files = await StorageService.getBlob(newProjRef.storageId, newProjRef.path, user);
const childbots = files.children.filter((f) => f.type === 'bot');
childbots.forEach((b) => {
botsToProcess.push({
storageId: newProjRef.storageId,
path: b.path,
name: b.name,
});
});
}
await Promise.all(
botsToProcess.map((botRef) => {
// eslint-disable-next-line no-async-promise-executor
return new Promise(async (resolve, reject) => {
try {
log('Open project', botRef);
const id = await BotProjectService.openProject(botRef, user, false);
// in the case of remote project, we need to update the eTag and alias used by the import mechanism
BotProjectService.setProjectLocationData(id, { alias, eTag });
log('Get Project by Id', id);
const currentProject = await BotProjectService.getProjectById(id, user);
// inject shared content into every new project. this comes from assets/shared
!createFromPva &&
(await AssetService.manager.copyBoilerplate(currentProject.dataDir, currentProject.fileStorage));
if (currentProject !== undefined) {
!createFromPva && (await ejectAndMerge(currentProject, jobId));
BackgroundProcessManager.updateProcess(jobId, 202, formatMessage('Initializing bot project'));
log('Updatebot info', id, preserveRoot);
await currentProject.updateBotInfo(botRef.name, description, true);
if (schemaUrl && !createFromPva) {
await currentProject.saveSchemaToProject(schemaUrl, botRef.path);
}
log('Init project', id);
await currentProject.init();
}
resolve(id);
} catch (err) {
return reject(err);
}
});
})
);
const rootBot = botsToProcess.find((b) => b.name === name);
if (rootBot) {
const id = await BotProjectService.openProject(
{ storageId: rootBot?.storageId, path: rootBot.path },
user,
creatingRootBot
);
const currentProject = await BotProjectService.getProjectById(id, user);
const project = currentProject.getProject();
log('Project created successfully.');
BackgroundProcessManager.updateProcess(jobId, 200, 'Created Successfully', {
id,
...project,
});
TelemetryService.trackEvent('CreateNewBotProjectCompleted', { template: templateId, status: 200 });
} else {
throw new Error('Could not find root bot');
}
} catch (err) {
// Clean up failed projects
log('Cleaning up failed project at ', locationRef.path);
const storage = StorageService.getStorageClient(locationRef.storageId, user);
await storage.rmrfDir(locationRef.path);
BackgroundProcessManager.updateProcess(jobId, 500, err instanceof Error ? err.message : err, err);
TelemetryService.trackEvent('CreateNewBotProjectFailed', {
reason: err instanceof Error ? err.message : err,
template: templateId,
status: 500,
});
}
}