@hecom/codearts 0.2.2 → 0.2.3
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/dist/bin/cli.js +15 -0
- package/dist/commands/config.command.js +138 -165
- package/dist/commands/daily.command.js +15 -3
- package/dist/constant/index.d.ts +1 -0
- package/dist/constant/index.js +29 -0
- package/dist/utils/logger.d.ts +1 -1
- package/dist/utils/logger.js +6 -1
- package/package.json +5 -4
- package/dist/index.d.ts +0 -3
- package/dist/index.js +0 -23
package/dist/bin/cli.js
CHANGED
|
@@ -41,6 +41,7 @@ const bug_command_1 = require("../commands/bug.command");
|
|
|
41
41
|
const config_command_1 = require("../commands/config.command");
|
|
42
42
|
const daily_command_1 = require("../commands/daily.command");
|
|
43
43
|
const work_hour_command_1 = require("../commands/work-hour.command");
|
|
44
|
+
const constant_1 = require("../constant");
|
|
44
45
|
const config_loader_1 = require("../utils/config-loader");
|
|
45
46
|
const logger_1 = require("../utils/logger");
|
|
46
47
|
// 读取 package.json 中的版本号
|
|
@@ -58,6 +59,7 @@ const configCmd = program
|
|
|
58
59
|
.command('config')
|
|
59
60
|
.description('交互式配置向导,引导用户创建或更新全局配置文件')
|
|
60
61
|
.action(async () => {
|
|
62
|
+
(0, constant_1.showLogo)();
|
|
61
63
|
await (0, config_command_1.configCommand)();
|
|
62
64
|
});
|
|
63
65
|
// config show 子命令 - 显示当前配置
|
|
@@ -65,6 +67,7 @@ configCmd
|
|
|
65
67
|
.command('show')
|
|
66
68
|
.description('显示当前配置信息')
|
|
67
69
|
.action(async () => {
|
|
70
|
+
(0, constant_1.showLogo)();
|
|
68
71
|
await (0, config_command_1.showConfigCommand)();
|
|
69
72
|
});
|
|
70
73
|
// 为每个项目配置项添加子命令
|
|
@@ -75,6 +78,7 @@ availableConfigs.forEach((configItem) => {
|
|
|
75
78
|
.command(subCommandName)
|
|
76
79
|
.description(`更新${configItem.label}`)
|
|
77
80
|
.action(async () => {
|
|
81
|
+
(0, constant_1.showLogo)();
|
|
78
82
|
await (0, config_command_1.updateProjectConfigCommand)(configItem.key);
|
|
79
83
|
});
|
|
80
84
|
});
|
|
@@ -111,6 +115,7 @@ async function checkConfigAndRun() {
|
|
|
111
115
|
const args = process.argv.slice(2);
|
|
112
116
|
// 如果没有参数(直接执行 codearts),检测配置
|
|
113
117
|
if (args.length === 0) {
|
|
118
|
+
(0, constant_1.showLogo)();
|
|
114
119
|
// 检查是否有全局配置
|
|
115
120
|
const hasConfig = (0, config_loader_1.configExists)();
|
|
116
121
|
if (!hasConfig) {
|
|
@@ -125,6 +130,16 @@ async function checkConfigAndRun() {
|
|
|
125
130
|
// 有参数,正常解析命令
|
|
126
131
|
program.parse();
|
|
127
132
|
}
|
|
133
|
+
process.on('uncaughtException', (error) => {
|
|
134
|
+
if (error instanceof Error && error.name === 'ExitPromptError') {
|
|
135
|
+
console.log('👋 操作取消!');
|
|
136
|
+
process.exit(0);
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
// 重新抛出未知错误
|
|
140
|
+
throw error;
|
|
141
|
+
}
|
|
142
|
+
});
|
|
128
143
|
checkConfigAndRun().catch((error) => {
|
|
129
144
|
logger_1.logger.error('执行失败: ', error);
|
|
130
145
|
process.exit(1);
|
|
@@ -40,7 +40,8 @@ exports.configCommand = configCommand;
|
|
|
40
40
|
exports.updateProjectConfigCommand = updateProjectConfigCommand;
|
|
41
41
|
exports.getAvailableProjectConfigs = getAvailableProjectConfigs;
|
|
42
42
|
exports.showConfigCommand = showConfigCommand;
|
|
43
|
-
const
|
|
43
|
+
const prompts_1 = require("@inquirer/prompts");
|
|
44
|
+
const picocolors_1 = __importDefault(require("picocolors"));
|
|
44
45
|
const readline = __importStar(require("readline"));
|
|
45
46
|
const business_service_1 = require("../services/business.service");
|
|
46
47
|
const types_1 = require("../types");
|
|
@@ -56,76 +57,71 @@ function clearLines(lines) {
|
|
|
56
57
|
readline.clearLine(process.stdout, 0); // 清除当前行
|
|
57
58
|
}
|
|
58
59
|
}
|
|
60
|
+
async function inputRoleIds(existingValue) {
|
|
61
|
+
return await (0, prompts_1.input)({
|
|
62
|
+
message: '角色 ID(支持逗号分隔,如: 1,2,3):',
|
|
63
|
+
default: existingValue || '',
|
|
64
|
+
validate: (inputValue) => {
|
|
65
|
+
if (!inputValue.trim()) {
|
|
66
|
+
return '角色 ID 不能为空';
|
|
67
|
+
}
|
|
68
|
+
const ids = inputValue.split(',').map((id) => id.trim());
|
|
69
|
+
const allValid = ids.every((id) => /^\d+$/.test(id));
|
|
70
|
+
return allValid ? true : '角色 ID 必须是数字或逗号分隔的数字列表';
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
}
|
|
59
74
|
/**
|
|
60
75
|
* 配置角色 ID
|
|
61
76
|
*/
|
|
62
77
|
async function configureRoleIds(businessService, projectId, existingValue) {
|
|
78
|
+
let roles = [];
|
|
63
79
|
try {
|
|
64
|
-
|
|
65
|
-
if (roles.length === 0) {
|
|
66
|
-
// 如果没有获取到角色,使用手动输入
|
|
67
|
-
const { manualRoleId } = await inquirer_1.default.prompt([
|
|
68
|
-
{
|
|
69
|
-
type: 'input',
|
|
70
|
-
name: 'manualRoleId',
|
|
71
|
-
message: '角色 ID(支持逗号分隔,如: 1,2,3):',
|
|
72
|
-
default: existingValue || '',
|
|
73
|
-
validate: (input) => {
|
|
74
|
-
if (!input.trim()) {
|
|
75
|
-
return '角色 ID 不能为空';
|
|
76
|
-
}
|
|
77
|
-
const ids = input.split(',').map((id) => id.trim());
|
|
78
|
-
const allValid = ids.every((id) => /^\d+$/.test(id));
|
|
79
|
-
return allValid ? true : '角色 ID 必须是数字或逗号分隔的数字列表';
|
|
80
|
-
},
|
|
81
|
-
},
|
|
82
|
-
]);
|
|
83
|
-
return manualRoleId;
|
|
84
|
-
}
|
|
85
|
-
else {
|
|
86
|
-
// 使用多选框选择角色
|
|
87
|
-
const roleChoices = roles.map((role) => ({
|
|
88
|
-
name: `${role.role_name} (${role.role_id})`,
|
|
89
|
-
value: role.role_id.toString(),
|
|
90
|
-
checked: existingValue ? existingValue.split(',').includes(role.role_id.toString()) : false,
|
|
91
|
-
}));
|
|
92
|
-
const { selectedRoleIds } = await inquirer_1.default.prompt([
|
|
93
|
-
{
|
|
94
|
-
type: 'checkbox',
|
|
95
|
-
name: 'selectedRoleIds',
|
|
96
|
-
message: '请选择角色:',
|
|
97
|
-
choices: roleChoices,
|
|
98
|
-
validate: (input) => {
|
|
99
|
-
if (input.length === 0) {
|
|
100
|
-
return '至少选择一个角色';
|
|
101
|
-
}
|
|
102
|
-
return true;
|
|
103
|
-
},
|
|
104
|
-
},
|
|
105
|
-
]);
|
|
106
|
-
return selectedRoleIds.join(',');
|
|
107
|
-
}
|
|
80
|
+
roles = await businessService.getProjectRoles(projectId);
|
|
108
81
|
}
|
|
109
82
|
catch (error) {
|
|
110
83
|
logger_1.logger.error('❌ 获取角色列表失败:', error);
|
|
111
84
|
// 如果获取失败,使用手动输入
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
85
|
+
return await inputRoleIds(existingValue);
|
|
86
|
+
}
|
|
87
|
+
if (roles.length === 0) {
|
|
88
|
+
// 如果没有获取到角色,使用手动输入
|
|
89
|
+
return await inputRoleIds(existingValue);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
// 使用多选框选择角色
|
|
93
|
+
const roleChoices = roles.map((role) => ({
|
|
94
|
+
name: `${role.role_name} (${role.role_id})`,
|
|
95
|
+
value: role.role_id.toString(),
|
|
96
|
+
checked: existingValue ? existingValue.split(',').includes(role.role_id.toString()) : false,
|
|
97
|
+
}));
|
|
98
|
+
const selectedRoleIds = await (0, prompts_1.checkbox)({
|
|
99
|
+
message: '请选择角色:',
|
|
100
|
+
choices: roleChoices,
|
|
101
|
+
validate: (answer) => {
|
|
102
|
+
if (answer.length === 0) {
|
|
103
|
+
return '至少需要选择一个角色';
|
|
104
|
+
}
|
|
105
|
+
return true;
|
|
106
|
+
},
|
|
107
|
+
theme: {
|
|
108
|
+
style: {
|
|
109
|
+
help: (text) => `\x1b[90m${123}\x1b[0m`, // 灰色
|
|
110
|
+
keysHelpTip: (keys) => {
|
|
111
|
+
const actionMap = {
|
|
112
|
+
navigate: '上下移动',
|
|
113
|
+
select: '选择/取消',
|
|
114
|
+
all: '全选',
|
|
115
|
+
invert: '反选',
|
|
116
|
+
submit: '提交',
|
|
117
|
+
};
|
|
118
|
+
const tips = keys.map(([key, action]) => `${key} \x1b[90m${actionMap[action] || action}\x1b[0m`);
|
|
119
|
+
return tips.join(' • ');
|
|
120
|
+
},
|
|
125
121
|
},
|
|
126
122
|
},
|
|
127
|
-
|
|
128
|
-
return
|
|
123
|
+
});
|
|
124
|
+
return selectedRoleIds.join(',');
|
|
129
125
|
}
|
|
130
126
|
}
|
|
131
127
|
/**
|
|
@@ -145,25 +141,28 @@ const PROJECT_CONFIG_ITEMS = [
|
|
|
145
141
|
// configure: configureCustomField,
|
|
146
142
|
// },
|
|
147
143
|
];
|
|
144
|
+
async function inputPassword() {
|
|
145
|
+
return await (0, prompts_1.password)({
|
|
146
|
+
message: 'IAM 密码:',
|
|
147
|
+
mask: '*',
|
|
148
|
+
validate: (inputValue) => (inputValue.trim() ? true : 'IAM 密码不能为空'),
|
|
149
|
+
});
|
|
150
|
+
}
|
|
148
151
|
/**
|
|
149
152
|
* 交互式配置向导命令
|
|
150
153
|
* 引导用户创建或更新全局配置文件
|
|
151
154
|
*/
|
|
152
155
|
async function configCommand() {
|
|
153
|
-
logger_1.logger.info('
|
|
156
|
+
logger_1.logger.info('欢迎使用 Hecom CodeArts 配置向导');
|
|
154
157
|
logger_1.logger.info('='.repeat(60));
|
|
155
|
-
logger_1.logger.info('此向导将帮助您配置华为云 CodeArts API
|
|
158
|
+
logger_1.logger.info('此向导将帮助您配置华为云 CodeArts API 访问凭证以及项目相关设置');
|
|
156
159
|
logger_1.logger.info(`配置将保存到: ${(0, config_loader_1.getConfigPath)()}\n`);
|
|
157
160
|
const existingConfig = (0, config_loader_1.configExists)() ? (0, config_loader_1.readConfig)() : {};
|
|
158
161
|
if ((0, config_loader_1.configExists)()) {
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
message: '检测到已存在全局配置,是否覆盖?',
|
|
164
|
-
default: false,
|
|
165
|
-
},
|
|
166
|
-
]);
|
|
162
|
+
const overwrite = await (0, prompts_1.confirm)({
|
|
163
|
+
message: '检测到已存在全局配置,是否覆盖?',
|
|
164
|
+
default: true,
|
|
165
|
+
});
|
|
167
166
|
if (!overwrite) {
|
|
168
167
|
logger_1.logger.info('\n已取消配置。');
|
|
169
168
|
return;
|
|
@@ -181,53 +180,52 @@ async function configCommand() {
|
|
|
181
180
|
password: '',
|
|
182
181
|
};
|
|
183
182
|
while (!credentialsValid) {
|
|
184
|
-
iamAnswers =
|
|
185
|
-
{
|
|
186
|
-
type: 'input',
|
|
187
|
-
name: 'iamEndpoint',
|
|
183
|
+
iamAnswers = {
|
|
184
|
+
iamEndpoint: await (0, prompts_1.input)({
|
|
188
185
|
message: 'IAM 认证端点:',
|
|
189
186
|
default: existingConfig[types_1.ConfigKey.HUAWEI_CLOUD_IAM_ENDPOINT] ||
|
|
190
187
|
'https://iam.cn-north-4.myhuaweicloud.com',
|
|
191
|
-
validate: (
|
|
192
|
-
},
|
|
193
|
-
{
|
|
194
|
-
type: 'input',
|
|
195
|
-
name: 'region',
|
|
188
|
+
validate: (inputValue) => (inputValue.trim() ? true : 'IAM 认证端点不能为空'),
|
|
189
|
+
}),
|
|
190
|
+
region: await (0, prompts_1.input)({
|
|
196
191
|
message: '华为云区域:',
|
|
197
192
|
default: existingConfig[types_1.ConfigKey.HUAWEI_CLOUD_REGION] || 'cn-north-4',
|
|
198
|
-
validate: (
|
|
199
|
-
},
|
|
200
|
-
{
|
|
201
|
-
type: 'input',
|
|
202
|
-
name: 'codeartsUrl',
|
|
193
|
+
validate: (inputValue) => (inputValue.trim() ? true : '华为云区域不能为空'),
|
|
194
|
+
}),
|
|
195
|
+
codeartsUrl: await (0, prompts_1.input)({
|
|
203
196
|
message: 'CodeArts API 地址:',
|
|
204
197
|
default: existingConfig[types_1.ConfigKey.CODEARTS_BASE_URL] ||
|
|
205
198
|
'https://projectman-ext.cn-north-4.myhuaweicloud.cn',
|
|
206
|
-
validate: (
|
|
207
|
-
},
|
|
208
|
-
{
|
|
209
|
-
type: 'input',
|
|
210
|
-
name: 'domain',
|
|
199
|
+
validate: (inputValue) => (inputValue.trim() ? true : 'CodeArts API 地址不能为空'),
|
|
200
|
+
}),
|
|
201
|
+
domain: await (0, prompts_1.input)({
|
|
211
202
|
message: '华为云账号名:',
|
|
212
203
|
default: existingConfig[types_1.ConfigKey.HUAWEI_CLOUD_DOMAIN] || '',
|
|
213
|
-
validate: (
|
|
214
|
-
},
|
|
215
|
-
{
|
|
216
|
-
type: 'input',
|
|
217
|
-
name: 'username',
|
|
204
|
+
validate: (inputValue) => (inputValue.trim() ? true : '华为云账号名不能为空'),
|
|
205
|
+
}),
|
|
206
|
+
username: await (0, prompts_1.input)({
|
|
218
207
|
message: 'IAM 用户名:',
|
|
219
208
|
default: existingConfig[types_1.ConfigKey.HUAWEI_CLOUD_USERNAME] || '',
|
|
220
|
-
validate: (
|
|
221
|
-
},
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
}
|
|
230
|
-
|
|
209
|
+
validate: (inputValue) => (inputValue.trim() ? true : 'IAM 用户名不能为空'),
|
|
210
|
+
}),
|
|
211
|
+
password: '',
|
|
212
|
+
};
|
|
213
|
+
// 处理密码:如果存在旧密码,询问是否重用
|
|
214
|
+
if (existingConfig[types_1.ConfigKey.HUAWEI_CLOUD_PASSWORD]) {
|
|
215
|
+
const useExistingPassword = await (0, prompts_1.confirm)({
|
|
216
|
+
message: 'IAM 密码: 是否使用已保存的密码?',
|
|
217
|
+
default: true,
|
|
218
|
+
});
|
|
219
|
+
if (useExistingPassword) {
|
|
220
|
+
iamAnswers.password = existingConfig[types_1.ConfigKey.HUAWEI_CLOUD_PASSWORD];
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
iamAnswers.password = await inputPassword();
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
else {
|
|
227
|
+
iamAnswers.password = await inputPassword();
|
|
228
|
+
}
|
|
231
229
|
// 创建 BusinessService 实例
|
|
232
230
|
businessService = new business_service_1.BusinessService({
|
|
233
231
|
iamEndpoint: iamAnswers.iamEndpoint,
|
|
@@ -246,14 +244,10 @@ async function configCommand() {
|
|
|
246
244
|
else {
|
|
247
245
|
const errorMessage = `❌ IAM 凭证验证失败: ${validationResult.error}\n`;
|
|
248
246
|
logger_1.logger.error(errorMessage);
|
|
249
|
-
const
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
message: '是否重新配置 IAM 凭证?',
|
|
254
|
-
default: true,
|
|
255
|
-
},
|
|
256
|
-
]);
|
|
247
|
+
const retry = await (0, prompts_1.confirm)({
|
|
248
|
+
message: '是否重新配置 IAM 凭证?',
|
|
249
|
+
default: true,
|
|
250
|
+
});
|
|
257
251
|
if (!retry) {
|
|
258
252
|
logger_1.logger.info('\n已取消配置。');
|
|
259
253
|
return;
|
|
@@ -267,51 +261,39 @@ async function configCommand() {
|
|
|
267
261
|
}
|
|
268
262
|
// 第二阶段:获取项目列表并选择项目
|
|
269
263
|
let projectId;
|
|
264
|
+
let projects = [];
|
|
265
|
+
async function inputProjectId() {
|
|
266
|
+
return await (0, prompts_1.input)({
|
|
267
|
+
message: '项目 ID:',
|
|
268
|
+
default: existingConfig[types_1.ConfigKey.PROJECT_ID] || '',
|
|
269
|
+
validate: (inputValue) => (inputValue.trim() ? true : '项目 ID 不能为空'),
|
|
270
|
+
});
|
|
271
|
+
}
|
|
270
272
|
try {
|
|
271
|
-
|
|
272
|
-
if (projects.length === 0) {
|
|
273
|
-
const { manualProjectId } = await inquirer_1.default.prompt([
|
|
274
|
-
{
|
|
275
|
-
type: 'input',
|
|
276
|
-
name: 'manualProjectId',
|
|
277
|
-
message: '项目 ID:',
|
|
278
|
-
default: existingConfig[types_1.ConfigKey.PROJECT_ID] || '',
|
|
279
|
-
validate: (input) => (input.trim() ? true : '项目 ID 不能为空'),
|
|
280
|
-
},
|
|
281
|
-
]);
|
|
282
|
-
projectId = manualProjectId;
|
|
283
|
-
}
|
|
284
|
-
else {
|
|
285
|
-
const projectChoices = projects.map((p) => ({
|
|
286
|
-
name: `${p.project_name} (${p.project_id})`,
|
|
287
|
-
value: p.project_id,
|
|
288
|
-
}));
|
|
289
|
-
const { selectedProjectId } = await inquirer_1.default.prompt([
|
|
290
|
-
{
|
|
291
|
-
type: 'list',
|
|
292
|
-
name: 'selectedProjectId',
|
|
293
|
-
message: '请选择项目:',
|
|
294
|
-
choices: projectChoices,
|
|
295
|
-
default: existingConfig[types_1.ConfigKey.PROJECT_ID] || projectChoices[0]?.value,
|
|
296
|
-
},
|
|
297
|
-
]);
|
|
298
|
-
projectId = selectedProjectId;
|
|
299
|
-
}
|
|
273
|
+
projects = await businessService.getProjects(100);
|
|
300
274
|
}
|
|
301
275
|
catch (error) {
|
|
302
|
-
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
303
276
|
logger_1.logger.error(`❌ 获取项目列表失败: `, error);
|
|
304
277
|
// 获取失败,使用手动输入
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
|
|
278
|
+
projectId = await inputProjectId();
|
|
279
|
+
}
|
|
280
|
+
if (projects.length === 0) {
|
|
281
|
+
projectId = await inputProjectId();
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
const projectChoices = projects.map((p) => ({
|
|
285
|
+
name: `${p.project_name} (${p.project_id})`,
|
|
286
|
+
value: p.project_id,
|
|
287
|
+
}));
|
|
288
|
+
// 确定默认项目 ID
|
|
289
|
+
const existingProjectId = existingConfig[types_1.ConfigKey.PROJECT_ID];
|
|
290
|
+
const isExistingProjectValid = existingProjectId && projects.some((p) => p.project_id === existingProjectId);
|
|
291
|
+
const defaultProjectId = isExistingProjectValid ? existingProjectId : projectChoices[0]?.value;
|
|
292
|
+
projectId = await (0, prompts_1.select)({
|
|
293
|
+
message: '请选择项目:',
|
|
294
|
+
choices: projectChoices,
|
|
295
|
+
default: defaultProjectId,
|
|
296
|
+
});
|
|
315
297
|
}
|
|
316
298
|
// 第三阶段:配置项目相关配置
|
|
317
299
|
const projectConfigs = {};
|
|
@@ -363,16 +345,6 @@ async function updateProjectConfigCommand(configKey) {
|
|
|
363
345
|
}
|
|
364
346
|
// 读取现有配置
|
|
365
347
|
const existingConfig = (0, config_loader_1.readConfig)();
|
|
366
|
-
// 检查必要的配置是否存在
|
|
367
|
-
if (!existingConfig[types_1.ConfigKey.HUAWEI_CLOUD_USERNAME] ||
|
|
368
|
-
!existingConfig[types_1.ConfigKey.HUAWEI_CLOUD_PASSWORD]) {
|
|
369
|
-
logger_1.logger.error('\n❌ 全局配置不完整,请先运行 `npx @hecom/codearts config` 完成配置。');
|
|
370
|
-
process.exit(1);
|
|
371
|
-
}
|
|
372
|
-
if (!existingConfig[types_1.ConfigKey.PROJECT_ID]) {
|
|
373
|
-
logger_1.logger.error('\n❌ 项目 ID 未配置,请先运行 `npx @hecom/codearts config` 完成配置。');
|
|
374
|
-
process.exit(1);
|
|
375
|
-
}
|
|
376
348
|
// 创建 BusinessService 实例
|
|
377
349
|
const businessService = new business_service_1.BusinessService({
|
|
378
350
|
iamEndpoint: existingConfig[types_1.ConfigKey.HUAWEI_CLOUD_IAM_ENDPOINT],
|
|
@@ -414,7 +386,7 @@ async function showConfigCommand() {
|
|
|
414
386
|
// 获取最终合并后的配置
|
|
415
387
|
const config = (0, config_loader_1.getConfig)();
|
|
416
388
|
// 按类别显示配置
|
|
417
|
-
logger_1.logger.info('
|
|
389
|
+
logger_1.logger.info(picocolors_1.default.cyan('【华为云 IAM 凭证】'));
|
|
418
390
|
const iamKeys = [
|
|
419
391
|
types_1.ConfigKey.HUAWEI_CLOUD_IAM_ENDPOINT,
|
|
420
392
|
types_1.ConfigKey.HUAWEI_CLOUD_REGION,
|
|
@@ -427,7 +399,8 @@ async function showConfigCommand() {
|
|
|
427
399
|
const displayValue = key.includes('PASSWORD') && value !== '(未配置)' ? '********' : value;
|
|
428
400
|
logger_1.logger.info(` ${formatKeyName(key)}: ${displayValue}`);
|
|
429
401
|
}
|
|
430
|
-
logger_1.logger.info(
|
|
402
|
+
logger_1.logger.info();
|
|
403
|
+
logger_1.logger.info(picocolors_1.default.cyanBright('【CodeArts 配置】'));
|
|
431
404
|
const codeartsKeys = [
|
|
432
405
|
types_1.ConfigKey.CODEARTS_BASE_URL,
|
|
433
406
|
types_1.ConfigKey.PROJECT_ID,
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.dailyCommand = dailyCommand;
|
|
7
|
+
const picocolors_1 = __importDefault(require("picocolors"));
|
|
4
8
|
const business_service_1 = require("../services/business.service");
|
|
5
9
|
const config_loader_1 = require("../utils/config-loader");
|
|
6
10
|
const csv_writer_1 = require("../utils/csv-writer");
|
|
@@ -165,6 +169,13 @@ async function queryDailyReportData(businessService, projectId, roleId, targetDa
|
|
|
165
169
|
totalHours: dailyStats.totalHours,
|
|
166
170
|
};
|
|
167
171
|
}
|
|
172
|
+
function issueTypeColor(type) {
|
|
173
|
+
const issueTypeColorMap = {
|
|
174
|
+
任务: picocolors_1.default.bgCyan,
|
|
175
|
+
缺陷: picocolors_1.default.bgRed,
|
|
176
|
+
};
|
|
177
|
+
return issueTypeColorMap[type] ? issueTypeColorMap[type](type) : picocolors_1.default.bgGreen(type);
|
|
178
|
+
}
|
|
168
179
|
/**
|
|
169
180
|
* 控制台输出日报(多角色统一汇总)
|
|
170
181
|
*/
|
|
@@ -195,17 +206,18 @@ function outputConsole(allReports, showReport = false) {
|
|
|
195
206
|
// 平铺所有用户的工时明细
|
|
196
207
|
allReports.forEach((report) => {
|
|
197
208
|
report.userStats.forEach((userStat) => {
|
|
198
|
-
logger_1.logger.info(
|
|
209
|
+
logger_1.logger.info();
|
|
210
|
+
logger_1.logger.info(picocolors_1.default.red(`${userStat.userName} ${userStat.totalHours}小时`));
|
|
199
211
|
userStat.workHours
|
|
200
212
|
.sort((a, b) => a.issueType.localeCompare(b.issueType))
|
|
201
213
|
.forEach((workHour) => {
|
|
202
214
|
const summaryPart = workHour.summary && workHour.summary.trim() !== ''
|
|
203
|
-
? `
|
|
215
|
+
? picocolors_1.default.cyan(` ${workHour.summary}`)
|
|
204
216
|
: '';
|
|
205
217
|
const workHoursTypePart = workHour.workHoursTypeName
|
|
206
218
|
? ` (${workHour.workHoursTypeName})`
|
|
207
219
|
: '';
|
|
208
|
-
logger_1.logger.info(`
|
|
220
|
+
logger_1.logger.info(` ${issueTypeColor(workHour.issueType)} ${workHour.subject}${summaryPart} ${workHoursTypePart} ${workHour.workHoursNum}小时`);
|
|
209
221
|
});
|
|
210
222
|
});
|
|
211
223
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function showLogo(): void;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.showLogo = showLogo;
|
|
4
|
+
const logger_1 = require("../utils/logger");
|
|
5
|
+
const LOGO_LINES = [
|
|
6
|
+
'██╗ ██╗███████╗ ██████╗ ██████╗ ███╗ ███╗',
|
|
7
|
+
'██║ ██║██╔════╝██╔════╝██╔═══██╗████╗ ████║',
|
|
8
|
+
'███████║█████╗ ██║ ██║ ██║██╔████╔██║',
|
|
9
|
+
'██╔══██║██╔══╝ ██║ ██║ ██║██║╚██╔╝██║',
|
|
10
|
+
'██║ ██║███████╗╚██████╗╚██████╔╝██║ ╚═╝ ██║',
|
|
11
|
+
'╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝',
|
|
12
|
+
];
|
|
13
|
+
const RESET = '\x1b[0m';
|
|
14
|
+
// 256-color middle grays - visible on both light and dark backgrounds
|
|
15
|
+
const GRAYS = [
|
|
16
|
+
'\x1b[38;5;250m', // lighter gray
|
|
17
|
+
'\x1b[38;5;248m',
|
|
18
|
+
'\x1b[38;5;245m', // mid gray
|
|
19
|
+
'\x1b[38;5;243m',
|
|
20
|
+
'\x1b[38;5;240m',
|
|
21
|
+
'\x1b[38;5;238m', // darker gray
|
|
22
|
+
];
|
|
23
|
+
function showLogo() {
|
|
24
|
+
logger_1.logger.info();
|
|
25
|
+
LOGO_LINES.forEach((line, i) => {
|
|
26
|
+
logger_1.logger.info(`${GRAYS[i]}${line}${RESET}`);
|
|
27
|
+
});
|
|
28
|
+
logger_1.logger.info();
|
|
29
|
+
}
|
package/dist/utils/logger.d.ts
CHANGED
package/dist/utils/logger.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hecom/codearts",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "华为云 CodeArts 统计分析工具",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -45,14 +45,15 @@
|
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"axios": "^1.5.0",
|
|
48
|
-
"commander": "^
|
|
49
|
-
"inquirer": "^
|
|
48
|
+
"commander": "^14.0.3",
|
|
49
|
+
"inquirer": "^13.2.2",
|
|
50
|
+
"picocolors": "^1.1.1"
|
|
50
51
|
},
|
|
51
52
|
"devDependencies": {
|
|
52
53
|
"@types/commander": "^2.12.0",
|
|
53
54
|
"@types/inquirer": "^9.0.9",
|
|
54
55
|
"@types/jest": "^29.5.5",
|
|
55
|
-
"@types/node": "^20.
|
|
56
|
+
"@types/node": "^20.19.33",
|
|
56
57
|
"@typescript-eslint/eslint-plugin": "^6.7.2",
|
|
57
58
|
"@typescript-eslint/parser": "^6.7.2",
|
|
58
59
|
"eslint": "^8.49.0",
|
package/dist/index.d.ts
DELETED
package/dist/index.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
-
};
|
|
16
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.BusinessService = exports.ApiService = void 0;
|
|
18
|
-
// 导出API服务和类型定义
|
|
19
|
-
var api_service_1 = require("./services/api.service");
|
|
20
|
-
Object.defineProperty(exports, "ApiService", { enumerable: true, get: function () { return api_service_1.ApiService; } });
|
|
21
|
-
var business_service_1 = require("./services/business.service");
|
|
22
|
-
Object.defineProperty(exports, "BusinessService", { enumerable: true, get: function () { return business_service_1.BusinessService; } });
|
|
23
|
-
__exportStar(require("./types"), exports);
|