public static async createProjectAsync()

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,
      });
    }
  }