@hubspot/cli 4.0.2-beta.6 → 4.1.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.
Files changed (27) hide show
  1. package/commands/accounts/list.js +4 -1
  2. package/commands/project/watch.js +10 -5
  3. package/commands/sandbox/create.js +3 -0
  4. package/commands/sandbox/delete.js +17 -3
  5. package/commands/secrets/addSecret.js +2 -1
  6. package/commands/secrets/deleteSecret.js +2 -1
  7. package/commands/secrets/listSecrets.js +2 -1
  8. package/commands/secrets/updateSecret.js +3 -1
  9. package/commands/theme/marketplace-validate.js +97 -59
  10. package/lib/prompts/accountsPrompt.js +3 -8
  11. package/lib/prompts/sandboxesPrompt.js +16 -1
  12. package/lib/validators/__tests__/validatorTestUtils.js +0 -28
  13. package/lib/validators/applyValidators.js +1 -17
  14. package/lib/validators/constants.js +0 -5
  15. package/lib/validators/index.js +0 -13
  16. package/package.json +4 -4
  17. package/lib/validators/__tests__/AbsoluteValidator.js +0 -28
  18. package/lib/validators/__tests__/TemplateValidator.js +0 -101
  19. package/lib/validators/__tests__/ThemeConfigValidator.js +0 -70
  20. package/lib/validators/__tests__/ThemeDependencyValidator.js +0 -89
  21. package/lib/validators/__tests__/ThemeModuleValidator.js +0 -84
  22. package/lib/validators/marketplaceValidators/AbsoluteValidator.js +0 -50
  23. package/lib/validators/marketplaceValidators/theme/SectionValidator.js +0 -96
  24. package/lib/validators/marketplaceValidators/theme/TemplateValidator.js +0 -175
  25. package/lib/validators/marketplaceValidators/theme/ThemeConfigValidator.js +0 -106
  26. package/lib/validators/marketplaceValidators/theme/ThemeDependencyValidator.js +0 -126
  27. package/lib/validators/marketplaceValidators/theme/ThemeModuleValidator.js +0 -117
