@hecom/codearts 0.2.0 → 0.2.2

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,56 +1,225 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
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.getConfigPath = getConfigPath;
37
+ exports.configExists = configExists;
38
+ exports.readConfig = readConfig;
39
+ exports.writeConfig = writeConfig;
40
+ exports.deleteConfig = deleteConfig;
6
41
  exports.loadConfig = loadConfig;
7
- const dotenv_1 = __importDefault(require("dotenv"));
8
- const global_config_1 = require("./global-config");
9
- // 加载当前目录的 .env 文件(如果存在)
10
- dotenv_1.default.config();
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 getConfigPath() {
65
+ return CONFIG_FILE;
66
+ }
67
+ /**
68
+ * 检查全局配置文件是否存在
69
+ */
70
+ function configExists() {
71
+ return fs.existsSync(CONFIG_FILE);
72
+ }
73
+ /**
74
+ * 读取全局配置
75
+ */
76
+ function readConfig() {
77
+ if (!configExists()) {
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 writeConfig(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 deleteConfig() {
165
+ if (configExists()) {
166
+ try {
167
+ fs.unlinkSync(CONFIG_FILE);
168
+ }
169
+ catch (error) {
170
+ throw new Error(`删除全局配置文件失败: ${error}`);
171
+ }
172
+ }
173
+ }
11
174
  // 加载全局配置
12
- const globalConfig = (0, global_config_1.globalConfigExists)() ? (0, global_config_1.readGlobalConfig)() : {};
175
+ const globalConfig = configExists() ? readConfig() : {};
13
176
  /**
14
- * 加载配置,优先级:命令行参数 > 当前目录 .env > 全局配置 > 默认值
177
+ * 加载配置,优先级:命令行参数 > 全局配置
15
178
  * @param cliOptions 命令行选项
16
179
  * @returns 加载的配置
17
180
  */
18
181
  function loadConfig(cliOptions = {}) {
19
- // 命令行参数 > 当前目录 .env > 全局配置
20
- const projectId = cliOptions.projectId || process.env.PROJECT_ID || globalConfig.PROJECT_ID;
21
- const roleIdStr = cliOptions.roleId || process.env.ROLE_ID || globalConfig.ROLE_ID;
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('缺少必需参数: --project-id 或环境变量 PROJECT_ID\n提示:运行 codearts config 创建配置');
186
+ throw new Error('缺少项目 ID');
24
187
  }
25
188
  if (!roleIdStr) {
26
- throw new Error('缺少必需参数: --role-id 或环境变量 ROLE_ID\n提示:运行 codearts config 创建配置');
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 = cliOptions.username || process.env.HUAWEI_CLOUD_USERNAME || globalConfig.HUAWEI_CLOUD_USERNAME;
33
- const password = cliOptions.password || process.env.HUAWEI_CLOUD_PASSWORD || globalConfig.HUAWEI_CLOUD_PASSWORD;
34
- const domain = cliOptions.domain || process.env.HUAWEI_CLOUD_DOMAIN || globalConfig.HUAWEI_CLOUD_DOMAIN;
35
- if (!username || !password || !domain) {
36
- throw new Error('缺少华为云认证信息: --username, --password, --domain 或对应的环境变量\n提示:运行 codearts config 创建配置');
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` 创建配置');
203
+ }
204
+ // 处理输出格式
205
+ const outputFormat = (cliOptions.output || 'console');
206
+ if (!['console', 'csv', 'json'].includes(outputFormat)) {
207
+ throw new Error('输出格式必须是 console、csv 或 json 之一');
37
208
  }
38
209
  const config = {
39
- iamEndpoint: cliOptions.iamEndpoint ||
40
- process.env.HUAWEI_CLOUD_IAM_ENDPOINT ||
41
- globalConfig.HUAWEI_CLOUD_IAM_ENDPOINT ||
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',
210
+ iamEndpoint,
211
+ region,
212
+ endpoint,
51
213
  username,
52
214
  password,
53
215
  domainName: domain,
54
216
  };
55
- return { projectId, roleIds, config };
217
+ return { projectId, roleIds, config, outputFormat };
218
+ }
219
+ /**
220
+ * 获取最终合并后的配置(用于显示)
221
+ * @returns 合并后的配置映射
222
+ */
223
+ function getConfig() {
224
+ return globalConfig;
56
225
  }
@@ -0,0 +1,12 @@
1
+ import { Logger } from './logger';
2
+ /**
3
+ * CSV 转义函数:处理双引号
4
+ */
5
+ export declare function escapeCsv(value: string): string;
6
+ /**
7
+ * 写入 CSV 文件到当前工作目录
8
+ * @param filename 文件名
9
+ * @param lines CSV 行数组
10
+ * @param logger 日志记录器(可选)
11
+ */
12
+ export declare function writeCsvFile(filename: string, lines: string[], logger?: Logger): void;
@@ -0,0 +1,60 @@
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 __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
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.escapeCsv = escapeCsv;
37
+ exports.writeCsvFile = writeCsvFile;
38
+ const fs = __importStar(require("fs"));
39
+ const path = __importStar(require("path"));
40
+ /**
41
+ * CSV 转义函数:处理双引号
42
+ */
43
+ function escapeCsv(value) {
44
+ if (!value)
45
+ return '';
46
+ return value.replace(/"/g, '""');
47
+ }
48
+ /**
49
+ * 写入 CSV 文件到当前工作目录
50
+ * @param filename 文件名
51
+ * @param lines CSV 行数组
52
+ * @param logger 日志记录器(可选)
53
+ */
54
+ function writeCsvFile(filename, lines, logger) {
55
+ const filepath = path.join(process.cwd(), filename);
56
+ fs.writeFileSync(filepath, lines.join('\n'), 'utf-8');
57
+ if (logger) {
58
+ logger.success(`CSV 文件已生成: ${filepath}`);
59
+ }
60
+ }
@@ -0,0 +1,62 @@
1
+ export type OutputFormat = 'console' | 'csv' | 'json';
2
+ /**
3
+ * 日志工具类(单例模式)
4
+ * 根据输出格式自动控制日志输出:
5
+ * - console/csv: 正常输出所有日志
6
+ * - json: 静默所有用户日志,只输出纯 JSON
7
+ */
8
+ export declare class Logger {
9
+ private static instance;
10
+ private silent;
11
+ private constructor();
12
+ /**
13
+ * 获取 Logger 单例实例
14
+ */
15
+ static getInstance(): Logger;
16
+ /**
17
+ * 设置输出格式,更新静默状态
18
+ * @param outputFormat 输出格式
19
+ */
20
+ setOutputFormat(outputFormat: string | null | undefined): void;
21
+ /**
22
+ * 信息日志(输出到 stdout)
23
+ * json 模式下会被静默
24
+ */
25
+ info(message: string, ...optionalParams: any[]): void;
26
+ /**
27
+ * 警告日志(输出到 stdout)
28
+ * json 模式下会被静默
29
+ */
30
+ warn(message: string, ...optionalParams: any[]): void;
31
+ /**
32
+ * 成功日志(输出到 stdout)
33
+ * json 模式下会被静默
34
+ */
35
+ success(message: string): void;
36
+ /**
37
+ * 错误日志(输出到 stderr)
38
+ * 始终输出,不受 silent 影响
39
+ */
40
+ error(message: string, ...optionalParams: any[]): void;
41
+ /**
42
+ * 调试日志(输出到 stdout)
43
+ * json 模式下会被静默
44
+ */
45
+ debug(message: string): void;
46
+ /**
47
+ * JSON 数据输出(输出到 stdout)
48
+ * 输出格式化的 JSON 字符串
49
+ * @param data 要输出的数据对象
50
+ */
51
+ json(data: any): void;
52
+ /**
53
+ * 表格输出(输出到 stdout)
54
+ * json 模式下会被静默
55
+ */
56
+ table(data: any): void;
57
+ /**
58
+ * 检查是否处于静默模式
59
+ */
60
+ isSilent(): boolean;
61
+ }
62
+ export declare const logger: Logger;
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.logger = exports.Logger = void 0;
4
+ /**
5
+ * 日志工具类(单例模式)
6
+ * 根据输出格式自动控制日志输出:
7
+ * - console/csv: 正常输出所有日志
8
+ * - json: 静默所有用户日志,只输出纯 JSON
9
+ */
10
+ class Logger {
11
+ constructor() {
12
+ this.silent = false;
13
+ }
14
+ /**
15
+ * 获取 Logger 单例实例
16
+ */
17
+ static getInstance() {
18
+ if (!Logger.instance) {
19
+ Logger.instance = new Logger();
20
+ }
21
+ return Logger.instance;
22
+ }
23
+ /**
24
+ * 设置输出格式,更新静默状态
25
+ * @param outputFormat 输出格式
26
+ */
27
+ setOutputFormat(outputFormat) {
28
+ this.silent = outputFormat === 'json';
29
+ }
30
+ /**
31
+ * 信息日志(输出到 stdout)
32
+ * json 模式下会被静默
33
+ */
34
+ info(message, ...optionalParams) {
35
+ if (!this.silent) {
36
+ console.log(message, ...optionalParams);
37
+ }
38
+ }
39
+ /**
40
+ * 警告日志(输出到 stdout)
41
+ * json 模式下会被静默
42
+ */
43
+ warn(message, ...optionalParams) {
44
+ if (!this.silent) {
45
+ console.warn(message, ...optionalParams);
46
+ }
47
+ }
48
+ /**
49
+ * 成功日志(输出到 stdout)
50
+ * json 模式下会被静默
51
+ */
52
+ success(message) {
53
+ if (!this.silent) {
54
+ console.log(message);
55
+ }
56
+ }
57
+ /**
58
+ * 错误日志(输出到 stderr)
59
+ * 始终输出,不受 silent 影响
60
+ */
61
+ error(message, ...optionalParams) {
62
+ console.error(message, ...optionalParams);
63
+ }
64
+ /**
65
+ * 调试日志(输出到 stdout)
66
+ * json 模式下会被静默
67
+ */
68
+ debug(message) {
69
+ if (!this.silent) {
70
+ console.log(message);
71
+ }
72
+ }
73
+ /**
74
+ * JSON 数据输出(输出到 stdout)
75
+ * 输出格式化的 JSON 字符串
76
+ * @param data 要输出的数据对象
77
+ */
78
+ json(data) {
79
+ console.log(JSON.stringify(data, null, 2));
80
+ }
81
+ /**
82
+ * 表格输出(输出到 stdout)
83
+ * json 模式下会被静默
84
+ */
85
+ table(data) {
86
+ if (!this.silent) {
87
+ console.table(data);
88
+ }
89
+ }
90
+ /**
91
+ * 检查是否处于静默模式
92
+ */
93
+ isSilent() {
94
+ return this.silent;
95
+ }
96
+ }
97
+ exports.Logger = Logger;
98
+ exports.logger = Logger.getInstance();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hecom/codearts",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
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;