@hubspot/cli 7.7.16-experimental.3 → 7.7.16-experimental.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,8 @@
1
+ import { CommonArgs, ConfigArgs, AccountArgs, EnvironmentArgs, YargsCommandModule, JSONOutputArgs } from '../../types/Yargs';
2
+ type InstallAppArgs = CommonArgs & ConfigArgs & AccountArgs & EnvironmentArgs & JSONOutputArgs & {
3
+ appUid?: string;
4
+ projectName?: string;
5
+ testAccountId?: number;
6
+ };
7
+ declare const installAppCommand: YargsCommandModule<unknown, InstallAppArgs>;
8
+ export default installAppCommand;
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const developerTestAccounts_1 = require("@hubspot/local-dev-lib/api/developerTestAccounts");
7
+ const usageTracking_1 = require("../../lib/usageTracking");
8
+ const en_1 = require("../../lang/en");
9
+ const exitCodes_1 = require("../../lib/enums/exitCodes");
10
+ const yargsUtils_1 = require("../../lib/yargsUtils");
11
+ const logger_1 = require("../../lib/ui/logger");
12
+ const SpinniesManager_1 = __importDefault(require("../../lib/ui/SpinniesManager"));
13
+ const errorHandlers_1 = require("../../lib/errorHandlers");
14
+ const polling_1 = require("../../lib/polling");
15
+ const command = 'install';
16
+ const describe = undefined; // commands.app.subcommands.install.describe;
17
+ async function handler(args) {
18
+ const { derivedAccountId, appUid, projectName, testAccountId, formatOutputAsJson, } = args;
19
+ (0, usageTracking_1.trackCommandUsage)('app-install', {}, derivedAccountId);
20
+ const jsonOutput = {};
21
+ try {
22
+ const { data } = await (0, developerTestAccounts_1.installOauthAppIntoDeveloperTestAccount)(derivedAccountId, testAccountId, projectName, appUid);
23
+ if (data?.authCodes.length > 0) {
24
+ jsonOutput.authCode = data.authCodes[0].authCode;
25
+ }
26
+ }
27
+ catch (err) {
28
+ (0, errorHandlers_1.logError)(err);
29
+ process.exit(exitCodes_1.EXIT_CODES.ERROR);
30
+ }
31
+ SpinniesManager_1.default.init({
32
+ succeedColor: 'white',
33
+ });
34
+ SpinniesManager_1.default.add('installApp', {
35
+ text: en_1.commands.app.subcommands.install.polling.start,
36
+ });
37
+ let appInstallSucceeded = false;
38
+ try {
39
+ await (0, polling_1.poll)(() => (0, developerTestAccounts_1.fetchDeveloperTestAccountOauthAppInstallStatus)(derivedAccountId, projectName, appUid), {
40
+ successStates: ['SUCCESS'],
41
+ errorStates: [],
42
+ });
43
+ appInstallSucceeded = true;
44
+ }
45
+ catch (err) {
46
+ SpinniesManager_1.default.fail('installApp');
47
+ (0, errorHandlers_1.logError)(err);
48
+ process.exit(exitCodes_1.EXIT_CODES.ERROR);
49
+ }
50
+ if (!appInstallSucceeded) {
51
+ SpinniesManager_1.default.fail('installApp');
52
+ process.exit(exitCodes_1.EXIT_CODES.ERROR);
53
+ }
54
+ SpinniesManager_1.default.succeed('installApp', {
55
+ text: en_1.commands.app.subcommands.install.polling.success,
56
+ });
57
+ if (formatOutputAsJson) {
58
+ logger_1.uiLogger.json(jsonOutput);
59
+ }
60
+ process.exit(exitCodes_1.EXIT_CODES.SUCCESS);
61
+ }
62
+ function installAppBuilder(yargs) {
63
+ yargs.option('test-account-id', {
64
+ describe: en_1.commands.app.subcommands.install.options.testAccountId,
65
+ type: 'number',
66
+ });
67
+ yargs.positional('app-uid', {
68
+ describe: en_1.commands.app.subcommands.install.options.appUid,
69
+ type: 'string',
70
+ });
71
+ yargs.option('project-name', {
72
+ describe: en_1.commands.app.subcommands.install.options.projectName,
73
+ type: 'string',
74
+ });
75
+ yargs.example('install --app-uid=1234567890 --project-name=my-project', en_1.commands.app.subcommands.install.example);
76
+ return yargs;
77
+ }
78
+ const builder = (0, yargsUtils_1.makeYargsBuilder)(installAppBuilder, command, en_1.commands.app.subcommands.install.describe, {
79
+ useGlobalOptions: true,
80
+ useAccountOptions: true,
81
+ useConfigOptions: true,
82
+ useEnvironmentOptions: true,
83
+ useJSONOutputOptions: true,
84
+ });
85
+ const installAppCommand = {
86
+ command,
87
+ describe,
88
+ handler,
89
+ builder,
90
+ };
91
+ exports.default = installAppCommand;
package/commands/app.js CHANGED
@@ -5,12 +5,17 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const migrate_1 = __importDefault(require("./app/migrate"));
7
7
  const secret_1 = __importDefault(require("./app/secret"));
8
+ const install_1 = __importDefault(require("./app/install"));
8
9
  const yargsUtils_1 = require("../lib/yargsUtils");
9
10
  const command = ['app', 'apps'];
10
11
  // Keep the command hidden for now
11
12
  const describe = undefined;
12
13
  function appBuilder(yargs) {
13
- yargs.command(migrate_1.default).command(secret_1.default).demandCommand(1, '');
14
+ yargs
15
+ .command(migrate_1.default)
16
+ .command(secret_1.default)
17
+ .command(install_1.default)
18
+ .demandCommand(1, '');
14
19
  return yargs;
15
20
  }
16
21
  const builder = (0, yargsUtils_1.makeYargsBuilder)(appBuilder, command, describe);
@@ -14,7 +14,7 @@ const usageTracking_1 = require("../lib/usageTracking");
14
14
  const exitCodes_1 = require("../lib/enums/exitCodes");
15
15
  const yargsUtils_1 = require("../lib/yargsUtils");
16
16
  const promptUtils_1 = require("../lib/prompts/promptUtils");
17
- const createProjectPrompt_1 = require("../lib/prompts/createProjectPrompt");
17
+ const projectNameAndDestPrompt_1 = require("../lib/prompts/projectNameAndDestPrompt");
18
18
  const ui_1 = require("../lib/ui");
19
19
  const logger_1 = require("../lib/ui/logger");
20
20
  const errorHandlers_1 = require("../lib/errorHandlers");
