@hubspot/cli 3.0.11 → 3.0.12-beta.2
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/commands/create/api-sample.js +2 -2
- package/commands/create/app.js +2 -2
- package/commands/create/react-app.js +2 -2
- package/commands/create/vue-app.js +2 -2
- package/commands/create/webpack-serverless.js +2 -2
- package/commands/create/website-theme.js +2 -2
- package/commands/project/create.js +6 -1
- package/commands/project/download.js +127 -0
- package/commands/project/upload.js +10 -106
- package/commands/project/watch.js +55 -13
- package/commands/project.js +2 -0
- package/lib/projects.js +218 -94
- package/lib/serverlessLogs.js +8 -16
- package/lib/ui.js +8 -1
- package/package.json +4 -4
|
@@ -10,7 +10,7 @@ const fs = require('fs-extra');
|
|
|
10
10
|
const ora = require('ora');
|
|
11
11
|
const { fetchJsonFromRepository } = require('@hubspot/cli-lib/github');
|
|
12
12
|
const { GITHUB_RELEASE_TYPES } = require('@hubspot/cli-lib/lib/constants');
|
|
13
|
-
const {
|
|
13
|
+
const { cloneGitHubRepo } = require('@hubspot/cli-lib/github');
|
|
14
14
|
const { i18n } = require('@hubspot/cli-lib/lib/lang');
|
|
15
15
|
|
|
16
16
|
const i18nKey = 'cli.commands.create.subcommands.apiSample';
|
|
@@ -60,7 +60,7 @@ module.exports = {
|
|
|
60
60
|
sampleLanguage,
|
|
61
61
|
})
|
|
62
62
|
);
|
|
63
|
-
const created = await
|
|
63
|
+
const created = await cloneGitHubRepo(
|
|
64
64
|
filePath,
|
|
65
65
|
assetType,
|
|
66
66
|
sampleType,
|
package/commands/create/app.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
const {
|
|
1
|
+
const { cloneGitHubRepo } = require('@hubspot/cli-lib/github');
|
|
2
2
|
|
|
3
3
|
module.exports = {
|
|
4
4
|
hidden: true,
|
|
5
5
|
dest: ({ name, assetType }) => name || assetType,
|
|
6
6
|
execute: async ({ options, dest, assetType }) =>
|
|
7
|
-
|
|
7
|
+
cloneGitHubRepo(dest, assetType, 'crm-card-weather-app', '', options),
|
|
8
8
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
const {
|
|
1
|
+
const { cloneGitHubRepo } = require('@hubspot/cli-lib/github');
|
|
2
2
|
|
|
3
3
|
module.exports = {
|
|
4
4
|
dest: ({ name, assetType }) => name || assetType,
|
|
5
5
|
execute: async ({ options, dest, assetType }) =>
|
|
6
|
-
|
|
6
|
+
cloneGitHubRepo(dest, assetType, 'cms-react-boilerplate', '', options),
|
|
7
7
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
const {
|
|
1
|
+
const { cloneGitHubRepo } = require('@hubspot/cli-lib/github');
|
|
2
2
|
|
|
3
3
|
module.exports = {
|
|
4
4
|
dest: ({ name, assetType }) => name || assetType,
|
|
5
5
|
execute: async ({ options, dest, assetType }) =>
|
|
6
|
-
|
|
6
|
+
cloneGitHubRepo(dest, assetType, 'cms-vue-boilerplate', '', options),
|
|
7
7
|
};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
const {
|
|
1
|
+
const { cloneGitHubRepo } = require('@hubspot/cli-lib/github');
|
|
2
2
|
|
|
3
3
|
module.exports = {
|
|
4
4
|
dest: ({ name, assetType }) => name || assetType,
|
|
5
5
|
execute: async ({ options, dest, assetType }) =>
|
|
6
|
-
|
|
6
|
+
cloneGitHubRepo(
|
|
7
7
|
dest,
|
|
8
8
|
assetType,
|
|
9
9
|
'cms-webpack-serverless-boilerplate',
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const {
|
|
1
|
+
const { cloneGitHubRepo } = require('@hubspot/cli-lib/github');
|
|
2
2
|
const { GITHUB_RELEASE_TYPES } = require('@hubspot/cli-lib/lib/constants');
|
|
3
3
|
const { getIsInProject } = require('../../lib/projects');
|
|
4
4
|
|
|
@@ -14,6 +14,6 @@ module.exports = {
|
|
|
14
14
|
// releaseType has to be 'REPOSITORY' to download a specific branch
|
|
15
15
|
options.releaseType = GITHUB_RELEASE_TYPES.REPOSITORY;
|
|
16
16
|
}
|
|
17
|
-
|
|
17
|
+
cloneGitHubRepo(dest, assetType, 'cms-theme-boilerplate', 'src', options);
|
|
18
18
|
},
|
|
19
19
|
};
|
|
@@ -11,7 +11,10 @@ const path = require('path');
|
|
|
11
11
|
const {
|
|
12
12
|
createProjectPrompt,
|
|
13
13
|
} = require('../../lib/prompts/createProjectPrompt');
|
|
14
|
-
const {
|
|
14
|
+
const {
|
|
15
|
+
createProjectConfig,
|
|
16
|
+
showProjectWelcomeMessage,
|
|
17
|
+
} = require('../../lib/projects');
|
|
15
18
|
const { i18n } = require('@hubspot/cli-lib/lib/lang');
|
|
16
19
|
|
|
17
20
|
const i18nKey = 'cli.commands.project.subcommands.create';
|
|
@@ -33,6 +36,8 @@ exports.handler = async options => {
|
|
|
33
36
|
options.name || name,
|
|
34
37
|
options.template || template
|
|
35
38
|
);
|
|
39
|
+
|
|
40
|
+
showProjectWelcomeMessage();
|
|
36
41
|
};
|
|
37
42
|
|
|
38
43
|
exports.builder = yargs => {
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
getAccountId,
|
|
5
|
+
addUseEnvironmentOptions,
|
|
6
|
+
} = require('../../lib/commonOpts');
|
|
7
|
+
const { trackCommandUsage } = require('../../lib/usageTracking');
|
|
8
|
+
const { getCwd } = require('@hubspot/cli-lib/path');
|
|
9
|
+
const {
|
|
10
|
+
logApiErrorInstance,
|
|
11
|
+
ApiErrorContext,
|
|
12
|
+
} = require('@hubspot/cli-lib/errorHandlers');
|
|
13
|
+
const { logger } = require('@hubspot/cli-lib/logger');
|
|
14
|
+
const { extractZipArchive } = require('@hubspot/cli-lib/archive');
|
|
15
|
+
const {
|
|
16
|
+
downloadProject,
|
|
17
|
+
fetchProjectBuilds,
|
|
18
|
+
} = require('@hubspot/cli-lib/api/dfs');
|
|
19
|
+
const {
|
|
20
|
+
createProjectConfig,
|
|
21
|
+
ensureProjectExists,
|
|
22
|
+
} = require('../../lib/projects');
|
|
23
|
+
const { loadAndValidateOptions } = require('../../lib/validation');
|
|
24
|
+
const { i18n } = require('@hubspot/cli-lib/lib/lang');
|
|
25
|
+
|
|
26
|
+
const i18nKey = 'cli.commands.project.subcommands.download';
|
|
27
|
+
const { EXIT_CODES } = require('../../lib/enums/exitCodes');
|
|
28
|
+
|
|
29
|
+
exports.command = 'download <name> [dest]';
|
|
30
|
+
exports.describe = i18n(`${i18nKey}.describe`);
|
|
31
|
+
|
|
32
|
+
exports.handler = async options => {
|
|
33
|
+
await loadAndValidateOptions(options);
|
|
34
|
+
|
|
35
|
+
const { name: projectName, dest, buildNumber } = options;
|
|
36
|
+
const accountId = getAccountId(options);
|
|
37
|
+
|
|
38
|
+
trackCommandUsage('project-download', { projectName }, accountId);
|
|
39
|
+
|
|
40
|
+
await ensureProjectExists(accountId, projectName, { allowCreate: false });
|
|
41
|
+
|
|
42
|
+
const absoluteDestPath = dest ? path.resolve(getCwd(), dest) : getCwd();
|
|
43
|
+
|
|
44
|
+
const projectConfigCreated = await createProjectConfig(
|
|
45
|
+
absoluteDestPath,
|
|
46
|
+
projectName,
|
|
47
|
+
'none'
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
if (!projectConfigCreated) {
|
|
51
|
+
logger.log(i18n(`${i18nKey}.logs.downloadCancelled`));
|
|
52
|
+
process.exit(EXIT_CODES.SUCCESS);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
let success = false;
|
|
56
|
+
let buildNumberToDownload = buildNumber;
|
|
57
|
+
|
|
58
|
+
if (!buildNumberToDownload) {
|
|
59
|
+
let projectBuildsResult;
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
projectBuildsResult = await fetchProjectBuilds(accountId, projectName);
|
|
63
|
+
} catch (e) {
|
|
64
|
+
logApiErrorInstance(e, new ApiErrorContext({ accountId }));
|
|
65
|
+
process.exit(EXIT_CODES.ERROR);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const { results: projectBuilds } = projectBuildsResult;
|
|
69
|
+
|
|
70
|
+
if (projectBuilds && projectBuilds.length) {
|
|
71
|
+
const latestBuild = projectBuilds[0];
|
|
72
|
+
buildNumberToDownload = latestBuild.buildId;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const zippedProject = await downloadProject(
|
|
77
|
+
accountId,
|
|
78
|
+
projectName,
|
|
79
|
+
buildNumberToDownload
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
success = await extractZipArchive(
|
|
83
|
+
zippedProject,
|
|
84
|
+
projectName,
|
|
85
|
+
path.resolve(absoluteDestPath, 'src'),
|
|
86
|
+
{
|
|
87
|
+
includesRootDir: false,
|
|
88
|
+
}
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
if (!success) {
|
|
92
|
+
logger.log(i18n(`${i18nKey}.errors.downloadFailed`));
|
|
93
|
+
process.exit(EXIT_CODES.ERROR);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
logger.log(
|
|
97
|
+
i18n(`${i18nKey}.logs.downloadSucceeded`, {
|
|
98
|
+
buildId: buildNumberToDownload,
|
|
99
|
+
projectName,
|
|
100
|
+
})
|
|
101
|
+
);
|
|
102
|
+
process.exit(EXIT_CODES.SUCCESS);
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
exports.builder = yargs => {
|
|
106
|
+
addUseEnvironmentOptions(yargs, true);
|
|
107
|
+
|
|
108
|
+
yargs.positional('name', {
|
|
109
|
+
describe: i18n(`${i18nKey}.positionals.name.describe`),
|
|
110
|
+
type: 'string',
|
|
111
|
+
});
|
|
112
|
+
yargs.positional('dest', {
|
|
113
|
+
describe: i18n(`${i18nKey}.positionals.dest.describe`),
|
|
114
|
+
type: 'string',
|
|
115
|
+
});
|
|
116
|
+
yargs.option('buildNumber', {
|
|
117
|
+
describe: i18n(`${i18nKey}.options.buildNumber.describe`),
|
|
118
|
+
type: 'number',
|
|
119
|
+
});
|
|
120
|
+
yargs.example([
|
|
121
|
+
[
|
|
122
|
+
'$0 project download myProject myProjectFolder',
|
|
123
|
+
i18n(`${i18nKey}.examples.default`),
|
|
124
|
+
],
|
|
125
|
+
]);
|
|
126
|
+
return yargs;
|
|
127
|
+
};
|
|
@@ -1,9 +1,4 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
|
-
const fs = require('fs');
|
|
3
|
-
const path = require('path');
|
|
4
|
-
const archiver = require('archiver');
|
|
5
|
-
const tmp = require('tmp');
|
|
6
|
-
const Spinnies = require('spinnies');
|
|
7
2
|
const {
|
|
8
3
|
addAccountOptions,
|
|
9
4
|
addConfigOptions,
|
|
@@ -11,84 +6,25 @@ const {
|
|
|
11
6
|
addUseEnvironmentOptions,
|
|
12
7
|
} = require('../../lib/commonOpts');
|
|
13
8
|
const { trackCommandUsage } = require('../../lib/usageTracking');
|
|
14
|
-
const {
|
|
15
|
-
logApiErrorInstance,
|
|
16
|
-
ApiErrorContext,
|
|
17
|
-
} = require('@hubspot/cli-lib/errorHandlers');
|
|
18
9
|
const { uiLine, uiAccountDescription } = require('../../lib/ui');
|
|
19
10
|
const { logger } = require('@hubspot/cli-lib/logger');
|
|
20
|
-
const { uploadProject } = require('@hubspot/cli-lib/api/dfs');
|
|
21
|
-
const { shouldIgnoreFile } = require('@hubspot/cli-lib/ignoreRules');
|
|
22
11
|
const { loadAndValidateOptions } = require('../../lib/validation');
|
|
23
12
|
const {
|
|
13
|
+
ensureProjectExists,
|
|
24
14
|
getProjectConfig,
|
|
25
|
-
|
|
15
|
+
handleProjectUpload,
|
|
26
16
|
pollBuildStatus,
|
|
27
|
-
ensureProjectExists,
|
|
28
17
|
pollDeployStatus,
|
|
18
|
+
validateProjectConfig,
|
|
29
19
|
} = require('../../lib/projects');
|
|
30
20
|
const { i18n } = require('@hubspot/cli-lib/lib/lang');
|
|
21
|
+
const { EXIT_CODES } = require('../../lib/enums/exitCodes');
|
|
31
22
|
|
|
32
23
|
const i18nKey = 'cli.commands.project.subcommands.upload';
|
|
33
|
-
const { EXIT_CODES } = require('../../lib/enums/exitCodes');
|
|
34
24
|
|
|
35
25
|
exports.command = 'upload [path]';
|
|
36
26
|
exports.describe = i18n(`${i18nKey}.describe`);
|
|
37
27
|
|
|
38
|
-
const uploadProjectFiles = async (accountId, projectName, filePath) => {
|
|
39
|
-
const spinnies = new Spinnies({
|
|
40
|
-
succeedColor: 'white',
|
|
41
|
-
});
|
|
42
|
-
const accountIdentifier = uiAccountDescription(accountId);
|
|
43
|
-
|
|
44
|
-
spinnies.add('upload', {
|
|
45
|
-
text: i18n(`${i18nKey}.loading.upload.add`, {
|
|
46
|
-
accountIdentifier,
|
|
47
|
-
projectName,
|
|
48
|
-
}),
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
let buildId;
|
|
52
|
-
|
|
53
|
-
try {
|
|
54
|
-
const upload = await uploadProject(accountId, projectName, filePath);
|
|
55
|
-
|
|
56
|
-
buildId = upload.buildId;
|
|
57
|
-
|
|
58
|
-
spinnies.succeed('upload', {
|
|
59
|
-
text: i18n(`${i18nKey}.loading.upload.succeed`, {
|
|
60
|
-
accountIdentifier,
|
|
61
|
-
projectName,
|
|
62
|
-
}),
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
logger.debug(
|
|
66
|
-
i18n(`${i18nKey}.debug.buildCreated`, {
|
|
67
|
-
buildId,
|
|
68
|
-
projectName,
|
|
69
|
-
})
|
|
70
|
-
);
|
|
71
|
-
} catch (err) {
|
|
72
|
-
spinnies.fail('upload', {
|
|
73
|
-
text: i18n(`${i18nKey}.loading.upload.fail`, {
|
|
74
|
-
accountIdentifier,
|
|
75
|
-
projectName,
|
|
76
|
-
}),
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
logApiErrorInstance(
|
|
80
|
-
err,
|
|
81
|
-
new ApiErrorContext({
|
|
82
|
-
accountId,
|
|
83
|
-
projectName,
|
|
84
|
-
})
|
|
85
|
-
);
|
|
86
|
-
process.exit(EXIT_CODES.ERROR);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
return { buildId };
|
|
90
|
-
};
|
|
91
|
-
|
|
92
28
|
exports.handler = async options => {
|
|
93
29
|
await loadAndValidateOptions(options);
|
|
94
30
|
|
|
@@ -101,32 +37,10 @@ exports.handler = async options => {
|
|
|
101
37
|
|
|
102
38
|
validateProjectConfig(projectConfig, projectDir);
|
|
103
39
|
|
|
104
|
-
await ensureProjectExists(accountId, projectConfig.name, forceCreate);
|
|
105
|
-
|
|
106
|
-
const tempFile = tmp.fileSync({ postfix: '.zip' });
|
|
107
|
-
|
|
108
|
-
logger.debug(
|
|
109
|
-
i18n(`${i18nKey}.debug.compressing`, {
|
|
110
|
-
path: tempFile.name,
|
|
111
|
-
})
|
|
112
|
-
);
|
|
113
|
-
|
|
114
|
-
const output = fs.createWriteStream(tempFile.name);
|
|
115
|
-
const archive = archiver('zip');
|
|
40
|
+
await ensureProjectExists(accountId, projectConfig.name, { forceCreate });
|
|
116
41
|
|
|
117
|
-
|
|
42
|
+
const startPolling = async (tempFile, buildId) => {
|
|
118
43
|
let exitCode = EXIT_CODES.SUCCESS;
|
|
119
|
-
logger.debug(
|
|
120
|
-
i18n(`${i18nKey}.debug.compressed`, {
|
|
121
|
-
byteCount: archive.pointer(),
|
|
122
|
-
})
|
|
123
|
-
);
|
|
124
|
-
|
|
125
|
-
const { buildId } = await uploadProjectFiles(
|
|
126
|
-
accountId,
|
|
127
|
-
projectConfig.name,
|
|
128
|
-
tempFile.name
|
|
129
|
-
);
|
|
130
44
|
|
|
131
45
|
const {
|
|
132
46
|
isAutoDeployEnabled,
|
|
@@ -134,6 +48,8 @@ exports.handler = async options => {
|
|
|
134
48
|
status,
|
|
135
49
|
} = await pollBuildStatus(accountId, projectConfig.name, buildId);
|
|
136
50
|
|
|
51
|
+
uiLine();
|
|
52
|
+
|
|
137
53
|
if (status === 'FAILURE') {
|
|
138
54
|
exitCode = EXIT_CODES.ERROR;
|
|
139
55
|
return;
|
|
@@ -183,21 +99,9 @@ exports.handler = async options => {
|
|
|
183
99
|
}
|
|
184
100
|
|
|
185
101
|
process.exit(exitCode);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
archive.on('error', function(err) {
|
|
189
|
-
throw err;
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
archive.pipe(output);
|
|
193
|
-
|
|
194
|
-
archive.directory(
|
|
195
|
-
path.resolve(projectDir, projectConfig.srcDir),
|
|
196
|
-
false,
|
|
197
|
-
file => (shouldIgnoreFile(file.name) ? false : file)
|
|
198
|
-
);
|
|
102
|
+
};
|
|
199
103
|
|
|
200
|
-
|
|
104
|
+
await handleProjectUpload(accountId, projectConfig, projectDir, startPolling);
|
|
201
105
|
};
|
|
202
106
|
|
|
203
107
|
exports.builder = yargs => {
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
const { i18n } = require('@hubspot/cli-lib/lib/lang');
|
|
2
2
|
const { createWatcher } = require('@hubspot/cli-lib/projectsWatch');
|
|
3
|
-
const { cancelStagedBuild } = require('@hubspot/cli-lib/api/dfs');
|
|
4
3
|
const {
|
|
5
4
|
logApiErrorInstance,
|
|
6
5
|
ApiErrorContext,
|
|
@@ -14,13 +13,20 @@ const {
|
|
|
14
13
|
} = require('../../lib/commonOpts');
|
|
15
14
|
const { trackCommandUsage } = require('../../lib/usageTracking');
|
|
16
15
|
const {
|
|
16
|
+
ensureProjectExists,
|
|
17
17
|
getProjectConfig,
|
|
18
|
-
|
|
18
|
+
handleProjectUpload,
|
|
19
19
|
pollBuildStatus,
|
|
20
20
|
pollDeployStatus,
|
|
21
|
+
validateProjectConfig,
|
|
21
22
|
} = require('../../lib/projects');
|
|
23
|
+
const {
|
|
24
|
+
cancelStagedBuild,
|
|
25
|
+
fetchProjectBuilds,
|
|
26
|
+
} = require('@hubspot/cli-lib/api/dfs');
|
|
22
27
|
const { loadAndValidateOptions } = require('../../lib/validation');
|
|
23
28
|
const { EXIT_CODES } = require('../../lib/enums/exitCodes');
|
|
29
|
+
const { handleKeypress, handleExit } = require('@hubspot/cli-lib/lib/process');
|
|
24
30
|
|
|
25
31
|
const i18nKey = 'cli.commands.project.subcommands.watch';
|
|
26
32
|
|
|
@@ -43,13 +49,13 @@ const handleBuildStatus = async (accountId, projectName, buildId) => {
|
|
|
43
49
|
}
|
|
44
50
|
};
|
|
45
51
|
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
52
|
+
const handleUserInput = (accountId, projectName, currentBuildId) => {
|
|
53
|
+
const onTerminate = async () => {
|
|
54
|
+
logger.log(i18n(`${i18nKey}.logs.processExited`));
|
|
55
|
+
|
|
49
56
|
if (currentBuildId) {
|
|
50
57
|
try {
|
|
51
58
|
await cancelStagedBuild(accountId, projectName);
|
|
52
|
-
logger.debug(i18n(`${i18nKey}.debug.buildCancelled`));
|
|
53
59
|
process.exit(EXIT_CODES.SUCCESS);
|
|
54
60
|
} catch (err) {
|
|
55
61
|
logApiErrorInstance(
|
|
@@ -61,13 +67,20 @@ const handleSigInt = (accountId, projectName, currentBuildId) => {
|
|
|
61
67
|
} else {
|
|
62
68
|
process.exit(EXIT_CODES.SUCCESS);
|
|
63
69
|
}
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
handleExit(onTerminate);
|
|
73
|
+
handleKeypress(key => {
|
|
74
|
+
if ((key.ctrl && key.name === 'c') || key.name === 'q') {
|
|
75
|
+
onTerminate();
|
|
76
|
+
}
|
|
64
77
|
});
|
|
65
78
|
};
|
|
66
79
|
|
|
67
80
|
exports.handler = async options => {
|
|
68
81
|
await loadAndValidateOptions(options);
|
|
69
82
|
|
|
70
|
-
const { path: projectPath } = options;
|
|
83
|
+
const { initialUpload, path: projectPath } = options;
|
|
71
84
|
const accountId = getAccountId(options);
|
|
72
85
|
|
|
73
86
|
trackCommandUsage('project-watch', { projectPath }, accountId);
|
|
@@ -76,21 +89,50 @@ exports.handler = async options => {
|
|
|
76
89
|
|
|
77
90
|
validateProjectConfig(projectConfig, projectDir);
|
|
78
91
|
|
|
79
|
-
await
|
|
92
|
+
await ensureProjectExists(accountId, projectConfig.name);
|
|
93
|
+
|
|
94
|
+
const { results: builds } = await fetchProjectBuilds(
|
|
80
95
|
accountId,
|
|
81
|
-
projectConfig,
|
|
82
|
-
|
|
83
|
-
handleBuildStatus,
|
|
84
|
-
handleSigInt
|
|
96
|
+
projectConfig.name,
|
|
97
|
+
options
|
|
85
98
|
);
|
|
99
|
+
const hasNoBuilds = !builds || !builds.length;
|
|
100
|
+
|
|
101
|
+
const startWatching = async () => {
|
|
102
|
+
await createWatcher(
|
|
103
|
+
accountId,
|
|
104
|
+
projectConfig,
|
|
105
|
+
projectDir,
|
|
106
|
+
handleBuildStatus,
|
|
107
|
+
handleUserInput
|
|
108
|
+
);
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
// Upload all files if no build exists for this project yet
|
|
112
|
+
if (initialUpload || hasNoBuilds) {
|
|
113
|
+
await handleProjectUpload(
|
|
114
|
+
accountId,
|
|
115
|
+
projectConfig,
|
|
116
|
+
projectDir,
|
|
117
|
+
startWatching
|
|
118
|
+
);
|
|
119
|
+
} else {
|
|
120
|
+
await startWatching();
|
|
121
|
+
}
|
|
86
122
|
};
|
|
87
123
|
|
|
88
124
|
exports.builder = yargs => {
|
|
89
125
|
yargs.positional('path', {
|
|
90
|
-
describe: i18n(`${i18nKey}.describe`),
|
|
126
|
+
describe: i18n(`${i18nKey}.positionals.path.describe`),
|
|
91
127
|
type: 'string',
|
|
92
128
|
});
|
|
93
129
|
|
|
130
|
+
yargs.option('initial-upload', {
|
|
131
|
+
alias: 'i',
|
|
132
|
+
describe: i18n(`${i18nKey}.options.initialUpload.describe`),
|
|
133
|
+
type: 'boolean',
|
|
134
|
+
});
|
|
135
|
+
|
|
94
136
|
yargs.example([
|
|
95
137
|
['$0 project watch myProjectFolder', i18n(`${i18nKey}.examples.default`)],
|
|
96
138
|
]);
|
package/commands/project.js
CHANGED
|
@@ -5,6 +5,7 @@ const upload = require('./project/upload');
|
|
|
5
5
|
const listBuilds = require('./project/listBuilds');
|
|
6
6
|
const logs = require('./project/logs');
|
|
7
7
|
const watch = require('./project/watch');
|
|
8
|
+
const download = require('./project/download');
|
|
8
9
|
|
|
9
10
|
exports.command = 'project';
|
|
10
11
|
exports.describe = false; //'Commands for working with projects';
|
|
@@ -20,6 +21,7 @@ exports.builder = yargs => {
|
|
|
20
21
|
yargs.command(watch).demandCommand(0, '');
|
|
21
22
|
yargs.command(listBuilds).demandCommand(0, '');
|
|
22
23
|
yargs.command(logs).demandCommand(1, '');
|
|
24
|
+
yargs.command(download).demandCommand(0, '');
|
|
23
25
|
|
|
24
26
|
return yargs;
|
|
25
27
|
};
|
package/lib/projects.js
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
const fs = require('fs-extra');
|
|
2
2
|
const path = require('path');
|
|
3
|
-
|
|
3
|
+
const archiver = require('archiver');
|
|
4
|
+
const tmp = require('tmp');
|
|
4
5
|
const chalk = require('chalk');
|
|
5
6
|
const findup = require('findup-sync');
|
|
6
7
|
const Spinnies = require('spinnies');
|
|
7
8
|
const { logger } = require('@hubspot/cli-lib/logger');
|
|
8
9
|
const { getEnv } = require('@hubspot/cli-lib/lib/config');
|
|
9
|
-
const {
|
|
10
|
-
createProject: createProjectTemplate,
|
|
11
|
-
} = require('@hubspot/cli-lib/projects');
|
|
10
|
+
const { cloneGitHubRepo } = require('@hubspot/cli-lib/github');
|
|
12
11
|
const { getHubSpotWebsiteOrigin } = require('@hubspot/cli-lib/lib/urls');
|
|
13
12
|
const {
|
|
14
13
|
ENVIRONMENTS,
|
|
15
14
|
POLLING_DELAY,
|
|
16
15
|
PROJECT_TEMPLATES,
|
|
17
|
-
|
|
16
|
+
PROJECT_BUILD_TEXT,
|
|
17
|
+
PROJECT_DEPLOY_TEXT,
|
|
18
18
|
PROJECT_CONFIG_FILE,
|
|
19
19
|
} = require('@hubspot/cli-lib/lib/constants');
|
|
20
20
|
const {
|
|
@@ -22,42 +22,18 @@ const {
|
|
|
22
22
|
getBuildStatus,
|
|
23
23
|
getDeployStatus,
|
|
24
24
|
fetchProject,
|
|
25
|
+
uploadProject,
|
|
25
26
|
} = require('@hubspot/cli-lib/api/dfs');
|
|
26
27
|
const {
|
|
27
28
|
logApiErrorInstance,
|
|
28
29
|
ApiErrorContext,
|
|
29
30
|
} = require('@hubspot/cli-lib/errorHandlers');
|
|
31
|
+
const { shouldIgnoreFile } = require('@hubspot/cli-lib/ignoreRules');
|
|
30
32
|
const { getCwd } = require('@hubspot/cli-lib/path');
|
|
31
33
|
const { promptUser } = require('./prompts/promptUtils');
|
|
32
34
|
const { EXIT_CODES } = require('./enums/exitCodes');
|
|
33
|
-
const { uiLine, uiAccountDescription } = require('../lib/ui');
|
|
34
|
-
|
|
35
|
-
const PROJECT_STRINGS = {
|
|
36
|
-
BUILD: {
|
|
37
|
-
INITIALIZE: (name, numOfComponents) =>
|
|
38
|
-
`Building ${chalk.bold(name)}\n\nFound ${numOfComponents} component${
|
|
39
|
-
numOfComponents !== 1 ? 's' : ''
|
|
40
|
-
} in this project ...\n`,
|
|
41
|
-
SUCCESS: name => `Built ${chalk.bold(name)}`,
|
|
42
|
-
FAIL: name => `Failed to build ${chalk.bold(name)}`,
|
|
43
|
-
SUBTASK_FAIL: (taskId, name) =>
|
|
44
|
-
`Build #${taskId} failed because there was a problem\nbuilding ${chalk.bold(
|
|
45
|
-
name
|
|
46
|
-
)}`,
|
|
47
|
-
},
|
|
48
|
-
DEPLOY: {
|
|
49
|
-
INITIALIZE: (name, numOfComponents) =>
|
|
50
|
-
`Deploying ${chalk.bold(name)}\n\nFound ${numOfComponents} component${
|
|
51
|
-
numOfComponents !== 1 ? 's' : ''
|
|
52
|
-
} in this project ...\n`,
|
|
53
|
-
SUCCESS: name => `Deployed ${chalk.bold(name)}`,
|
|
54
|
-
FAIL: name => `Failed to deploy ${chalk.bold(name)}`,
|
|
55
|
-
SUBTASK_FAIL: (taskId, name) =>
|
|
56
|
-
`Deploy for build #${taskId} failed because there was a\nproblem deploying ${chalk.bold(
|
|
57
|
-
name
|
|
58
|
-
)}`,
|
|
59
|
-
},
|
|
60
|
-
};
|
|
35
|
+
const { uiLine, uiLink, uiAccountDescription } = require('../lib/ui');
|
|
36
|
+
const { i18n } = require('@hubspot/cli-lib/lib/lang');
|
|
61
37
|
|
|
62
38
|
const writeProjectConfig = (configPath, config) => {
|
|
63
39
|
try {
|
|
@@ -127,14 +103,16 @@ const createProjectConfig = async (projectPath, projectName, template) => {
|
|
|
127
103
|
]);
|
|
128
104
|
|
|
129
105
|
if (!shouldContinue) {
|
|
130
|
-
return;
|
|
106
|
+
return false;
|
|
131
107
|
}
|
|
132
108
|
}
|
|
133
109
|
|
|
134
110
|
const projectConfigPath = path.join(projectPath, PROJECT_CONFIG_FILE);
|
|
135
111
|
|
|
136
112
|
logger.log(
|
|
137
|
-
`Creating project in ${
|
|
113
|
+
`Creating project config in ${
|
|
114
|
+
projectPath ? projectPath : 'the current folder'
|
|
115
|
+
}`
|
|
138
116
|
);
|
|
139
117
|
|
|
140
118
|
if (template === 'none') {
|
|
@@ -145,7 +123,7 @@ const createProjectConfig = async (projectPath, projectName, template) => {
|
|
|
145
123
|
srcDir: 'src',
|
|
146
124
|
});
|
|
147
125
|
} else {
|
|
148
|
-
await
|
|
126
|
+
await cloneGitHubRepo(
|
|
149
127
|
projectPath,
|
|
150
128
|
'project',
|
|
151
129
|
PROJECT_TEMPLATES.find(t => t.name === template).repo,
|
|
@@ -158,7 +136,7 @@ const createProjectConfig = async (projectPath, projectName, template) => {
|
|
|
158
136
|
});
|
|
159
137
|
}
|
|
160
138
|
|
|
161
|
-
return
|
|
139
|
+
return true;
|
|
162
140
|
};
|
|
163
141
|
|
|
164
142
|
const validateProjectConfig = (projectConfig, projectDir) => {
|
|
@@ -184,14 +162,18 @@ const validateProjectConfig = (projectConfig, projectDir) => {
|
|
|
184
162
|
}
|
|
185
163
|
};
|
|
186
164
|
|
|
187
|
-
const ensureProjectExists = async (
|
|
165
|
+
const ensureProjectExists = async (
|
|
166
|
+
accountId,
|
|
167
|
+
projectName,
|
|
168
|
+
{ forceCreate = false, allowCreate = true } = {}
|
|
169
|
+
) => {
|
|
188
170
|
try {
|
|
189
171
|
await fetchProject(accountId, projectName);
|
|
190
172
|
} catch (err) {
|
|
191
173
|
if (err.statusCode === 404) {
|
|
192
174
|
let shouldCreateProject = forceCreate;
|
|
193
175
|
|
|
194
|
-
if (!shouldCreateProject) {
|
|
176
|
+
if (allowCreate && !shouldCreateProject) {
|
|
195
177
|
const promptResult = await promptUser([
|
|
196
178
|
{
|
|
197
179
|
name: 'shouldCreateProject',
|
|
@@ -232,12 +214,119 @@ const getProjectDetailUrl = (projectName, accountId) => {
|
|
|
232
214
|
return `${baseUrl}/developer-projects/${accountId}/project/${projectName}`;
|
|
233
215
|
};
|
|
234
216
|
|
|
235
|
-
const
|
|
217
|
+
const getProjectBuildDetailUrl = (projectName, buildId, accountId) => {
|
|
218
|
+
if (!projectName || !buildId || !accountId) return;
|
|
219
|
+
return `${getProjectDetailUrl(projectName, accountId)}/build/${buildId}`;
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
const uploadProjectFiles = async (accountId, projectName, filePath) => {
|
|
223
|
+
const i18nKey = 'cli.commands.project.subcommands.upload';
|
|
224
|
+
const spinnies = new Spinnies({
|
|
225
|
+
succeedColor: 'white',
|
|
226
|
+
});
|
|
227
|
+
const accountIdentifier = uiAccountDescription(accountId);
|
|
228
|
+
|
|
229
|
+
spinnies.add('upload', {
|
|
230
|
+
text: i18n(`${i18nKey}.loading.upload.add`, {
|
|
231
|
+
accountIdentifier,
|
|
232
|
+
projectName,
|
|
233
|
+
}),
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
let buildId;
|
|
237
|
+
|
|
238
|
+
try {
|
|
239
|
+
const upload = await uploadProject(accountId, projectName, filePath);
|
|
240
|
+
|
|
241
|
+
buildId = upload.buildId;
|
|
242
|
+
|
|
243
|
+
spinnies.succeed('upload', {
|
|
244
|
+
text: i18n(`${i18nKey}.loading.upload.succeed`, {
|
|
245
|
+
accountIdentifier,
|
|
246
|
+
projectName,
|
|
247
|
+
}),
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
logger.debug(
|
|
251
|
+
i18n(`${i18nKey}.debug.buildCreated`, {
|
|
252
|
+
buildId,
|
|
253
|
+
projectName,
|
|
254
|
+
})
|
|
255
|
+
);
|
|
256
|
+
} catch (err) {
|
|
257
|
+
spinnies.fail('upload', {
|
|
258
|
+
text: i18n(`${i18nKey}.loading.upload.fail`, {
|
|
259
|
+
accountIdentifier,
|
|
260
|
+
projectName,
|
|
261
|
+
}),
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
logApiErrorInstance(
|
|
265
|
+
err,
|
|
266
|
+
new ApiErrorContext({
|
|
267
|
+
accountId,
|
|
268
|
+
projectName,
|
|
269
|
+
})
|
|
270
|
+
);
|
|
271
|
+
process.exit(EXIT_CODES.ERROR);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
return { buildId };
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
const handleProjectUpload = async (
|
|
278
|
+
accountId,
|
|
279
|
+
projectConfig,
|
|
280
|
+
projectDir,
|
|
281
|
+
callbackFunc
|
|
282
|
+
) => {
|
|
283
|
+
const i18nKey = 'cli.commands.project.subcommands.upload';
|
|
284
|
+
const tempFile = tmp.fileSync({ postfix: '.zip' });
|
|
285
|
+
|
|
286
|
+
logger.debug(
|
|
287
|
+
i18n(`${i18nKey}.debug.compressing`, {
|
|
288
|
+
path: tempFile.name,
|
|
289
|
+
})
|
|
290
|
+
);
|
|
291
|
+
|
|
292
|
+
const output = fs.createWriteStream(tempFile.name);
|
|
293
|
+
const archive = archiver('zip');
|
|
294
|
+
|
|
295
|
+
output.on('close', async function() {
|
|
296
|
+
logger.debug(
|
|
297
|
+
i18n(`${i18nKey}.debug.compressed`, {
|
|
298
|
+
byteCount: archive.pointer(),
|
|
299
|
+
})
|
|
300
|
+
);
|
|
301
|
+
|
|
302
|
+
const { buildId } = await uploadProjectFiles(
|
|
303
|
+
accountId,
|
|
304
|
+
projectConfig.name,
|
|
305
|
+
tempFile.name
|
|
306
|
+
);
|
|
307
|
+
|
|
308
|
+
if (callbackFunc) {
|
|
309
|
+
callbackFunc(tempFile, buildId);
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
archive.pipe(output);
|
|
314
|
+
|
|
315
|
+
archive.directory(
|
|
316
|
+
path.resolve(projectDir, projectConfig.srcDir),
|
|
317
|
+
false,
|
|
318
|
+
file => (shouldIgnoreFile(file.name) ? false : file)
|
|
319
|
+
);
|
|
320
|
+
|
|
321
|
+
archive.finalize();
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
const showProjectWelcomeMessage = () => {
|
|
236
325
|
logger.log('');
|
|
237
326
|
logger.log(chalk.bold('Welcome to HubSpot Developer Projects!'));
|
|
238
|
-
logger.log(
|
|
239
|
-
|
|
240
|
-
);
|
|
327
|
+
logger.log('\n');
|
|
328
|
+
uiLine();
|
|
329
|
+
logger.log('\n');
|
|
241
330
|
logger.log(chalk.bold("What's next?\n"));
|
|
242
331
|
logger.log('🎨 Add components to your project with `hs create`.\n');
|
|
243
332
|
logger.log(
|
|
@@ -249,34 +338,31 @@ const showWelcomeMessage = () => {
|
|
|
249
338
|
logger.log(
|
|
250
339
|
`🔗 Use \`hs project --help\` to learn more about available commands.\n`
|
|
251
340
|
);
|
|
252
|
-
|
|
341
|
+
uiLine();
|
|
253
342
|
};
|
|
254
343
|
|
|
255
|
-
const
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
}
|
|
344
|
+
const makePollTaskStatusFunc = ({
|
|
345
|
+
statusFn,
|
|
346
|
+
statusText,
|
|
347
|
+
statusStrings,
|
|
348
|
+
linkToHubSpot,
|
|
349
|
+
}) => {
|
|
350
|
+
const isTaskComplete = task => {
|
|
351
|
+
if (
|
|
352
|
+
!task[statusText.SUBTASK_KEY].length ||
|
|
353
|
+
task.status === statusText.STATES.FAILURE
|
|
354
|
+
) {
|
|
355
|
+
return true;
|
|
356
|
+
} else if (task.status === statusText.STATES.SUCCESS) {
|
|
357
|
+
return task.isAutoDeployEnabled ? !!task.deployStatusTaskLocator : true;
|
|
358
|
+
}
|
|
359
|
+
};
|
|
271
360
|
|
|
272
|
-
return async (accountId, taskName, taskId
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
return task.isAutoDeployEnabled ? !!task.deployStatusTaskLocator : true;
|
|
278
|
-
}
|
|
279
|
-
};
|
|
361
|
+
return async (accountId, taskName, taskId) => {
|
|
362
|
+
let hubspotLinkText = '';
|
|
363
|
+
if (linkToHubSpot) {
|
|
364
|
+
logger.log(`\n${linkToHubSpot(taskName, taskId, accountId)}\n`);
|
|
365
|
+
}
|
|
280
366
|
|
|
281
367
|
const spinnies = new Spinnies({
|
|
282
368
|
succeedColor: 'white',
|
|
@@ -288,17 +374,23 @@ const makeGetTaskStatus = taskType => {
|
|
|
288
374
|
|
|
289
375
|
const initialTaskStatus = await statusFn(accountId, taskName, taskId);
|
|
290
376
|
|
|
377
|
+
const numOfComponents = initialTaskStatus[statusText.SUBTASK_KEY].length;
|
|
378
|
+
const componentCountText = `\nFound ${numOfComponents} component${
|
|
379
|
+
numOfComponents !== 1 ? 's' : ''
|
|
380
|
+
} in this project ...\n`;
|
|
381
|
+
|
|
291
382
|
spinnies.update('overallTaskStatus', {
|
|
292
|
-
text: statusStrings.INITIALIZE(
|
|
293
|
-
taskName,
|
|
294
|
-
initialTaskStatus[statusText.SUBTASK_KEY].length
|
|
295
|
-
),
|
|
383
|
+
text: `${statusStrings.INITIALIZE(taskName)}${componentCountText}`,
|
|
296
384
|
});
|
|
297
385
|
|
|
298
386
|
for (let subTask of initialTaskStatus[statusText.SUBTASK_KEY]) {
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
387
|
+
const subTaskName = subTask[statusText.SUBTASK_NAME_KEY];
|
|
388
|
+
|
|
389
|
+
spinnies.add(subTaskName, {
|
|
390
|
+
text: `${chalk.bold(subTaskName)} #${taskId} ${
|
|
391
|
+
statusText.STATUS_TEXT[statusText.STATES.ENQUEUED]
|
|
392
|
+
}\n`,
|
|
393
|
+
indent: 2,
|
|
302
394
|
});
|
|
303
395
|
}
|
|
304
396
|
|
|
@@ -312,29 +404,25 @@ const makeGetTaskStatus = taskType => {
|
|
|
312
404
|
|
|
313
405
|
if (spinnies.hasActiveSpinners()) {
|
|
314
406
|
subTaskStatus.forEach(subTask => {
|
|
315
|
-
|
|
407
|
+
const subTaskName = subTask[statusText.SUBTASK_NAME_KEY];
|
|
408
|
+
|
|
409
|
+
if (!spinnies.pick(subTaskName)) {
|
|
316
410
|
return;
|
|
317
411
|
}
|
|
318
412
|
|
|
319
|
-
const updatedText = `${chalk.bold(
|
|
320
|
-
|
|
321
|
-
|
|
413
|
+
const updatedText = `${chalk.bold(subTaskName)} #${taskId} ${
|
|
414
|
+
statusText.STATUS_TEXT[subTask.status]
|
|
415
|
+
}\n`;
|
|
322
416
|
|
|
323
417
|
switch (subTask.status) {
|
|
324
418
|
case statusText.STATES.SUCCESS:
|
|
325
|
-
spinnies.succeed(
|
|
326
|
-
text: updatedText,
|
|
327
|
-
});
|
|
419
|
+
spinnies.succeed(subTaskName, { text: updatedText });
|
|
328
420
|
break;
|
|
329
421
|
case statusText.STATES.FAILURE:
|
|
330
|
-
spinnies.fail(
|
|
331
|
-
text: updatedText,
|
|
332
|
-
});
|
|
422
|
+
spinnies.fail(subTaskName, { text: updatedText });
|
|
333
423
|
break;
|
|
334
424
|
default:
|
|
335
|
-
spinnies.update(
|
|
336
|
-
text: updatedText,
|
|
337
|
-
});
|
|
425
|
+
spinnies.update(subTaskName, { text: updatedText });
|
|
338
426
|
break;
|
|
339
427
|
}
|
|
340
428
|
});
|
|
@@ -346,11 +434,11 @@ const makeGetTaskStatus = taskType => {
|
|
|
346
434
|
|
|
347
435
|
if (status === statusText.STATES.SUCCESS) {
|
|
348
436
|
spinnies.succeed('overallTaskStatus', {
|
|
349
|
-
text: statusStrings.SUCCESS(taskName)
|
|
437
|
+
text: `${statusStrings.SUCCESS(taskName)}${hubspotLinkText}`,
|
|
350
438
|
});
|
|
351
439
|
} else if (status === statusText.STATES.FAILURE) {
|
|
352
440
|
spinnies.fail('overallTaskStatus', {
|
|
353
|
-
text: statusStrings.FAIL(taskName)
|
|
441
|
+
text: `${statusStrings.FAIL(taskName)}${hubspotLinkText}`,
|
|
354
442
|
});
|
|
355
443
|
|
|
356
444
|
const failedSubtask = subTaskStatus.filter(
|
|
@@ -360,7 +448,7 @@ const makeGetTaskStatus = taskType => {
|
|
|
360
448
|
uiLine();
|
|
361
449
|
logger.log(
|
|
362
450
|
`${statusStrings.SUBTASK_FAIL(
|
|
363
|
-
|
|
451
|
+
taskId,
|
|
364
452
|
failedSubtask.length === 1
|
|
365
453
|
? failedSubtask[0][statusText.SUBTASK_NAME_KEY]
|
|
366
454
|
: failedSubtask.length + ' components'
|
|
@@ -388,15 +476,51 @@ const makeGetTaskStatus = taskType => {
|
|
|
388
476
|
};
|
|
389
477
|
};
|
|
390
478
|
|
|
479
|
+
const pollBuildStatus = makePollTaskStatusFunc({
|
|
480
|
+
linkToHubSpot: (projectName, buildId, accountId) =>
|
|
481
|
+
uiLink(
|
|
482
|
+
`View build #${buildId} in HubSpot`,
|
|
483
|
+
getProjectBuildDetailUrl(projectName, buildId, accountId),
|
|
484
|
+
{ useColor: true }
|
|
485
|
+
),
|
|
486
|
+
statusFn: getBuildStatus,
|
|
487
|
+
statusText: PROJECT_BUILD_TEXT,
|
|
488
|
+
statusStrings: {
|
|
489
|
+
INITIALIZE: name => `Building ${chalk.bold(name)}`,
|
|
490
|
+
SUCCESS: name => `Built ${chalk.bold(name)}`,
|
|
491
|
+
FAIL: name => `Failed to build ${chalk.bold(name)}`,
|
|
492
|
+
SUBTASK_FAIL: (taskId, name) =>
|
|
493
|
+
`Build #${taskId} failed because there was a problem\nbuilding ${chalk.bold(
|
|
494
|
+
name
|
|
495
|
+
)}`,
|
|
496
|
+
},
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
const pollDeployStatus = makePollTaskStatusFunc({
|
|
500
|
+
statusFn: getDeployStatus,
|
|
501
|
+
statusText: PROJECT_DEPLOY_TEXT,
|
|
502
|
+
statusStrings: {
|
|
503
|
+
INITIALIZE: name => `Deploying ${chalk.bold(name)}`,
|
|
504
|
+
SUCCESS: name => `Deployed ${chalk.bold(name)}`,
|
|
505
|
+
FAIL: name => `Failed to deploy ${chalk.bold(name)}`,
|
|
506
|
+
SUBTASK_FAIL: (taskId, name) =>
|
|
507
|
+
`Deploy for build #${taskId} failed because there was a\nproblem deploying ${chalk.bold(
|
|
508
|
+
name
|
|
509
|
+
)}`,
|
|
510
|
+
},
|
|
511
|
+
});
|
|
512
|
+
|
|
391
513
|
module.exports = {
|
|
392
514
|
writeProjectConfig,
|
|
393
515
|
getProjectConfig,
|
|
394
516
|
getIsInProject,
|
|
517
|
+
handleProjectUpload,
|
|
395
518
|
createProjectConfig,
|
|
396
519
|
validateProjectConfig,
|
|
397
|
-
|
|
520
|
+
showProjectWelcomeMessage,
|
|
398
521
|
getProjectDetailUrl,
|
|
399
|
-
|
|
400
|
-
|
|
522
|
+
getProjectBuildDetailUrl,
|
|
523
|
+
pollBuildStatus,
|
|
524
|
+
pollDeployStatus,
|
|
401
525
|
ensureProjectExists,
|
|
402
526
|
};
|
package/lib/serverlessLogs.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
const https = require('https');
|
|
2
|
-
const readline = require('readline');
|
|
3
2
|
|
|
4
3
|
const { logger } = require('@hubspot/cli-lib/logger');
|
|
5
4
|
const { outputLogs } = require('@hubspot/cli-lib/lib/logs');
|
|
@@ -9,20 +8,12 @@ const {
|
|
|
9
8
|
ApiErrorContext,
|
|
10
9
|
} = require('@hubspot/cli-lib/errorHandlers');
|
|
11
10
|
const { base64EncodeString } = require('@hubspot/cli-lib/lib/encoding');
|
|
11
|
+
const { handleKeypress } = require('@hubspot/cli-lib/lib/process');
|
|
12
|
+
|
|
12
13
|
const { EXIT_CODES } = require('../lib/enums/exitCodes');
|
|
13
14
|
|
|
14
15
|
const TAIL_DELAY = 5000;
|
|
15
16
|
|
|
16
|
-
const handleKeypressToExit = exit => {
|
|
17
|
-
readline.emitKeypressEvents(process.stdin);
|
|
18
|
-
process.stdin.setRawMode(true);
|
|
19
|
-
process.stdin.on('keypress', (str, key) => {
|
|
20
|
-
if (key && ((key.ctrl && key.name == 'c') || key.name === 'escape')) {
|
|
21
|
-
exit(key.name === 'escape' ? 'esc' : 'ctrl+c');
|
|
22
|
-
}
|
|
23
|
-
});
|
|
24
|
-
};
|
|
25
|
-
|
|
26
17
|
const tailLogs = async ({
|
|
27
18
|
accountId,
|
|
28
19
|
compact,
|
|
@@ -76,12 +67,13 @@ const tailLogs = async ({
|
|
|
76
67
|
}, TAIL_DELAY);
|
|
77
68
|
};
|
|
78
69
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
text: `Stopped polling
|
|
82
|
-
|
|
83
|
-
|
|
70
|
+
handleKeypress(key => {
|
|
71
|
+
if ((key.ctrl && key.name == 'c') || key.name === 'escape') {
|
|
72
|
+
spinnies.succeed('tailLogs', { text: `Stopped polling` });
|
|
73
|
+
process.exit(EXIT_CODES.SUCCESS);
|
|
74
|
+
}
|
|
84
75
|
});
|
|
76
|
+
|
|
85
77
|
await tail(initialAfter);
|
|
86
78
|
};
|
|
87
79
|
|
package/lib/ui.js
CHANGED
|
@@ -22,7 +22,14 @@ const uiLine = () => {
|
|
|
22
22
|
*/
|
|
23
23
|
const uiLink = (linkText, url, options = {}) => {
|
|
24
24
|
if (supportsHyperlinks.stdout) {
|
|
25
|
-
|
|
25
|
+
const result = [
|
|
26
|
+
'\u001B]8;;',
|
|
27
|
+
url,
|
|
28
|
+
'\u0007',
|
|
29
|
+
linkText,
|
|
30
|
+
'\u001B]8;;\u0007',
|
|
31
|
+
].join('');
|
|
32
|
+
return options.useColor ? chalk.cyan(result) : result;
|
|
26
33
|
} else {
|
|
27
34
|
return options.fallback ? `${linkText}: ${url}` : linkText;
|
|
28
35
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hubspot/cli",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.12-beta.2",
|
|
4
4
|
"description": "CLI for working with HubSpot",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
"url": "https://github.com/HubSpot/hubspot-cms-tools"
|
|
9
9
|
},
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"@hubspot/cli-lib": "^3.0.
|
|
12
|
-
"@hubspot/serverless-dev-runtime": "^3.0.
|
|
11
|
+
"@hubspot/cli-lib": "^3.0.12-beta.2",
|
|
12
|
+
"@hubspot/serverless-dev-runtime": "^3.0.12-beta.2",
|
|
13
13
|
"archiver": "^5.3.0",
|
|
14
14
|
"chalk": "^4.1.2",
|
|
15
15
|
"express": "^4.17.1",
|
|
@@ -39,5 +39,5 @@
|
|
|
39
39
|
"publishConfig": {
|
|
40
40
|
"access": "public"
|
|
41
41
|
},
|
|
42
|
-
"gitHead": "
|
|
42
|
+
"gitHead": "7ef17e48b31d6cc9bff3a0f7ab7857df4b82f14c"
|
|
43
43
|
}
|