@hubspot/cli 8.0.12-experimental.1 → 8.1.0-experimental.0
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.
- package/bin/cli.js +3 -3
- package/commands/project/dev/unifiedFlow.js +19 -10
- package/commands/project/upload.d.ts +0 -2
- package/commands/project/upload.js +3 -47
- package/lang/en.d.ts +1 -19
- package/lang/en.js +1 -19
- package/lib/constants.d.ts +0 -1
- package/lib/constants.js +0 -1
- package/lib/projects/upload.d.ts +0 -1
- package/lib/projects/upload.js +4 -5
- package/lib/projects/workspaces.d.ts +11 -1
- package/lib/projects/workspaces.js +27 -12
- package/lib/prompts/projectDevTargetAccountPrompt.d.ts +1 -0
- package/lib/prompts/projectDevTargetAccountPrompt.js +10 -0
- package/lib/usageTracking.js +1 -1
- package/package.json +2 -2
- package/lib/projects/preview.d.ts +0 -7
- package/lib/projects/preview.js +0 -58
package/bin/cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import yargs from 'yargs';
|
|
3
|
-
import { logError } from '../lib/errorHandlers/index.js';
|
|
3
|
+
import { logError, debugError } from '../lib/errorHandlers/index.js';
|
|
4
4
|
import { setCLILogLevel, getCommandName } from '../lib/commonOpts.js';
|
|
5
5
|
import { trackHelpUsage, trackConvertFieldsUsage, } from '../lib/usageTracking.js';
|
|
6
6
|
import { EXIT_CODES } from '../lib/enums/exitCodes.js';
|
|
@@ -132,11 +132,11 @@ const argvWithSuggestions = await parseYargsOrExit(parser, handleFailure);
|
|
|
132
132
|
if ('help' in argvWithSuggestions && argvWithSuggestions.help !== undefined) {
|
|
133
133
|
(async () => {
|
|
134
134
|
await trackHelpUsage(getCommandName(argvWithSuggestions));
|
|
135
|
-
})();
|
|
135
|
+
})().catch(debugError);
|
|
136
136
|
}
|
|
137
137
|
if ('convertFields' in argvWithSuggestions &&
|
|
138
138
|
argvWithSuggestions.convertFields !== undefined) {
|
|
139
139
|
(async () => {
|
|
140
140
|
await trackConvertFieldsUsage(getCommandName(argvWithSuggestions));
|
|
141
|
-
})();
|
|
141
|
+
})().catch(debugError);
|
|
142
142
|
}
|
|
@@ -3,13 +3,13 @@ import util from 'util';
|
|
|
3
3
|
import { HUBSPOT_ACCOUNT_TYPES } from '@hubspot/local-dev-lib/constants/config';
|
|
4
4
|
import { startPortManagerServer, stopPortManagerServer, } from '@hubspot/local-dev-lib/portManager';
|
|
5
5
|
import { isTranslationError, translateForLocalDev, } from '@hubspot/project-parsing-lib/translate';
|
|
6
|
-
import { getConfigAccountEnvironment, getLinkedOrAllConfigAccounts, getConfigAccountById, } from '@hubspot/local-dev-lib/config';
|
|
6
|
+
import { getConfigAccountEnvironment, getLinkedOrAllConfigAccounts, getConfigAccountById, getConfigAccountIfExists, } from '@hubspot/local-dev-lib/config';
|
|
7
7
|
import { logError } from '../../../lib/errorHandlers/index.js';
|
|
8
8
|
import { EXIT_CODES } from '../../../lib/enums/exitCodes.js';
|
|
9
9
|
import { ensureProjectExists } from '../../../lib/projects/ensureProjectExists.js';
|
|
10
10
|
import { createInitialBuildForNewProject, createNewProjectForLocalDev, compareLocalProjectToDeployed, checkAndInstallDependencies, } from '../../../lib/projects/localDev/helpers/project.js';
|
|
11
11
|
import { useExistingDevTestAccount, createDeveloperTestAccountForLocalDev, selectAccountTypePrompt, createSandboxForLocalDev, } from '../../../lib/projects/localDev/helpers/account.js';
|
|
12
|
-
import { selectDeveloperTestTargetAccountPrompt, selectSandboxTargetAccountPrompt, } from '../../../lib/prompts/projectDevTargetAccountPrompt.js';
|
|
12
|
+
import { selectDeveloperTestTargetAccountPrompt, selectSandboxTargetAccountPrompt, confirmLinkExistingDeveloperTestAccountPrompt, } from '../../../lib/prompts/projectDevTargetAccountPrompt.js';
|
|
13
13
|
import LocalDevProcess from '../../../lib/projects/localDev/LocalDevProcess.js';
|
|
14
14
|
import LocalDevWatcher from '../../../lib/projects/localDev/LocalDevWatcher.js';
|
|
15
15
|
import { handleExit, handleKeypress } from '../../../lib/process.js';
|
|
@@ -89,17 +89,26 @@ export async function unifiedProjectDevFlow({ args, targetProjectAccountId, prov
|
|
|
89
89
|
const accountType = await selectAccountTypePrompt(targetProjectAccountConfig);
|
|
90
90
|
if (accountType === HUBSPOT_ACCOUNT_TYPES.DEVELOPER_TEST) {
|
|
91
91
|
const devAccountPromptResponse = await selectDeveloperTestTargetAccountPrompt(accounts, targetProjectAccountConfig);
|
|
92
|
+
const { notInConfigAccount } = devAccountPromptResponse;
|
|
92
93
|
targetTestingAccountId =
|
|
93
94
|
devAccountPromptResponse.targetAccountId || undefined;
|
|
94
|
-
if (
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
95
|
+
if (notInConfigAccount) {
|
|
96
|
+
const existingGlobalConfig = getConfigAccountIfExists(notInConfigAccount.id);
|
|
97
|
+
if (directoryIsLinked && existingGlobalConfig) {
|
|
98
|
+
const shouldLink = await confirmLinkExistingDeveloperTestAccountPrompt(notInConfigAccount.accountName);
|
|
99
|
+
if (!shouldLink) {
|
|
100
|
+
return exit(EXIT_CODES.SUCCESS);
|
|
101
|
+
}
|
|
102
|
+
addAccountToLinkedSettings(notInConfigAccount.id);
|
|
100
103
|
}
|
|
101
|
-
|
|
102
|
-
|
|
104
|
+
else {
|
|
105
|
+
const accountAdded = await useExistingDevTestAccount(env, notInConfigAccount);
|
|
106
|
+
if (!accountAdded) {
|
|
107
|
+
return exit(EXIT_CODES.SUCCESS);
|
|
108
|
+
}
|
|
109
|
+
if (directoryIsLinked) {
|
|
110
|
+
addAccountToLinkedSettings(notInConfigAccount.id);
|
|
111
|
+
}
|
|
103
112
|
}
|
|
104
113
|
}
|
|
105
114
|
else if (devAccountPromptResponse.createNestedAccount) {
|
|
@@ -5,8 +5,6 @@ export type ProjectUploadArgs = CommonArgs & JSONOutputArgs & {
|
|
|
5
5
|
m: string;
|
|
6
6
|
skipValidation: boolean;
|
|
7
7
|
profile?: string;
|
|
8
|
-
preview: boolean;
|
|
9
|
-
target?: number;
|
|
10
8
|
};
|
|
11
9
|
declare const projectUploadCommand: YargsCommandModule<unknown, ProjectUploadArgs>;
|
|
12
10
|
export default projectUploadCommand;
|
|
@@ -8,8 +8,7 @@ import { logFeedbackMessage } from '../../lib/projects/ui.js';
|
|
|
8
8
|
import { handleProjectUpload } from '../../lib/projects/upload.js';
|
|
9
9
|
import { loadAndValidateProfile } from '../../lib/projects/projectProfiles.js';
|
|
10
10
|
import { displayWarnLogs, pollProjectBuildAndDeploy, } from '../../lib/projects/pollProjectBuildAndDeploy.js';
|
|
11
|
-
import {
|
|
12
|
-
import { commands, lib } from '../../lang/en.js';
|
|
11
|
+
import { commands } from '../../lang/en.js';
|
|
13
12
|
import { PROJECT_ERROR_TYPES } from '../../lib/constants.js';
|
|
14
13
|
import { logError, ApiErrorContext } from '../../lib/errorHandlers/index.js';
|
|
15
14
|
import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
|
|
@@ -18,22 +17,8 @@ import { makeYargsBuilder } from '../../lib/yargsUtils.js';
|
|
|
18
17
|
import { projectProfilePrompt } from '../../lib/prompts/projectProfilePrompt.js';
|
|
19
18
|
const command = 'upload';
|
|
20
19
|
const describe = commands.project.upload.describe;
|
|
21
|
-
async function handlePreview(accountId, projectId, buildId, targetPortalId) {
|
|
22
|
-
if (!projectId) {
|
|
23
|
-
uiLogger.warn(lib.projectPreview.missingProjectId);
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
const previewResult = await triggerAndPollPreview(accountId, projectId, buildId, targetPortalId);
|
|
27
|
-
if (!previewResult.succeeded) {
|
|
28
|
-
uiLogger.warn(lib.projectPreview.warning);
|
|
29
|
-
}
|
|
30
|
-
return {
|
|
31
|
-
releaseTag: previewResult.releaseTag,
|
|
32
|
-
succeeded: previewResult.succeeded,
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
20
|
async function handler(args) {
|
|
36
|
-
const { forceCreate, message, derivedAccountId, skipValidation, formatOutputAsJson, profile: profileOption, useEnv: useEnvOption,
|
|
21
|
+
const { forceCreate, message, derivedAccountId, skipValidation, formatOutputAsJson, profile: profileOption, useEnv: useEnvOption, exit, addUsageMetadata, } = args;
|
|
37
22
|
const jsonOutput = {};
|
|
38
23
|
const { projectConfig, projectDir } = await getProjectConfig();
|
|
39
24
|
try {
|
|
@@ -71,7 +56,7 @@ async function handler(args) {
|
|
|
71
56
|
assetType: projectConfig.platformVersion,
|
|
72
57
|
});
|
|
73
58
|
try {
|
|
74
|
-
const { result, uploadError
|
|
59
|
+
const { result, uploadError } = await handleProjectUpload({
|
|
75
60
|
accountId: targetAccountId,
|
|
76
61
|
projectConfig,
|
|
77
62
|
projectDir,
|
|
@@ -105,12 +90,6 @@ async function handler(args) {
|
|
|
105
90
|
logFeedbackMessage(result.buildId);
|
|
106
91
|
await displayWarnLogs(targetAccountId, projectConfig.name, result.buildId);
|
|
107
92
|
}
|
|
108
|
-
if (result && result.succeeded && preview && targetPortalId) {
|
|
109
|
-
const previewJson = await handlePreview(targetAccountId, projectId, result.buildId, targetPortalId);
|
|
110
|
-
if (previewJson && formatOutputAsJson) {
|
|
111
|
-
jsonOutput.preview = previewJson;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
93
|
if (result && result.succeeded && formatOutputAsJson) {
|
|
115
94
|
jsonOutput.buildId = result.buildId;
|
|
116
95
|
if (result.deployResult) {
|
|
@@ -153,25 +132,6 @@ function projectUploadBuilder(yargs) {
|
|
|
153
132
|
alias: 'p',
|
|
154
133
|
describe: commands.project.upload.options.profile.describe,
|
|
155
134
|
},
|
|
156
|
-
preview: {
|
|
157
|
-
describe: commands.project.upload.options.preview.describe,
|
|
158
|
-
type: 'boolean',
|
|
159
|
-
default: false,
|
|
160
|
-
},
|
|
161
|
-
target: {
|
|
162
|
-
describe: commands.project.upload.options.target.describe,
|
|
163
|
-
type: 'number',
|
|
164
|
-
requiresArg: true,
|
|
165
|
-
},
|
|
166
|
-
});
|
|
167
|
-
yargs.check(argv => {
|
|
168
|
-
if (argv.preview && argv.target == null) {
|
|
169
|
-
throw new Error(commands.project.upload.errors.previewRequiresTarget);
|
|
170
|
-
}
|
|
171
|
-
if (argv.target != null && !argv.preview) {
|
|
172
|
-
throw new Error(commands.project.upload.errors.targetRequiresPreview);
|
|
173
|
-
}
|
|
174
|
-
return true;
|
|
175
135
|
});
|
|
176
136
|
yargs.conflicts('profile', 'account');
|
|
177
137
|
yargs.example([
|
|
@@ -180,10 +140,6 @@ function projectUploadBuilder(yargs) {
|
|
|
180
140
|
'$0 project upload --profile=profileName',
|
|
181
141
|
commands.project.upload.examples.withProfile,
|
|
182
142
|
],
|
|
183
|
-
[
|
|
184
|
-
'$0 project upload --preview --target=12345',
|
|
185
|
-
commands.project.upload.examples.withPreview,
|
|
186
|
-
],
|
|
187
143
|
]);
|
|
188
144
|
return yargs;
|
|
189
145
|
}
|
package/lang/en.d.ts
CHANGED
|
@@ -1805,7 +1805,6 @@ export declare const commands: {
|
|
|
1805
1805
|
examples: {
|
|
1806
1806
|
default: string;
|
|
1807
1807
|
withProfile: string;
|
|
1808
|
-
withPreview: string;
|
|
1809
1808
|
};
|
|
1810
1809
|
logs: {
|
|
1811
1810
|
buildSucceeded: (buildId: number) => string;
|
|
@@ -1816,8 +1815,6 @@ export declare const commands: {
|
|
|
1816
1815
|
errors: {
|
|
1817
1816
|
noProjectConfig: string;
|
|
1818
1817
|
projectLockedError: string;
|
|
1819
|
-
previewRequiresTarget: string;
|
|
1820
|
-
targetRequiresPreview: string;
|
|
1821
1818
|
};
|
|
1822
1819
|
options: {
|
|
1823
1820
|
forceCreate: {
|
|
@@ -1829,12 +1826,6 @@ export declare const commands: {
|
|
|
1829
1826
|
profile: {
|
|
1830
1827
|
describe: string;
|
|
1831
1828
|
};
|
|
1832
|
-
preview: {
|
|
1833
|
-
describe: string;
|
|
1834
|
-
};
|
|
1835
|
-
target: {
|
|
1836
|
-
describe: string;
|
|
1837
|
-
};
|
|
1838
1829
|
};
|
|
1839
1830
|
};
|
|
1840
1831
|
watch: {
|
|
@@ -3402,16 +3393,6 @@ export declare const lib: {
|
|
|
3402
3393
|
updatedFileDependency: (packageName: string, relativePath: string) => string;
|
|
3403
3394
|
};
|
|
3404
3395
|
};
|
|
3405
|
-
projectPreview: {
|
|
3406
|
-
triggeringPreview: (buildId: number, targetPortalId: number) => string;
|
|
3407
|
-
pollingStatus: (releaseTag: string, targetPortalId: number) => string;
|
|
3408
|
-
succeeded: (releaseTag: string, targetPortalId: number) => string;
|
|
3409
|
-
triggerFailed: string;
|
|
3410
|
-
pollFailed: string;
|
|
3411
|
-
timeout: string;
|
|
3412
|
-
warning: string;
|
|
3413
|
-
missingProjectId: string;
|
|
3414
|
-
};
|
|
3415
3396
|
importData: {
|
|
3416
3397
|
errors: {
|
|
3417
3398
|
incorrectAccountType: (derivedAccountId: number) => string;
|
|
@@ -3642,6 +3623,7 @@ export declare const lib: {
|
|
|
3642
3623
|
developerTestAccountLimit: (limit: number) => string;
|
|
3643
3624
|
confirmDefaultAccount: (accountName: string, accountType: string) => string;
|
|
3644
3625
|
confirmUseExistingDeveloperTestAccount: (accountName: string) => string;
|
|
3626
|
+
confirmLinkExistingDeveloperTestAccount: (accountName: string) => string;
|
|
3645
3627
|
noAccountId: string;
|
|
3646
3628
|
};
|
|
3647
3629
|
projectLogsPrompt: {
|
package/lang/en.js
CHANGED
|
@@ -1822,7 +1822,6 @@ export const commands = {
|
|
|
1822
1822
|
examples: {
|
|
1823
1823
|
default: 'Upload a project into your HubSpot account',
|
|
1824
1824
|
withProfile: 'Upload a project into your HubSpot account when using profiles',
|
|
1825
|
-
withPreview: 'Upload and preview the build on a target portal',
|
|
1826
1825
|
},
|
|
1827
1826
|
logs: {
|
|
1828
1827
|
buildSucceeded: (buildId) => `Build #${buildId} succeeded\n`,
|
|
@@ -1833,8 +1832,6 @@ export const commands = {
|
|
|
1833
1832
|
errors: {
|
|
1834
1833
|
noProjectConfig: 'No project detected. Run this command from a project directory.',
|
|
1835
1834
|
projectLockedError: `Your project is locked. This may mean that another user is running the ${uiCommandReference('hs project dev')} command for this project. If this is you, unlock the project in Projects UI.`,
|
|
1836
|
-
previewRequiresTarget: `${uiCommandReference('--preview')} requires ${uiCommandReference('--target=<portalId>')} to specify the portal to preview on.`,
|
|
1837
|
-
targetRequiresPreview: `${uiCommandReference('--target')} can only be used with ${uiCommandReference('--preview')}.`,
|
|
1838
1835
|
},
|
|
1839
1836
|
options: {
|
|
1840
1837
|
forceCreate: {
|
|
@@ -1846,12 +1843,6 @@ export const commands = {
|
|
|
1846
1843
|
profile: {
|
|
1847
1844
|
describe: 'Profile to target for this upload',
|
|
1848
1845
|
},
|
|
1849
|
-
preview: {
|
|
1850
|
-
describe: 'Preview the build on a target portal after a successful upload',
|
|
1851
|
-
},
|
|
1852
|
-
target: {
|
|
1853
|
-
describe: 'Portal ID to preview the build on',
|
|
1854
|
-
},
|
|
1855
1846
|
},
|
|
1856
1847
|
},
|
|
1857
1848
|
watch: {
|
|
@@ -3428,16 +3419,6 @@ export const lib = {
|
|
|
3428
3419
|
updatedFileDependency: (packageName, relativePath) => ` Updated dependencies.${packageName}: file:${relativePath}`,
|
|
3429
3420
|
},
|
|
3430
3421
|
},
|
|
3431
|
-
projectPreview: {
|
|
3432
|
-
triggeringPreview: (buildId, targetPortalId) => `Previewing build #${buildId} on portal ${targetPortalId}`,
|
|
3433
|
-
pollingStatus: (releaseTag, targetPortalId) => `Previewing ${releaseTag} on portal ${targetPortalId}`,
|
|
3434
|
-
succeeded: (releaseTag, targetPortalId) => `Previewed ${releaseTag} on portal ${targetPortalId}`,
|
|
3435
|
-
triggerFailed: 'Failed to trigger preview',
|
|
3436
|
-
pollFailed: 'Failed to poll preview status',
|
|
3437
|
-
timeout: 'Preview timed out after 5 minutes',
|
|
3438
|
-
warning: 'The build succeeded but the preview failed. You can manually preview this build from the project UI.',
|
|
3439
|
-
missingProjectId: 'Unable to preview: could not resolve the project ID.',
|
|
3440
|
-
},
|
|
3441
3422
|
importData: {
|
|
3442
3423
|
errors: {
|
|
3443
3424
|
incorrectAccountType: (derivedAccountId) => `The account ${uiAccountDescription(derivedAccountId)} is not a standard account, developer test account, or app developer account.`,
|
|
@@ -3668,6 +3649,7 @@ export const lib = {
|
|
|
3668
3649
|
developerTestAccountLimit: (limit) => `Your account reached the limit of ${limit} developer test accounts.`,
|
|
3669
3650
|
confirmDefaultAccount: (accountName, accountType) => `Continue testing on ${chalk.bold(`${accountName} (${accountType})`)}? (Y/n)`,
|
|
3670
3651
|
confirmUseExistingDeveloperTestAccount: (accountName) => `Continue with ${accountName}? This account isn't currently connected to the HubSpot CLI. By continuing, you'll be prompted to generate a personal access key and connect it.`,
|
|
3652
|
+
confirmLinkExistingDeveloperTestAccount: (accountName) => `${accountName} is not linked to this directory. Would you like to link it?`,
|
|
3671
3653
|
noAccountId: 'No account ID found for the selected account. Please try again.',
|
|
3672
3654
|
},
|
|
3673
3655
|
projectLogsPrompt: {
|
package/lib/constants.d.ts
CHANGED
|
@@ -4,7 +4,6 @@ export declare const FEEDBACK_INTERVAL: 10;
|
|
|
4
4
|
export declare const HUBSPOT_FOLDER: "@hubspot";
|
|
5
5
|
export declare const MARKETPLACE_FOLDER: "@marketplace";
|
|
6
6
|
export declare const DEFAULT_POLLING_DELAY = 2000;
|
|
7
|
-
export declare const PREVIEW_POLL_TIMEOUT: number;
|
|
8
7
|
export declare const PROJECT_CONFIG_FILE: "hsproject.json";
|
|
9
8
|
export declare const PROJECT_BUILD_STATES: {
|
|
10
9
|
readonly BUILDING: "BUILDING";
|
package/lib/constants.js
CHANGED
|
@@ -4,7 +4,6 @@ export const FEEDBACK_INTERVAL = 10;
|
|
|
4
4
|
export const HUBSPOT_FOLDER = '@hubspot';
|
|
5
5
|
export const MARKETPLACE_FOLDER = '@marketplace';
|
|
6
6
|
export const DEFAULT_POLLING_DELAY = 2000;
|
|
7
|
-
export const PREVIEW_POLL_TIMEOUT = 5 * 60 * 1000;
|
|
8
7
|
export const PROJECT_CONFIG_FILE = 'hsproject.json';
|
|
9
8
|
export const PROJECT_BUILD_STATES = {
|
|
10
9
|
BUILDING: 'BUILDING',
|
package/lib/projects/upload.d.ts
CHANGED
package/lib/projects/upload.js
CHANGED
|
@@ -79,7 +79,7 @@ export async function handleProjectUpload({ accountId, projectConfig, projectDir
|
|
|
79
79
|
return resolve({ uploadError: e });
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
|
-
const { projectExists
|
|
82
|
+
const { projectExists } = await ensureProjectExists(accountId, projectConfig.name, {
|
|
83
83
|
forceCreate,
|
|
84
84
|
uploadCommand: isUploadCommand,
|
|
85
85
|
noLogs: true,
|
|
@@ -88,14 +88,13 @@ export async function handleProjectUpload({ accountId, projectConfig, projectDir
|
|
|
88
88
|
uiLogger.log(lib.projectUpload.handleProjectUpload.projectDoesNotExist(accountId));
|
|
89
89
|
return resolve({ projectNotFound: true });
|
|
90
90
|
}
|
|
91
|
-
const projectId = project?.id;
|
|
92
91
|
const { buildId, error } = await uploadProjectFiles(accountId, projectConfig.name, tempFile.name, uploadMessage, projectConfig.platformVersion, intermediateRepresentation);
|
|
93
92
|
if (error) {
|
|
94
|
-
resolve({ uploadError: error
|
|
93
|
+
resolve({ uploadError: error });
|
|
95
94
|
}
|
|
96
95
|
else if (callbackFunc) {
|
|
97
96
|
const uploadResult = await callbackFunc(accountId, projectConfig, tempFile, buildId);
|
|
98
|
-
resolve({ result: uploadResult
|
|
97
|
+
resolve({ result: uploadResult });
|
|
99
98
|
}
|
|
100
99
|
}
|
|
101
100
|
catch (e) {
|
|
@@ -124,7 +123,7 @@ export async function handleProjectUpload({ accountId, projectConfig, projectDir
|
|
|
124
123
|
return ignored ? false : file;
|
|
125
124
|
});
|
|
126
125
|
// Archive workspaces and file: dependencies
|
|
127
|
-
await archiveWorkspacesAndDependencies(archive, srcDir,
|
|
126
|
+
await archiveWorkspacesAndDependencies(archive, srcDir, workspaceMappings, fileDependencyMappings);
|
|
128
127
|
archive.finalize();
|
|
129
128
|
return result;
|
|
130
129
|
}
|
|
@@ -12,6 +12,16 @@ export type WorkspaceArchiveResult = {
|
|
|
12
12
|
* Uses SHA256 truncated to 8 hex characters (4 billion possibilities).
|
|
13
13
|
*/
|
|
14
14
|
export declare function shortHash(input: string): string;
|
|
15
|
+
/**
|
|
16
|
+
* Converts native path separators to POSIX forward slashes.
|
|
17
|
+
*
|
|
18
|
+
* Zip entry names and npm workspace globs are POSIX-only. On Windows,
|
|
19
|
+
* `path.relative` returns backslash-separated paths; archiver normalizes
|
|
20
|
+
* its appended entry names to forward slashes but its filter callback
|
|
21
|
+
* receives forward-slashed names too. Without this normalization, lookups
|
|
22
|
+
* in our exclusion Sets miss on Windows and a file gets archived twice.
|
|
23
|
+
*/
|
|
24
|
+
export declare function toPosixPath(p: string): string;
|
|
15
25
|
/**
|
|
16
26
|
* Determines the archive path for an external workspace or file: dependency.
|
|
17
27
|
* Produces `_workspaces/<basename>-<hash>` with no subdirectory.
|
|
@@ -39,4 +49,4 @@ export declare function getLockfilePathsToUpdate(srcDir: string, workspaceMappin
|
|
|
39
49
|
* Main orchestration function that handles archiving of workspaces and file dependencies.
|
|
40
50
|
* This is the clean integration point for upload.ts.
|
|
41
51
|
*/
|
|
42
|
-
export declare function archiveWorkspacesAndDependencies(archive: archiver.Archiver, srcDir: string,
|
|
52
|
+
export declare function archiveWorkspacesAndDependencies(archive: archiver.Archiver, srcDir: string, workspaceMappings: WorkspaceMapping[], fileDependencyMappings: FileDependencyMapping[]): Promise<WorkspaceArchiveResult>;
|
|
@@ -12,6 +12,21 @@ import { lib } from '../../lang/en.js';
|
|
|
12
12
|
export function shortHash(input) {
|
|
13
13
|
return crypto.createHash('sha256').update(input).digest('hex').slice(0, 8);
|
|
14
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* Converts native path separators to POSIX forward slashes.
|
|
17
|
+
*
|
|
18
|
+
* Zip entry names and npm workspace globs are POSIX-only. On Windows,
|
|
19
|
+
* `path.relative` returns backslash-separated paths; archiver normalizes
|
|
20
|
+
* its appended entry names to forward slashes but its filter callback
|
|
21
|
+
* receives forward-slashed names too. Without this normalization, lookups
|
|
22
|
+
* in our exclusion Sets miss on Windows and a file gets archived twice.
|
|
23
|
+
*/
|
|
24
|
+
export function toPosixPath(p) {
|
|
25
|
+
if (path.sep === path.posix.sep) {
|
|
26
|
+
return p;
|
|
27
|
+
}
|
|
28
|
+
return p.replaceAll(path.sep, path.posix.sep);
|
|
29
|
+
}
|
|
15
30
|
/**
|
|
16
31
|
* Determines the archive path for an external workspace or file: dependency.
|
|
17
32
|
* Produces `_workspaces/<basename>-<hash>` with no subdirectory.
|
|
@@ -20,7 +35,7 @@ export function shortHash(input) {
|
|
|
20
35
|
export function computeExternalArchivePath(absolutePath) {
|
|
21
36
|
const resolved = path.resolve(absolutePath);
|
|
22
37
|
const name = path.basename(resolved);
|
|
23
|
-
return path.join('_workspaces', `${name}-${shortHash(resolved)}`);
|
|
38
|
+
return path.posix.join('_workspaces', `${name}-${shortHash(resolved)}`);
|
|
24
39
|
}
|
|
25
40
|
/**
|
|
26
41
|
* Returns true if dir is inside srcDir (i.e. it will already be included
|
|
@@ -71,7 +86,7 @@ async function archiveWorkspaceDirectories(archive, srcDir, workspaceMappings) {
|
|
|
71
86
|
if (isInsideSrcDir(workspaceDir, srcDir)) {
|
|
72
87
|
// Internal: already in archive from srcDir walk.
|
|
73
88
|
// Store the relative path from the package.json directory so npm can resolve it.
|
|
74
|
-
const relPath = path.relative(path.dirname(sourcePackageJsonPath), path.resolve(workspaceDir));
|
|
89
|
+
const relPath = toPosixPath(path.relative(path.dirname(sourcePackageJsonPath), path.resolve(workspaceDir)));
|
|
75
90
|
packageWorkspaceEntries.get(sourcePackageJsonPath).push(relPath);
|
|
76
91
|
}
|
|
77
92
|
else {
|
|
@@ -89,7 +104,7 @@ async function archiveWorkspaceDirectories(archive, srcDir, workspaceMappings) {
|
|
|
89
104
|
externalsToArchive.push({ dir: workspaceDir, archivePath });
|
|
90
105
|
}
|
|
91
106
|
const relPkgJsonDir = path.relative(srcDir, path.dirname(sourcePackageJsonPath));
|
|
92
|
-
const relativeEntry = path.relative(relPkgJsonDir, archivePath);
|
|
107
|
+
const relativeEntry = toPosixPath(path.relative(relPkgJsonDir, archivePath));
|
|
93
108
|
packageWorkspaceEntries.get(sourcePackageJsonPath).push(relativeEntry);
|
|
94
109
|
}
|
|
95
110
|
}
|
|
@@ -130,7 +145,7 @@ async function archiveFileDependencies(archive, srcDir, fileDependencyMappings,
|
|
|
130
145
|
packageFileDeps.set(sourcePackageJsonPath, new Map());
|
|
131
146
|
}
|
|
132
147
|
const relPkgJsonDir = path.relative(srcDir, path.dirname(sourcePackageJsonPath));
|
|
133
|
-
const relativeArchivePath = path.relative(relPkgJsonDir, archivePath);
|
|
148
|
+
const relativeArchivePath = toPosixPath(path.relative(relPkgJsonDir, archivePath));
|
|
134
149
|
packageFileDeps
|
|
135
150
|
.get(sourcePackageJsonPath)
|
|
136
151
|
.set(packageName, relativeArchivePath);
|
|
@@ -172,7 +187,7 @@ export async function updatePackageJsonInArchive(archive, srcDir, packageWorkspa
|
|
|
172
187
|
if (!fs.existsSync(packageJsonPath)) {
|
|
173
188
|
continue;
|
|
174
189
|
}
|
|
175
|
-
const relativePackageJsonPath = path.relative(srcDir, packageJsonPath);
|
|
190
|
+
const relativePackageJsonPath = toPosixPath(path.relative(srcDir, packageJsonPath));
|
|
176
191
|
let rawContent;
|
|
177
192
|
try {
|
|
178
193
|
rawContent = fs.readFileSync(packageJsonPath, 'utf8');
|
|
@@ -261,11 +276,11 @@ export function rewriteLockfileForExternalDeps(lockfileContent, pathMappings) {
|
|
|
261
276
|
export function getPackageJsonPathsToUpdate(srcDir, workspaceMappings, fileDependencyMappings) {
|
|
262
277
|
const paths = new Set();
|
|
263
278
|
for (const { sourcePackageJsonPath } of workspaceMappings) {
|
|
264
|
-
paths.add(path.relative(srcDir, sourcePackageJsonPath));
|
|
279
|
+
paths.add(toPosixPath(path.relative(srcDir, sourcePackageJsonPath)));
|
|
265
280
|
}
|
|
266
281
|
for (const { localPath, sourcePackageJsonPath } of fileDependencyMappings) {
|
|
267
282
|
if (!isInsideSrcDir(localPath, srcDir)) {
|
|
268
|
-
paths.add(path.relative(srcDir, sourcePackageJsonPath));
|
|
283
|
+
paths.add(toPosixPath(path.relative(srcDir, sourcePackageJsonPath)));
|
|
269
284
|
}
|
|
270
285
|
}
|
|
271
286
|
return paths;
|
|
@@ -290,7 +305,7 @@ export function getLockfilePathsToUpdate(srcDir, workspaceMappings, fileDependen
|
|
|
290
305
|
for (const dir of dirsWithExternalDeps) {
|
|
291
306
|
const lockfilePath = path.join(dir, 'package-lock.json');
|
|
292
307
|
if (fs.existsSync(lockfilePath)) {
|
|
293
|
-
paths.add(path.relative(srcDir, lockfilePath));
|
|
308
|
+
paths.add(toPosixPath(path.relative(srcDir, lockfilePath)));
|
|
294
309
|
}
|
|
295
310
|
}
|
|
296
311
|
return paths;
|
|
@@ -319,12 +334,12 @@ async function rewriteLockfilesInArchive(archive, srcDir, externalArchivePaths,
|
|
|
319
334
|
const pathMappings = [];
|
|
320
335
|
for (const [absoluteExternalPath, archivePath] of externalArchivePaths) {
|
|
321
336
|
pathMappings.push({
|
|
322
|
-
oldPath: path.relative(dir, absoluteExternalPath),
|
|
323
|
-
newPath: path.relative(dir, path.join(srcDir, archivePath)),
|
|
337
|
+
oldPath: toPosixPath(path.relative(dir, absoluteExternalPath)),
|
|
338
|
+
newPath: toPosixPath(path.relative(dir, path.join(srcDir, archivePath))),
|
|
324
339
|
});
|
|
325
340
|
}
|
|
326
341
|
const rewritten = rewriteLockfileForExternalDeps(lockfileContent, pathMappings);
|
|
327
|
-
const relativeLockfilePath = path.relative(srcDir, lockfilePath);
|
|
342
|
+
const relativeLockfilePath = toPosixPath(path.relative(srcDir, lockfilePath));
|
|
328
343
|
uiLogger.debug(lib.projectUpload.handleProjectUpload.updatingLockfile(relativeLockfilePath));
|
|
329
344
|
archive.append(JSON.stringify(rewritten, null, 2), {
|
|
330
345
|
name: relativeLockfilePath,
|
|
@@ -336,7 +351,7 @@ async function rewriteLockfilesInArchive(archive, srcDir, externalArchivePaths,
|
|
|
336
351
|
* Main orchestration function that handles archiving of workspaces and file dependencies.
|
|
337
352
|
* This is the clean integration point for upload.ts.
|
|
338
353
|
*/
|
|
339
|
-
export async function archiveWorkspacesAndDependencies(archive, srcDir,
|
|
354
|
+
export async function archiveWorkspacesAndDependencies(archive, srcDir, workspaceMappings, fileDependencyMappings) {
|
|
340
355
|
// Archive workspace directories (internal ones are skipped, externals are copied)
|
|
341
356
|
const { externalArchivePaths, packageWorkspaceEntries } = await archiveWorkspaceDirectories(archive, srcDir, workspaceMappings);
|
|
342
357
|
// Archive external file: dependencies (internals are skipped)
|
|
@@ -10,3 +10,4 @@ export declare function selectSandboxTargetAccountPrompt(accounts: HubSpotConfig
|
|
|
10
10
|
export declare function selectDeveloperTestTargetAccountPrompt(accounts: HubSpotConfigAccount[], defaultAccountConfig: HubSpotConfigAccount): Promise<ProjectDevTargetAccountPromptResponse>;
|
|
11
11
|
export declare function confirmDefaultAccountPrompt(accountName: string, accountType: string): Promise<boolean>;
|
|
12
12
|
export declare function confirmUseExistingDeveloperTestAccountPrompt(account: DeveloperTestAccount): Promise<boolean>;
|
|
13
|
+
export declare function confirmLinkExistingDeveloperTestAccountPrompt(accountName: string): Promise<boolean>;
|
|
@@ -164,3 +164,13 @@ export async function confirmUseExistingDeveloperTestAccountPrompt(account) {
|
|
|
164
164
|
]);
|
|
165
165
|
return confirmUseExistingDeveloperTestAccount;
|
|
166
166
|
}
|
|
167
|
+
export async function confirmLinkExistingDeveloperTestAccountPrompt(accountName) {
|
|
168
|
+
const { confirmLinkExistingDeveloperTestAccount } = await promptUser([
|
|
169
|
+
{
|
|
170
|
+
name: 'confirmLinkExistingDeveloperTestAccount',
|
|
171
|
+
type: 'confirm',
|
|
172
|
+
message: lib.prompts.projectDevTargetAccountPrompt.confirmLinkExistingDeveloperTestAccount(accountName),
|
|
173
|
+
},
|
|
174
|
+
]);
|
|
175
|
+
return confirmLinkExistingDeveloperTestAccount;
|
|
176
|
+
}
|
package/lib/usageTracking.js
CHANGED
|
@@ -162,7 +162,7 @@ async function trackCliInteraction({ action, accountId, command, authType, meta
|
|
|
162
162
|
}
|
|
163
163
|
try {
|
|
164
164
|
uiLogger.debug('Sent usage tracking command event:', usageTrackingEvent);
|
|
165
|
-
|
|
165
|
+
await trackUsage('cli-interaction', EventClass.INTERACTION, usageTrackingEvent, accountId);
|
|
166
166
|
}
|
|
167
167
|
catch (error) {
|
|
168
168
|
debugError(error);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hubspot/cli",
|
|
3
|
-
"version": "8.0
|
|
3
|
+
"version": "8.1.0-experimental.0",
|
|
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",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"!**/__tests__/**"
|
|
11
11
|
],
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@hubspot/local-dev-lib": "
|
|
13
|
+
"@hubspot/local-dev-lib": "5.6.0",
|
|
14
14
|
"@hubspot/project-parsing-lib": "0.16.0",
|
|
15
15
|
"@hubspot/serverless-dev-runtime": "7.0.7",
|
|
16
16
|
"@hubspot/ui-extensions-dev-server": "2.0.5",
|
package/lib/projects/preview.js
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { triggerAutoRelease, getAutoReleaseStatus, } from '@hubspot/local-dev-lib/api/projects';
|
|
2
|
-
import { DEFAULT_POLLING_DELAY, PREVIEW_POLL_TIMEOUT } from '../constants.js';
|
|
3
|
-
import SpinniesManager from '../ui/SpinniesManager.js';
|
|
4
|
-
import { logError, ApiErrorContext } from '../errorHandlers/index.js';
|
|
5
|
-
import { lib } from '../../lang/en.js';
|
|
6
|
-
export async function triggerAndPollPreview(accountId, projectId, buildId, targetPortalId) {
|
|
7
|
-
let triggerResponse;
|
|
8
|
-
SpinniesManager.add('preview', {
|
|
9
|
-
text: lib.projectPreview.triggeringPreview(buildId, targetPortalId),
|
|
10
|
-
succeedColor: 'white',
|
|
11
|
-
});
|
|
12
|
-
try {
|
|
13
|
-
const { data } = await triggerAutoRelease(accountId, projectId, buildId, targetPortalId);
|
|
14
|
-
triggerResponse = data;
|
|
15
|
-
}
|
|
16
|
-
catch (e) {
|
|
17
|
-
SpinniesManager.fail('preview', {
|
|
18
|
-
text: lib.projectPreview.triggerFailed,
|
|
19
|
-
});
|
|
20
|
-
logError(e, new ApiErrorContext({
|
|
21
|
-
accountId,
|
|
22
|
-
request: 'preview trigger',
|
|
23
|
-
}));
|
|
24
|
-
return { succeeded: false };
|
|
25
|
-
}
|
|
26
|
-
const { releaseTag, appId } = triggerResponse;
|
|
27
|
-
SpinniesManager.update('preview', {
|
|
28
|
-
text: lib.projectPreview.pollingStatus(releaseTag, targetPortalId),
|
|
29
|
-
});
|
|
30
|
-
try {
|
|
31
|
-
await pollPreviewStatus(accountId, projectId, targetPortalId, releaseTag, appId);
|
|
32
|
-
}
|
|
33
|
-
catch (e) {
|
|
34
|
-
SpinniesManager.fail('preview', {
|
|
35
|
-
text: lib.projectPreview.pollFailed,
|
|
36
|
-
});
|
|
37
|
-
logError(e, new ApiErrorContext({
|
|
38
|
-
accountId,
|
|
39
|
-
request: 'preview status',
|
|
40
|
-
}));
|
|
41
|
-
return { succeeded: false, releaseTag, appId };
|
|
42
|
-
}
|
|
43
|
-
SpinniesManager.succeed('preview', {
|
|
44
|
-
text: lib.projectPreview.succeeded(releaseTag, targetPortalId),
|
|
45
|
-
});
|
|
46
|
-
return { succeeded: true, releaseTag, appId };
|
|
47
|
-
}
|
|
48
|
-
async function pollPreviewStatus(accountId, projectId, targetPortalId, expectedReleaseTag, appId) {
|
|
49
|
-
const startTime = Date.now();
|
|
50
|
-
while (Date.now() - startTime < PREVIEW_POLL_TIMEOUT) {
|
|
51
|
-
await new Promise(resolve => setTimeout(resolve, DEFAULT_POLLING_DELAY));
|
|
52
|
-
const { data } = await getAutoReleaseStatus(accountId, projectId, targetPortalId, expectedReleaseTag, appId);
|
|
53
|
-
if (data.status === 'COMPLETE') {
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
throw new Error(lib.projectPreview.timeout);
|
|
58
|
-
}
|