@lazycatcloud/lzc-cli 1.3.12 → 1.3.14

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.
@@ -1,224 +1,255 @@
1
- import { Publish } from "./publish.js"
2
- import logger from "loglevel"
3
- import { PrePublish } from "./prePublish.js"
4
- import { reLogin, request } from "./login.js"
5
- import fs from "node:fs"
6
- import { sleep } from "../utils.js"
7
- import { appStoreServerUrl } from "./env.js"
1
+ import fs from 'node:fs';
2
+ import logger from 'loglevel';
3
+
4
+ import { sleep } from '../utils.js';
5
+ import { t } from '../i18n/index.js';
6
+
7
+ import { Publish } from './publish.js';
8
+ import { PrePublish } from './prePublish.js';
9
+ import { reLogin, request } from './login.js';
10
+ import { appStoreServerUrl } from './env.js';
8
11
 
9
12
  export function appstoreCommand(program) {
10
- let subCommands = [
11
- {
12
- command: "login",
13
- desc: "登录",
14
- handler: async () => {
15
- await reLogin()
16
- }
17
- },
18
- {
19
- command: "pre-publish <pkgPath>",
20
- desc: "发布到内测",
21
- builder: (args) => {
22
- args.option("c", {
23
- alias: "changelog",
24
- describe: "更改日志",
25
- type: "string"
26
- })
27
- args.option("F", {
28
- alias: "file",
29
- describe: "更改日志文件",
30
- type: "string"
31
- })
32
- args.option("G", {
33
- alias: "gid",
34
- describe: "内测组ID",
35
- type: "string"
36
- })
37
- },
38
- handler: async ({ pkgPath, changelog, file, gid }) => {
39
- const p = new PrePublish()
40
- if (!changelog && file) {
41
- changelog = fs.readFileSync(file, "utf8")
42
- }
43
- await p.publish(pkgPath, changelog, gid)
44
- }
45
- },
46
- {
47
- command: "publish <pkgPath>",
48
- desc: "发布到商店",
49
- builder: (args) => {
50
- args.option("c", {
51
- alias: "changelog",
52
- describe: "更新日志",
53
- type: "string"
54
- })
55
- args.option("clang", {
56
- alias: "changelog-locale",
57
- describe: "更新日志语言标识,默认通过当前 shell 语言环境识别",
58
- type: "string"
59
- })
60
- args.option("F", {
61
- alias: "file",
62
- describe: "更新日志文件",
63
- type: "string"
64
- })
65
- },
66
- handler: async ({ pkgPath, changelog, changelogLocale, file }) => {
67
- const locale = changelogLocale ?? program.locale()
68
- const p = new Publish()
69
- if (!changelog && file) {
70
- changelog = fs.readFileSync(file, "utf8")
71
- }
72
- await p.publish(pkgPath, changelog, locale)
73
- }
74
- },
75
- {
76
- command: "copy-image <img>",
77
- desc: `复制镜像至懒猫微服官方源`,
78
- builder: (yargs) => {
79
- yargs.option("arch", {
80
- describe: "image arch 'amd64', 'arm64'",
81
- default: "amd64",
82
- type: "string"
83
- })
84
- // 出于 CI 目的增加控制是否打印进度选项
85
- yargs.option("trace-level", {
86
- describe: "trace level 'verbose', 'quiet'",
87
- default: "verbose",
88
- type: "string"
89
- })
90
- return yargs
91
- },
92
- handler: async ({ img: imageName, arch: platform, traceLevel }) => {
93
- const uploadUrl = `${appStoreServerUrl}/api/v3/developer/app/docker/image/push/v3/copy?image=${imageName}&platform=${platform}`
94
- const progressUrl = `${appStoreServerUrl}/api/v3/developer/app/docker/image/push/v3/progress?image=${imageName}&platform=${platform}`
13
+ let subCommands = [
14
+ {
15
+ command: 'login',
16
+ desc: t('lzc_cli.lib.appstore.index.login_cmd_desc', '登录'),
17
+ handler: async () => {
18
+ await reLogin();
19
+ },
20
+ },
21
+ {
22
+ command: 'pre-publish <pkgPath>',
23
+ desc: t('lzc_cli.lib.appstore.index.pre_publish_cmd_desc', '发布到内测'),
24
+ builder: (yargs) => {
25
+ yargs.option('c', {
26
+ alias: 'changelog',
27
+ describe: t('lzc_cli.lib.appstore.index.pre_publish_cmd_changelog_desc', '更改日志'),
28
+ type: 'string',
29
+ });
30
+ yargs.option('F', {
31
+ alias: 'file',
32
+ describe: t('lzc_cli.lib.appstore.index.pre_publish_cmd_changelog_file_desc', '更改日志文件'),
33
+ type: 'string',
34
+ });
35
+ yargs.option('G', {
36
+ alias: 'gid',
37
+ describe: t('lzc_cli.lib.appstore.index.pre_publish_cmd_gid_desc', '内测组ID'),
38
+ type: 'string',
39
+ });
40
+ },
41
+ handler: async ({ pkgPath, changelog, file, gid }) => {
42
+ const p = new PrePublish();
43
+ if (!changelog && file) {
44
+ changelog = fs.readFileSync(file, 'utf8');
45
+ }
46
+ await p.publish(pkgPath, changelog, gid);
47
+ },
48
+ },
49
+ {
50
+ command: 'publish <pkgPath>',
51
+ desc: t('lzc_cli.lib.appstore.index.publish_cmd_desc', '发布到商店'),
52
+ builder: (yargs) => {
53
+ yargs.option('c', {
54
+ alias: 'changelog',
55
+ describe: t('lzc_cli.lib.appstore.index.publish_cmd_changelog_desc', '更新日志'),
56
+ type: 'string',
57
+ });
58
+ yargs.option('clang', {
59
+ alias: 'changelog-locale',
60
+ describe: t('lzc_cli.lib.appstore.index.publish_cmd_changelog_lang_desc', '更新日志语言标识,默认通过当前 shell 语言环境识别'),
61
+ type: 'string',
62
+ });
63
+ yargs.option('clangs', {
64
+ alias: 'changelog-files',
65
+ type: 'string',
66
+ array: true,
67
+ describe: t('lzc_cli.lib.appstore.index.publish_cmd_changelog_files_desc', '更新日志本地化语言文件 lang:path 例如 en:changelog.en.md'),
68
+ });
69
+ yargs.option('F', {
70
+ alias: 'file',
71
+ deprecate: 'use --clangs=en:clog_en.txt',
72
+ describe: t('lzc_cli.lib.appstore.index.publish_cmd_changelog_file_desc', '更新日志文件'),
73
+ type: 'string',
74
+ });
75
+ },
76
+ handler: async ({ pkgPath, changelog, changelogLocale, file, changelogFiles }) => {
77
+ const currentLocale = changelogLocale ?? program.locale();
78
+ const p = new Publish();
79
+
80
+ async function readChangelogFiles(files, changelogs = {}) {
81
+ const result = {}
82
+ if (!files || !Array.isArray(files) || files.length < 1) {
83
+ return { ...result, ...changelogs }
84
+ }
85
+ for (const item of files) {
86
+ const [lang, path] = item.split(':');
87
+ if (!lang || !path) {
88
+ throw new Error('changelog files resolution error')
89
+ }
90
+ if (!fs.existsSync(path)) {
91
+ throw new Error(`changelog ${lang} file ${path} does not exist`)
92
+ }
93
+ const content = fs.readFileSync(path, 'utf8');
94
+ if (!content) {
95
+ throw new Error(`changelog ${lang} file ${path} content is empty`)
96
+ }
97
+ result[lang] = content.trim()
98
+ }
99
+ return { ...result, ...changelogs }
100
+ }
101
+
102
+ // deprecate: 移除 `--file` 参数时删除该逻辑
103
+ if (!changelog && file) {
104
+ changelog = fs.readFileSync(file, 'utf8');
105
+ }
106
+
107
+ const changelogInitial = {}
108
+ if (changelog) {
109
+ changelogInitial[currentLocale] = changelog
110
+ }
111
+ const changelogs = await readChangelogFiles(changelogFiles, changelogInitial)
112
+
113
+ await p.publish(pkgPath, changelogs, currentLocale);
114
+ },
115
+ },
116
+ {
117
+ command: 'copy-image <img>',
118
+ desc: t('lzc_cli.lib.appstore.index.copy_image_cmd_desc', `复制镜像至懒猫微服官方源`),
119
+ builder: (yargs) => {
120
+ yargs.option('arch', {
121
+ describe: "image arch 'amd64', 'arm64'",
122
+ default: 'amd64',
123
+ type: 'string',
124
+ });
125
+ // 出于 CI 目的增加控制是否打印进度选项
126
+ yargs.option('trace-level', {
127
+ describe: "trace level 'verbose', 'quiet'",
128
+ default: 'verbose',
129
+ type: 'string',
130
+ });
131
+ return yargs;
132
+ },
133
+ handler: async ({ img: imageName, arch: platform, traceLevel }) => {
134
+ const uploadUrl = `${appStoreServerUrl}/api/v3/developer/app/docker/image/push/v3/copy?image=${imageName}&platform=${platform}`;
135
+ const progressUrl = `${appStoreServerUrl}/api/v3/developer/app/docker/image/push/v3/progress?image=${imageName}&platform=${platform}`;
95
136
 
96
- const useCI = traceLevel === "quiet"
97
- const _logger = logger
98
- _logger.setLevel(useCI ? _logger.levels.ERROR : _logger.levels.INFO)
137
+ const useCI = traceLevel === 'quiet';
138
+ const _logger = logger;
139
+ _logger.setLevel(useCI ? _logger.levels.ERROR : _logger.levels.INFO);
99
140
 
100
- _logger.info(
101
- `Waiting ... ( copy ${imageName} (${platform}) to lazycat offical registry)`
102
- )
103
- try {
104
- const resp = await request(uploadUrl)
105
- if (resp.ok) {
106
- _logger.info("uploading")
107
- } else {
108
- _logger.error("error: ", resp, await resp.text())
109
- return
110
- }
111
- sleep(1000)
112
- let prevLineCount = 0 // 新增:记录上次输出行数
113
- let layers = []
141
+ _logger.info(`Waiting ... ( copy ${imageName} (${platform}) to lazycat offical registry)`);
142
+ try {
143
+ const resp = await request(uploadUrl);
144
+ if (resp.ok) {
145
+ _logger.info('uploading');
146
+ } else {
147
+ _logger.error('error: ', resp, await resp.text());
148
+ return;
149
+ }
150
+ sleep(1000);
151
+ let prevLineCount = 0; // 新增:记录上次输出行数
152
+ let layers = [];
114
153
 
115
- let refreshProgress = (lys) => {
116
- if (useCI) {
117
- // 日志级别为 quiet 时不输出进度(用于 CI 目的)
118
- return
119
- }
120
- // 关键修改:动态回退多行
121
- process.stdout.write("\x1B[?25l") // 隐藏光标
122
- if (prevLineCount > 0) {
123
- process.stdout.write(`\x1B[${prevLineCount}A`) // 移动光标到之前输出的起始行
124
- }
154
+ let refreshProgress = (lys) => {
155
+ if (useCI) {
156
+ // 日志级别为 quiet 时不输出进度(用于 CI 目的)
157
+ return;
158
+ }
159
+ // 关键修改:动态回退多行
160
+ process.stdout.write('\x1B[?25l'); // 隐藏光标
161
+ if (prevLineCount > 0) {
162
+ process.stdout.write(`\x1B[${prevLineCount}A`); // 移动光标到之前输出的起始行
163
+ }
125
164
 
126
- // 构建多行进度字符串
127
- let output = []
128
- ;(lys || []).forEach((v) => {
129
- const progressBar =
130
- "#".repeat(v.progress) + " ".repeat(100 - v.progress)
131
- output.push(
132
- `${v.hash.substring(0, 8)}: [${progressBar}] ${v.progress}%`
133
- )
134
- })
165
+ // 构建多行进度字符串
166
+ let output = [];
167
+ (lys || []).forEach((v) => {
168
+ const progressBar = '#'.repeat(v.progress) + ' '.repeat(100 - v.progress);
169
+ output.push(`${v.hash.substring(0, 8)}: [${progressBar}] ${v.progress}%`);
170
+ });
135
171
 
136
- // 清除旧行并写入新内容
137
- output.forEach((line) => {
138
- process.stdout.write("\x1B[2K") // 清除当前行
139
- process.stdout.write(line + "\n")
140
- })
141
- prevLineCount = output.length // 记录本次输出行数
142
- process.stdout.write("\x1B[?25h") // 恢复光标显示
143
- }
172
+ // 清除旧行并写入新内容
173
+ output.forEach((line) => {
174
+ process.stdout.write('\x1B[2K'); // 清除当前行
175
+ process.stdout.write(line + '\n');
176
+ });
177
+ prevLineCount = output.length; // 记录本次输出行数
178
+ process.stdout.write('\x1B[?25h'); // 恢复光标显示
179
+ };
144
180
 
145
- for (;;) {
146
- const pgsResp = await request(progressUrl)
147
- if (pgsResp.ok) {
148
- const pgs = JSON.parse(await pgsResp.text())
149
- if (pgs.finished) {
150
- ;(layers ? layers : [])?.forEach((v) => {
151
- v.progress = 100
152
- })
153
- if (pgs.errmsg) {
154
- throw Error(
155
- `failed to copyimage ${imageName} err: ${pgs.errmsg}`
156
- )
157
- }
158
- if (!useCI) {
159
- refreshProgress(layers)
160
- process.stdout.write("\n")
161
- _logger.info("uploaded: ", pgs.lzc_image)
162
- } else {
163
- // 日志级别为 quiet 时仅输出结果(用于 CI 目的)
164
- console.log(pgs.lzc_image)
165
- }
166
- break
167
- }
168
- layers = pgs?.layers
169
- refreshProgress(layers)
170
- await sleep(1000)
171
- } else {
172
- throw Error(`error: ${await resp.text()}`)
173
- }
174
- }
175
- } catch (err) {
176
- _logger.error(err?.message ?? "unknown exception")
177
- }
178
- }
179
- },
180
- {
181
- command: "my-images",
182
- desc: "查看已上传镜像列表",
183
- handler: async () => {
184
- const url = `${appStoreServerUrl}/api/v3/developer/app/docker/image/push/v3/myimages`
185
- try {
186
- const resp = await request(url)
187
- if (resp.ok) {
188
- const ilist = JSON.parse(await resp.text())
189
- ilist.sort((a, b) => {
190
- return (
191
- new Date(b.UpdatedAt).getTime() -
192
- new Date(a.UpdatedAt).getTime()
193
- )
194
- })
195
- const tableItems = []
196
- ilist?.forEach((v) => {
197
- if (v.errmsg) {
198
- return
199
- }
200
- tableItems.push({
201
- "Source Image": v.source_image,
202
- "Lazycat Image": v.lzc_image,
203
- "Updated At": new Date(v.UpdatedAt).toLocaleString()
204
- })
205
- })
206
- console.table(tableItems)
207
- } else {
208
- logger.error("error: ", await resp.text())
209
- }
210
- } catch (err) {
211
- console.error(err)
212
- }
213
- }
214
- }
215
- ]
181
+ for (; ;) {
182
+ const pgsResp = await request(progressUrl);
183
+ if (pgsResp.ok) {
184
+ const pgs = JSON.parse(await pgsResp.text());
185
+ if (pgs.finished) {
186
+ (layers ? layers : [])?.forEach((v) => {
187
+ v.progress = 100;
188
+ });
189
+ if (pgs.errmsg) {
190
+ throw Error(`failed to copyimage ${imageName} err: ${pgs.errmsg}`);
191
+ }
192
+ if (!useCI) {
193
+ refreshProgress(layers);
194
+ process.stdout.write('\n');
195
+ _logger.info('uploaded: ', pgs.lzc_image);
196
+ } else {
197
+ // 日志级别为 quiet 时仅输出结果(用于 CI 目的)
198
+ console.log(pgs.lzc_image);
199
+ }
200
+ break;
201
+ }
202
+ layers = pgs?.layers;
203
+ refreshProgress(layers);
204
+ await sleep(1000);
205
+ } else {
206
+ throw Error(`error: ${await resp.text()}`);
207
+ }
208
+ }
209
+ } catch (err) {
210
+ _logger.error(err?.message ?? 'unknown exception');
211
+ }
212
+ },
213
+ },
214
+ {
215
+ command: 'my-images',
216
+ desc: t('lzc_cli.lib.appstore.index.my_images_cmd_desc', '查看已上传镜像列表'),
217
+ handler: async () => {
218
+ const url = `${appStoreServerUrl}/api/v3/developer/app/docker/image/push/v3/myimages`;
219
+ try {
220
+ const resp = await request(url);
221
+ if (resp.ok) {
222
+ const ilist = JSON.parse(await resp.text());
223
+ ilist.sort((a, b) => {
224
+ return new Date(b.UpdatedAt).getTime() - new Date(a.UpdatedAt).getTime();
225
+ });
226
+ const tableItems = [];
227
+ ilist?.forEach((v) => {
228
+ if (v.errmsg) {
229
+ return;
230
+ }
231
+ tableItems.push({
232
+ 'Source Image': v.source_image,
233
+ 'Lazycat Image': v.lzc_image,
234
+ 'Updated At': new Date(v.UpdatedAt).toLocaleString(),
235
+ });
236
+ });
237
+ console.table(tableItems);
238
+ } else {
239
+ logger.error('error: ', await resp.text());
240
+ }
241
+ } catch (err) {
242
+ console.error(err);
243
+ }
244
+ },
245
+ },
246
+ ];
216
247
 
217
- program.command({
218
- command: "appstore",
219
- desc: "应用商店",
220
- builder: (args) => {
221
- args.command(subCommands)
222
- }
223
- })
248
+ program.command({
249
+ command: 'appstore',
250
+ desc: t('lzc_cli.lib.appstore.index.appstore_cmd_desc', '应用商店'),
251
+ builder: (args) => {
252
+ args.command(subCommands);
253
+ },
254
+ });
224
255
  }