@@ -76,7 +76,7 @@ async function handler(args) {
76
76
  logger_1.uiLogger.log(en_1.commands.getStarted.prompts.appSelected);
77
77
  // 1. Fetch project templates
78
78
  let latestRepoReleaseTag;
79
- const { dest, name } = await (0, createProjectPrompt_1.createProjectPrompt)(args);
79
+ const { dest, name } = await (0, projectNameAndDestPrompt_1.projectNameAndDestPrompt)(args);
80
80
  // Specific template for get-started command
81
81
  const projectTemplate = {
82
82
  name: 'private-app-get-started-template',
@@ -8,7 +8,7 @@ const fs_1 = __importDefault(require("fs"));
8
8
  const usageTracking_1 = require("../../lib/usageTracking");
9
9
  const lang_1 = require("../../lib/lang");
10
10
  const selectPublicAppForMigrationPrompt_1 = require("../../lib/prompts/selectPublicAppForMigrationPrompt");
11
- const createProjectPrompt_1 = require("../../lib/prompts/createProjectPrompt");
11
+ const projectNameAndDestPrompt_1 = require("../../lib/prompts/projectNameAndDestPrompt");
12
12
  const polling_1 = require("../../lib/polling");
13
13
  const errorHandlers_1 = require("../../lib/errorHandlers");
14
14
  const exitCodes_1 = require("../../lib/enums/exitCodes");
@@ -53,9 +53,9 @@ async function handler(args) {
53
53
  });
54
54
  appId = appIdResponse.appId;
55
55
  }
56
- const createProjectPromptResponse = await (0, createProjectPrompt_1.createProjectPrompt)(args);
57
- projectName = createProjectPromptResponse.name;
58
- projectDest = createProjectPromptResponse.dest;
56
+ const projectNameAndDestPromptResponse = await (0, projectNameAndDestPrompt_1.projectNameAndDestPrompt)(args);
57
+ projectName = projectNameAndDestPromptResponse.name;
58
+ projectDest = projectNameAndDestPromptResponse.dest;
59
59
  }
