@shoper/cli 0.1.0-33 → 0.1.0-35
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/build/cli/core/cli_setup.js +3 -1
- package/build/cli/features/controls/controls_constants.js +12 -0
- package/build/cli/features/controls/{controls_dto_to_ui_mappers.js → controls_dto_mappers.js} +21 -5
- package/build/cli/features/controls/ui/controls_mappers.js +22 -4
- package/build/cli/features/controls/ui/form.js +1 -2
- package/build/cli/features/controls/ui/form_constants.js +7 -13
- package/build/theme/commands/publish/theme_publish_command.js +92 -0
- package/build/theme/commands/pull/theme_pull_command.js +6 -4
- package/build/theme/commands/theme_commands_constants.js +2 -1
- package/build/theme/features/theme/actions/theme_actions_constants.js +1 -1
- package/build/theme/features/theme/merge/service/theme_merge_service.js +12 -6
- package/build/theme/features/theme/push/service/theme_push_service.js +55 -48
- package/build/theme/features/theme/skinstore/api/theme_skinstore_api.js +4 -2
- package/build/theme/features/theme/skinstore/service/theme_skinstore_service.js +3 -2
- package/build/theme/features/theme/skinstore/theme_publish_constants.js +2 -0
- package/build/theme/features/theme/skinstore/theme_skinstore_initialzier.js +20 -0
- package/build/theme/features/theme/utils/files_structure/theme_files_structure_utils.js +7 -1
- package/build/theme/features/theme/utils/resources/theme_resources_with_id_directory_utils.js +1 -1
- package/build/theme/index.js +3 -1
- package/package.json +2 -2
|
@@ -15,6 +15,7 @@ import { ThemeMergeInitializer } from '../../theme/features/theme/merge/theme_me
|
|
|
15
15
|
import { ThemeActionsInitializer } from '../../theme/features/theme/actions/theme_actions_initializer.js';
|
|
16
16
|
import { ThemePushInitializer } from '../../theme/features/theme/push/theme_push_initializer.js';
|
|
17
17
|
import { ThemeDeleteInitializer } from '../../theme/features/theme/delete/theme_delete_initalizer.js';
|
|
18
|
+
import { ThemeSkinstoreInitializer } from '../../theme/features/theme/skinstore/theme_skinstore_initialzier.js';
|
|
18
19
|
tmp.setGracefulCleanup();
|
|
19
20
|
export const cliSetup = async () => {
|
|
20
21
|
//TODO jakis ładny komuniakt błedu
|
|
@@ -36,7 +37,8 @@ export const cliSetup = async () => {
|
|
|
36
37
|
ThemeMergeInitializer,
|
|
37
38
|
ThemeFetchInitializer,
|
|
38
39
|
ThemePushInitializer,
|
|
39
|
-
ThemeDeleteInitializer
|
|
40
|
+
ThemeDeleteInitializer,
|
|
41
|
+
ThemeSkinstoreInitializer
|
|
40
42
|
],
|
|
41
43
|
options: {
|
|
42
44
|
featuresTracking: false,
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export const CONTROLS_DTO_TYPES = {
|
|
2
|
+
text: 'text',
|
|
3
|
+
number: 'number',
|
|
4
|
+
select: 'select',
|
|
5
|
+
multiSelectDropDown: 'multiSelectDropDown'
|
|
6
|
+
};
|
|
7
|
+
export const CONTROLS_TYPES = {
|
|
8
|
+
text: 'text',
|
|
9
|
+
number: 'number',
|
|
10
|
+
select: 'select',
|
|
11
|
+
multiSelect: 'multiSelect'
|
|
12
|
+
};
|
package/build/cli/features/controls/{controls_dto_to_ui_mappers.js → controls_dto_mappers.js}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CONTROLS_TYPES } from './
|
|
1
|
+
import { CONTROLS_DTO_TYPES, CONTROLS_TYPES } from './controls_constants.js';
|
|
2
2
|
export const toTextControl = ({ validators, label, isRequired, defaultValue, name }) => {
|
|
3
3
|
return {
|
|
4
4
|
type: CONTROLS_TYPES.text,
|
|
@@ -11,7 +11,7 @@ export const toTextControl = ({ validators, label, isRequired, defaultValue, nam
|
|
|
11
11
|
};
|
|
12
12
|
export const toNumberControl = ({ validators, label, isRequired, name }) => {
|
|
13
13
|
return {
|
|
14
|
-
type:
|
|
14
|
+
type: CONTROLS_TYPES.number,
|
|
15
15
|
name,
|
|
16
16
|
label,
|
|
17
17
|
isRequired,
|
|
@@ -20,7 +20,7 @@ export const toNumberControl = ({ validators, label, isRequired, name }) => {
|
|
|
20
20
|
};
|
|
21
21
|
export const toSelectControl = ({ label, isRequired, name, options }) => {
|
|
22
22
|
return {
|
|
23
|
-
type:
|
|
23
|
+
type: CONTROLS_TYPES.select,
|
|
24
24
|
name,
|
|
25
25
|
label,
|
|
26
26
|
isRequired,
|
|
@@ -28,12 +28,28 @@ export const toSelectControl = ({ label, isRequired, name, options }) => {
|
|
|
28
28
|
};
|
|
29
29
|
};
|
|
30
30
|
export const toMultiSelectControl = ({ label, isRequired, name, options }) => {
|
|
31
|
-
//TODO multiple checkboxes
|
|
32
31
|
return {
|
|
33
|
-
type:
|
|
32
|
+
type: CONTROLS_TYPES.multiSelect,
|
|
34
33
|
name,
|
|
35
34
|
label,
|
|
36
35
|
isRequired,
|
|
37
36
|
options: options.selectOptions.map(({ label, key }) => ({ label, value: key }))
|
|
38
37
|
};
|
|
39
38
|
};
|
|
39
|
+
export const toControls = (controls) => {
|
|
40
|
+
return controls.map(toControl);
|
|
41
|
+
};
|
|
42
|
+
export const toControl = (control) => {
|
|
43
|
+
switch (control.type) {
|
|
44
|
+
case CONTROLS_DTO_TYPES.text:
|
|
45
|
+
return toTextControl(control);
|
|
46
|
+
case CONTROLS_DTO_TYPES.number:
|
|
47
|
+
return toNumberControl(control);
|
|
48
|
+
case CONTROLS_DTO_TYPES.select:
|
|
49
|
+
return toSelectControl(control);
|
|
50
|
+
case CONTROLS_DTO_TYPES.multiSelectDropDown:
|
|
51
|
+
return toMultiSelectControl(control);
|
|
52
|
+
default:
|
|
53
|
+
throw new Error(`Unknown control type`);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
import { CONTROLS_TYPES } from '../controls_constants.js';
|
|
2
|
+
const toTextControl = ({ validators, label, isRequired, defaultValue, name }) => {
|
|
2
3
|
return {
|
|
3
4
|
type: 'input',
|
|
4
5
|
name,
|
|
@@ -7,7 +8,7 @@ export const toTextControl = ({ validators, label, isRequired, defaultValue, nam
|
|
|
7
8
|
validate: toInquirerValidate(validators)
|
|
8
9
|
};
|
|
9
10
|
};
|
|
10
|
-
|
|
11
|
+
const toNumberControl = ({ validators, label, isRequired, defaultValue, name }) => {
|
|
11
12
|
return {
|
|
12
13
|
type: 'number',
|
|
13
14
|
name,
|
|
@@ -16,7 +17,7 @@ export const toNumberControl = ({ validators, label, isRequired, defaultValue, n
|
|
|
16
17
|
validate: toInquirerValidate(validators)
|
|
17
18
|
};
|
|
18
19
|
};
|
|
19
|
-
|
|
20
|
+
const toSelectControl = ({ validators, label, isRequired, defaultValue, name, options }) => {
|
|
20
21
|
return {
|
|
21
22
|
type: 'list',
|
|
22
23
|
name,
|
|
@@ -26,7 +27,7 @@ export const toSelectControl = ({ validators, label, isRequired, defaultValue, n
|
|
|
26
27
|
validate: toInquirerValidate(validators)
|
|
27
28
|
};
|
|
28
29
|
};
|
|
29
|
-
|
|
30
|
+
const toMultiSelectControl = ({ validators, label, isRequired, defaultValue, name, options }) => {
|
|
30
31
|
//TODO multiple checkboxes
|
|
31
32
|
return {
|
|
32
33
|
type: 'checkbox',
|
|
@@ -37,6 +38,23 @@ export const toMultiSelectControl = ({ validators, label, isRequired, defaultVal
|
|
|
37
38
|
validate: toInquirerValidate(validators)
|
|
38
39
|
};
|
|
39
40
|
};
|
|
41
|
+
export const toInquirerControls = (controls) => {
|
|
42
|
+
return controls.map(toInquirerControl);
|
|
43
|
+
};
|
|
44
|
+
export const toInquirerControl = (control) => {
|
|
45
|
+
switch (control.type) {
|
|
46
|
+
case CONTROLS_TYPES.text:
|
|
47
|
+
return toTextControl(control);
|
|
48
|
+
case CONTROLS_TYPES.number:
|
|
49
|
+
return toNumberControl(control);
|
|
50
|
+
case CONTROLS_TYPES.select:
|
|
51
|
+
return toSelectControl(control);
|
|
52
|
+
case CONTROLS_TYPES.multiSelect:
|
|
53
|
+
return toMultiSelectControl(control);
|
|
54
|
+
default:
|
|
55
|
+
throw new Error(`Unknown control type`);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
40
58
|
export const toInquirerValidate = (validators) => {
|
|
41
59
|
return (value) => {
|
|
42
60
|
return validators?.find((v) => !v.isValid(value))?.getErrorMessage() ?? true;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import inquirer from 'inquirer';
|
|
2
|
-
import { CONTROL_TYPE_TO_MAPPERS } from './form_constants.js';
|
|
3
2
|
export const Form = ({ controls, onSubmit }) => {
|
|
4
|
-
inquirer.prompt(controls
|
|
3
|
+
inquirer.prompt(controls).then(onSubmit);
|
|
5
4
|
};
|
|
@@ -1,13 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
export const
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
};
|
|
8
|
-
export const CONTROL_TYPE_TO_MAPPERS = {
|
|
9
|
-
[CONTROLS_TYPES.text]: toTextControl,
|
|
10
|
-
[CONTROLS_TYPES.number]: toNumberControl,
|
|
11
|
-
[CONTROLS_TYPES.select]: toSelectControl,
|
|
12
|
-
[CONTROLS_TYPES.multiSelect]: toMultiSelectControl
|
|
13
|
-
};
|
|
1
|
+
export {};
|
|
2
|
+
// export const CONTROL_TYPE_TO_MAPPERS: Record<TControlType, Function> = {
|
|
3
|
+
// [CONTROLS_TYPES.text]: toTextControl,
|
|
4
|
+
// [CONTROLS_TYPES.number]: toNumberControl,
|
|
5
|
+
// [CONTROLS_TYPES.select]: toSelectControl,
|
|
6
|
+
// [CONTROLS_TYPES.multiSelect]: toMultiSelectControl
|
|
7
|
+
// };
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { Args } from '@oclif/core';
|
|
2
|
+
import { BaseThemeCommand } from '../../class/base_theme_command.js';
|
|
3
|
+
import { CLI_AUTH_API_NAME } from '../../../cli/auth/cli_auth_constants.js';
|
|
4
|
+
import { THEME_ACTION_NOT_FOUND_ERROR_CODE, THEME_ACTIONS_API_NAME, THEME_ACTIONS_TYPES } from '../../features/theme/actions/theme_actions_constants.js';
|
|
5
|
+
import { EXECUTION_CONTEXT_API_NAME, EXECUTION_CONTEXTS } from '../../../cli/features/execution_context/execution_context_constants.js';
|
|
6
|
+
import { renderOnce } from '../../../ui/ui_utils.js';
|
|
7
|
+
import { MissingCredentialsError } from '../../../cli/commands/auth/ui/missing_credentials_error.js';
|
|
8
|
+
import React from 'react';
|
|
9
|
+
import { UnpermittedCommandError } from '../ui/unpermitted_command_error.js';
|
|
10
|
+
import { Error } from '../../../ui/message_box/error.js';
|
|
11
|
+
import { Text } from '../../../ui/text.js';
|
|
12
|
+
import { MissingThemeIdError } from '../ui/missing_theme_id_error.js';
|
|
13
|
+
import { THEME_SKINSTORE_API_NAME } from '../../features/theme/skinstore/theme_publish_constants.js';
|
|
14
|
+
import { Form } from '../../../cli/features/controls/ui/form.js';
|
|
15
|
+
export class ThemePublishCommand extends BaseThemeCommand {
|
|
16
|
+
static summary = 'Permanently deletes the specified theme from your store.';
|
|
17
|
+
static description = 'This action cannot be undone, so make sure you really want to remove this theme.\n\nYou can run this command from a specific theme directory (ID not needed) or outside any theme directory (theme ID required).';
|
|
18
|
+
static examples = [
|
|
19
|
+
{
|
|
20
|
+
description: 'This will delete the theme with ID 123 permanently from your store. Make sure you have a backup if needed.',
|
|
21
|
+
command: '<%= config.bin %> <%= command.id %> 123'
|
|
22
|
+
}
|
|
23
|
+
];
|
|
24
|
+
static hidden = true;
|
|
25
|
+
static args = {
|
|
26
|
+
id: Args.string({
|
|
27
|
+
description: 'Theme id',
|
|
28
|
+
name: 'id',
|
|
29
|
+
required: false,
|
|
30
|
+
type: 'string'
|
|
31
|
+
})
|
|
32
|
+
};
|
|
33
|
+
async run() {
|
|
34
|
+
const data = await this.parse(ThemePublishCommand);
|
|
35
|
+
const { args } = data;
|
|
36
|
+
const themeId = args.id;
|
|
37
|
+
const cliAuthApi = this.getApi(CLI_AUTH_API_NAME);
|
|
38
|
+
const executionContextApi = this.getApi(EXECUTION_CONTEXT_API_NAME);
|
|
39
|
+
const credentials = cliAuthApi.getCredentials();
|
|
40
|
+
if (!credentials) {
|
|
41
|
+
renderOnce(React.createElement(MissingCredentialsError, null));
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const executionContext = await executionContextApi.getExecutionContext();
|
|
45
|
+
try {
|
|
46
|
+
let _themeId = themeId;
|
|
47
|
+
if (executionContext.type !== EXECUTION_CONTEXTS.theme && !_themeId) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (executionContext.type === EXECUTION_CONTEXTS.theme) {
|
|
51
|
+
_themeId = _themeId ?? executionContext.themeId;
|
|
52
|
+
}
|
|
53
|
+
if (!_themeId) {
|
|
54
|
+
renderOnce(React.createElement(MissingThemeIdError, null));
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const themeActionsApi = this.getApi(THEME_ACTIONS_API_NAME);
|
|
58
|
+
const themeSkinstoreApi = this.getApi(THEME_SKINSTORE_API_NAME);
|
|
59
|
+
const pushAction = themeActionsApi.getThemeAction({
|
|
60
|
+
actionType: THEME_ACTIONS_TYPES.publishForm,
|
|
61
|
+
themeId: _themeId,
|
|
62
|
+
credentials
|
|
63
|
+
});
|
|
64
|
+
const controls = await themeSkinstoreApi.getPublishFormData({
|
|
65
|
+
actionData: pushAction.data,
|
|
66
|
+
credentials
|
|
67
|
+
});
|
|
68
|
+
Form({
|
|
69
|
+
controls,
|
|
70
|
+
onSubmit: (formData) => {
|
|
71
|
+
console.log('formData', formData);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
this._handleError(err, themeId);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
_handleError(err, themeId) {
|
|
81
|
+
if (err?.code === THEME_ACTION_NOT_FOUND_ERROR_CODE && themeId) {
|
|
82
|
+
renderOnce(React.createElement(UnpermittedCommandError, { themeId: themeId, commandName: "delete" }));
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (err?.message) {
|
|
86
|
+
renderOnce(React.createElement(Error, null,
|
|
87
|
+
React.createElement(Text, null, err.message)));
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
this.error(String(err));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -171,11 +171,13 @@ export class ThemePullCommand extends BaseThemeCommand {
|
|
|
171
171
|
dist: tmpDir
|
|
172
172
|
}
|
|
173
173
|
});
|
|
174
|
-
const
|
|
175
|
-
|
|
176
|
-
|
|
174
|
+
const localModulesPath = join(executionContext.themeRootDir, 'modules');
|
|
175
|
+
const fetchedThemePath = join(tmpDir, name);
|
|
176
|
+
const fetchedModulesPath = join(fetchedThemePath, 'modules');
|
|
177
|
+
if ((await directoryExists(localModulesPath)) && (await directoryExists(fetchedModulesPath)))
|
|
178
|
+
await ThemeResourcesWithIdDirectoryUtils.updateDirectoryNamesOfResourcesWithIdAccordingToLocalThemeNames(localModulesPath, fetchedModulesPath, fetchedThemePath);
|
|
177
179
|
this.#spinner.stop();
|
|
178
|
-
const changes = await themeMergeApi.getChangesBetweenThemes(
|
|
180
|
+
const changes = await themeMergeApi.getChangesBetweenThemes(fetchedThemePath, executionContext.themeRootDir);
|
|
179
181
|
const themeChecksums = new ThemeChecksums(executionContext.themeRootDir);
|
|
180
182
|
if (changes.length && (await themeChecksums.hasThemeBeenModified())) {
|
|
181
183
|
renderOnce(React.createElement(ThemePullUnpublishedChangesWarning, { changes: changes }));
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import FSTree from 'fs-tree-diff';
|
|
2
2
|
import { copyFileSync, getAllDirectoriesNamesInside } from '../../../../../utils/fs/fs_utils.js';
|
|
3
3
|
import walkSync from 'walk-sync';
|
|
4
|
-
import { SHOPER_THEME_METADATA_DIR } from '../../../../constants/directory_contstants.js';
|
|
5
4
|
import { ThemeChecksums } from '../../../../class/checksums/theme_checksums.js';
|
|
5
|
+
import { ThemeFilesStructureUtils } from '../../utils/files_structure/theme_files_structure_utils.js';
|
|
6
|
+
import { SHOPER_THEME_METADATA_DIR } from '../../../../constants/directory_contstants.js';
|
|
7
|
+
import { join, platformSeparator } from '../../../../../utils/path_utils.js';
|
|
6
8
|
export class ThemeMergeService {
|
|
7
9
|
async applyChanges(fromTheme, toTheme, changes) {
|
|
8
10
|
FSTree.applyPatch(fromTheme, toTheme, changes, {
|
|
@@ -24,10 +26,7 @@ export class ThemeMergeService {
|
|
|
24
26
|
});
|
|
25
27
|
const theme1Checksums = new ThemeChecksums(theme1);
|
|
26
28
|
const theme2Checksums = new ThemeChecksums(theme2);
|
|
27
|
-
const
|
|
28
|
-
recursive: false,
|
|
29
|
-
hidden: true
|
|
30
|
-
});
|
|
29
|
+
const userDirectories = await this._getUserRootDirectories(theme2);
|
|
31
30
|
return theme2Tree
|
|
32
31
|
.calculatePatch(theme1Tree, (entryA, entryB) => {
|
|
33
32
|
if (entryA.isDirectory() && entryB.isDirectory())
|
|
@@ -36,7 +35,14 @@ export class ThemeMergeService {
|
|
|
36
35
|
theme2Checksums.getCurrentChecksumFromPathSync(entryB.relativePath));
|
|
37
36
|
})
|
|
38
37
|
.filter(([_, name]) => {
|
|
39
|
-
return !name.startsWith(SHOPER_THEME_METADATA_DIR) &&
|
|
38
|
+
return !name.startsWith(SHOPER_THEME_METADATA_DIR) && !userDirectories.some((userDir) => name.startsWith(userDir));
|
|
40
39
|
});
|
|
41
40
|
}
|
|
41
|
+
async _getUserRootDirectories(themeDir) {
|
|
42
|
+
const filesStructure = await ThemeFilesStructureUtils.getThemeRootDirectories(themeDir);
|
|
43
|
+
return (await getAllDirectoriesNamesInside(themeDir, {
|
|
44
|
+
recursive: false,
|
|
45
|
+
hidden: true
|
|
46
|
+
})).filter((directory) => !filesStructure.includes(join(directory, platformSeparator)));
|
|
47
|
+
}
|
|
42
48
|
}
|
|
@@ -25,66 +25,73 @@ export class ThemePushService {
|
|
|
25
25
|
}
|
|
26
26
|
async push({ pushAction, filesStructure, credentials, executionContext, themeChecksums }) {
|
|
27
27
|
const { path: tmpDir } = await tmp.dir({ unsafeCleanup: true });
|
|
28
|
-
|
|
28
|
+
const themeRootDir = executionContext.themeRootDir;
|
|
29
|
+
if (await themeChecksums.hasThemeFileBeenCreated(ThemePublishUtils.getSkinStoreSettingsFilePath(themeRootDir)))
|
|
29
30
|
throw ThemePushErrorsFactory.createErrorWhilePushingUnpublishedThemeWithSkinstoreData(credentials.shopUrl);
|
|
30
|
-
const { uploadData, localFiles } = await this._getActionDataForFilesToUpload({
|
|
31
|
-
pushAction,
|
|
32
|
-
filesStructure,
|
|
33
|
-
executionContext,
|
|
34
|
-
themeChecksums
|
|
35
|
-
});
|
|
36
|
-
if (uploadData.length) {
|
|
37
|
-
await this._uploadThemeFiles({
|
|
38
|
-
filesToUpload: uploadData,
|
|
39
|
-
credentials,
|
|
40
|
-
localFiles,
|
|
41
|
-
themeRootDir: executionContext.themeRootDir
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
else {
|
|
45
|
-
await this._createAFilesListFile(executionContext.themeRootDir, localFiles);
|
|
46
|
-
}
|
|
47
|
-
const themeArchivePath = join(tmpDir, `${uuid()}.zip`);
|
|
48
31
|
try {
|
|
32
|
+
const { uploadData, localFiles } = await this._getActionDataForFilesToUpload({
|
|
33
|
+
pushAction,
|
|
34
|
+
filesStructure,
|
|
35
|
+
executionContext,
|
|
36
|
+
themeChecksums
|
|
37
|
+
});
|
|
38
|
+
if (uploadData.length) {
|
|
39
|
+
const { newFiles } = await this._uploadThemeFiles({
|
|
40
|
+
filesToUpload: uploadData,
|
|
41
|
+
credentials,
|
|
42
|
+
localFiles,
|
|
43
|
+
themeRootDir
|
|
44
|
+
});
|
|
45
|
+
await this._createAFilesListFile(themeRootDir, newFiles);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
await this._createAFilesListFile(themeRootDir, localFiles);
|
|
49
|
+
}
|
|
50
|
+
const themeArchivePath = join(tmpDir, `${uuid()}.zip`);
|
|
49
51
|
await this._createThemeArchive({
|
|
50
|
-
themeRootDir:
|
|
52
|
+
themeRootDir: themeRootDir,
|
|
51
53
|
filesToArchive: ThemeActionsUtils.getFilesGlobsThatMatchesActionName({
|
|
52
54
|
actionType: THEME_ACTIONS_TYPES.push,
|
|
53
55
|
actionValue: THEME_WILDCARD_ACTION_NAME,
|
|
54
56
|
filesStructure
|
|
55
57
|
}),
|
|
56
|
-
dist: themeArchivePath
|
|
58
|
+
dist: themeArchivePath,
|
|
59
|
+
credentials
|
|
60
|
+
});
|
|
61
|
+
const { resources, modules } = await this._uploadThemeArchive({
|
|
62
|
+
themeArchivePath,
|
|
63
|
+
credentials,
|
|
64
|
+
pushAction
|
|
65
|
+
});
|
|
66
|
+
if (modules)
|
|
67
|
+
await this._updateDataForNewCreatedModules({ modules, themeRootDir });
|
|
68
|
+
if (resources) {
|
|
69
|
+
await removeOldResources(themeRootDir, resources);
|
|
70
|
+
await this.#themeFetchApi.fetchResources(credentials.shopUrl, themeRootDir, resources);
|
|
71
|
+
}
|
|
72
|
+
await themeChecksums.updateAllChecksums();
|
|
73
|
+
}
|
|
74
|
+
finally {
|
|
75
|
+
await removeFile(join(themeRootDir, THEME_FILES_LIST_FILE_NAME));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
async _createThemeArchive({ themeRootDir, filesToArchive, dist, credentials }) {
|
|
79
|
+
try {
|
|
80
|
+
const filesInThemeDirectory = await globs(filesToArchive, {
|
|
81
|
+
suppressErrors: true,
|
|
82
|
+
onlyFiles: true,
|
|
83
|
+
cwd: themeRootDir
|
|
84
|
+
});
|
|
85
|
+
await this._formatJsonFiles(themeRootDir, filesInThemeDirectory);
|
|
86
|
+
return createZip({
|
|
87
|
+
files: filesInThemeDirectory,
|
|
88
|
+
baseDir: themeRootDir,
|
|
89
|
+
dist
|
|
57
90
|
});
|
|
58
91
|
}
|
|
59
92
|
catch (err) {
|
|
60
93
|
throw ThemePushErrorsFactory.createErrorWhileCreatingThemeArchive(credentials.shopUrl, err);
|
|
61
94
|
}
|
|
62
|
-
const { resources, modules } = await this._uploadThemeArchive({
|
|
63
|
-
themeArchivePath,
|
|
64
|
-
credentials,
|
|
65
|
-
pushAction
|
|
66
|
-
});
|
|
67
|
-
if (modules)
|
|
68
|
-
await this._updateDataForNewCreatedModules({ modules, themeRootDir: executionContext.themeRootDir });
|
|
69
|
-
if (resources) {
|
|
70
|
-
await removeOldResources(executionContext.themeRootDir, resources);
|
|
71
|
-
await this.#themeFetchApi.fetchResources(credentials.shopUrl, executionContext.themeRootDir, resources);
|
|
72
|
-
}
|
|
73
|
-
await removeFile(join(executionContext.themeRootDir, THEME_FILES_LIST_FILE_NAME));
|
|
74
|
-
await themeChecksums.updateAllChecksums();
|
|
75
|
-
}
|
|
76
|
-
async _createThemeArchive({ themeRootDir, filesToArchive, dist }) {
|
|
77
|
-
const filesInThemeDirectory = await globs(filesToArchive, {
|
|
78
|
-
suppressErrors: true,
|
|
79
|
-
onlyFiles: true,
|
|
80
|
-
cwd: themeRootDir
|
|
81
|
-
});
|
|
82
|
-
await this._formatJsonFiles(themeRootDir, filesInThemeDirectory);
|
|
83
|
-
return createZip({
|
|
84
|
-
files: filesInThemeDirectory,
|
|
85
|
-
baseDir: themeRootDir,
|
|
86
|
-
dist
|
|
87
|
-
});
|
|
88
95
|
}
|
|
89
96
|
async _uploadThemeArchive({ themeArchivePath, credentials, pushAction }) {
|
|
90
97
|
try {
|
|
@@ -116,7 +123,7 @@ export class ThemePushService {
|
|
|
116
123
|
await ThemeImagesUtils.removeUploadedOriginalFiles(themeRootDir, uploadedImageData);
|
|
117
124
|
if (rejectedImageData.length)
|
|
118
125
|
await this._removeUploadedThemeFiles(rejectedImageData, themeRootDir);
|
|
119
|
-
|
|
126
|
+
return { newFiles: newFilesList };
|
|
120
127
|
}
|
|
121
128
|
catch (err) {
|
|
122
129
|
throw ThemePushErrorsFactory.createErrorWhileUploadingThemeFiles(credentials.shopUrl, err);
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { FeatureApi } from '@dreamcommerce/star_core';
|
|
2
|
+
import { THEME_SKINSTORE_API_NAME } from '../theme_publish_constants.js';
|
|
2
3
|
export class ThemeSkinstoreApi extends FeatureApi {
|
|
4
|
+
moduleName = THEME_SKINSTORE_API_NAME;
|
|
3
5
|
#service;
|
|
4
6
|
constructor(service) {
|
|
5
7
|
super();
|
|
6
8
|
this.#service = service;
|
|
7
9
|
}
|
|
8
|
-
async getPublishFormData() {
|
|
9
|
-
|
|
10
|
+
async getPublishFormData(props) {
|
|
11
|
+
return this.#service.getPublishFormData(props);
|
|
10
12
|
}
|
|
11
13
|
async publish(themeId) {
|
|
12
14
|
// return this.#service.publish(themeId);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { STATUS_CODES } from '@dreamcommerce/star_core';
|
|
2
2
|
import { HttpErrorsFactory } from '../../../../../cli/class/errors/http/http_errors_factory.js';
|
|
3
3
|
import { DownloadFileErrorsFactory } from '../../../../../utils/download_file/download_file_errors_factory.js';
|
|
4
|
+
import { toControls } from '../../../../../cli/features/controls/controls_dto_mappers.js';
|
|
4
5
|
export class ThemeSkinstoreService {
|
|
5
6
|
#httpApi;
|
|
6
7
|
constructor(httpApi) {
|
|
@@ -11,8 +12,8 @@ export class ThemeSkinstoreService {
|
|
|
11
12
|
const { response: request } = this.#httpApi.getPublishFormData({ actionData, shopUrl: credentials.shopUrl });
|
|
12
13
|
const response = await request;
|
|
13
14
|
if (response?.status !== STATUS_CODES.ok)
|
|
14
|
-
|
|
15
|
-
return response?.data;
|
|
15
|
+
throw response;
|
|
16
|
+
return response?.data ? toControls(response.data) : [];
|
|
16
17
|
}
|
|
17
18
|
catch (err) {
|
|
18
19
|
//TODO to basic class
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { FEATURE_CORES_TYPES, HTTP_REQUESTER_API_NAME, SyncFeatureInitializer } from '@dreamcommerce/star_core';
|
|
2
|
+
import { THEME_SKINSTORE_FEATURE_NAME } from './theme_publish_constants.js';
|
|
3
|
+
import { ThemeSkinstoreService } from './service/theme_skinstore_service.js';
|
|
4
|
+
import { ThemeSkinstoreHttpApi } from './http/theme_skinstore_http_api.js';
|
|
5
|
+
import { ThemeSkinstoreApi } from './api/theme_skinstore_api.js';
|
|
6
|
+
export class ThemeSkinstoreInitializer extends SyncFeatureInitializer {
|
|
7
|
+
static featureName = THEME_SKINSTORE_FEATURE_NAME;
|
|
8
|
+
init() {
|
|
9
|
+
const httpApi = this.getApiSync(HTTP_REQUESTER_API_NAME);
|
|
10
|
+
const service = new ThemeSkinstoreService(new ThemeSkinstoreHttpApi(httpApi));
|
|
11
|
+
return {
|
|
12
|
+
cores: [
|
|
13
|
+
{
|
|
14
|
+
type: FEATURE_CORES_TYPES.api,
|
|
15
|
+
instance: new ThemeSkinstoreApi(service)
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { readJSONFile, writeJSONFile } from '../../../../../utils/fs/fs_utils.js';
|
|
2
|
-
import { join, mapKeysPathsToWindowPlatform } from '../../../../../utils/path_utils.js';
|
|
2
|
+
import { join, looksLikeDirectory, mapKeysPathsToWindowPlatform } from '../../../../../utils/path_utils.js';
|
|
3
3
|
import { SHOPER_THEME_METADATA_DIR } from '../../../../constants/directory_contstants.js';
|
|
4
4
|
import { THEME_FILES_STRUCTURE_FILE_NAME } from '../../theme_constants.js';
|
|
5
5
|
import { isWindowsOs } from '../../../../../utils/platform_utils.js';
|
|
@@ -31,4 +31,10 @@ export class ThemeFilesStructureUtils {
|
|
|
31
31
|
rootDirectory
|
|
32
32
|
});
|
|
33
33
|
}
|
|
34
|
+
static async getThemeRootDirectories(themeDirectory) {
|
|
35
|
+
const filesStructure = await ThemeFilesStructureUtils.getThemeFilesStructure(themeDirectory);
|
|
36
|
+
return Object.keys(filesStructure).filter((path) => {
|
|
37
|
+
return looksLikeDirectory(path);
|
|
38
|
+
});
|
|
39
|
+
}
|
|
34
40
|
}
|
package/build/theme/features/theme/utils/resources/theme_resources_with_id_directory_utils.js
CHANGED
|
@@ -3,7 +3,7 @@ import walkSync from 'walk-sync';
|
|
|
3
3
|
import { THEME_FILES_OPERATIONS } from '../../merge/theme_merge_constants.js';
|
|
4
4
|
import { fileExists, readJSONFile, renameFile } from '../../../../../utils/fs/fs_utils.js';
|
|
5
5
|
import { join } from '../../../../../utils/path_utils.js';
|
|
6
|
-
import { ThemeChecksums } from '
|
|
6
|
+
import { ThemeChecksums } from '../../../../class/checksums/theme_checksums.js';
|
|
7
7
|
export class ThemeResourcesWithIdDirectoryUtils {
|
|
8
8
|
static async updateDirectoryNamesOfResourcesWithIdAccordingToLocalThemeNames(localResourcesDir, remoteResourcesDir, remoteThemeDir) {
|
|
9
9
|
const localThemeTree = new FSTree({
|
package/build/theme/index.js
CHANGED
|
@@ -7,6 +7,7 @@ import { ThemeShowChangesCommand } from './commands/theme_show_changes_command.j
|
|
|
7
7
|
import { ThemeVerifyCommand } from './commands/theme_verify_command.js';
|
|
8
8
|
import { ThemeInfoCommand } from './commands/info/theme_info_command.js';
|
|
9
9
|
import { ThemeDeleteCommand } from './commands/delete/theme_delete_command.js';
|
|
10
|
+
import { ThemePublishCommand } from './commands/publish/theme_publish_command.js';
|
|
10
11
|
export const COMMANDS = {
|
|
11
12
|
[THEME_COMMANDS_NAME.list]: ThemeListCommand,
|
|
12
13
|
[THEME_COMMANDS_NAME.pull]: ThemePullCommand,
|
|
@@ -15,5 +16,6 @@ export const COMMANDS = {
|
|
|
15
16
|
[THEME_COMMANDS_NAME.showChanges]: ThemeShowChangesCommand,
|
|
16
17
|
[THEME_COMMANDS_NAME.verify]: ThemeVerifyCommand,
|
|
17
18
|
[THEME_COMMANDS_NAME.info]: ThemeInfoCommand,
|
|
18
|
-
[THEME_COMMANDS_NAME.delete]: ThemeDeleteCommand
|
|
19
|
+
[THEME_COMMANDS_NAME.delete]: ThemeDeleteCommand,
|
|
20
|
+
[THEME_COMMANDS_NAME.publish]: ThemePublishCommand
|
|
19
21
|
};
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@shoper/cli",
|
|
3
3
|
"packageManager": "yarn@3.2.0",
|
|
4
4
|
"sideEffects": false,
|
|
5
|
-
"version": "0.1.0-
|
|
5
|
+
"version": "0.1.0-35",
|
|
6
6
|
"description": "CLI tool for Shoper",
|
|
7
7
|
"author": "Joanna Firek",
|
|
8
8
|
"license": "MIT",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"deploy:beta": "npm run build && npm version prerelease --no-git-tag-version && npm publish --tag beta --access public"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@dreamcommerce/star_core": "1.8.
|
|
33
|
+
"@dreamcommerce/star_core": "1.8.5",
|
|
34
34
|
"@oclif/core": "4.2.10",
|
|
35
35
|
"@oclif/plugin-autocomplete": "3.2.27",
|
|
36
36
|
"@oclif/plugin-help": "6.2.27",
|