@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.
- package/commands/accounts/list.js +4 -1
- package/commands/project/watch.js +10 -5
- package/commands/sandbox/create.js +3 -0
- package/commands/sandbox/delete.js +17 -3
- package/commands/secrets/addSecret.js +2 -1
- package/commands/secrets/deleteSecret.js +2 -1
- package/commands/secrets/listSecrets.js +2 -1
- package/commands/secrets/updateSecret.js +3 -1
- package/commands/theme/marketplace-validate.js +97 -59
- package/lib/prompts/accountsPrompt.js +3 -8
- package/lib/prompts/sandboxesPrompt.js +16 -1
- package/lib/validators/__tests__/validatorTestUtils.js +0 -28
- package/lib/validators/applyValidators.js +1 -17
- package/lib/validators/constants.js +0 -5
- package/lib/validators/index.js +0 -13
- package/package.json +4 -4
- package/lib/validators/__tests__/AbsoluteValidator.js +0 -28
- package/lib/validators/__tests__/TemplateValidator.js +0 -101
- package/lib/validators/__tests__/ThemeConfigValidator.js +0 -70
- package/lib/validators/__tests__/ThemeDependencyValidator.js +0 -89
- package/lib/validators/__tests__/ThemeModuleValidator.js +0 -84
- package/lib/validators/marketplaceValidators/AbsoluteValidator.js +0 -50
- package/lib/validators/marketplaceValidators/theme/SectionValidator.js +0 -96
- package/lib/validators/marketplaceValidators/theme/TemplateValidator.js +0 -175
- package/lib/validators/marketplaceValidators/theme/ThemeConfigValidator.js +0 -106
- package/lib/validators/marketplaceValidators/theme/ThemeDependencyValidator.js +0 -126
- 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
|
-
});
|