@hecom/codearts 0.2.0 → 0.2.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/README.md +34 -169
- package/dist/bin/cli.js +26 -15
- package/dist/commands/bug.command.js +1 -1
- package/dist/commands/config.command.d.ts +25 -0
- package/dist/commands/config.command.js +417 -71
- package/dist/services/api.service.d.ts +9 -2
- package/dist/services/api.service.js +12 -4
- package/dist/services/business.service.d.ts +21 -1
- package/dist/services/business.service.js +66 -1
- package/dist/types/index.d.ts +43 -0
- package/dist/types/index.js +34 -1
- package/dist/utils/config-loader.d.ts +28 -9
- package/dist/utils/config-loader.js +195 -31
- package/package.json +1 -3
- package/.env.example +0 -20
- package/dist/utils/global-config.d.ts +0 -24
- package/dist/utils/global-config.js +0 -153
|
@@ -32,6 +32,45 @@ class BusinessService {
|
|
|
32
32
|
const allMembers = membersResponse.data?.members || [];
|
|
33
33
|
return allMembers.filter((member) => member.role_id === roleId);
|
|
34
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* 获取项目中的所有角色列表(去重)
|
|
37
|
+
* @param projectId 项目ID
|
|
38
|
+
* @returns 项目中的所有角色列表
|
|
39
|
+
*/
|
|
40
|
+
async getProjectRoles(projectId) {
|
|
41
|
+
// 分页获取所有成员
|
|
42
|
+
const allMembers = [];
|
|
43
|
+
const pageSize = 100;
|
|
44
|
+
let offset = 0;
|
|
45
|
+
let hasMore = true;
|
|
46
|
+
while (hasMore) {
|
|
47
|
+
const membersResponse = await this.apiService.getMembers(projectId, {
|
|
48
|
+
limit: pageSize,
|
|
49
|
+
offset: offset,
|
|
50
|
+
});
|
|
51
|
+
if (!membersResponse.success) {
|
|
52
|
+
throw new Error(`获取成员列表失败: ${membersResponse.error || '未知错误'}`);
|
|
53
|
+
}
|
|
54
|
+
const members = membersResponse.data?.members.filter((member) => member.role_id !== -1 && member.nick_name != null) || [];
|
|
55
|
+
allMembers.push(...members);
|
|
56
|
+
// 判断是否还有更多数据
|
|
57
|
+
const total = membersResponse.data?.total || 0;
|
|
58
|
+
offset += pageSize;
|
|
59
|
+
hasMore = offset < total;
|
|
60
|
+
}
|
|
61
|
+
// 使用 Map 去重,key 为 role_id
|
|
62
|
+
const rolesMap = new Map();
|
|
63
|
+
allMembers.forEach((member) => {
|
|
64
|
+
if (!rolesMap.has(member.role_id)) {
|
|
65
|
+
rolesMap.set(member.role_id, {
|
|
66
|
+
role_id: member.role_id,
|
|
67
|
+
role_name: member.role_name,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
// 转换为数组并按 role_id 排序
|
|
72
|
+
return Array.from(rolesMap.values()).sort((a, b) => a.role_id - b.role_id);
|
|
73
|
+
}
|
|
35
74
|
/**
|
|
36
75
|
* 获取指定日期之后的迭代列表
|
|
37
76
|
* @param projectId 项目ID
|
|
@@ -383,7 +422,7 @@ class BusinessService {
|
|
|
383
422
|
let pageNo = 1;
|
|
384
423
|
let hasMore = true;
|
|
385
424
|
while (hasMore) {
|
|
386
|
-
const response = await this.apiService.
|
|
425
|
+
const response = await this.apiService.getChildIssuesV2(projectId, issueId, pageSize, pageNo);
|
|
387
426
|
if (!response.success || !response.data) {
|
|
388
427
|
throw new Error(`获取子工作项失败: ${response.error || '未知错误'}`);
|
|
389
428
|
}
|
|
@@ -395,5 +434,31 @@ class BusinessService {
|
|
|
395
434
|
}
|
|
396
435
|
return allChildIssues;
|
|
397
436
|
}
|
|
437
|
+
/**
|
|
438
|
+
* 验证 IAM 凭证是否有效
|
|
439
|
+
* @returns 验证结果,包含成功状态和可能的错误信息
|
|
440
|
+
*/
|
|
441
|
+
async validateCredentials() {
|
|
442
|
+
try {
|
|
443
|
+
await this.apiService.refreshToken();
|
|
444
|
+
return { success: true };
|
|
445
|
+
}
|
|
446
|
+
catch (error) {
|
|
447
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
448
|
+
return { success: false, error: errorMsg };
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* 获取项目列表
|
|
453
|
+
* @param limit 返回的项目数量限制,默认100
|
|
454
|
+
* @returns 项目列表
|
|
455
|
+
*/
|
|
456
|
+
async getProjects(limit = 100) {
|
|
457
|
+
const response = await this.apiService.getProjects({ limit });
|
|
458
|
+
if (!response.success || !response.data) {
|
|
459
|
+
throw new Error(response.error || '获取项目列表失败');
|
|
460
|
+
}
|
|
461
|
+
return response.data.projects;
|
|
462
|
+
}
|
|
398
463
|
}
|
|
399
464
|
exports.BusinessService = BusinessService;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -152,6 +152,10 @@ export interface ProjectMemberQueryParams {
|
|
|
152
152
|
offset?: number;
|
|
153
153
|
limit?: number;
|
|
154
154
|
}
|
|
155
|
+
export interface ProjectRole {
|
|
156
|
+
role_id: number;
|
|
157
|
+
role_name: string;
|
|
158
|
+
}
|
|
155
159
|
export interface ShowProjectWorkHoursRequest {
|
|
156
160
|
begin_time?: string;
|
|
157
161
|
end_time?: string;
|
|
@@ -521,3 +525,42 @@ export interface AllWorkHourStats {
|
|
|
521
525
|
totalEntries: number;
|
|
522
526
|
userStats: UserAllWorkHourStats[];
|
|
523
527
|
}
|
|
528
|
+
/**
|
|
529
|
+
* 配置键枚举
|
|
530
|
+
* 用于类型安全的配置项访问
|
|
531
|
+
*/
|
|
532
|
+
export declare enum ConfigKey {
|
|
533
|
+
HUAWEI_CLOUD_IAM_ENDPOINT = "HUAWEI_CLOUD_IAM_ENDPOINT",
|
|
534
|
+
HUAWEI_CLOUD_REGION = "HUAWEI_CLOUD_REGION",
|
|
535
|
+
HUAWEI_CLOUD_USERNAME = "HUAWEI_CLOUD_USERNAME",
|
|
536
|
+
HUAWEI_CLOUD_PASSWORD = "HUAWEI_CLOUD_PASSWORD",
|
|
537
|
+
HUAWEI_CLOUD_DOMAIN = "HUAWEI_CLOUD_DOMAIN",
|
|
538
|
+
CODEARTS_BASE_URL = "CODEARTS_BASE_URL",
|
|
539
|
+
PROJECT_ID = "PROJECT_ID",
|
|
540
|
+
ROLE_ID = "ROLE_ID"
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* 不可变配置键(只能通过 config 命令设置)
|
|
544
|
+
*/
|
|
545
|
+
export declare const IMMUTABLE_CONFIG_KEYS: ConfigKey[];
|
|
546
|
+
/**
|
|
547
|
+
* 可变配置键(可以通过命令行参数覆盖)
|
|
548
|
+
*/
|
|
549
|
+
export declare const MUTABLE_CONFIG_KEYS: ConfigKey[];
|
|
550
|
+
/**
|
|
551
|
+
* 类型安全的配置映射
|
|
552
|
+
*/
|
|
553
|
+
export type ConfigMap = {
|
|
554
|
+
[ConfigKey.HUAWEI_CLOUD_IAM_ENDPOINT]: string;
|
|
555
|
+
[ConfigKey.HUAWEI_CLOUD_REGION]: string;
|
|
556
|
+
[ConfigKey.HUAWEI_CLOUD_USERNAME]: string;
|
|
557
|
+
[ConfigKey.HUAWEI_CLOUD_PASSWORD]: string;
|
|
558
|
+
[ConfigKey.HUAWEI_CLOUD_DOMAIN]: string;
|
|
559
|
+
[ConfigKey.CODEARTS_BASE_URL]: string;
|
|
560
|
+
[ConfigKey.PROJECT_ID]: string;
|
|
561
|
+
[ConfigKey.ROLE_ID]: string;
|
|
562
|
+
};
|
|
563
|
+
/**
|
|
564
|
+
* 部分配置映射(用于读取配置文件)
|
|
565
|
+
*/
|
|
566
|
+
export type PartialConfigMap = Partial<ConfigMap>;
|
package/dist/types/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DefectAnalysisType = void 0;
|
|
3
|
+
exports.MUTABLE_CONFIG_KEYS = exports.IMMUTABLE_CONFIG_KEYS = exports.ConfigKey = exports.DefectAnalysisType = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* 缺陷技术分析选项枚举
|
|
6
6
|
* custom_field32(缺陷技术分析)字段的选项值枚举定义
|
|
@@ -23,3 +23,36 @@ var DefectAnalysisType;
|
|
|
23
23
|
DefectAnalysisType["USAGE_AND_CONFIG"] = "\u4F7F\u7528\u53CA\u914D\u7F6E\u95EE\u9898";
|
|
24
24
|
DefectAnalysisType["OTHER"] = "\u5176\u4ED6\u95EE\u9898";
|
|
25
25
|
})(DefectAnalysisType || (exports.DefectAnalysisType = DefectAnalysisType = {}));
|
|
26
|
+
/**
|
|
27
|
+
* 配置键枚举
|
|
28
|
+
* 用于类型安全的配置项访问
|
|
29
|
+
*/
|
|
30
|
+
var ConfigKey;
|
|
31
|
+
(function (ConfigKey) {
|
|
32
|
+
// 不可变配置(只能通过 config 命令设置)
|
|
33
|
+
ConfigKey["HUAWEI_CLOUD_IAM_ENDPOINT"] = "HUAWEI_CLOUD_IAM_ENDPOINT";
|
|
34
|
+
ConfigKey["HUAWEI_CLOUD_REGION"] = "HUAWEI_CLOUD_REGION";
|
|
35
|
+
ConfigKey["HUAWEI_CLOUD_USERNAME"] = "HUAWEI_CLOUD_USERNAME";
|
|
36
|
+
ConfigKey["HUAWEI_CLOUD_PASSWORD"] = "HUAWEI_CLOUD_PASSWORD";
|
|
37
|
+
ConfigKey["HUAWEI_CLOUD_DOMAIN"] = "HUAWEI_CLOUD_DOMAIN";
|
|
38
|
+
ConfigKey["CODEARTS_BASE_URL"] = "CODEARTS_BASE_URL";
|
|
39
|
+
ConfigKey["PROJECT_ID"] = "PROJECT_ID";
|
|
40
|
+
// 可变配置(可以通过命令行参数覆盖)
|
|
41
|
+
ConfigKey["ROLE_ID"] = "ROLE_ID";
|
|
42
|
+
})(ConfigKey || (exports.ConfigKey = ConfigKey = {}));
|
|
43
|
+
/**
|
|
44
|
+
* 不可变配置键(只能通过 config 命令设置)
|
|
45
|
+
*/
|
|
46
|
+
exports.IMMUTABLE_CONFIG_KEYS = [
|
|
47
|
+
ConfigKey.HUAWEI_CLOUD_IAM_ENDPOINT,
|
|
48
|
+
ConfigKey.HUAWEI_CLOUD_REGION,
|
|
49
|
+
ConfigKey.HUAWEI_CLOUD_USERNAME,
|
|
50
|
+
ConfigKey.HUAWEI_CLOUD_PASSWORD,
|
|
51
|
+
ConfigKey.HUAWEI_CLOUD_DOMAIN,
|
|
52
|
+
ConfigKey.CODEARTS_BASE_URL,
|
|
53
|
+
ConfigKey.PROJECT_ID,
|
|
54
|
+
];
|
|
55
|
+
/**
|
|
56
|
+
* 可变配置键(可以通过命令行参数覆盖)
|
|
57
|
+
*/
|
|
58
|
+
exports.MUTABLE_CONFIG_KEYS = [ConfigKey.ROLE_ID];
|
|
@@ -1,13 +1,27 @@
|
|
|
1
|
-
import { HuaweiCloudConfig } from '../types';
|
|
1
|
+
import { HuaweiCloudConfig, PartialConfigMap } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* 获取全局配置文件路径
|
|
4
|
+
*/
|
|
5
|
+
export declare function getGlobalConfigPath(): string;
|
|
6
|
+
/**
|
|
7
|
+
* 检查全局配置文件是否存在
|
|
8
|
+
*/
|
|
9
|
+
export declare function globalConfigExists(): boolean;
|
|
10
|
+
/**
|
|
11
|
+
* 读取全局配置
|
|
12
|
+
*/
|
|
13
|
+
export declare function readGlobalConfig(): PartialConfigMap;
|
|
14
|
+
/**
|
|
15
|
+
* 写入全局配置
|
|
16
|
+
* 支持动态配置项,自动按分组组织配置文件
|
|
17
|
+
*/
|
|
18
|
+
export declare function writeGlobalConfig(config: PartialConfigMap): void;
|
|
19
|
+
/**
|
|
20
|
+
* 删除全局配置
|
|
21
|
+
*/
|
|
22
|
+
export declare function deleteGlobalConfig(): void;
|
|
2
23
|
export interface CliOptions {
|
|
3
|
-
projectId?: string;
|
|
4
24
|
roleId?: string;
|
|
5
|
-
username?: string;
|
|
6
|
-
password?: string;
|
|
7
|
-
domain?: string;
|
|
8
|
-
region?: string;
|
|
9
|
-
iamEndpoint?: string;
|
|
10
|
-
codeartsUrl?: string;
|
|
11
25
|
}
|
|
12
26
|
export interface LoadedConfig {
|
|
13
27
|
projectId: string;
|
|
@@ -15,8 +29,13 @@ export interface LoadedConfig {
|
|
|
15
29
|
config: HuaweiCloudConfig;
|
|
16
30
|
}
|
|
17
31
|
/**
|
|
18
|
-
* 加载配置,优先级:命令行参数 >
|
|
32
|
+
* 加载配置,优先级:命令行参数 > 全局配置
|
|
19
33
|
* @param cliOptions 命令行选项
|
|
20
34
|
* @returns 加载的配置
|
|
21
35
|
*/
|
|
22
36
|
export declare function loadConfig(cliOptions?: CliOptions): LoadedConfig;
|
|
37
|
+
/**
|
|
38
|
+
* 获取最终合并后的配置(用于显示)
|
|
39
|
+
* @returns 合并后的配置映射
|
|
40
|
+
*/
|
|
41
|
+
export declare function getConfig(): PartialConfigMap;
|
|
@@ -1,56 +1,220 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var
|
|
3
|
-
|
|
4
|
-
|
|
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
5
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.getGlobalConfigPath = getGlobalConfigPath;
|
|
37
|
+
exports.globalConfigExists = globalConfigExists;
|
|
38
|
+
exports.readGlobalConfig = readGlobalConfig;
|
|
39
|
+
exports.writeGlobalConfig = writeGlobalConfig;
|
|
40
|
+
exports.deleteGlobalConfig = deleteGlobalConfig;
|
|
6
41
|
exports.loadConfig = loadConfig;
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
42
|
+
exports.getConfig = getConfig;
|
|
43
|
+
const fs = __importStar(require("fs"));
|
|
44
|
+
const os = __importStar(require("os"));
|
|
45
|
+
const path = __importStar(require("path"));
|
|
46
|
+
const types_1 = require("../types");
|
|
47
|
+
/**
|
|
48
|
+
* 全局配置管理工具
|
|
49
|
+
* 配置文件存储在用户主目录下的 .hecom-codearts 目录
|
|
50
|
+
*/
|
|
51
|
+
const CONFIG_DIR = path.join(os.homedir(), '.hecom-codearts');
|
|
52
|
+
const CONFIG_FILE = path.join(CONFIG_DIR, 'config.env');
|
|
53
|
+
/**
|
|
54
|
+
* 确保配置目录存在
|
|
55
|
+
*/
|
|
56
|
+
function ensureConfigDir() {
|
|
57
|
+
if (!fs.existsSync(CONFIG_DIR)) {
|
|
58
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* 获取全局配置文件路径
|
|
63
|
+
*/
|
|
64
|
+
function getGlobalConfigPath() {
|
|
65
|
+
return CONFIG_FILE;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* 检查全局配置文件是否存在
|
|
69
|
+
*/
|
|
70
|
+
function globalConfigExists() {
|
|
71
|
+
return fs.existsSync(CONFIG_FILE);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* 读取全局配置
|
|
75
|
+
*/
|
|
76
|
+
function readGlobalConfig() {
|
|
77
|
+
if (!globalConfigExists()) {
|
|
78
|
+
return {};
|
|
79
|
+
}
|
|
80
|
+
const config = {};
|
|
81
|
+
try {
|
|
82
|
+
const content = fs.readFileSync(CONFIG_FILE, 'utf-8');
|
|
83
|
+
const lines = content.split('\n');
|
|
84
|
+
for (const line of lines) {
|
|
85
|
+
const trimmedLine = line.trim();
|
|
86
|
+
if (!trimmedLine || trimmedLine.startsWith('#')) {
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
const equalIndex = trimmedLine.indexOf('=');
|
|
90
|
+
if (equalIndex > 0) {
|
|
91
|
+
const key = trimmedLine.substring(0, equalIndex).trim();
|
|
92
|
+
const value = trimmedLine.substring(equalIndex + 1).trim();
|
|
93
|
+
// 只保存合法的配置键
|
|
94
|
+
if (Object.values(types_1.ConfigKey).includes(key)) {
|
|
95
|
+
config[key] = value;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
console.error('读取全局配置文件失败:', error);
|
|
102
|
+
}
|
|
103
|
+
return config;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* 配置项分组和顺序定义
|
|
107
|
+
*/
|
|
108
|
+
const CONFIG_GROUPS = [
|
|
109
|
+
{
|
|
110
|
+
title: '华为云IAM认证端点(根据区域调整)',
|
|
111
|
+
keys: [types_1.ConfigKey.HUAWEI_CLOUD_IAM_ENDPOINT, types_1.ConfigKey.HUAWEI_CLOUD_REGION],
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
title: 'IAM用户凭证',
|
|
115
|
+
keys: [
|
|
116
|
+
types_1.ConfigKey.HUAWEI_CLOUD_USERNAME,
|
|
117
|
+
types_1.ConfigKey.HUAWEI_CLOUD_PASSWORD,
|
|
118
|
+
types_1.ConfigKey.HUAWEI_CLOUD_DOMAIN,
|
|
119
|
+
],
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
title: '项目配置',
|
|
123
|
+
keys: [types_1.ConfigKey.CODEARTS_BASE_URL, types_1.ConfigKey.PROJECT_ID, types_1.ConfigKey.ROLE_ID],
|
|
124
|
+
},
|
|
125
|
+
];
|
|
126
|
+
/**
|
|
127
|
+
* 写入全局配置
|
|
128
|
+
* 支持动态配置项,自动按分组组织配置文件
|
|
129
|
+
*/
|
|
130
|
+
function writeGlobalConfig(config) {
|
|
131
|
+
ensureConfigDir();
|
|
132
|
+
// 构建配置文件头部
|
|
133
|
+
let content = `# Hecom CodeArts 全局配置文件`;
|
|
134
|
+
// 记录已写入的配置项
|
|
135
|
+
const writtenKeys = new Set();
|
|
136
|
+
// 按分组写入配置
|
|
137
|
+
for (const group of CONFIG_GROUPS) {
|
|
138
|
+
content += `\n# ${group.title}\n`;
|
|
139
|
+
for (const key of group.keys) {
|
|
140
|
+
const value = config[key] || '';
|
|
141
|
+
content += `${key}=${value}\n`;
|
|
142
|
+
writtenKeys.add(key);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
// 写入未分组的其他配置项(支持未来扩展)
|
|
146
|
+
const otherKeys = Object.keys(config).filter((key) => !writtenKeys.has(key));
|
|
147
|
+
if (otherKeys.length > 0) {
|
|
148
|
+
content += `\n# 其他配置\n`;
|
|
149
|
+
for (const key of otherKeys) {
|
|
150
|
+
const value = config[key] || '';
|
|
151
|
+
content += `${key}=${value}\n`;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
try {
|
|
155
|
+
fs.writeFileSync(CONFIG_FILE, content, 'utf-8');
|
|
156
|
+
}
|
|
157
|
+
catch (error) {
|
|
158
|
+
throw new Error(`写入全局配置文件失败: ${error}`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* 删除全局配置
|
|
163
|
+
*/
|
|
164
|
+
function deleteGlobalConfig() {
|
|
165
|
+
if (globalConfigExists()) {
|
|
166
|
+
try {
|
|
167
|
+
fs.unlinkSync(CONFIG_FILE);
|
|
168
|
+
}
|
|
169
|
+
catch (error) {
|
|
170
|
+
throw new Error(`删除全局配置文件失败: ${error}`);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
11
174
|
// 加载全局配置
|
|
12
|
-
const globalConfig =
|
|
175
|
+
const globalConfig = globalConfigExists() ? readGlobalConfig() : {};
|
|
13
176
|
/**
|
|
14
|
-
* 加载配置,优先级:命令行参数 >
|
|
177
|
+
* 加载配置,优先级:命令行参数 > 全局配置
|
|
15
178
|
* @param cliOptions 命令行选项
|
|
16
179
|
* @returns 加载的配置
|
|
17
180
|
*/
|
|
18
181
|
function loadConfig(cliOptions = {}) {
|
|
19
|
-
// 命令行参数 >
|
|
20
|
-
const projectId =
|
|
21
|
-
const roleIdStr = cliOptions.roleId ||
|
|
182
|
+
// 命令行参数 > 全局配置
|
|
183
|
+
const projectId = globalConfig[types_1.ConfigKey.PROJECT_ID];
|
|
184
|
+
const roleIdStr = cliOptions.roleId || globalConfig[types_1.ConfigKey.ROLE_ID];
|
|
22
185
|
if (!projectId) {
|
|
23
|
-
throw new Error('
|
|
186
|
+
throw new Error('缺少项目 ID');
|
|
24
187
|
}
|
|
25
188
|
if (!roleIdStr) {
|
|
26
|
-
throw new Error('
|
|
189
|
+
throw new Error('缺少角色 ID');
|
|
27
190
|
}
|
|
28
191
|
const roleIds = roleIdStr.split(',').map((id) => parseInt(id.trim()));
|
|
29
192
|
if (roleIds.some((id) => isNaN(id))) {
|
|
30
193
|
throw new Error('ROLE_ID 格式不正确,应为数字或逗号分隔的数字列表');
|
|
31
194
|
}
|
|
32
|
-
const username =
|
|
33
|
-
const password =
|
|
34
|
-
const domain =
|
|
35
|
-
|
|
36
|
-
|
|
195
|
+
const username = globalConfig[types_1.ConfigKey.HUAWEI_CLOUD_USERNAME];
|
|
196
|
+
const password = globalConfig[types_1.ConfigKey.HUAWEI_CLOUD_PASSWORD];
|
|
197
|
+
const domain = globalConfig[types_1.ConfigKey.HUAWEI_CLOUD_DOMAIN];
|
|
198
|
+
const iamEndpoint = globalConfig[types_1.ConfigKey.HUAWEI_CLOUD_IAM_ENDPOINT];
|
|
199
|
+
const region = globalConfig[types_1.ConfigKey.HUAWEI_CLOUD_REGION];
|
|
200
|
+
const endpoint = globalConfig[types_1.ConfigKey.CODEARTS_BASE_URL];
|
|
201
|
+
if (!username || !password || !domain || !iamEndpoint || !region || !endpoint) {
|
|
202
|
+
throw new Error('缺少华为云认证信息,请先运行 `npx @hecom/codearts config` 创建配置');
|
|
37
203
|
}
|
|
38
204
|
const config = {
|
|
39
|
-
iamEndpoint
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
'https://iam.cn-north-4.myhuaweicloud.com',
|
|
43
|
-
region: cliOptions.region ||
|
|
44
|
-
process.env.HUAWEI_CLOUD_REGION ||
|
|
45
|
-
globalConfig.HUAWEI_CLOUD_REGION ||
|
|
46
|
-
'cn-north-4',
|
|
47
|
-
endpoint: cliOptions.codeartsUrl ||
|
|
48
|
-
process.env.CODEARTS_BASE_URL ||
|
|
49
|
-
globalConfig.CODEARTS_BASE_URL ||
|
|
50
|
-
'https://projectman-ext.cn-north-4.myhuaweicloud.cn',
|
|
205
|
+
iamEndpoint,
|
|
206
|
+
region,
|
|
207
|
+
endpoint,
|
|
51
208
|
username,
|
|
52
209
|
password,
|
|
53
210
|
domainName: domain,
|
|
54
211
|
};
|
|
55
212
|
return { projectId, roleIds, config };
|
|
56
213
|
}
|
|
214
|
+
/**
|
|
215
|
+
* 获取最终合并后的配置(用于显示)
|
|
216
|
+
* @returns 合并后的配置映射
|
|
217
|
+
*/
|
|
218
|
+
function getConfig() {
|
|
219
|
+
return globalConfig;
|
|
220
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hecom/codearts",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "华为云 CodeArts 统计分析工具",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -10,7 +10,6 @@
|
|
|
10
10
|
"files": [
|
|
11
11
|
"dist",
|
|
12
12
|
"bin",
|
|
13
|
-
".env.example",
|
|
14
13
|
"README.md"
|
|
15
14
|
],
|
|
16
15
|
"scripts": {
|
|
@@ -47,7 +46,6 @@
|
|
|
47
46
|
"dependencies": {
|
|
48
47
|
"axios": "^1.5.0",
|
|
49
48
|
"commander": "^12.1.0",
|
|
50
|
-
"dotenv": "^16.3.1",
|
|
51
49
|
"inquirer": "^9.3.8"
|
|
52
50
|
},
|
|
53
51
|
"devDependencies": {
|
package/.env.example
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
# 华为云CodeArts API 环境变量配置
|
|
2
|
-
# 复制此文件为 .env 并填入真实的配置值
|
|
3
|
-
|
|
4
|
-
# 华为云IAM认证端点(根据区域调整)
|
|
5
|
-
HUAWEI_CLOUD_IAM_ENDPOINT=https://iam.cn-north-4.myhuaweicloud.com
|
|
6
|
-
HUAWEI_CLOUD_REGION=cn-north-4
|
|
7
|
-
|
|
8
|
-
# IAM用户凭证
|
|
9
|
-
HUAWEI_CLOUD_USERNAME=your-iam-username
|
|
10
|
-
HUAWEI_CLOUD_PASSWORD=your-iam-password
|
|
11
|
-
HUAWEI_CLOUD_DOMAIN=your-domain-name
|
|
12
|
-
|
|
13
|
-
# CodeArts API基础URL(可选,默认根据区域自动生成)
|
|
14
|
-
CODEARTS_BASE_URL=https://projectman-ext.cn-north-4.myhuaweicloud.cn
|
|
15
|
-
|
|
16
|
-
PROJECT_ID=your-project-id
|
|
17
|
-
|
|
18
|
-
# 角色ID(支持多个,逗号分隔)
|
|
19
|
-
ROLE_ID=your-role-id
|
|
20
|
-
# 示例:ROLE_ID=1,2,3
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 获取全局配置文件路径
|
|
3
|
-
*/
|
|
4
|
-
export declare function getGlobalConfigPath(): string;
|
|
5
|
-
/**
|
|
6
|
-
* 检查全局配置文件是否存在
|
|
7
|
-
*/
|
|
8
|
-
export declare function globalConfigExists(): boolean;
|
|
9
|
-
/**
|
|
10
|
-
* 读取全局配置
|
|
11
|
-
*/
|
|
12
|
-
export declare function readGlobalConfig(): Record<string, string>;
|
|
13
|
-
/**
|
|
14
|
-
* 写入全局配置
|
|
15
|
-
*/
|
|
16
|
-
export declare function writeGlobalConfig(config: Record<string, string>): void;
|
|
17
|
-
/**
|
|
18
|
-
* 删除全局配置
|
|
19
|
-
*/
|
|
20
|
-
export declare function deleteGlobalConfig(): void;
|
|
21
|
-
/**
|
|
22
|
-
* 获取配置信息(用于显示)
|
|
23
|
-
*/
|
|
24
|
-
export declare function getConfigInfo(): string;
|