shoplazza-cli 1.0.5 → 1.0.7-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/shoplazza +3 -14
- package/lib/app/api/index.js +96 -0
- package/lib/app/commands/build.js +101 -53
- package/lib/app/commands/create.js +101 -0
- package/lib/app/commands/deploy.js +44 -208
- package/lib/app/commands/list.js +35 -0
- package/lib/app/commands/serve.js +171 -0
- package/lib/app/commands/versions.js +52 -0
- package/lib/app/index.js +19 -30
- package/lib/app/template/basic-app/README.md +98 -0
- package/lib/app/template/basic-app/package.json +16 -0
- package/lib/app/template/basic-app/theme-app/assets/index.css +4 -0
- package/lib/app/template/basic-app/theme-app/assets-manifest.json +1 -0
- package/lib/app/template/basic-app/theme-app/blocks/index.liquid +16 -0
- package/lib/app/template/basic-app/theme-app/snippets/index.liquid +8 -0
- package/lib/app/template/basic-app/theme-extension.config.json +4 -0
- package/lib/app/template/embed-app/README.md +97 -0
- package/lib/app/template/embed-app/package.json +16 -0
- package/lib/app/template/embed-app/theme-app/assets-manifest.json +1 -0
- package/lib/app/template/embed-app/theme-app/blocks/index.liquid +18 -0
- package/lib/app/template/embed-app/theme-app/locales/ar-SA.json +3 -0
- package/lib/app/template/embed-app/theme-app/locales/de-DE.json +3 -0
- package/lib/app/template/embed-app/theme-app/locales/en-US.json +3 -0
- package/lib/app/template/embed-app/theme-app/locales/es-ES.json +3 -0
- package/lib/app/template/embed-app/theme-app/locales/fr-FR.json +3 -0
- package/lib/app/template/embed-app/theme-app/locales/id-ID.json +3 -0
- package/lib/app/template/embed-app/theme-app/locales/it-IT.json +3 -0
- package/lib/app/template/embed-app/theme-app/locales/ja-JP.json +3 -0
- package/lib/app/template/embed-app/theme-app/locales/ko-KR.json +3 -0
- package/lib/app/template/embed-app/theme-app/locales/nl-NL.json +3 -0
- package/lib/app/template/embed-app/theme-app/locales/pl-PL.json +3 -0
- package/lib/app/template/embed-app/theme-app/locales/pt-PT.json +3 -0
- package/lib/app/template/embed-app/theme-app/locales/ru-RU.json +3 -0
- package/lib/app/template/embed-app/theme-app/locales/th-TH.json +3 -0
- package/lib/app/template/embed-app/theme-app/locales/zh-CN.json +3 -0
- package/lib/app/template/embed-app/theme-app/locales/zh-TW.json +3 -0
- package/lib/app/template/embed-app/theme-app/snippets/index.liquid +8 -0
- package/lib/app/template/embed-app/theme-app/snippets/index_css.liquid +6 -0
- package/lib/app/template/embed-app/theme-extension.config.json +4 -0
- package/lib/app/utils/config.js +32 -0
- package/lib/app/utils/index.js +213 -0
- package/lib/checkout/api.js +11 -34
- package/lib/checkout/build/plugin/vite-plugin-transform-extension-html.js +1 -1
- package/lib/checkout/dev/index.js +2 -1
- package/lib/commands/login.js +1 -1
- package/lib/commands/logout.js +1 -1
- package/lib/openAPI/index.js +21 -10
- package/lib/oss.js +99 -0
- package/lib/utils.js +52 -0
- package/package.json +2 -2
- package/lib/app/commands/generate.js +0 -50
- package/lib/app/commands/publish.js +0 -52
- package/lib/app/extensions/index.js +0 -13
- package/lib/app/extensions/theme-app.js +0 -103
- package/lib/app/inquirers/version.js +0 -131
- /package/lib/{app → common}/constants.js +0 -0
- /package/lib/{app → common}/db/partner.js +0 -0
- /package/lib/{app → common}/inquirers/choose-app.js +0 -0
- /package/lib/{app → common}/inquirers/choose-partner.js +0 -0
- /package/lib/{app → common}/log.js +0 -0
- /package/lib/{app → common}/login.js +0 -0
- /package/lib/{app → common}/logout.js +0 -0
package/bin/shoplazza
CHANGED
|
@@ -10,8 +10,7 @@ const report = require('../lib/report');
|
|
|
10
10
|
require('../lib/tracing');
|
|
11
11
|
|
|
12
12
|
const { makeCheckoutCommand } = require('../lib/checkout');
|
|
13
|
-
|
|
14
|
-
const { generateExtension, deployExtension, publishExtension, buildExtension, retry } = require('../lib/app');
|
|
13
|
+
const { initThemeAppCommand } = require('../lib/app');
|
|
15
14
|
|
|
16
15
|
Sentry.init({
|
|
17
16
|
dsn: 'https://89964605acaf4db8839f2d5237396d6c@sentry.shoplazza.com/730',
|
|
@@ -113,21 +112,11 @@ theme
|
|
|
113
112
|
.option('-t, --theme <theme>', 'The ID of the theme that you want to delete.')
|
|
114
113
|
.action(require('../lib/commands/theme/delete'));
|
|
115
114
|
|
|
116
|
-
const app = program.command('app').description('Shoplazza app extensions cli');
|
|
117
|
-
|
|
118
|
-
app.command('generate').command('extension').description('Generate your extension').action(generateExtension);
|
|
119
|
-
app.command('deploy').command('extension').description('Deploy your extension to cdn').action(deployExtension);
|
|
120
|
-
app.command('publish').command('extension').description('Publish your extension').action(publishExtension);
|
|
121
|
-
app.command('build').description('Build your extension').action(buildExtension);
|
|
122
|
-
app
|
|
123
|
-
.command('retry')
|
|
124
|
-
.description('Retry to do some tasks.')
|
|
125
|
-
.option('-p, --partner', 'Retry get and choose your partner list.')
|
|
126
|
-
.option('-a, --app', 'Retry get and choose your app list.')
|
|
127
|
-
.action(retry);
|
|
128
115
|
|
|
129
116
|
// checkout cli
|
|
130
117
|
makeCheckoutCommand(program);
|
|
118
|
+
// theme app cli
|
|
119
|
+
initThemeAppCommand(program);
|
|
131
120
|
|
|
132
121
|
program.parse(process.argv);
|
|
133
122
|
!program.args.length && program.help();
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
const instance = require('../../openAPI/index');
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 获取主题列表
|
|
6
|
+
*/
|
|
7
|
+
async function getThemeList() {
|
|
8
|
+
return instance.get('/themes');
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* 获取店铺私有主题插件列表
|
|
13
|
+
* @returns
|
|
14
|
+
*/
|
|
15
|
+
async function getThemeAppList() {
|
|
16
|
+
return instance.get('/theme-extensions');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 创建主题插件 or 更新主题插件信息
|
|
21
|
+
*/
|
|
22
|
+
async function toCreateThemeApp(data) {
|
|
23
|
+
return instance.put('/theme-extensions', data);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* 上传主题插件
|
|
28
|
+
*/
|
|
29
|
+
async function toUploadThemeApp(extension_id, data) {
|
|
30
|
+
return instance.patch(`/theme-extensions/${extension_id}/dev-doctree`, data);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* 新增文件
|
|
35
|
+
*/
|
|
36
|
+
async function toCreateFile(extension_id, data) {
|
|
37
|
+
return instance.post(`/theme-extensions/${extension_id}/dev-doc`, data);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* 更新文件
|
|
42
|
+
*/
|
|
43
|
+
async function toUpdateFile(extension_id, data) {
|
|
44
|
+
return instance.patch(`/theme-extensions/${extension_id}/dev-doc`, data);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* 删除文件
|
|
49
|
+
*/
|
|
50
|
+
async function toDeleteFile(extension_id, params) {
|
|
51
|
+
return instance.delete(`/theme-extensions/${extension_id}/dev-doc`, {
|
|
52
|
+
params
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* 获取任务状态
|
|
58
|
+
*/
|
|
59
|
+
async function getTaskStatus(data) {
|
|
60
|
+
return instance.get(`/theme-extensions/version-tasks/${data.taskId}`);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* 获取主题插件版本列表
|
|
65
|
+
*/
|
|
66
|
+
async function getThemeAppVersionList(extension_id) {
|
|
67
|
+
return instance.get(`/theme-extensions/${extension_id}/versions`);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* 创建主题插件版本
|
|
72
|
+
*/
|
|
73
|
+
async function toCreateThemeAppVersion(data) {
|
|
74
|
+
return instance.post(`/theme-extensions/version-tasks`, data);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* 部署主题插件
|
|
79
|
+
*/
|
|
80
|
+
async function toDeployThemeApp(data) {
|
|
81
|
+
return instance.post(`/theme-extensions/publications`, data);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
module.exports = {
|
|
85
|
+
getThemeList,
|
|
86
|
+
getThemeAppList,
|
|
87
|
+
toCreateThemeApp,
|
|
88
|
+
toCreateFile,
|
|
89
|
+
toUpdateFile,
|
|
90
|
+
toDeleteFile,
|
|
91
|
+
toUploadThemeApp,
|
|
92
|
+
getThemeAppVersionList,
|
|
93
|
+
toCreateThemeAppVersion,
|
|
94
|
+
toDeployThemeApp,
|
|
95
|
+
getTaskStatus
|
|
96
|
+
};
|
|
@@ -1,66 +1,114 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
|
+
const inquirer = require('inquirer');
|
|
2
3
|
const ora = require('ora');
|
|
3
|
-
const
|
|
4
|
-
const
|
|
4
|
+
const fsExtra = require('fs-extra');
|
|
5
|
+
const { getThemeAppConfig, compareVersions, compress } = require('../utils');
|
|
6
|
+
const { THEME_APP_DIR_PATH, EXCHANGE_TOKEN, STORE_DOMAIN } = require('../utils/config');
|
|
7
|
+
const { getThemeAppVersionList, toCreateThemeAppVersion, getTaskStatus } = require('../api');
|
|
8
|
+
const { useOss } = require('../../oss');
|
|
5
9
|
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
const {
|
|
10
|
+
async function createNewVersion(extensionId, version, description) {
|
|
11
|
+
const spinner = ora('Start building a new version...').start();
|
|
12
|
+
const { zipPath, zipName } = await compress(THEME_APP_DIR_PATH);
|
|
13
|
+
const { uploadOss } = useOss(
|
|
14
|
+
EXCHANGE_TOKEN,
|
|
15
|
+
STORE_DOMAIN,
|
|
16
|
+
`✗ No store found. Please run ${chalk.cyan('shoplazza login')} to login to a specific store.`
|
|
17
|
+
);
|
|
18
|
+
const zipOssUrl = await uploadOss(zipPath, zipName);
|
|
19
|
+
// 上传完成删除压缩包
|
|
20
|
+
fsExtra.removeSync(zipPath);
|
|
21
|
+
const res = await toCreateThemeAppVersion({
|
|
22
|
+
extension_id: extensionId,
|
|
23
|
+
version,
|
|
24
|
+
exts: description,
|
|
25
|
+
resource_url: zipOssUrl
|
|
26
|
+
});
|
|
27
|
+
const taskId = res.data?.task_id;
|
|
9
28
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const clearManifest = async () => {
|
|
15
|
-
try {
|
|
16
|
-
if (isFileExist('./assets-manifest.json') && isFileExist('./assets')) {
|
|
17
|
-
const mainfest = JSON.parse(fs.readFileSync('./assets-manifest.json', { encoding: 'utf-8' }));
|
|
18
|
-
await Promise.all(
|
|
19
|
-
Object.values(mainfest).map((path) => {
|
|
20
|
-
if (isFileExist(path)) {
|
|
21
|
-
return fs.unlink(path);
|
|
22
|
-
}
|
|
23
|
-
return Promise.resolve(true);
|
|
24
|
-
})
|
|
25
|
-
);
|
|
26
|
-
await fs.unlink('./assets-manifest.json');
|
|
27
|
-
}
|
|
28
|
-
return true;
|
|
29
|
-
} catch (e) {
|
|
30
|
-
console.log(e);
|
|
29
|
+
if (!taskId) {
|
|
30
|
+
spinner.fail(chalk.red(`Failed to build a new version!`));
|
|
31
|
+
throw new Error('taskId is required');
|
|
31
32
|
}
|
|
32
|
-
|
|
33
|
+
return new Promise((resolve, reject) => {
|
|
34
|
+
const timer = setInterval(async () => {
|
|
35
|
+
const res = await getTaskStatus({ taskId });
|
|
36
|
+
if (res.data?.state === 1) {
|
|
37
|
+
clearInterval(timer);
|
|
38
|
+
spinner.succeed(chalk.green(`Successfully built a new version(v${version})!`));
|
|
39
|
+
resolve();
|
|
40
|
+
} else if (res.data?.state === 2) {
|
|
41
|
+
clearInterval(timer);
|
|
42
|
+
spinner.fail(chalk.red(`Failed to build a new version!`));
|
|
43
|
+
reject(new Error(res.data?.message));
|
|
44
|
+
} else {
|
|
45
|
+
spinner.text = chalk.blue(`[WAITING] Building a new version...`);
|
|
46
|
+
}
|
|
47
|
+
}, 1000);
|
|
48
|
+
});
|
|
49
|
+
}
|
|
33
50
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
51
|
+
/**
|
|
52
|
+
* 交互式命令行
|
|
53
|
+
*/
|
|
54
|
+
async function usePrompt(extensionId) {
|
|
55
|
+
const res = await getThemeAppVersionList(extensionId);
|
|
37
56
|
|
|
38
|
-
const
|
|
39
|
-
const zipPath = `${process.cwd()}/${name}.zip`;
|
|
40
|
-
isFileExist(zipPath) && (await fs.unlink(zipPath));
|
|
41
|
-
zipTheme(process.cwd(), name);
|
|
42
|
-
};
|
|
57
|
+
const latestVersion = res.data?.data?.[0];
|
|
43
58
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
} catch (e) {
|
|
52
|
-
spinner.fail(e.message);
|
|
59
|
+
if (latestVersion) {
|
|
60
|
+
console.log(
|
|
61
|
+
chalk.cyanBright(`\n🔍 Latest version: `) +
|
|
62
|
+
chalk.yellow(`${latestVersion.version} `) +
|
|
63
|
+
chalk.white(`(${latestVersion.description})`) +
|
|
64
|
+
chalk.gray(` [Released on: ${latestVersion.created_at}]`)
|
|
65
|
+
);
|
|
53
66
|
}
|
|
54
|
-
};
|
|
55
67
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
68
|
+
return inquirer.prompt([
|
|
69
|
+
{
|
|
70
|
+
type: 'input',
|
|
71
|
+
name: 'newVersion',
|
|
72
|
+
message: 'Enter the new version number:',
|
|
73
|
+
validate: (newVersion) => {
|
|
74
|
+
if (!/^[0-9]+\.[0-9]+\.[0-9]+$/.test(newVersion)) {
|
|
75
|
+
return chalk.red('❌ Version must follow the format X.Y.Z (e.g., 1.0.0).');
|
|
76
|
+
}
|
|
77
|
+
if (latestVersion) {
|
|
78
|
+
if (compareVersions(newVersion, latestVersion.version) !== 1) {
|
|
79
|
+
return chalk.red('❌ Version must be greater than the latest version.');
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
type: 'input',
|
|
87
|
+
name: 'description',
|
|
88
|
+
message: 'Enter the description for this version:',
|
|
89
|
+
validate: (description) => {
|
|
90
|
+
if (!description.trim()) {
|
|
91
|
+
return chalk.red('❌ Description cannot be empty.');
|
|
92
|
+
}
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
]);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async function build() {
|
|
100
|
+
try {
|
|
101
|
+
const { extensionId } = await getThemeAppConfig();
|
|
102
|
+
if (!extensionId) {
|
|
103
|
+
throw new Error('ExtensionId is empty, please use `serve` command first.');
|
|
104
|
+
}
|
|
105
|
+
const { newVersion, description } = await usePrompt(extensionId);
|
|
106
|
+
await createNewVersion(extensionId, newVersion, description);
|
|
107
|
+
} catch (error) {
|
|
108
|
+
console.error(chalk.red(`[ERROR IN BUILD] ${error.message}`));
|
|
109
|
+
}
|
|
110
|
+
}
|
|
62
111
|
|
|
63
112
|
module.exports = {
|
|
64
|
-
build
|
|
65
|
-
getZipName
|
|
113
|
+
build
|
|
66
114
|
};
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
const inquirer = require('inquirer');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const fsExtra = require('fs-extra');
|
|
4
|
+
const chalk = require('chalk');
|
|
5
|
+
const { WORKSPACE_PATH, THEME_APP_TYPE } = require('../utils/config');
|
|
6
|
+
const { replacePlaceholders, renameFile } = require('../utils');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* 交互式命令行
|
|
10
|
+
*/
|
|
11
|
+
async function usePrompt() {
|
|
12
|
+
return await inquirer.prompt([
|
|
13
|
+
{
|
|
14
|
+
type: 'list',
|
|
15
|
+
name: 'themeAppType',
|
|
16
|
+
message: 'Select theme extension type:',
|
|
17
|
+
choices: [THEME_APP_TYPE.BASIC_APP.description, THEME_APP_TYPE.EMBEDS_APP.description],
|
|
18
|
+
prefix: '*'
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
type: 'input',
|
|
22
|
+
name: 'projectName',
|
|
23
|
+
message: 'Please enter the theme extension project name:',
|
|
24
|
+
prefix: '*',
|
|
25
|
+
validate: (projectName) => {
|
|
26
|
+
if (!projectName.trim()) {
|
|
27
|
+
return 'Project name cannot be empty';
|
|
28
|
+
}
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
]);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 初始化项目
|
|
37
|
+
*/
|
|
38
|
+
async function initProj(projectPath, projectName, isBasicApp = false) {
|
|
39
|
+
// 替换占位符 key文件相对路径 value替换的内容
|
|
40
|
+
const replacementConfig = {
|
|
41
|
+
'package.json': { projectName },
|
|
42
|
+
'theme-app/blocks/index.liquid': { projectName },
|
|
43
|
+
'theme-extension.config.json': { projectName }
|
|
44
|
+
};
|
|
45
|
+
for (const [filePath, replacements] of Object.entries(replacementConfig)) {
|
|
46
|
+
const fullPath = path.resolve(projectPath, filePath);
|
|
47
|
+
await replacePlaceholders(fullPath, replacements);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// 重命名文件
|
|
51
|
+
const filesToRename = [
|
|
52
|
+
isBasicApp ? 'assets/index.css' : 'snippets/index_css.liquid',
|
|
53
|
+
'blocks/index.liquid',
|
|
54
|
+
'snippets/index.liquid'
|
|
55
|
+
];
|
|
56
|
+
for (const file of filesToRename) {
|
|
57
|
+
const filePath = path.resolve(projectPath, 'theme-app', file);
|
|
58
|
+
await renameFile(filePath, `${projectName}${filePath.includes('_css') ? '_css' : ''}`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* 控制台提示信息
|
|
64
|
+
*/
|
|
65
|
+
function consoleTips(projectName) {
|
|
66
|
+
console.log(chalk.green(`Theme extension project "${projectName}" has been successfully created.`));
|
|
67
|
+
console.log(chalk.bold(`To get started:\n`));
|
|
68
|
+
console.log(` ${chalk.cyan(`cd ${projectName}`)}`);
|
|
69
|
+
console.log(` ${chalk.cyan(`npm start`)}\n`);
|
|
70
|
+
console.log(chalk.greenBright(`Happy coding! 🎉🎉🎉`));
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* 创建项目
|
|
75
|
+
*/
|
|
76
|
+
async function _create(themeAppDescription, projectName) {
|
|
77
|
+
const projectPath = path.resolve(WORKSPACE_PATH, projectName);
|
|
78
|
+
|
|
79
|
+
if (fsExtra.pathExistsSync(projectPath)) {
|
|
80
|
+
throw new Error(`Project directory "${projectName}" already exists.`);
|
|
81
|
+
}
|
|
82
|
+
await fsExtra.ensureDir(projectPath);
|
|
83
|
+
const isBasicApp = themeAppDescription === THEME_APP_TYPE.BASIC_APP.description;
|
|
84
|
+
const templatePath = isBasicApp ? THEME_APP_TYPE.BASIC_APP.templatePath : THEME_APP_TYPE.EMBEDS_APP.templatePath;
|
|
85
|
+
await fsExtra.copy(templatePath, projectPath);
|
|
86
|
+
await initProj(projectPath, projectName, isBasicApp);
|
|
87
|
+
consoleTips(projectName);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async function create() {
|
|
91
|
+
try {
|
|
92
|
+
const { themeAppType, projectName } = await usePrompt();
|
|
93
|
+
await _create(themeAppType, projectName);
|
|
94
|
+
} catch (error) {
|
|
95
|
+
console.error(chalk.red(`[ERROR IN CREATE] ${error.message}`));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
module.exports = {
|
|
100
|
+
create
|
|
101
|
+
};
|
|
@@ -1,218 +1,54 @@
|
|
|
1
|
-
const
|
|
2
|
-
const ora = require('ora');
|
|
1
|
+
const inquirer = require('inquirer');
|
|
3
2
|
const chalk = require('chalk');
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
3
|
+
const ora = require('ora');
|
|
4
|
+
const { getThemeAppConfig } = require('../utils');
|
|
5
|
+
const { getThemeAppVersionList, toDeployThemeApp } = require('../api');
|
|
6
|
+
|
|
7
|
+
async function deployVersion(extensionId, versionInfo) {
|
|
8
|
+
await toDeployThemeApp({
|
|
9
|
+
extension_id: extensionId,
|
|
10
|
+
version_id: versionInfo.version_id,
|
|
11
|
+
type: 'enable'
|
|
12
|
+
});
|
|
13
|
+
console.log(chalk.green(`Version ${versionInfo.version} has been deployed successfully.`));
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async function usePrompt(versionList) {
|
|
17
|
+
const choices = versionList.map((v) => ({
|
|
18
|
+
name: `${v.version} (${v.exts}) - ${v.created_at}`,
|
|
19
|
+
value: v.version_id
|
|
20
|
+
}));
|
|
21
|
+
return inquirer.prompt([
|
|
22
|
+
{
|
|
23
|
+
type: 'list',
|
|
24
|
+
name: 'selectedVersion',
|
|
25
|
+
message: 'Select a version to deploy:',
|
|
26
|
+
choices
|
|
26
27
|
}
|
|
28
|
+
]);
|
|
29
|
+
}
|
|
27
30
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
spinner.succeed(
|
|
31
|
-
chalk.cyan(
|
|
32
|
-
`Success to find your zip: ${chalk.green(`${filename} ${(fileInfo.size / (1024 * 1024)).toFixed(2)}M`)}`
|
|
33
|
-
)
|
|
34
|
-
);
|
|
35
|
-
return path.resolve(process.cwd(), filename);
|
|
36
|
-
} catch (e) {
|
|
37
|
-
spinner.fail(chalk.red('Failed to find your zip, be sure you have built app in root dir!'));
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
const getBufferAndMd5 = async (filePath) => {
|
|
42
|
-
const spinner = ora(chalk.cyan('Begin to read zip and generate md5 code ...')).start();
|
|
43
|
-
|
|
31
|
+
async function deploy() {
|
|
44
32
|
try {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const rs = fs.createReadStream(filePath, { autoClose: true });
|
|
50
|
-
rs.on('data', (data) => {
|
|
51
|
-
buffers.push(data);
|
|
52
|
-
spark.append(data);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
rs.on('end', () => {
|
|
56
|
-
const md5 = spark.end();
|
|
57
|
-
const completedBuffer = Buffer.concat(buffers);
|
|
58
|
-
spinner.succeed(chalk.cyan('Success to analyse zip'));
|
|
59
|
-
resolve([completedBuffer, md5 + '.zip']);
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
rs.on('error', (err) => {
|
|
63
|
-
reject(err);
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
} catch (e) {
|
|
67
|
-
spinner.fail(chalk.red('Failed to analyse zip, please try again!'));
|
|
68
|
-
}
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
const getSign = async () => {
|
|
72
|
-
const spinner = ora(chalk.cyan('Waiting get file sign ...')).start();
|
|
73
|
-
|
|
74
|
-
try {
|
|
75
|
-
const app = getApp();
|
|
76
|
-
const partnerId = getValue(PARTNER_KEYS.PARTNER_ID);
|
|
77
|
-
const sessionId = getValue(PARTNER_KEYS.SESSION_ID);
|
|
78
|
-
|
|
79
|
-
const url = `${PARNTER_URL}/api/partner/apps/${app.uid}/theme_extensions/file/signv2`;
|
|
80
|
-
const res = await axios.get(url, {
|
|
81
|
-
headers: {
|
|
82
|
-
Cookie: `awesomev2=${sessionId}`,
|
|
83
|
-
'x-shoplazza-partner-id': partnerId
|
|
84
|
-
}
|
|
85
|
-
});
|
|
86
|
-
spinner.succeed(chalk.cyan('Success to get file sign'));
|
|
87
|
-
return res.data;
|
|
88
|
-
} catch (e) {
|
|
89
|
-
spinner.fail(chalk.red(e.message || e));
|
|
90
|
-
}
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
const deployOss = async () => {
|
|
94
|
-
const path = getZipPath();
|
|
95
|
-
if (path) {
|
|
96
|
-
const [buffer, md5] = await getBufferAndMd5(path);
|
|
97
|
-
const signData = await getSign();
|
|
98
|
-
if (!signData) {
|
|
99
|
-
return;
|
|
33
|
+
const { extensionId } = await getThemeAppConfig();
|
|
34
|
+
if (!extensionId) {
|
|
35
|
+
throw new Error('ExtensionId is empty, please use `serve` command first.');
|
|
100
36
|
}
|
|
101
|
-
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
formData.append('OSSAccessKeyId', signData.access_id);
|
|
108
|
-
formData.append('success_action_status', 200);
|
|
109
|
-
formData.append('signature', signData.sign);
|
|
110
|
-
formData.append('x-oss-forbid-overwrite', 'true');
|
|
111
|
-
formData.append('key', md5);
|
|
112
|
-
formData.append('file', buffer);
|
|
113
|
-
|
|
114
|
-
const url = `https:${signData.write_host}/`;
|
|
115
|
-
const res = await axios.post(url, formData, {
|
|
116
|
-
global: true,
|
|
117
|
-
maxContentLength: 100000000,
|
|
118
|
-
maxBodyLength: 1000000000
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
if (res.status !== 200) {
|
|
122
|
-
throw new Error(`${res.status} ${resstatusText}`);
|
|
123
|
-
}
|
|
124
|
-
spinner.succeed();
|
|
125
|
-
return md5;
|
|
126
|
-
} catch (e) {
|
|
127
|
-
// 409 repeat filename
|
|
128
|
-
if (e?.response?.status === 409) {
|
|
129
|
-
spinner.succeed();
|
|
130
|
-
return md5;
|
|
131
|
-
}
|
|
132
|
-
spinner.fail();
|
|
133
|
-
console.log(chalk.red(e.message || e));
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
};
|
|
137
|
-
|
|
138
|
-
const deployPartner = async () => {
|
|
139
|
-
const md5 = await deployOss();
|
|
140
|
-
if (!md5) {
|
|
141
|
-
return;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
const spinner = ora(chalk.cyan('Deploying your zip to PARTNER ...')).start();
|
|
145
|
-
try {
|
|
146
|
-
const app = getApp();
|
|
147
|
-
if (!app) {
|
|
148
|
-
spinner.fail(chalk.red('Please choose your partner first!'));
|
|
149
|
-
return;
|
|
37
|
+
const spinner = ora('Fetching version list...').start();
|
|
38
|
+
const res = await getThemeAppVersionList(extensionId);
|
|
39
|
+
const versionList = res.data?.data || [];
|
|
40
|
+
if (!versionList.length) {
|
|
41
|
+
spinner.succeed('Version list loaded.');
|
|
42
|
+
throw new Error('No version found, please use `build` command to upload a version first.');
|
|
150
43
|
}
|
|
151
|
-
|
|
152
|
-
const
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
title: getZipName(),
|
|
158
|
-
name: getZipName(),
|
|
159
|
-
file_name: md5
|
|
160
|
-
},
|
|
161
|
-
{
|
|
162
|
-
headers: {
|
|
163
|
-
cookie: `awesomev2=${getValue(PARTNER_KEYS.SESSION_ID)};`,
|
|
164
|
-
'x-shoplazza-partner-id': partnerId
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
);
|
|
168
|
-
|
|
169
|
-
set({ [PARTNER_KEYS.EXTENSION_ID]: res.data.extension_id });
|
|
170
|
-
spinner.succeed();
|
|
171
|
-
return true;
|
|
172
|
-
} catch (e) {
|
|
173
|
-
spinner.fail();
|
|
174
|
-
console.log(e.message || e);
|
|
175
|
-
console.log(chalk.red(JSON.stringify(e.response.data)));
|
|
44
|
+
spinner.succeed('Version list loaded.');
|
|
45
|
+
const { selectedVersion } = await usePrompt(versionList);
|
|
46
|
+
const versionInfo = versionList.find((v) => v.version_id === selectedVersion);
|
|
47
|
+
await deployVersion(extensionId, versionInfo);
|
|
48
|
+
} catch (error) {
|
|
49
|
+
console.error(chalk.red(`[ERROR IN DEPLOY] ${error.message}`));
|
|
176
50
|
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
const createVersion = async (version) => {
|
|
180
|
-
const spinner = ora(chalk.cyan('Creating your version task ...')).start();
|
|
181
|
-
|
|
182
|
-
try {
|
|
183
|
-
const app = getApp();
|
|
184
|
-
const extensionId = getValue(PARTNER_KEYS.EXTENSION_ID);
|
|
185
|
-
const partnerId = getValue(PARTNER_KEYS.PARTNER_ID);
|
|
186
|
-
|
|
187
|
-
const url = `${PARNTER_URL}/api/partner/apps/${app.uid}/theme_extensions/${extensionId}/version_tasks`;
|
|
188
|
-
await axios.post(
|
|
189
|
-
url,
|
|
190
|
-
{
|
|
191
|
-
version
|
|
192
|
-
},
|
|
193
|
-
{
|
|
194
|
-
headers: {
|
|
195
|
-
cookie: `awesomev2=${getValue(PARTNER_KEYS.SESSION_ID)};`,
|
|
196
|
-
'x-shoplazza-partner-id': partnerId
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
);
|
|
200
|
-
spinner.succeed();
|
|
201
|
-
return true;
|
|
202
|
-
} catch (e) {
|
|
203
|
-
spinner.fail();
|
|
204
|
-
console.log(chalk.red(e.message || e));
|
|
205
|
-
console.log(chalk.red(JSON.stringify(e.response?.data)));
|
|
206
|
-
}
|
|
207
|
-
};
|
|
208
|
-
|
|
209
|
-
const deploy = async () => {
|
|
210
|
-
line();
|
|
211
|
-
ora(chalk.cyan('Deploy Begin')).succeed();
|
|
212
|
-
let version;
|
|
213
|
-
(await deployPartner()) && (version = await inputVersion()) && (await createVersion(version)) && done();
|
|
214
|
-
line();
|
|
215
|
-
};
|
|
51
|
+
}
|
|
216
52
|
|
|
217
53
|
module.exports = {
|
|
218
54
|
deploy
|