@hubspot/cli 5.3.1 → 5.4.1-beta.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 +24 -5
- package/commands/__tests__/projects.test.js +105 -0
- package/commands/accounts/clean.js +1 -1
- package/commands/cms/convertFields.js +13 -7
- package/commands/project/__tests__/deploy.test.js +1 -1
- package/commands/project/__tests__/installDeps.test.js +168 -0
- package/commands/project/__tests__/logs.test.js +305 -0
- package/commands/project/add.js +24 -12
- package/commands/project/cloneApp.js +13 -21
- package/commands/project/deploy.js +4 -1
- package/commands/project/dev.js +22 -11
- package/commands/project/download.js +6 -3
- package/commands/project/installDeps.js +78 -0
- package/commands/project/logs.js +80 -242
- package/commands/project/migrateApp.js +8 -9
- package/commands/project/upload.js +5 -3
- package/commands/project/watch.js +3 -9
- package/commands/project.js +2 -0
- package/commands/sandbox/create.js +1 -0
- package/commands/sandbox.js +0 -2
- package/lang/en.lyaml +40 -75
- package/lib/LocalDevManager.js +1 -22
- package/lib/__tests__/dependencyManagement.test.js +245 -0
- package/lib/__tests__/projectLogsManager.test.js +210 -0
- package/lib/dependencyManagement.js +157 -0
- package/lib/errorHandlers/apiErrors.js +1 -3
- package/lib/errorHandlers/overrideErrors.js +57 -36
- package/lib/localDev.js +25 -16
- package/lib/projectLogsManager.js +144 -0
- package/lib/projects.js +17 -7
- package/lib/projectsWatch.js +2 -5
- package/lib/prompts/__tests__/projectsLogsPrompt.test.js +46 -0
- package/lib/prompts/createProjectPrompt.js +4 -0
- package/lib/prompts/projectAddPrompt.js +4 -21
- package/lib/prompts/projectDevTargetAccountPrompt.js +16 -25
- package/lib/prompts/projectsLogsPrompt.js +17 -108
- package/lib/sandboxSync.js +13 -15
- package/package.json +6 -6
- package/commands/sandbox/sync.js +0 -225
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
jest.mock('../projects');
|
|
2
|
+
jest.mock('@hubspot/local-dev-lib/api/projects');
|
|
3
|
+
|
|
4
|
+
const ProjectLogsManager = require('../projectLogsManager');
|
|
5
|
+
const { getProjectConfig, ensureProjectExists } = require('../projects');
|
|
6
|
+
const {
|
|
7
|
+
fetchProjectComponentsMetadata,
|
|
8
|
+
} = require('@hubspot/local-dev-lib/api/projects');
|
|
9
|
+
|
|
10
|
+
describe('cli/lib/projectLogsManager', () => {
|
|
11
|
+
const accountId = 12345678;
|
|
12
|
+
const appId = 999999;
|
|
13
|
+
const projectName = 'super cool test project';
|
|
14
|
+
const projectConfig = { projectConfig: { name: projectName } };
|
|
15
|
+
const projectId = 987654321;
|
|
16
|
+
const projectDetails = {
|
|
17
|
+
project: {
|
|
18
|
+
id: projectId,
|
|
19
|
+
deployedBuild: {
|
|
20
|
+
subbuildStatuses: {},
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const function1 = {
|
|
26
|
+
componentName: 'function1',
|
|
27
|
+
type: {
|
|
28
|
+
name: 'APP_FUNCTION',
|
|
29
|
+
},
|
|
30
|
+
deployOutput: {
|
|
31
|
+
appId,
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
const functions = [
|
|
35
|
+
function1,
|
|
36
|
+
{
|
|
37
|
+
componentName: 'function2',
|
|
38
|
+
type: {
|
|
39
|
+
name: 'APP_FUNCTION',
|
|
40
|
+
},
|
|
41
|
+
deployOutput: {
|
|
42
|
+
appId,
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
beforeEach(() => {
|
|
48
|
+
ProjectLogsManager.reset();
|
|
49
|
+
|
|
50
|
+
getProjectConfig.mockResolvedValue(projectConfig);
|
|
51
|
+
ensureProjectExists.mockResolvedValue(projectDetails);
|
|
52
|
+
fetchProjectComponentsMetadata.mockResolvedValue({
|
|
53
|
+
topLevelComponentMetadata: [
|
|
54
|
+
{
|
|
55
|
+
type: {
|
|
56
|
+
name: 'PRIVATE_APP',
|
|
57
|
+
},
|
|
58
|
+
deployOutput: {
|
|
59
|
+
appId,
|
|
60
|
+
},
|
|
61
|
+
featureComponents: [
|
|
62
|
+
...functions,
|
|
63
|
+
{
|
|
64
|
+
type: {
|
|
65
|
+
name: 'NOT_AN_APP_FUNCTION',
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe('init', () => {
|
|
75
|
+
it('should load the project config', async () => {
|
|
76
|
+
await ProjectLogsManager.init(accountId);
|
|
77
|
+
expect(getProjectConfig).toHaveBeenCalledTimes(1);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('should throw an error if there is a problem with the config', async () => {
|
|
81
|
+
getProjectConfig.mockResolvedValue({});
|
|
82
|
+
await expect(async () =>
|
|
83
|
+
ProjectLogsManager.init(accountId)
|
|
84
|
+
).rejects.toThrow(
|
|
85
|
+
'No project detected. Run this command again from a project directory.'
|
|
86
|
+
);
|
|
87
|
+
expect(getProjectConfig).toHaveBeenCalledTimes(1);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('should ensure the project exists', async () => {
|
|
91
|
+
await ProjectLogsManager.init(accountId);
|
|
92
|
+
expect(ensureProjectExists).toHaveBeenCalledTimes(1);
|
|
93
|
+
expect(ensureProjectExists).toHaveBeenCalledWith(accountId, projectName, {
|
|
94
|
+
allowCreate: false,
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('should throw an error if there is data missing from the project details', async () => {
|
|
99
|
+
ensureProjectExists.mockResolvedValue({});
|
|
100
|
+
await expect(async () =>
|
|
101
|
+
ProjectLogsManager.init(accountId)
|
|
102
|
+
).rejects.toThrow(/There was an error fetching project details/);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('should set all of the expected fields correctly', async () => {
|
|
106
|
+
await ProjectLogsManager.init(accountId);
|
|
107
|
+
expect(ProjectLogsManager.projectId).toEqual(projectId);
|
|
108
|
+
expect(ProjectLogsManager.projectName).toEqual(projectName);
|
|
109
|
+
expect(ProjectLogsManager.accountId).toEqual(accountId);
|
|
110
|
+
expect(ProjectLogsManager.functions).toEqual(functions);
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
describe('fetchFunctionDetails', () => {
|
|
115
|
+
it('should throw an error if the projectId is null when the method is called', async () => {
|
|
116
|
+
await expect(async () =>
|
|
117
|
+
ProjectLogsManager.fetchFunctionDetails()
|
|
118
|
+
).rejects.toThrow(
|
|
119
|
+
'No project detected. Run this command again from a project directory.'
|
|
120
|
+
);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('should fetch the component metadata', async () => {
|
|
124
|
+
ProjectLogsManager.projectId = projectId;
|
|
125
|
+
ProjectLogsManager.accountId = accountId;
|
|
126
|
+
await ProjectLogsManager.fetchFunctionDetails();
|
|
127
|
+
expect(fetchProjectComponentsMetadata).toHaveBeenCalledTimes(1);
|
|
128
|
+
expect(fetchProjectComponentsMetadata).toHaveBeenCalledWith(
|
|
129
|
+
accountId,
|
|
130
|
+
projectId
|
|
131
|
+
);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it('should set the functions correctly', async () => {
|
|
135
|
+
ProjectLogsManager.projectId = projectId;
|
|
136
|
+
ProjectLogsManager.accountId = accountId;
|
|
137
|
+
await ProjectLogsManager.fetchFunctionDetails();
|
|
138
|
+
expect(ProjectLogsManager.functions).toEqual(functions);
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
describe('getFunctionNames', () => {
|
|
143
|
+
it('should return an empty array if functions is nullable', async () => {
|
|
144
|
+
ProjectLogsManager.functions = undefined;
|
|
145
|
+
expect(ProjectLogsManager.getFunctionNames()).toEqual([]);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it('should return an array of the componentNames', async () => {
|
|
149
|
+
ProjectLogsManager.functions = functions;
|
|
150
|
+
expect(ProjectLogsManager.getFunctionNames()).toEqual([
|
|
151
|
+
'function1',
|
|
152
|
+
'function2',
|
|
153
|
+
]);
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
describe('setFunction', () => {
|
|
158
|
+
it('should throw an error when functions is nullable', async () => {
|
|
159
|
+
ProjectLogsManager.functions = undefined;
|
|
160
|
+
expect(() => ProjectLogsManager.setFunction('foo')).toThrow(
|
|
161
|
+
`There aren't any functions in this project`
|
|
162
|
+
);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it('should throw an error when the provided function is invalid', async () => {
|
|
166
|
+
ProjectLogsManager.functions = functions;
|
|
167
|
+
const badName = 'foo';
|
|
168
|
+
expect(() => ProjectLogsManager.setFunction(badName)).toThrow(
|
|
169
|
+
`No function with name "${badName}"`
|
|
170
|
+
);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
it('should set the data correctly for public functions', async () => {
|
|
174
|
+
const functionToChoose = {
|
|
175
|
+
componentName: 'function1',
|
|
176
|
+
type: {
|
|
177
|
+
name: 'APP_FUNCTION',
|
|
178
|
+
},
|
|
179
|
+
deployOutput: {
|
|
180
|
+
endpoint: { path: 'yooooooo', method: ['GET'] },
|
|
181
|
+
},
|
|
182
|
+
};
|
|
183
|
+
ProjectLogsManager.functions = [functionToChoose];
|
|
184
|
+
ProjectLogsManager.setFunction('function1');
|
|
185
|
+
expect(ProjectLogsManager.functionName).toEqual('function1');
|
|
186
|
+
expect(ProjectLogsManager.endpointName).toEqual('yooooooo');
|
|
187
|
+
expect(ProjectLogsManager.selectedFunction).toEqual(functionToChoose);
|
|
188
|
+
expect(ProjectLogsManager.method).toEqual(['GET']);
|
|
189
|
+
expect(ProjectLogsManager.isPublicFunction).toEqual(true);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it('should set the data correctly for public functions', async () => {
|
|
193
|
+
ProjectLogsManager.functions = functions;
|
|
194
|
+
ProjectLogsManager.setFunction('function1');
|
|
195
|
+
expect(ProjectLogsManager.selectedFunction).toEqual(function1);
|
|
196
|
+
expect(ProjectLogsManager.functionName).toEqual('function1');
|
|
197
|
+
expect(ProjectLogsManager.isPublicFunction).toEqual(false);
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
describe('reset', () => {
|
|
202
|
+
it('should reset all the values', async () => {
|
|
203
|
+
ProjectLogsManager.someRandomField = 'value';
|
|
204
|
+
expect(ProjectLogsManager.someRandomField).toBeDefined();
|
|
205
|
+
|
|
206
|
+
ProjectLogsManager.reset();
|
|
207
|
+
expect(ProjectLogsManager.isPublicFunction).toBeUndefined();
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
});
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
const { logger } = require('@hubspot/local-dev-lib/logger');
|
|
2
|
+
const { getProjectConfig } = require('./projects');
|
|
3
|
+
const { exec: execAsync } = require('child_process');
|
|
4
|
+
const { walk } = require('@hubspot/local-dev-lib/fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const { uiLink } = require('./ui');
|
|
7
|
+
const util = require('util');
|
|
8
|
+
const { i18n } = require('./lang');
|
|
9
|
+
const SpinniesManager = require('./ui/SpinniesManager');
|
|
10
|
+
const fs = require('fs');
|
|
11
|
+
|
|
12
|
+
const DEFAULT_PACKAGE_MANAGER = 'npm';
|
|
13
|
+
|
|
14
|
+
const i18nKey = `commands.project.subcommands.installDeps`;
|
|
15
|
+
|
|
16
|
+
class NoPackageJsonFilesError extends Error {
|
|
17
|
+
constructor(projectName) {
|
|
18
|
+
super(
|
|
19
|
+
i18n(`${i18nKey}.noPackageJsonInProject`, {
|
|
20
|
+
projectName,
|
|
21
|
+
link: uiLink(
|
|
22
|
+
'Learn how to create a project from scratch.',
|
|
23
|
+
'https://developers.hubspot.com/beta-docs/guides/crm/intro/create-a-project'
|
|
24
|
+
),
|
|
25
|
+
})
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async function isGloballyInstalled(command) {
|
|
31
|
+
const exec = util.promisify(execAsync);
|
|
32
|
+
try {
|
|
33
|
+
await exec(`${command} --version`);
|
|
34
|
+
return true;
|
|
35
|
+
} catch (e) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function installPackages({ packages, installLocations }) {
|
|
41
|
+
const installDirs =
|
|
42
|
+
installLocations || (await getProjectPackageJsonLocations());
|
|
43
|
+
await Promise.all(
|
|
44
|
+
installDirs.map(async dir => {
|
|
45
|
+
await installPackagesInDirectory(packages, dir);
|
|
46
|
+
})
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async function installPackagesInDirectory(packages, directory) {
|
|
51
|
+
const spinner = `installingDependencies-${directory}`;
|
|
52
|
+
const relativeDir = path.relative(process.cwd(), directory);
|
|
53
|
+
SpinniesManager.init();
|
|
54
|
+
SpinniesManager.add(spinner, {
|
|
55
|
+
text:
|
|
56
|
+
packages && packages.length
|
|
57
|
+
? i18n(`${i18nKey}.addingDependenciesToLocation`, {
|
|
58
|
+
dependencies: `[${packages.join(', ')}]`,
|
|
59
|
+
directory: relativeDir,
|
|
60
|
+
})
|
|
61
|
+
: i18n(`${i18nKey}.installingDependencies`, {
|
|
62
|
+
directory: relativeDir,
|
|
63
|
+
}),
|
|
64
|
+
});
|
|
65
|
+
let installCommand = `${DEFAULT_PACKAGE_MANAGER} --prefix=${directory} install`;
|
|
66
|
+
|
|
67
|
+
if (packages) {
|
|
68
|
+
installCommand = `${installCommand} ${packages.join(' ')}`;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
logger.debug(`Running ${installCommand}`);
|
|
72
|
+
try {
|
|
73
|
+
const exec = util.promisify(execAsync);
|
|
74
|
+
await exec(installCommand);
|
|
75
|
+
SpinniesManager.succeed(spinner, {
|
|
76
|
+
text: i18n(`${i18nKey}.installationSuccessful`, {
|
|
77
|
+
directory: relativeDir,
|
|
78
|
+
}),
|
|
79
|
+
});
|
|
80
|
+
} catch (e) {
|
|
81
|
+
SpinniesManager.fail(spinner, {
|
|
82
|
+
text: i18n(`${i18nKey}.installingDependenciesFailed`, {
|
|
83
|
+
directory: relativeDir,
|
|
84
|
+
}),
|
|
85
|
+
});
|
|
86
|
+
throw new Error(
|
|
87
|
+
i18n(`${i18nKey}.installingDependenciesFailed`, {
|
|
88
|
+
directory: relativeDir,
|
|
89
|
+
}),
|
|
90
|
+
{
|
|
91
|
+
cause: e,
|
|
92
|
+
}
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async function getProjectPackageJsonLocations() {
|
|
98
|
+
const projectConfig = await getProjectConfig();
|
|
99
|
+
|
|
100
|
+
if (
|
|
101
|
+
!projectConfig ||
|
|
102
|
+
!projectConfig.projectDir ||
|
|
103
|
+
!projectConfig.projectConfig
|
|
104
|
+
) {
|
|
105
|
+
throw new Error(i18n(`${i18nKey}.noProjectConfig`));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const {
|
|
109
|
+
projectDir,
|
|
110
|
+
projectConfig: { srcDir, name },
|
|
111
|
+
} = projectConfig;
|
|
112
|
+
|
|
113
|
+
if (!(await isGloballyInstalled(DEFAULT_PACKAGE_MANAGER))) {
|
|
114
|
+
throw new Error(
|
|
115
|
+
i18n(`${i18nKey}.packageManagerNotInstalled`, {
|
|
116
|
+
packageManager: DEFAULT_PACKAGE_MANAGER,
|
|
117
|
+
link: uiLink(
|
|
118
|
+
DEFAULT_PACKAGE_MANAGER,
|
|
119
|
+
'https://docs.npmjs.com/downloading-and-installing-node-js-and-npm'
|
|
120
|
+
),
|
|
121
|
+
})
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (
|
|
126
|
+
!fs.existsSync(projectConfig.projectDir) ||
|
|
127
|
+
!fs.existsSync(path.join(projectDir, srcDir))
|
|
128
|
+
) {
|
|
129
|
+
throw new NoPackageJsonFilesError(name);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const packageJsonFiles = (await walk(path.join(projectDir, srcDir))).filter(
|
|
133
|
+
file =>
|
|
134
|
+
file.includes('package.json') &&
|
|
135
|
+
!file.includes('node_modules') &&
|
|
136
|
+
!file.includes('.vite')
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
if (packageJsonFiles.length === 0) {
|
|
140
|
+
throw new NoPackageJsonFilesError(name);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const packageParentDirs = [];
|
|
144
|
+
packageJsonFiles.forEach(packageJsonFile => {
|
|
145
|
+
const parentDir = path.dirname(packageJsonFile);
|
|
146
|
+
packageParentDirs.push(parentDir);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
return packageParentDirs;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
module.exports = {
|
|
153
|
+
isGloballyInstalled,
|
|
154
|
+
installPackages,
|
|
155
|
+
DEFAULT_PACKAGE_MANAGER,
|
|
156
|
+
getProjectPackageJsonLocations,
|
|
157
|
+
};
|
|
@@ -28,8 +28,6 @@ class ApiErrorContext extends ErrorContext {
|
|
|
28
28
|
this.request = props.request || '';
|
|
29
29
|
/** @type {string} */
|
|
30
30
|
this.payload = props.payload || '';
|
|
31
|
-
/** @type {string} */
|
|
32
|
-
this.projectName = props.projectName || '';
|
|
33
31
|
}
|
|
34
32
|
}
|
|
35
33
|
|
|
@@ -54,7 +52,7 @@ function logValidationErrors(error, context) {
|
|
|
54
52
|
*/
|
|
55
53
|
function logApiErrorInstance(error, context) {
|
|
56
54
|
if (error.isAxiosError) {
|
|
57
|
-
if (overrideErrors(error)) return;
|
|
55
|
+
if (overrideErrors(error, context)) return;
|
|
58
56
|
const errorWithContext = getAxiosErrorWithContext(error, context);
|
|
59
57
|
logger.error(errorWithContext.message);
|
|
60
58
|
return;
|
|
@@ -1,38 +1,43 @@
|
|
|
1
|
-
const {
|
|
1
|
+
const {
|
|
2
|
+
isSpecifiedError,
|
|
3
|
+
isMissingScopeError,
|
|
4
|
+
} = require('@hubspot/local-dev-lib/errors/apiErrors');
|
|
2
5
|
const { logger } = require('@hubspot/local-dev-lib/logger');
|
|
3
|
-
|
|
4
6
|
const { PLATFORM_VERSION_ERROR_TYPES } = require('../constants');
|
|
5
7
|
const { i18n } = require('../lang');
|
|
6
|
-
const {
|
|
8
|
+
const {
|
|
9
|
+
uiAccountDescription,
|
|
10
|
+
uiLine,
|
|
11
|
+
uiLink,
|
|
12
|
+
uiCommandReference,
|
|
13
|
+
} = require('../ui');
|
|
7
14
|
|
|
8
15
|
const i18nKey = 'lib.errorHandlers.overrideErrors';
|
|
9
16
|
|
|
10
|
-
function createPlatformVersionError(
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const platformVersionKey = {
|
|
17
|
-
[PLATFORM_VERSION_ERROR_TYPES.PLATFORM_VERSION_NOT_SPECIFIED]:
|
|
18
|
-
'unspecified platformVersion',
|
|
19
|
-
[PLATFORM_VERSION_ERROR_TYPES.PLATFORM_VERSION_RETIRED]:
|
|
20
|
-
errData.context.RETIRED_PLATFORM_VERSION,
|
|
21
|
-
[PLATFORM_VERSION_ERROR_TYPES.PLATFORM_VERSION_SPECIFIED_DOES_NOT_EXIST]:
|
|
22
|
-
errData.context.PLATFORM_VERSION,
|
|
23
|
-
};
|
|
17
|
+
function createPlatformVersionError(err, subCategory) {
|
|
18
|
+
let translationKey = 'unspecifiedPlatformVersion';
|
|
19
|
+
let platformVersion = 'unspecified platformVersion';
|
|
20
|
+
const errorContext =
|
|
21
|
+
err.response && err.response.data && err.response.data.context;
|
|
24
22
|
|
|
25
|
-
|
|
26
|
-
[PLATFORM_VERSION_ERROR_TYPES.
|
|
27
|
-
'
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
23
|
+
switch (subCategory) {
|
|
24
|
+
case [PLATFORM_VERSION_ERROR_TYPES.PLATFORM_VERSION_RETIRED]:
|
|
25
|
+
translationKey = 'platformVersionRetired';
|
|
26
|
+
if (errorContext && errorContext[subCategory]) {
|
|
27
|
+
platformVersion = errorContext[subCategory];
|
|
28
|
+
}
|
|
29
|
+
break;
|
|
30
|
+
case [
|
|
31
|
+
PLATFORM_VERSION_ERROR_TYPES.PLATFORM_VERSION_SPECIFIED_DOES_NOT_EXIST,
|
|
32
|
+
]:
|
|
33
|
+
translationKey = 'nonExistentPlatformVersion';
|
|
34
|
+
if (errorContext && errorContext[subCategory]) {
|
|
35
|
+
platformVersion = errorContext[subCategory];
|
|
36
|
+
}
|
|
37
|
+
break;
|
|
38
|
+
default:
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
36
41
|
|
|
37
42
|
uiLine();
|
|
38
43
|
logger.error(i18n(`${i18nKey}.platformVersionErrors.header`));
|
|
@@ -44,21 +49,37 @@ function createPlatformVersionError(subCategory, errData) {
|
|
|
44
49
|
logger.log(i18n(`${i18nKey}.platformVersionErrors.updateProject`));
|
|
45
50
|
logger.log(
|
|
46
51
|
i18n(`${i18nKey}.platformVersionErrors.betaLink`, {
|
|
47
|
-
docsLink
|
|
52
|
+
docsLink: uiLink(
|
|
53
|
+
i18n(`${i18nKey}.platformVersionErrors.docsLink`),
|
|
54
|
+
'https://developers.hubspot.com/docs/platform/platform-versioning'
|
|
55
|
+
),
|
|
48
56
|
})
|
|
49
57
|
);
|
|
50
58
|
uiLine();
|
|
51
59
|
}
|
|
52
60
|
|
|
53
|
-
function overrideErrors(err) {
|
|
61
|
+
function overrideErrors(err, context) {
|
|
62
|
+
if (isMissingScopeError(err)) {
|
|
63
|
+
logger.error(
|
|
64
|
+
i18n(`${i18nKey}.missingScopeError`, {
|
|
65
|
+
accountName: context.accountId
|
|
66
|
+
? uiAccountDescription(context.accountId)
|
|
67
|
+
: '',
|
|
68
|
+
request: context.request || 'request',
|
|
69
|
+
authCommand: uiCommandReference('hs auth'),
|
|
70
|
+
})
|
|
71
|
+
);
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
|
|
54
75
|
if (
|
|
55
76
|
isSpecifiedError(err, {
|
|
56
77
|
subCategory: PLATFORM_VERSION_ERROR_TYPES.PLATFORM_VERSION_NOT_SPECIFIED,
|
|
57
78
|
})
|
|
58
79
|
) {
|
|
59
80
|
createPlatformVersionError(
|
|
60
|
-
|
|
61
|
-
|
|
81
|
+
err,
|
|
82
|
+
PLATFORM_VERSION_ERROR_TYPES.PLATFORM_VERSION_NOT_SPECIFIED
|
|
62
83
|
);
|
|
63
84
|
return true;
|
|
64
85
|
}
|
|
@@ -69,8 +90,8 @@ function overrideErrors(err) {
|
|
|
69
90
|
})
|
|
70
91
|
) {
|
|
71
92
|
createPlatformVersionError(
|
|
72
|
-
|
|
73
|
-
|
|
93
|
+
err,
|
|
94
|
+
PLATFORM_VERSION_ERROR_TYPES.PLATFORM_VERSION_RETIRED
|
|
74
95
|
);
|
|
75
96
|
return true;
|
|
76
97
|
}
|
|
@@ -82,8 +103,8 @@ function overrideErrors(err) {
|
|
|
82
103
|
})
|
|
83
104
|
) {
|
|
84
105
|
createPlatformVersionError(
|
|
85
|
-
|
|
86
|
-
|
|
106
|
+
err,
|
|
107
|
+
PLATFORM_VERSION_ERROR_TYPES.PLATFORM_VERSION_SPECIFIED_DOES_NOT_EXIST
|
|
87
108
|
);
|
|
88
109
|
return true;
|
|
89
110
|
}
|
package/lib/localDev.js
CHANGED
|
@@ -85,15 +85,32 @@ const confirmDefaultAccountIsTarget = async accountConfig => {
|
|
|
85
85
|
// Confirm the default account is a developer account if developing public apps
|
|
86
86
|
const checkIfAppDeveloperAccount = accountConfig => {
|
|
87
87
|
if (!isAppDeveloperAccount(accountConfig)) {
|
|
88
|
-
logger.error(
|
|
88
|
+
logger.error(
|
|
89
|
+
i18n(`${i18nKey}.checkIfAppDevloperAccount`, {
|
|
90
|
+
useCommand: uiCommandReference('hs accounts use'),
|
|
91
|
+
authCommand: uiCommandReference('hs auth'),
|
|
92
|
+
})
|
|
93
|
+
);
|
|
89
94
|
process.exit(EXIT_CODES.SUCCESS);
|
|
90
95
|
}
|
|
91
96
|
};
|
|
92
97
|
|
|
93
98
|
// Confirm the default account is a developer account if developing public apps
|
|
94
|
-
const
|
|
95
|
-
if (!isDeveloperTestAccount(accountConfig)) {
|
|
96
|
-
logger.error(
|
|
99
|
+
const validateAccountOption = (accountConfig, hasPublicApps) => {
|
|
100
|
+
if (hasPublicApps && !isDeveloperTestAccount(accountConfig)) {
|
|
101
|
+
logger.error(
|
|
102
|
+
i18n(`${i18nKey}.validateAccountOption.invalidPublicAppAccount`, {
|
|
103
|
+
useCommand: uiCommandReference('hs accounts use'),
|
|
104
|
+
devCommand: uiCommandReference('hs project dev'),
|
|
105
|
+
})
|
|
106
|
+
);
|
|
107
|
+
process.exit(EXIT_CODES.SUCCESS);
|
|
108
|
+
} else if (isAppDeveloperAccount(accountConfig)) {
|
|
109
|
+
logger.error(
|
|
110
|
+
i18n(`${i18nKey}.validateAccountOption.invalidPrivateAppAccount`, {
|
|
111
|
+
useCommand: uiCommandReference('hs accounts use'),
|
|
112
|
+
})
|
|
113
|
+
);
|
|
97
114
|
process.exit(EXIT_CODES.SUCCESS);
|
|
98
115
|
}
|
|
99
116
|
};
|
|
@@ -109,20 +126,11 @@ const suggestRecommendedNestedAccount = async (
|
|
|
109
126
|
if (hasPublicApps) {
|
|
110
127
|
logger.log(
|
|
111
128
|
i18n(
|
|
112
|
-
`${i18nKey}.
|
|
129
|
+
`${i18nKey}.validateAccountOption.publicAppNonDeveloperTestAccountWarning`
|
|
113
130
|
)
|
|
114
131
|
);
|
|
115
|
-
} else if (isAppDeveloperAccount(accountConfig)) {
|
|
116
|
-
logger.error(
|
|
117
|
-
i18n(
|
|
118
|
-
`${i18nKey}.suggestRecommendedNestedAccount.privateAppInAppDeveloperAccountError`
|
|
119
|
-
)
|
|
120
|
-
);
|
|
121
|
-
process.exit(EXIT_CODES.ERROR);
|
|
122
132
|
} else {
|
|
123
|
-
logger.log(
|
|
124
|
-
i18n(`${i18nKey}.suggestRecommendedNestedAccount.nonSandboxWarning`)
|
|
125
|
-
);
|
|
133
|
+
logger.log(i18n(`${i18nKey}.validateAccountOption.nonSandboxWarning`));
|
|
126
134
|
}
|
|
127
135
|
uiLine();
|
|
128
136
|
logger.log();
|
|
@@ -187,6 +195,7 @@ const createSandboxForLocalDev = async (accountId, accountConfig, env) => {
|
|
|
187
195
|
accountConfig,
|
|
188
196
|
sandboxAccountConfig
|
|
189
197
|
);
|
|
198
|
+
// For v1 sandboxes, keep sync here. Once we migrate to v2, this will be handled by BE automatically
|
|
190
199
|
await syncSandbox({
|
|
191
200
|
accountConfig: sandboxAccountConfig,
|
|
192
201
|
parentAccountConfig: accountConfig,
|
|
@@ -439,7 +448,7 @@ const getAccountHomeUrl = accountId => {
|
|
|
439
448
|
module.exports = {
|
|
440
449
|
confirmDefaultAccountIsTarget,
|
|
441
450
|
checkIfAppDeveloperAccount,
|
|
442
|
-
|
|
451
|
+
validateAccountOption,
|
|
443
452
|
suggestRecommendedNestedAccount,
|
|
444
453
|
createSandboxForLocalDev,
|
|
445
454
|
createDeveloperTestAccountForLocalDev,
|