@@ -1,106 +0,0 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
-
4
- const { isRelativePath } = require('@hubspot/cli-lib/path');
5
- const AbsoluteValidator = require('../AbsoluteValidator');
6
- const { VALIDATOR_KEYS } = require('../../constants');
7
-
8
- class ThemeValidator extends AbsoluteValidator {
9
- constructor(options) {
10
- super(options);
11
-
12
- this.errors = {
13
- MISSING_THEME_JSON: {
14
- key: 'missingThemeJSON',
15
- getCopy: () =>
16
- 'Missing the theme.json file. This file is required in all themes',
17
- },
18
- INVALID_THEME_JSON: {
19
- key: 'invalidThemeJSON',
20
- getCopy: ({ filePath }) => `Invalid json in the ${filePath} file`,
21
- },
22
- MISSING_LABEL: {
23
- key: 'missingLabel',
24
- getCopy: ({ filePath }) =>
25
- `Missing required field in ${filePath}. The "label" field is required`,
26
- },
27
- MISSING_SCREENSHOT_PATH: {
28
- key: 'missingScreenshotPath',
29
- getCopy: ({ filePath }) =>
30
- `Missing required field in ${filePath}. The "screenshot_path" field is required`,
31
- },
32
- ABSOLUTE_SCREENSHOT_PATH: {
33
- key: 'absoluteScreenshotPath',
34
- getCopy: ({ fieldPath }) =>
35
- `Relative path required. The path for "screenshot_path" in ${fieldPath} must be relative`,
36
- },
37
- MISSING_SCREENSHOT: {
38
- key: 'missingScreenshot',
39
- getCopy: ({ fieldPath }) =>
40
- `File not found. No file exists for the provided "screenshot_path" in ${fieldPath}`,
41
- },
42
- };
43
- }
44
-
45
- // Validates:
46
- // - Theme contains a theme.json file at the theme root dir
47
- // - theme.json file contains valid json
48
- // - theme.json file has a "label" field
49
- // - theme.json file has a relative path for "screenshot" field that resolves
50
- validate(files) {
51
- let validationErrors = [];
52
- const themeJSONFile = files.find(filePath => {
53
- // Check for theme.json at the theme root
54
- const fileName = this.getRelativePath(filePath);
55
- return fileName === 'theme.json';
56
- });
57
-
58
- if (!themeJSONFile) {
59
- validationErrors.push(this.getError(this.errors.MISSING_THEME_JSON));
60
- } else {
61
- let themeJSON;
62
-
63
- try {
64
- themeJSON = JSON.parse(fs.readFileSync(themeJSONFile));
65
- } catch (err) {
66
- validationErrors.push(
67
- this.getError(this.errors.INVALID_THEME_JSON, themeJSONFile)
68
- );
69
- }
70
-
71
- if (themeJSON) {
72
- if (!themeJSON.label) {
73
- validationErrors.push(
74
- this.getError(this.errors.MISSING_LABEL, themeJSONFile)
75
- );
76
- }
77
- if (!themeJSON.screenshot_path) {
78
- validationErrors.push(
79
- this.getError(this.errors.MISSING_SCREENSHOT_PATH, themeJSONFile)
80
- );
81
- } else if (!isRelativePath(themeJSON.screenshot_path)) {
82
- validationErrors.push(
83
- this.getError(this.errors.ABSOLUTE_SCREENSHOT_PATH, themeJSONFile)
84
- );
85
- } else {
86
- const absoluteScreenshotPath = path.resolve(
87
- this._absolutePath,
88
- themeJSON.screenshot_path
89
- );
90
- if (!fs.existsSync(absoluteScreenshotPath)) {
91
- validationErrors.push(
92
- this.getError(this.errors.MISSING_SCREENSHOT, themeJSONFile)
93
- );
94
- }
95
- }
96
- }
97
- }
98
-
99
- return validationErrors;
100
- }
101
- }
102
-
103
- module.exports = new ThemeValidator({
104
- name: 'Theme config',
105
- key: VALIDATOR_KEYS.themeConfig,
106
- });
@@ -1,126 +0,0 @@
1
- const fs = require('fs-extra');
2
- const path = require('path');
3
-
4
- const { logger } = require('@hubspot/cli-lib/logger');
5
- const {
6
- HUBL_EXTENSIONS,
7
- HUBSPOT_FOLDER,
8
- } = require('@hubspot/cli-lib/lib/constants');
9
- const {
10
- fetchTemplateDependencies,
11
- } = require('@hubspot/cli-lib/api/marketplace');
12
- const { getExt, isRelativePath } = require('@hubspot/cli-lib/path');
13
-
14
- const AbsoluteValidator = require('../AbsoluteValidator');
15
- const { VALIDATOR_KEYS } = require('../../constants');
16
-
17
- class ThemeDependencyValidator extends AbsoluteValidator {
18
- constructor(options) {
19
- super(options);
20
-
21
- this.errors = {
22
- FAILED_TO_FETCH_DEPS: {
23
- key: 'failedDepFetch',
24
- getCopy: ({ filePath }) =>
25
- `Internal Error. Failed to fetch dependencies for ${filePath}. Please try again`,
26
- },
27
- EXTERNAL_DEPENDENCY: {
28
- key: 'externalDependency',
29
- getCopy: ({ filePath, referencedFilePath }) =>
30
- `External dependency. ${filePath} references a file (${referencedFilePath}) that is outside of the theme`,
31
- },
32
- ABSOLUTE_DEPENDENCY_PATH: {
33
- key: 'absoluteDependencyPath',
34
- getCopy: ({ filePath, referencedFilePath }) =>
35
- `Relative path required. ${filePath} references a file (${referencedFilePath}) using an absolute path`,
36
- },
37
- };
38
- }
39
-
40
- failedToFetchDependencies(err, file, validationErrors) {
41
- logger.debug(`Failed to fetch dependencies for ${file}: `, err.error);
42
-
43
- validationErrors.push(
44
- this.getError(this.errors.FAILED_TO_FETCH_DEPS, file)
45
- );
46
- }
47
-
48
- async getAllDependenciesByFile(files, accountId, validationErrors) {
49
- return Promise.all(
50
- files
51
- .filter(file => HUBL_EXTENSIONS.has(getExt(file)))
52
- .map(async file => {
53
- const source = await fs.readFile(file, { encoding: 'utf8' });
54
- let deps = [];
55
- if (!(source && source.trim())) {
56
- return { file, deps };
57
- }
58
- const file_deps = await fetchTemplateDependencies(
59
- accountId,
60
- source
61
- ).catch(err => {
62
- this.failedToFetchDependencies(err, file, validationErrors);
63
- return null;
64
- });
65
- if (file_deps) {
66
- deps = file_deps.dependencies || [];
67
- }
68
- return { file, deps };
69
- })
70
- );
71
- }
72
-
73
- isExternalDep(file, relativeDepPath) {
74
- // Get dir of file that references the dep
75
- const { dir } = path.parse(file);
76
- // Use dir to get the dep's absolute path
77
- const absoluteDepPath = path.resolve(dir, relativeDepPath);
78
- // Get relative path to dep using theme absolute path and dep absolute path
79
- const relativePath = this.getRelativePath(absoluteDepPath);
80
- // Check that dep is not within the theme
81
- return relativePath && relativePath.startsWith('..');
82
- }
83
-
84
- // Validates:
85
- // - Theme does not contain external dependencies
86
- // - All paths are either @hubspot or relative
87
- async validate(files, accountId) {
88
- let validationErrors = [];
89
-
90
- const dependencyData = await this.getAllDependenciesByFile(
91
- files,
92
- accountId,
93
- validationErrors
94
- );
95
-
96
- dependencyData.forEach(depData => {
97
- const { file, deps } = depData;
98
- deps.forEach(dependency => {
99
- // Ignore:
100
- // - Hubspot modules
101
- if (!dependency.startsWith(HUBSPOT_FOLDER)) {
102
- if (!isRelativePath(dependency)) {
103
- validationErrors.push(
104
- this.getError(this.errors.ABSOLUTE_DEPENDENCY_PATH, file, {
105
- referencedFilePath: dependency,
106
- })
107
- );
108
- } else if (this.isExternalDep(file, dependency)) {
109
- validationErrors.push(
110
- this.getError(this.errors.EXTERNAL_DEPENDENCY, file, {
111
- referencedFilePath: dependency,
112
- })
113
- );
114
- }
115
- }
116
- });
117
- });
118
-
119
- return validationErrors;
120
- }
121
- }
122
-
123
- module.exports = new ThemeDependencyValidator({
124
- name: 'Theme dependency',
125
- key: VALIDATOR_KEYS.themeDependency,
126
- });
@@ -1,117 +0,0 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
-
4
- const { isModuleFolderChild } = require('@hubspot/cli-lib/modules');
5
- const AbsoluteValidator = require('../AbsoluteValidator');
6
- const { VALIDATOR_KEYS } = require('../../constants');
7
-
8
- const MODULE_LIMIT = 50;
9
-
10
- class ThemeModuleValidator extends AbsoluteValidator {
11
- constructor(options) {
12
- super(options);
13
-
14
- this.errors = {
15
- LIMIT_EXCEEDED: {
16
- key: 'limitExceeded',
17
- getCopy: ({ limit, total }) =>
18
- `Module limit exceeded. Themes can only have ${limit} modules, but this theme has ${total}`,
19
- },
20
- MISSING_META_JSON: {
21
- key: 'missingMetaJSON',
22
- getCopy: ({ filePath }) =>
23
- `Module ${filePath} is missing the meta.json file`,
24
- },
25
- INVALID_META_JSON: {
26
- key: 'invalidMetaJSON',
27
- getCopy: ({ filePath }) =>
28
- `Module ${filePath} has invalid json in the meta.json file`,
29
- },
30
- MISSING_LABEL: {
31
- key: 'missingLabel',
32
- getCopy: ({ filePath }) =>
33
- `Missing required property for ${filePath}. The meta.json file is missing the "label" property`,
34
- },
35
- MISSING_ICON: {
36
- key: 'missingIcon',
37
- getCopy: ({ filePath }) =>
38
- `Missing required property for ${filePath}. The meta.json file is missing the "icon" property`,
39
- },
40
- };
41
- }
42
-
43
- getUniqueModulesFromFiles(files) {
44
- const uniqueModules = {};
45
-
46
- files.forEach(file => {
47
- if (isModuleFolderChild({ isLocal: true, path: file }, true)) {
48
- const { base, dir } = path.parse(file);
49
- if (!uniqueModules[dir]) {
50
- uniqueModules[dir] = {};
51
- }
52
- uniqueModules[dir][base] = file;
53
- }
54
- });
55
- return uniqueModules;
56
- }
57
-
58
- // Validates:
59
- // - Theme does not have more than MODULE_LIMIT modules
60
- // - Each module folder contains a meta.json file
61
- // - Each module meta.json file contains valid json
62
- // - Each module meta.json file has a "label" field
63
- // - Each module meta.json file has an "icon" field
64
- validate(files) {
65
- let validationErrors = [];
66
- const uniqueModules = this.getUniqueModulesFromFiles(files);
67
- const numModules = Object.keys(uniqueModules).length;
68
-
69
- if (numModules > MODULE_LIMIT) {
70
- validationErrors.push(
71
- this.getError(this.errors.LIMIT_EXCEEDED, null, {
72
- limit: MODULE_LIMIT,
73
- total: numModules,
74
- })
75
- );
76
- }
77
-
78
- Object.keys(uniqueModules).forEach(modulePath => {
79
- const metaJSONFile = uniqueModules[modulePath]['meta.json'];
80
-
81
- if (!metaJSONFile) {
82
- validationErrors.push(
83
- this.getError(this.errors.MISSING_META_JSON, modulePath)
84
- );
85
- } else {
86
- let metaJSON;
87
- try {
88
- metaJSON = JSON.parse(fs.readFileSync(metaJSONFile));
89
- } catch (err) {
90
- validationErrors.push(
91
- this.getError(this.errors.INVALID_META_JSON, modulePath)
92
- );
93
- }
94
-
95
- if (metaJSON) {
96
- if (!metaJSON.label) {
97
- validationErrors.push(
98
- this.getError(this.errors.MISSING_LABEL, modulePath)
99
- );
100
- }
101
- if (!metaJSON.icon) {
102
- validationErrors.push(
103
- this.getError(this.errors.MISSING_ICON, modulePath)
104
- );
105
- }
106
- }
107
- }
108
- });
109
-
110
- return validationErrors;
111
- }
112
- }
113
-
114
- module.exports = new ThemeModuleValidator({
115
- name: 'Theme modules',
116
- key: VALIDATOR_KEYS.themeModule,
117
- });