60
60
  catch (error) {
61
61
  (0, errorHandlers_1.logError)(error, new errorHandlers_1.ApiErrorContext({ accountId: derivedAccountId }));
@@ -39,15 +39,15 @@ async function handler(args) {
39
39
  (0, errorHandlers_1.logError)(error);
40
40
  process.exit(exitCodes_1.EXIT_CODES.ERROR);
41
41
  }
42
- const { authType, distribution, repoConfig, projectContents, createProjectPromptResponse, } = handleResult;
42
+ const { authType, distribution, repoConfig, projectContents, selectProjectTemplatePromptResponse, projectNameAndDestPromptResponse, } = handleResult;
43
43
  (0, usageTracking_1.trackCommandUsage)('project-create', {
44
- type: createProjectPromptResponse.projectTemplate?.name ||
45
- (createProjectPromptResponse.componentTemplates || [])
44
+ type: selectProjectTemplatePromptResponse.projectTemplate?.name ||
45
+ (selectProjectTemplatePromptResponse.componentTemplates || [])
46
46
  // @ts-expect-error
47
47
  .map((item) => item.label)
48
48
  .join(','),
49
49
  }, derivedAccountId);
50
- const projectDest = path_1.default.resolve((0, path_2.getCwd)(), createProjectPromptResponse.dest);
50
+ const projectDest = path_1.default.resolve((0, path_2.getCwd)(), projectNameAndDestPromptResponse.dest);
51
51
  const { projectConfig: existingProjectConfig, projectDir: existingProjectDir, } = await (0, config_1.getProjectConfig)(projectDest);
52
52
  // Exit if the target destination is within an existing project
53
53
  if (existingProjectConfig &&
@@ -57,7 +57,7 @@ async function handler(args) {
57
57
  process.exit(exitCodes_1.EXIT_CODES.ERROR);
58
58
  }
59
59
  const components = (0, v3_2.generateComponentPaths)({
60
- createProjectPromptResponse,
60
+ selectProjectTemplatePromptResponse,
61
61
  platformVersion,
62
62
  repoConfig,
63
63
  projectContents,
@@ -66,7 +66,7 @@ async function handler(args) {
66
66
  });
67
67
  try {
68
68
  await (0, github_1.cloneGithubRepo)(repo, projectDest, {
69
- sourceDir: createProjectPromptResponse.projectTemplate?.path || components,
69
+ sourceDir: selectProjectTemplatePromptResponse.projectTemplate?.path || components,
70
70
  hideLogs: true,
71
71
  branch: 'main',
72
72
  });
@@ -80,15 +80,15 @@ async function handler(args) {
80
80
  const parsedConfigFile = JSON.parse(fs_extra_1.default.readFileSync(projectConfigPath).toString());
81
81
  (0, config_1.writeProjectConfig)(projectConfigPath, {
82
82
  ...parsedConfigFile,
83
- name: createProjectPromptResponse.name,
83
+ name: projectNameAndDestPromptResponse.name,
84
84
  });
85
85
  // If the template is 'no-template', we need to manually create a src directory
86
- if (createProjectPromptResponse.projectTemplate?.name ===
86
+ if (selectProjectTemplatePromptResponse.projectTemplate?.name ===
87
87
  legacy_1.EMPTY_PROJECT_TEMPLATE_NAME ||
88
88
  projectContents === v3_1.EMPTY_PROJECT) {
89
89
  fs_extra_1.default.ensureDirSync(path_1.default.join(projectDest, 'src'));
90
90
  }
91
- logger_1.uiLogger.success(en_1.commands.project.create.logs.success(createProjectPromptResponse.name, projectDest));
91
+ logger_1.uiLogger.success(en_1.commands.project.create.logs.success(projectNameAndDestPromptResponse.name, projectDest));
92
92
  logger_1.uiLogger.log(en_1.commands.project.create.logs.welcomeMessage);
93
93
  (0, ui_1.uiFeatureHighlight)([
94
94
  'projectCommandTip',
@@ -121,6 +121,7 @@ async function unifiedProjectDevFlow({ args, targetProjectAccountId, providedTar
121
121
  debug: args.debug,
122
122
  deployedBuild,
123
123
  isGithubLinked,
124
+ profile: args.profile,
124
125
  targetProjectAccountId,
125
126
  targetTestingAccountId: targetTestingAccountId,
126
127
  projectConfig,
@@ -92,14 +92,18 @@ async function handler(args) {
92
92
  await (0, polling_1.poll)(() => (0, developerTestAccounts_1.fetchDeveloperTestAccountGateSyncStatus)(derivedAccountId, testAccountId), {
93
93
  successStates: ['SUCCESS'],
94
94
  errorStates: [],
95
+ }, 5000 // 5 seconds
96
+ );
97
+ SpinniesManager_1.default.succeed('createTestAccount', {
98
+ text: en_1.commands.testAccount.create.polling.success(testAccountConfig.accountName, testAccountId),
95
99
  });
96
100
  }
97
101
  catch (err) {
98
- (0, errorHandlers_1.logError)(err);
102
+ (0, errorHandlers_1.debugError)(err);
103
+ SpinniesManager_1.default.fail('createTestAccount', {
104
+ text: en_1.commands.testAccount.create.polling.failure,
105
+ });
99
106
  }
100
- SpinniesManager_1.default.succeed('createTestAccount', {
101
- text: en_1.commands.testAccount.create.polling.success(testAccountConfig.accountName, testAccountId),
102
- });
103
107
  if (formatOutputAsJson) {
104
108
  logger_1.uiLogger.json(jsonOutput);
105
109
  }
package/lang/en.d.ts CHANGED
@@ -1498,6 +1498,21 @@ ${string}`;
1498
1498
  readonly app: {
1499
1499
  readonly describe: "Commands for managing apps.";
1500
1500
  readonly subcommands: {
1501
+ readonly install: {
1502
+ readonly describe: "Install an app.";
1503
+ readonly options: {
1504
+ readonly appUid: "The uid of the app to install";
1505
+ readonly projectName: "The name of the project to install the app to";
1506
+ readonly testAccountId: "The id of the test account to install the app into";
1507
+ };
1508
+ readonly polling: {
1509
+ readonly start: "Installing app...";
1510
+ readonly success: "App installed successfully";
1511
+ readonly failure: "App installation failed";
1512
+ readonly error: "Error installing app";
1513
+ };
1514
+ readonly example: "Install the app with uid 1234567890 from the project named \"my-project\" into the target account";
1515
+ };
1501
1516
  readonly secret: {
1502
1517
  readonly describe: "Commands for managing secrets.";
1503
1518
  readonly subcommands: {
@@ -1807,6 +1822,7 @@ ${string}`;
1807
1822
  readonly start: (testAccountName: string) => string;
1808
1823
  readonly syncing: "Test account created! Syncing account data... (may take a few minutes - you can exit and the sync will continue)";
1809
1824
  readonly success: (testAccountName: string, testAccountId: number) => string;
1825
+ readonly failure: "Failed to sync data into test account. The account may not be ready to use.";
1810
1826
  };
1811
1827
  readonly options: {
1812
1828
  readonly configPath: "The path to the test account config";
@@ -2608,6 +2624,9 @@ Run ${string} to upgrade to version ${string}`;
2608
2624
  readonly invalidAuthDistCombo: (authType: string, distribution: string) => string;
2609
2625
  };
2610
2626
  };
2627
+ readonly add: {
2628
+ readonly nothingAdded: "No features added.";
2629
+ };
2611
2630
  readonly validateProjectConfig: {
2612
2631
  readonly configNotFound: `Unable to locate a project configuration file. Try running again from a project directory, or run ${string} to create a new project.`;
2613
2632
  readonly configMissingFields: "The project configuration file is missing required fields.";
@@ -2918,16 +2937,20 @@ Run ${string} to upgrade to version ${string}`;
2918
2937
  readonly languageRequired: "Please select API sample app's language";
2919
2938
  };
2920
2939
  };
2921
- readonly createProjectPrompt: {
2940
+ readonly projectNameAndDestPrompt: {
2922
2941
  readonly enterName: "[--name] Give your project a name: ";
2923
2942
  readonly enterDest: "[--dest] Enter the folder to create the project in:";
2924
- readonly selectTemplate: "[--template] Choose a project template: ";
2925
- readonly features: "[--features] Which features would you like your app to include?";
2926
2943
  readonly errors: {
2927
2944
  readonly nameRequired: "A project name is required";
2928
2945
  readonly destRequired: "A project dest is required";
2929
2946
  readonly invalidDest: "There is an existing project at this destination. Please provide a new path for this project.";
2930
2947
  readonly invalidCharacters: "The selected destination contains invalid characters. Please provide a new path and try again.";
2948
+ };
2949
+ };
2950
+ readonly selectProjectTemplatePrompt: {
2951
+ readonly selectTemplate: "[--template] Choose a project template: ";
2952
+ readonly features: "[--features] Which features would you like your app to include?";
2953
+ readonly errors: {
2931
2954
  readonly invalidTemplate: (template: string) => string;
2932
2955
  readonly projectTemplateRequired: "Project template is required when projectTemplates is provided";
2933
2956
  };
@@ -3032,6 +3055,9 @@ Run ${string} to upgrade to version ${string}`;
3032
3055
  };
3033
3056
  };
3034
3057
  };
3058
+ readonly polling: {
3059
+ readonly timeoutError: (timeoutMs: number) => string;
3060
+ };
3035
3061
  readonly convertFields: {
3036
3062
  readonly positionals: {
3037
3063
  readonly src: {
package/lang/en.js CHANGED
@@ -1496,6 +1496,21 @@ exports.commands = {
1496
1496
  app: {
1497
1497
  describe: 'Commands for managing apps.',
1498
1498
  subcommands: {
1499
+ install: {
1500
+ describe: 'Install an app.',
1501
+ options: {
1502
+ appUid: 'The uid of the app to install',
1503
+ projectName: 'The name of the project to install the app to',
1504
+ testAccountId: 'The id of the test account to install the app into',
1505
+ },
1506
+ polling: {
1507
+ start: 'Installing app...',
1508
+ success: 'App installed successfully',
1509
+ failure: 'App installation failed',
1510
+ error: 'Error installing app',
1511
+ },
1512
+ example: 'Install the app with uid 1234567890 from the project named "my-project" into the target account',
1513
+ },
1499
1514
  secret: {
1500
1515
  describe: 'Commands for managing secrets.',
1501
1516
  subcommands: {
@@ -1805,6 +1820,7 @@ exports.commands = {
1805
1820
  start: (testAccountName) => `Creating test account "${chalk_1.default.bold(testAccountName)}"...`,
1806
1821
  syncing: 'Test account created! Syncing account data... (may take a few minutes - you can exit and the sync will continue)',
1807
1822
  success: (testAccountName, testAccountId) => `Test account "${chalk_1.default.bold(testAccountName)}" successfully created with id: ${chalk_1.default.bold(testAccountId)}`,
1823
+ failure: 'Failed to sync data into test account. The account may not be ready to use.',
1808
1824
  },
1809
1825
  options: {
1810
1826
  configPath: 'The path to the test account config',
@@ -2605,6 +2621,9 @@ exports.lib = {
2605
2621
  invalidAuthDistCombo: (authType, distribution) => `Invalid distribution and auth combination. Apps with distribution '${distribution}' must have auth '${authType}'`,
2606
2622
  },
2607
2623
  },
2624
+ add: {
2625
+ nothingAdded: 'No features added.',
2626
+ },
2608
2627
  validateProjectConfig: {
2609
2628
  configNotFound: `Unable to locate a project configuration file. Try running again from a project directory, or run ${(0, ui_1.uiCommandReference)('hs project create')} to create a new project.`,
2610
2629
  configMissingFields: 'The project configuration file is missing required fields.',
@@ -2913,16 +2932,20 @@ exports.lib = {
2913
2932
  languageRequired: "Please select API sample app's language",
2914
2933
  },
2915
2934
  },
2916
- createProjectPrompt: {
2935
+ projectNameAndDestPrompt: {
2917
2936
  enterName: '[--name] Give your project a name: ',
2918
2937
  enterDest: '[--dest] Enter the folder to create the project in:',
2919
- selectTemplate: '[--template] Choose a project template: ',
2920
- features: '[--features] Which features would you like your app to include?',
2921
2938
  errors: {
2922
2939
  nameRequired: 'A project name is required',
2923
2940
  destRequired: 'A project dest is required',
2924
2941
  invalidDest: 'There is an existing project at this destination. Please provide a new path for this project.',
2925
2942
  invalidCharacters: 'The selected destination contains invalid characters. Please provide a new path and try again.',
2943
+ },
2944
+ },
2945
+ selectProjectTemplatePrompt: {
2946
+ selectTemplate: '[--template] Choose a project template: ',
2947
+ features: '[--features] Which features would you like your app to include?',
2948
+ errors: {
2926
2949
  invalidTemplate: (template) => `[--template] Could not find template "${template}". Please choose an available template:`,
2927
2950
  projectTemplateRequired: 'Project template is required when projectTemplates is provided',
2928
2951
  },
@@ -3027,6 +3050,9 @@ exports.lib = {
3027
3050
  },
3028
3051
  },
3029
3052
  },
3053
+ polling: {
3054
+ timeoutError: (timeoutMs) => `Polling timed out after ${timeoutMs}ms.`,
3055
+ },
3030
3056
  convertFields: {
3031
3057
  positionals: {
3032
3058
  src: {
@@ -18,7 +18,7 @@ const ui_1 = require("../ui");
18
18
  const lang_1 = require("../lang");
19
19
  const accountTypes_1 = require("../accountTypes");
20
20
  const selectPublicAppForMigrationPrompt_1 = require("../prompts/selectPublicAppForMigrationPrompt");
21
- const createProjectPrompt_1 = require("../prompts/createProjectPrompt");
21
+ const projectNameAndDestPrompt_1 = require("../prompts/projectNameAndDestPrompt");
22
22
  const ensureProjectExists_1 = require("../projects/ensureProjectExists");
23
23
  const usageTracking_1 = require("../usageTracking");
24
24
  const SpinniesManager_1 = __importDefault(require("../ui/SpinniesManager"));
@@ -58,8 +58,7 @@ async function migrateApp2023_2(derivedAccountId, options, accountConfig) {
58
58
  (0, errorHandlers_1.logError)(error, new errorHandlers_1.ApiErrorContext({ accountId: derivedAccountId }));
59
59
  return process.exit(exitCodes_1.EXIT_CODES.ERROR);
60
60
  }
61
- const createProjectPromptResponse = await (0, createProjectPrompt_1.createProjectPrompt)(options);
62
- const { name: projectName, dest: projectDest } = createProjectPromptResponse;
61
+ const { name: projectName, dest: projectDest } = await (0, projectNameAndDestPrompt_1.projectNameAndDestPrompt)(options);
63
62
  const { projectExists } = await (0, ensureProjectExists_1.ensureProjectExists)(derivedAccountId, projectName, {
64
63
  allowCreate: false,
65
64
  noLogs: true,
package/lib/polling.d.ts CHANGED
@@ -17,5 +17,5 @@ type PollingCallback<T extends GenericPollingResponse> = () => HubSpotPromise<T>
17
17
  export declare function poll<T extends GenericPollingResponse>(callback: PollingCallback<T>, statusLookup?: {
18
18
  successStates: string[];
19
19
  errorStates: string[];
20
- }): Promise<T>;
20
+ }, timeoutMs?: number): Promise<T>;
21
21
  export {};
package/lib/polling.js CHANGED
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DEFAULT_POLLING_STATUS_LOOKUP = exports.DEFAULT_POLLING_STATES = void 0;
4
4
  exports.poll = poll;
5
5
  const constants_1 = require("./constants");
6
+ const en_1 = require("../lang/en");
6
7
  exports.DEFAULT_POLLING_STATES = {
7
8
  STARTED: 'STARTED',
8
9
  SUCCESS: 'SUCCESS',
@@ -18,7 +19,8 @@ exports.DEFAULT_POLLING_STATUS_LOOKUP = {
18
19
  exports.DEFAULT_POLLING_STATES.FAILURE,
19
20
  ],
20
21
  };
21
- function poll(callback, statusLookup = exports.DEFAULT_POLLING_STATUS_LOOKUP) {
22
+ function poll(callback, statusLookup = exports.DEFAULT_POLLING_STATUS_LOOKUP, timeoutMs = 60000 // Default 60 second timeout
23
+ ) {
22
24
  return new Promise((resolve, reject) => {
23
25
  const pollInterval = setInterval(async () => {
24
26
  try {
@@ -26,17 +28,25 @@ function poll(callback, statusLookup = exports.DEFAULT_POLLING_STATUS_LOOKUP) {
26
28
  const { status } = pollResp;
27
29
  if (statusLookup.successStates.includes(status)) {
28
30
  clearInterval(pollInterval);
31
+ clearTimeout(timeoutId);
29
32
  resolve(pollResp);
30
33
  }
31
34
  else if (statusLookup.errorStates.includes(status)) {
32
35
  clearInterval(pollInterval);
36
+ clearTimeout(timeoutId);
33
37
  reject(pollResp);
34
38
  }
35
39
  }
36
40
  catch (error) {
37
41
  clearInterval(pollInterval);
42
+ clearTimeout(timeoutId);
38
43
  reject(error);
39
44
  }
40
45
  }, constants_1.DEFAULT_POLLING_DELAY);
46
+ // Set a timeout to stop polling after specified duration
47
+ const timeoutId = setTimeout(() => {
48
+ clearInterval(pollInterval);
49
+ reject(new Error(en_1.lib.polling.timeoutError(timeoutMs)));
50
+ }, timeoutMs);
41
51
  });
42
52
  }
@@ -66,6 +66,10 @@ async function v3AddComponent(args, projectDir, projectConfig) {
66
66
  components.push(path_1.default.join(projectConfig.platformVersion, parentComponent.path));
67
67
  }
68
68
  }
69
+ if (components.length === 0) {
70
+ logger_1.uiLogger.log(en_1.lib.projects.add.nothingAdded);
71
+ return;
72
+ }
69
73
  await (0, github_1.cloneGithubRepo)(constants_1.HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH, projectDir, {
70
74
  sourceDir: components,
71
75
  hideLogs: true,
@@ -1,6 +1,6 @@
1
1
  import { ArgumentsCamelCase } from 'yargs';
2
2
  import { ProjectTemplateRepoConfig } from '../../../types/Projects';
3
- import { CreateProjectPromptResponse } from '../../prompts/createProjectPrompt';
3
+ import { SelectProjectTemplatePromptResponse, ProjectNameAndDestPromptResponse } from '../../prompts/selectProjectTemplatePrompt';
4
4
  import { AccountArgs, CommonArgs, ConfigArgs, EnvironmentArgs } from '../../../types/Yargs';
5
5
  import { RepoPath } from '@hubspot/local-dev-lib/types/Github';
6
6
  export type ProjectCreateArgs = CommonArgs & ConfigArgs & AccountArgs & EnvironmentArgs & {
@@ -19,5 +19,6 @@ export declare function handleProjectCreationFlow(args: ArgumentsCamelCase<Proje
19
19
  distribution?: string;
20
20
  repoConfig?: ProjectTemplateRepoConfig;
21
21
  projectContents?: string;
22
- createProjectPromptResponse: CreateProjectPromptResponse;
22
+ selectProjectTemplatePromptResponse: SelectProjectTemplatePromptResponse;
23
+ projectNameAndDestPromptResponse: ProjectNameAndDestPromptResponse;
23
24
  }>;
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.handleProjectCreationFlow = handleProjectCreationFlow;
4
- const createProjectPrompt_1 = require("../../prompts/createProjectPrompt");
4
+ const selectProjectTemplatePrompt_1 = require("../../prompts/selectProjectTemplatePrompt");
5
+ const projectNameAndDestPrompt_1 = require("../../prompts/projectNameAndDestPrompt");
5
6
  const constants_1 = require("../../constants");
6
7
  const buildAndDeploy_1 = require("../buildAndDeploy");
7
8
  const v3_1 = require("./v3");
@@ -12,15 +13,17 @@ const exitCodes_1 = require("../../enums/exitCodes");
12
13
  async function handleProjectCreationFlow(args) {
13
14
  const { platformVersion, templateSource, projectBase, auth: providedAuth, distribution: providedDistribution, } = args;
14
15
  const repo = templateSource || constants_1.HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH;
16
+ const projectNameAndDestPromptResponse = await (0, projectNameAndDestPrompt_1.projectNameAndDestPrompt)(args);
15
17
  if ((0, buildAndDeploy_1.useV3Api)(platformVersion)) {
16
18
  const { componentTemplateChoices, authType, distribution, repoConfig, projectContents, } = await (0, v3_1.v3ComponentFlow)(platformVersion, projectBase, providedAuth, providedDistribution);
17
- const createProjectPromptResponse = await (0, createProjectPrompt_1.createProjectPrompt)(args, undefined, projectContents !== v3_1.EMPTY_PROJECT ? componentTemplateChoices : undefined);
19
+ const selectProjectTemplatePromptResponse = await (0, selectProjectTemplatePrompt_1.selectProjectTemplatePrompt)(args, undefined, projectContents !== v3_1.EMPTY_PROJECT ? componentTemplateChoices : undefined);
18
20
  return {
19
21
  authType,
20
22
  distribution,
21
23
  repoConfig,
22
24
  projectContents,
23
- createProjectPromptResponse,
25
+ selectProjectTemplatePromptResponse,
26
+ projectNameAndDestPromptResponse,
24
27
  };
25
28
  }
26
29
  const projectTemplates = await (0, legacy_1.getProjectTemplateListFromRepo)(repo, 'main');
@@ -28,6 +31,9 @@ async function handleProjectCreationFlow(args) {
28
31
  logger_1.uiLogger.error(en_1.commands.project.create.errors.failedToFetchProjectList);
29
32
  process.exit(exitCodes_1.EXIT_CODES.ERROR);
30
33
  }
31
- const createProjectPromptResponse = await (0, createProjectPrompt_1.createProjectPrompt)(args, projectTemplates);
32
- return { createProjectPromptResponse };
34
+ const selectProjectTemplatePromptResponse = await (0, selectProjectTemplatePrompt_1.selectProjectTemplatePrompt)(args, projectTemplates);
35
+ return {
36
+ selectProjectTemplatePromptResponse,
37
+ projectNameAndDestPromptResponse,
38
+ };
33
39
  }
@@ -1,6 +1,6 @@
1
1
  import { ComponentTemplate, ComponentTemplateChoice, ProjectTemplateRepoConfig } from '../../../types/Projects';
2
2
  import { ProjectMetadata } from '@hubspot/project-parsing-lib/src/lib/project';
3
- import { CreateProjectPromptResponse } from '../../prompts/createProjectPrompt';
3
+ import { SelectProjectTemplatePromptResponse } from '../../prompts/selectProjectTemplatePrompt';
4
4
  export declare const EMPTY_PROJECT = "empty";
5
5
  export declare const PROJECT_WITH_APP = "app";
6
6
  export declare function createV3App(providedAuth: string | undefined, providedDistribution: string | undefined): Promise<{
@@ -16,8 +16,8 @@ type V3ComponentInfo = {
16
16
  componentTemplateChoices?: ComponentTemplateChoice[];
17
17
  };
18
18
  export declare function v3ComponentFlow(platformVersion: string, projectBase: string | undefined, providedAuth: string | undefined, providedDistribution: string | undefined): Promise<V3ComponentInfo>;
19
- export declare function generateComponentPaths({ createProjectPromptResponse, platformVersion, repoConfig, projectContents, authType, distribution, }: {
20
- createProjectPromptResponse: CreateProjectPromptResponse;
19
+ export declare function generateComponentPaths({ selectProjectTemplatePromptResponse, platformVersion, repoConfig, projectContents, authType, distribution, }: {
20
+ selectProjectTemplatePromptResponse: SelectProjectTemplatePromptResponse;
21
21
  platformVersion: string;
22
22
  repoConfig?: ProjectTemplateRepoConfig;
23
23
  projectContents?: string;
@@ -134,11 +134,11 @@ async function v3ComponentFlow(platformVersion, projectBase, providedAuth, provi
134
134
  repoConfig,
135
135
  };
136
136
  }
137
- function generateComponentPaths({ createProjectPromptResponse, platformVersion, repoConfig, projectContents, authType, distribution, }) {
137
+ function generateComponentPaths({ selectProjectTemplatePromptResponse, platformVersion, repoConfig, projectContents, authType, distribution, }) {
138
138
  if (!(0, buildAndDeploy_1.useV3Api)(platformVersion)) {
139
139
  return [];
140
140
  }
141
- const components = createProjectPromptResponse.componentTemplates?.map((componentTemplate) => {
141
+ const components = selectProjectTemplatePromptResponse.componentTemplates?.map((componentTemplate) => {
142
142
  return path_1.default.join(platformVersion, componentTemplate.path);
143
143
  }) || [];
144
144
  if (projectContents && projectContents !== exports.EMPTY_PROJECT) {
@@ -16,15 +16,16 @@ declare class LocalDevProcess {
16
16
  [key: string]: IntermediateRepresentationNodeLocalDev;
17
17
  };
18
18
  get logger(): LocalDevLogger;
19
- get configFilesUpdatedSinceLastUpload(): Set<string>;
20
19
  private setupDevServers;
21
20
  private startDevServers;
22
21
  private cleanupDevServers;
23
22
  private compareLocalProjectToDeployed;
24
23
  private projectConfigValidForUpload;
24
+ private getIntermediateRepresentation;
25
25
  private updateProjectNodes;
26
+ private updateProjectNodesAfterUpload;
26
27
  handleFileChange(filePath: string, event: string): Promise<void>;
27
- handleConfigFileChange(filePath: string, event: string): Promise<void>;
28
+ handleConfigFileChange(): Promise<void>;
28
29
  start(): Promise<void>;
29
30
  stop(showProgress?: boolean): Promise<void>;
30
31
  uploadProject(): Promise<boolean>;
@@ -46,9 +46,6 @@ class LocalDevProcess {
46
46
  get logger() {
47
47
  return this._logger;
48
48
  }
49
- get configFilesUpdatedSinceLastUpload() {
50
- return this.state.configFilesUpdatedSinceLastUpload;
51
- }
52
49
  async setupDevServers() {
53
50
  try {
54
51
  await this.devServerManager.setup();
@@ -105,17 +102,28 @@ class LocalDevProcess {
105
102
  });
106
103
  return true;
107
104
  }
108
- async updateProjectNodes() {
109
- const intermediateRepresentation = await (0, project_parsing_lib_1.translateForLocalDev)({
105
+ getIntermediateRepresentation(projectNodesAtLastUpload) {
106
+ return (0, project_parsing_lib_1.translateForLocalDev)({
110
107
  projectSourceDir: path_1.default.join(this.state.projectDir, this.state.projectConfig.srcDir),
111
108
  platformVersion: this.state.projectConfig.platformVersion,
112
109
  accountId: this.state.targetProjectAccountId,
113
110
  }, {
114
- configFilesUpdatedSinceLastUpload: this.state.configFilesUpdatedSinceLastUpload,
111
+ projectNodesAtLastUpload,
112
+ profile: this.state.profile,
115
113
  });
114
+ }
115
+ async updateProjectNodes() {
116
+ const intermediateRepresentation = await this.getIntermediateRepresentation(this.state.projectNodesAtLastUpload);
116
117
  this.state.projectNodes =
117
118
  intermediateRepresentation.intermediateNodesIndexedByUid;
118
119
  }
120
+ async updateProjectNodesAfterUpload() {
121
+ const intermediateRepresentation = await this.getIntermediateRepresentation();
122
+ this.state.projectNodes =
123
+ intermediateRepresentation.intermediateNodesIndexedByUid;
124
+ this.state.projectNodesAtLastUpload =
125
+ intermediateRepresentation.intermediateNodesIndexedByUid;
126
+ }
119
127
  async handleFileChange(filePath, event) {
120
128
  await this.updateProjectNodes();
121
129
  try {
@@ -125,10 +133,7 @@ class LocalDevProcess {
125
133
  this.logger.fileChangeError(e);
126
134
  }
127
135
  }
128
- async handleConfigFileChange(filePath, event) {
129
- if (event === 'add' || event === 'change') {
130
- this.state.addUpdatedConfigFileUpdatedSinceLastUpload(filePath);
131
- }
136
+ async handleConfigFileChange() {
132
137
  await this.updateProjectNodes();
133
138
  this.logger.uploadWarning();
134
139
  }
@@ -185,8 +190,7 @@ class LocalDevProcess {
185
190
  this.logger.uploadError(uploadError);
186
191
  return false;
187
192
  }
188
- this.state.resetConfigFilesUpdatedSinceLastUpload();
189
- this.updateProjectNodes();
193
+ await this.updateProjectNodesAfterUpload();
190
194
  this.logger.uploadSuccess();
191
195
  this.logger.clearUploadWarnings();
192
196
  return true;
@@ -6,6 +6,7 @@ import { LocalDevStateConstructorOptions, LocalDevStateListener, AppLocalDevData
6
6
  declare class LocalDevState {
7
7
  private _targetProjectAccountId;
8
8
  private _targetTestingAccountId;
9
+ private _profile?;
9
10
  private _projectConfig;
10
11
  private _projectDir;
11
12
  private _projectId;
@@ -14,15 +15,16 @@ declare class LocalDevState {
14
15
  private _deployedBuild?;
15
16
  private _isGithubLinked;
16
17
  private _projectNodes;
18
+ private _projectNodesAtLastUpload;
17
19
  private _env;
18
20
  private _listeners;
19
- private _configFilesUpdatedSinceLastUpload;
20
21
  private _appData;
21
22
  private _devServerMessage;
22
- constructor({ targetProjectAccountId, targetTestingAccountId, projectConfig, projectDir, projectId, projectName, debug, deployedBuild, isGithubLinked, initialProjectNodes, env, }: LocalDevStateConstructorOptions);
23
+ constructor({ targetProjectAccountId, targetTestingAccountId, projectConfig, projectDir, projectId, projectName, debug, deployedBuild, isGithubLinked, initialProjectNodes, profile, env, }: LocalDevStateConstructorOptions);
23
24
  private runListeners;
24
25
  get targetProjectAccountId(): number;
25
26
  get targetTestingAccountId(): number;
27
+ get profile(): string | undefined;
26
28
  get projectConfig(): ProjectConfig;
27
29
  get projectDir(): string;
28
30
  get projectId(): number;
@@ -36,10 +38,13 @@ declare class LocalDevState {
36
38
  set projectNodes(nodes: {
37
39
  [key: string]: IntermediateRepresentationNodeLocalDev;
38
40
  });
41
+ get projectNodesAtLastUpload(): {
42
+ [key: string]: IntermediateRepresentationNodeLocalDev;
43
+ };
44
+ set projectNodesAtLastUpload(nodes: {
45
+ [key: string]: IntermediateRepresentationNodeLocalDev;
46
+ });
39
47
  get env(): Environment;
40
- get configFilesUpdatedSinceLastUpload(): Set<string>;
41
- addUpdatedConfigFileUpdatedSinceLastUpload(filePath: string): void;
42
- resetConfigFilesUpdatedSinceLastUpload(): void;
43
48
  get appData(): Record<string, AppLocalDevData>;
44
49
  getAppDataByUid(uid: string): AppLocalDevData | undefined;
45
50
  setAppDataForUid(uid: string, appData: AppLocalDevData): void;
@@ -4,6 +4,7 @@ const constants_1 = require("../../constants");
4
4
  class LocalDevState {
5
5
  _targetProjectAccountId;
6
6
  _targetTestingAccountId;
7
+ _profile;
7
8
  _projectConfig;
8
9
  _projectDir;
9
10
  _projectId;
@@ -12,14 +13,15 @@ class LocalDevState {
12
13
  _deployedBuild;
13
14
  _isGithubLinked;
14
15
  _projectNodes;
16
+ _projectNodesAtLastUpload;
15
17
  _env;
16
18
  _listeners;
17
- _configFilesUpdatedSinceLastUpload;
18
19
  _appData;
19
20
  _devServerMessage;
20
- constructor({ targetProjectAccountId, targetTestingAccountId, projectConfig, projectDir, projectId, projectName, debug, deployedBuild, isGithubLinked, initialProjectNodes, env, }) {
21
+ constructor({ targetProjectAccountId, targetTestingAccountId, projectConfig, projectDir, projectId, projectName, debug, deployedBuild, isGithubLinked, initialProjectNodes, profile, env, }) {
21
22
  this._targetProjectAccountId = targetProjectAccountId;
22
23
  this._targetTestingAccountId = targetTestingAccountId;
24
+ this._profile = profile;
23
25
  this._projectConfig = projectConfig;
24
26
  this._projectDir = projectDir;
25
27
  this._projectId = projectId;
@@ -28,8 +30,8 @@ class LocalDevState {
28
30
  this._deployedBuild = deployedBuild;
29
31
  this._isGithubLinked = isGithubLinked;
30
32
  this._projectNodes = initialProjectNodes;
33
+ this._projectNodesAtLastUpload = initialProjectNodes;
31
34
  this._env = env;
32
- this._configFilesUpdatedSinceLastUpload = new Set();
33
35
  this._appData = {};
34
36
  this._devServerMessage = constants_1.LOCAL_DEV_SERVER_MESSAGE_TYPES.INITIAL;
35
37
  this._listeners = {};
@@ -45,10 +47,11 @@ class LocalDevState {
45
47
  get targetTestingAccountId() {
46
48
  return this._targetTestingAccountId;
47
49
  }
50
+ get profile() {
51
+ return this._profile;
52
+ }
48
53
  get projectConfig() {
49
- return {
50
- ...this._projectConfig,
51
- };
54
+ return structuredClone(this._projectConfig);
52
55
  }
53
56
  get projectDir() {
54
57
  return this._projectDir;
@@ -63,34 +66,29 @@ class LocalDevState {
63
66
  return this._debug;
64
67
  }
65
68
  get deployedBuild() {
66
- return (this._deployedBuild && {
67
- ...this._deployedBuild,
68
- });
69
+ return this._deployedBuild && structuredClone(this._deployedBuild);
69
70
  }
70
71
  get isGithubLinked() {
71
72
  return this._isGithubLinked;
72
73
  }
73
74
  get projectNodes() {
74
- return { ...this._projectNodes };
75
+ return structuredClone(this._projectNodes);
75
76
  }
76
77
  set projectNodes(nodes) {
77
78
  this._projectNodes = nodes;
78
79
  this.runListeners('projectNodes');
79
80
  }
80
- get env() {
81
- return this._env;
82
- }
83
- get configFilesUpdatedSinceLastUpload() {
84
- return this._configFilesUpdatedSinceLastUpload;
81
+ get projectNodesAtLastUpload() {
82
+ return structuredClone(this._projectNodesAtLastUpload);
85
83
  }
86
- addUpdatedConfigFileUpdatedSinceLastUpload(filePath) {
87
- this._configFilesUpdatedSinceLastUpload.add(filePath);
84
+ set projectNodesAtLastUpload(nodes) {
85
+ this._projectNodesAtLastUpload = nodes;
88
86
  }
89
- resetConfigFilesUpdatedSinceLastUpload() {
90
- this._configFilesUpdatedSinceLastUpload.clear();
87
+ get env() {
88
+ return this._env;
91
89
  }
92
90
  get appData() {
93
- return { ...this._appData };
91
+ return structuredClone(this._appData);
94
92
  }
95
93
  getAppDataByUid(uid) {
96
94
  return { ...this._appData[uid] };
@@ -21,7 +21,7 @@ class LocalDevWatcher {
21
21
  }
22
22
  handleWatchEvent(filePath, event, configPaths) {
23
23
  if (configPaths.includes(filePath)) {
24
- return this.localDevProcess.handleConfigFileChange(filePath, event);
24
+ return this.localDevProcess.handleConfigFileChange();
25
25
  }
26
26
  return this.localDevProcess.handleFileChange(filePath, event);
27
27
  }
@@ -0,0 +1,3 @@
1
+ import { PromptOptionsArg, ProjectNameAndDestPromptResponse } from './selectProjectTemplatePrompt';
2
+ export declare function projectNameAndDestPrompt(promptOptions: PromptOptionsArg): Promise<ProjectNameAndDestPromptResponse>;
3
+ export declare function validateProjectDirectory(input?: string): string | boolean;
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.projectNameAndDestPrompt = projectNameAndDestPrompt;
7
+ exports.validateProjectDirectory = validateProjectDirectory;
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const path_1 = __importDefault(require("path"));
10
+ const path_2 = require("@hubspot/local-dev-lib/path");
11
+ const en_1 = require("../../lang/en");
12
+ const promptUtils_1 = require("./promptUtils");
13
+ const constants_1 = require("../constants");
14
+ async function projectNameAndDestPrompt(promptOptions) {
15
+ const result = await (0, promptUtils_1.promptUser)([
16
+ {
17
+ name: 'name',
18
+ message: en_1.lib.prompts.projectNameAndDestPrompt.enterName,
19
+ when: !promptOptions.name,
20
+ validate: (input) => {
21
+ if (!input) {
22
+ return en_1.lib.prompts.projectNameAndDestPrompt.errors.nameRequired;
23
+ }
24
+ return true;
25
+ },
26
+ },
27
+ {
28
+ name: 'dest',
29
+ message: en_1.lib.prompts.projectNameAndDestPrompt.enterDest,
30
+ when: !promptOptions.dest,
31
+ default: answers => {
32
+ const projectName = (0, path_2.sanitizeFileName)(promptOptions.name || answers.name);
33
+ return path_1.default.resolve((0, path_2.getCwd)(), projectName);
34
+ },
35
+ validate: validateProjectDirectory,
36
+ filter: input => {
37
+ return (0, path_2.untildify)(input);
38
+ },
39
+ },
40
+ ]);
41
+ if (!result.name) {
42
+ result.name = promptOptions.name;
43
+ }
44
+ if (!result.dest) {
45
+ result.dest = promptOptions.dest;
46
+ }
47
+ return result;
48
+ }
49
+ function validateProjectDirectory(input) {
50
+ if (!input) {
51
+ return en_1.lib.prompts.projectNameAndDestPrompt.errors.destRequired;
52
+ }
53
+ if (fs_1.default.existsSync(path_1.default.resolve((0, path_2.getCwd)(), path_1.default.join(input, constants_1.PROJECT_CONFIG_FILE)))) {
54
+ return en_1.lib.prompts.projectNameAndDestPrompt.errors.invalidDest;
55
+ }
56
+ if (!(0, path_2.isValidPath)(input)) {
57
+ return en_1.lib.prompts.projectNameAndDestPrompt.errors.invalidCharacters;
58
+ }
59
+ return true;
60
+ }
@@ -0,0 +1,26 @@
1
+ import { ComponentTemplate, ComponentTemplateChoice, ProjectTemplate } from '../../types/Projects';
2
+ export type SelectProjectTemplatePromptResponse = {
3
+ projectTemplate?: ProjectTemplate;
4
+ componentTemplates?: ComponentTemplate[];
5
+ };
6
+ type SelectProjectTemplatePromptResponseProjectTemplate = {
7
+ projectTemplate: ProjectTemplate;
8
+ componentTemplates: undefined;
9
+ };
10
+ type SelectProjectTemplatePromptResponseComponentTemplates = {
11
+ projectTemplate?: undefined;
12
+ componentTemplates?: ComponentTemplate[];
13
+ };
14
+ export type ProjectNameAndDestPromptResponse = {
15
+ name: string;
16
+ dest: string;
17
+ };
18
+ export type PromptOptionsArg = {
19
+ name?: string;
20
+ dest?: string;
21
+ template?: string;
22
+ features?: string[];
23
+ };
24
+ export declare function selectProjectTemplatePrompt(promptOptions: PromptOptionsArg, projectTemplates?: ProjectTemplate[], componentTemplates?: undefined): Promise<SelectProjectTemplatePromptResponseProjectTemplate>;
25
+ export declare function selectProjectTemplatePrompt(promptOptions: PromptOptionsArg, projectTemplates?: undefined, componentTemplates?: ComponentTemplateChoice[]): Promise<SelectProjectTemplatePromptResponseComponentTemplates>;
26
+ export {};
@@ -1,31 +1,12 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.createProjectPrompt = createProjectPrompt;
7
- const fs_1 = __importDefault(require("fs"));
8
- const path_1 = __importDefault(require("path"));
9
- const path_2 = require("@hubspot/local-dev-lib/path");
3
+ exports.selectProjectTemplatePrompt = selectProjectTemplatePrompt;
10
4
  const promptUtils_1 = require("./promptUtils");
11
- const constants_1 = require("../constants");
12
5
  const en_1 = require("../../lang/en");
13
- function validateProjectDirectory(input) {
14
- if (!input) {
15
- return en_1.lib.prompts.createProjectPrompt.errors.destRequired;
16
- }
17
- if (fs_1.default.existsSync(path_1.default.resolve((0, path_2.getCwd)(), path_1.default.join(input, constants_1.PROJECT_CONFIG_FILE)))) {
18
- return en_1.lib.prompts.createProjectPrompt.errors.invalidDest;
19
- }
20
- if (!(0, path_2.isValidPath)(input)) {
21
- return en_1.lib.prompts.createProjectPrompt.errors.invalidCharacters;
22
- }
23
- return true;
24
- }
25
6
  function findTemplateByNameOrLabel(projectTemplates, templateNameOrLabel) {
26
7
  return projectTemplates.find(t => t.name === templateNameOrLabel || t.label === templateNameOrLabel);
27
8
  }
28
- async function createProjectPrompt(promptOptions, projectTemplates, componentTemplates) {
9
+ async function selectProjectTemplatePrompt(promptOptions, projectTemplates, componentTemplates) {
29
10
  const createProjectFromTemplate = !!projectTemplates && projectTemplates.length > 0;
30
11
  const createProjectFromComponents = Array.isArray(componentTemplates) && componentTemplates?.length > 0;
31
12
  const selectedComponents = [];
@@ -46,36 +27,12 @@ async function createProjectPrompt(promptOptions, projectTemplates, componentTem
46
27
  !!promptOptions.template &&
47
28
  !!findTemplateByNameOrLabel(projectTemplates, promptOptions.template);
48
29
  const result = await (0, promptUtils_1.promptUser)([
49
- {
50
- name: 'name',
51
- message: en_1.lib.prompts.createProjectPrompt.enterName,
52
- when: !promptOptions.name,
53
- validate: (input) => {
54
- if (!input) {
55
- return en_1.lib.prompts.createProjectPrompt.errors.nameRequired;
56
- }
57
- return true;
58
- },
59
- },
60
- {
61
- name: 'dest',
62
- message: en_1.lib.prompts.createProjectPrompt.enterDest,
63
- when: !promptOptions.dest,
64
- default: answers => {
65
- const projectName = (0, path_2.sanitizeFileName)(promptOptions.name || answers.name);
66
- return path_1.default.resolve((0, path_2.getCwd)(), projectName);
67
- },
68
- validate: validateProjectDirectory,
69
- filter: input => {
70
- return (0, path_2.untildify)(input);
71
- },
72
- },
73
30
  {
74
31
  name: 'projectTemplate',
75
32
  message: () => {
76
33
  return promptOptions.template && !providedTemplateIsValid
77
- ? en_1.lib.prompts.createProjectPrompt.errors.invalidTemplate(promptOptions.template)
78
- : en_1.lib.prompts.createProjectPrompt.selectTemplate;
34
+ ? en_1.lib.prompts.selectProjectTemplatePrompt.errors.invalidTemplate(promptOptions.template)
35
+ : en_1.lib.prompts.selectProjectTemplatePrompt.selectTemplate;
79
36
  },
80
37
  when: createProjectFromTemplate && !providedTemplateIsValid,
81
38
  type: 'list',
@@ -90,7 +47,7 @@ async function createProjectPrompt(promptOptions, projectTemplates, componentTem
90
47
  },
91
48
  {
92
49
  name: 'componentTemplates',
93
- message: en_1.lib.prompts.createProjectPrompt.features,
50
+ message: en_1.lib.prompts.selectProjectTemplatePrompt.features,
94
51
  when: !promptOptions.features &&
95
52
  createProjectFromComponents &&
96
53
  selectedComponents.length === 0,
@@ -98,12 +55,6 @@ async function createProjectPrompt(promptOptions, projectTemplates, componentTem
98
55
  choices: componentTemplates,
99
56
  },
100
57
  ]);
101
- if (!result.name) {
102
- result.name = promptOptions.name;
103
- }
104
- if (!result.dest) {
105
- result.dest = promptOptions.dest;
106
- }
107
58
  if (!result.componentTemplates) {
108
59
  result.componentTemplates = selectedComponents;
109
60
  }
@@ -112,7 +63,7 @@ async function createProjectPrompt(promptOptions, projectTemplates, componentTem
112
63
  }
113
64
  if (projectTemplates && projectTemplates.length > 0) {
114
65
  if (!result.projectTemplate) {
115
- throw new Error(en_1.lib.prompts.createProjectPrompt.errors.projectTemplateRequired);
66
+ throw new Error(en_1.lib.prompts.selectProjectTemplatePrompt.errors.projectTemplateRequired);
116
67
  }
117
68
  return result;
118
69
  }
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@hubspot/cli",
3
- "version": "7.7.16-experimental.3",
3
+ "version": "7.7.16-experimental.4",
4
4
  "description": "The official CLI for developing on HubSpot",
5
5
  "license": "Apache-2.0",
6
6
  "repository": "https://github.com/HubSpot/hubspot-cli",
7
7
  "dependencies": {
8
8
  "@hubspot/local-dev-lib": "3.11.0",
9
- "@hubspot/project-parsing-lib": "0.3.2",
9
+ "@hubspot/project-parsing-lib": "0.5.0",
10
10
  "@hubspot/serverless-dev-runtime": "7.0.6",
11
11
  "@hubspot/theme-preview-dev-server": "0.0.10",
12
12
  "@hubspot/ui-extensions-dev-server": "0.9.2",
@@ -8,6 +8,7 @@ import { APP_INSTALLATION_STATES, LOCAL_DEV_SERVER_MESSAGE_TYPES } from '../lib/
8
8
  export type LocalDevStateConstructorOptions = {
9
9
  targetProjectAccountId: number;
10
10
  targetTestingAccountId: number;
11
+ profile?: string;
11
12
  projectConfig: ProjectConfig;
12
13
  projectDir: string;
13
14
  projectId: number;
@@ -1,28 +0,0 @@
1
- import { ComponentTemplate, ComponentTemplateChoice, ProjectTemplate } from '../../types/Projects';
2
- export type CreateProjectPromptResponse = {
3
- name: string;
4
- dest: string;
5
- projectTemplate?: ProjectTemplate;
6
- componentTemplates?: ComponentTemplate[];
7
- };
8
- type CreateProjectPromptResponseProjectTemplate = {
9
- name: string;
10
- dest: string;
11
- projectTemplate: ProjectTemplate;
12
- componentTemplates: undefined;
13
- };
14
- type CreateProjectPromptResponseComponentTemplates = {
15
- name: string;
16
- dest: string;
17
- projectTemplate?: undefined;
18
- componentTemplates?: ComponentTemplate[];
19
- };
20
- type PromptOptionsArg = {
21
- name?: string;
22
- dest?: string;
23
- template?: string;
24
- features?: string[];
25
- };
26
- export declare function createProjectPrompt(promptOptions: PromptOptionsArg, projectTemplates?: ProjectTemplate[], componentTemplates?: undefined): Promise<CreateProjectPromptResponseProjectTemplate>;
27
- export declare function createProjectPrompt(promptOptions: PromptOptionsArg, projectTemplates?: undefined, componentTemplates?: ComponentTemplateChoice[]): Promise<CreateProjectPromptResponseComponentTemplates>;
28
- export {};