@hecom/codearts 0.3.2 → 0.4.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.
Files changed (43) hide show
  1. package/README.md +1 -1
  2. package/dist/bin/cli.js +25 -4
  3. package/dist/charts/chart.interface.d.ts +5 -0
  4. package/dist/charts/chart.interface.js +2 -0
  5. package/dist/charts/index.d.ts +2 -0
  6. package/dist/charts/index.js +17 -0
  7. package/dist/charts/modules/__tests__/bug-by-developer-hours.test.d.ts +1 -0
  8. package/dist/charts/modules/__tests__/bug-by-developer-hours.test.js +54 -0
  9. package/dist/charts/modules/__tests__/bug-by-fix-duration.test.d.ts +1 -0
  10. package/dist/charts/modules/__tests__/bug-by-fix-duration.test.js +89 -0
  11. package/dist/charts/modules/__tests__/bug-open-priority-heatmap.test.d.ts +1 -0
  12. package/dist/charts/modules/__tests__/bug-open-priority-heatmap.test.js +61 -0
  13. package/dist/charts/modules/bug-by-assignee.d.ts +2 -0
  14. package/dist/charts/modules/bug-by-assignee.js +30 -0
  15. package/dist/charts/modules/bug-by-defect-analysis.d.ts +2 -0
  16. package/dist/charts/modules/bug-by-defect-analysis.js +30 -0
  17. package/dist/charts/modules/bug-by-developer-hours.d.ts +2 -0
  18. package/dist/charts/modules/bug-by-developer-hours.js +32 -0
  19. package/dist/charts/modules/bug-by-fix-duration.d.ts +2 -0
  20. package/dist/charts/modules/bug-by-fix-duration.js +46 -0
  21. package/dist/charts/modules/bug-by-module.d.ts +2 -0
  22. package/dist/charts/modules/bug-by-module.js +34 -0
  23. package/dist/charts/modules/bug-open-priority-heatmap.d.ts +2 -0
  24. package/dist/charts/modules/bug-open-priority-heatmap.js +74 -0
  25. package/dist/charts/renderer.d.ts +21 -0
  26. package/dist/charts/renderer.js +163 -0
  27. package/dist/commands/config.command.d.ts +1 -1
  28. package/dist/commands/config.command.js +6 -6
  29. package/dist/commands/fix.command.d.ts +6 -0
  30. package/dist/commands/fix.command.js +220 -0
  31. package/dist/commands/index.d.ts +2 -0
  32. package/dist/commands/index.js +5 -1
  33. package/dist/commands/rebug.command.d.ts +5 -0
  34. package/dist/commands/rebug.command.js +113 -0
  35. package/dist/services/api.service.d.ts +10 -2
  36. package/dist/services/api.service.js +19 -0
  37. package/dist/services/business.service.d.ts +40 -1
  38. package/dist/services/business.service.js +226 -5
  39. package/dist/types/index.d.ts +107 -1
  40. package/dist/types/index.js +60 -1
  41. package/dist/utils/config-loader.d.ts +7 -6
  42. package/dist/utils/config-loader.js +13 -13
  43. package/package.json +5 -2
@@ -1,4 +1,4 @@
1
- import { AllWorkHourStats, HuaweiCloudConfig, IssueItem, IssueItemV2, IterationInfo, ProjectMember, ProjectRole, WorkHourStats, WorkProgressStats } from '../types';
1
+ import { AllWorkHourStats, BugFixData, HuaweiCloudConfig, IssueItem, IssueItemV2, IterationInfo, ProjectMember, ProjectRole, WorkHourStats, WorkProgressStats } from '../types';
2
2
  /**
3
3
  * 业务服务类
4
4
  * 提供面向业务场景的高级操作,封装ApiService的底层调用
@@ -102,4 +102,43 @@ export declare class BusinessService {
102
102
  * @returns 项目列表
103
103
  */
104
104
  getProjects(limit?: number): Promise<import('../types').Project[]>;
105
+ /**
106
+ * 查询当前用户的所有 Bug
107
+ * @param projectId 项目ID
108
+ * @param options 查询选项
109
+ * @param options.hasIteration 是否有迭代(true: 有迭代, false: 无迭代, undefined: 不过滤)
110
+ * @returns Bug 类型的工作项列表,按创建时间倒序排列
111
+ */
112
+ getCurrentUserBugs(projectId: string, options?: {
113
+ hasIteration?: boolean;
114
+ }): Promise<IssueItem[]>;
115
+ /**
116
+ * 根据迭代 ID 和终端类型查询有效 Bug(分页获取全量)
117
+ * @param projectId 项目ID
118
+ * @param iterationIds 迭代 ID 列表
119
+ * @param terminalTypes 终端类型列表(对应 custom_field24),为空则不过滤
120
+ * @returns Bug 类型工作项列表
121
+ */
122
+ getBugsByIterationsAndTerminals(projectId: string, iterationIds: number[], terminalTypes: string[]): Promise<IssueItem[]>;
123
+ /**
124
+ * 批量获取自定义字段的选项
125
+ * @param projectId 项目ID
126
+ * @param customFieldIds 自定义字段ID列表
127
+ * @returns 自定义字段选项映射,key为字段ID,value为选项数组
128
+ */
129
+ getCustomFieldOptions(projectId: string, customFieldIds: string[]): Promise<Record<string, string[]>>;
130
+ /**
131
+ * 修复缺陷工作项
132
+ * 根据填写的缺陷分析信息更新缺陷工作项,仅当问题为缺陷且状态为可处理状态时才更新
133
+ * @param projectId 项目ID
134
+ * @param issue 选中的缺陷工作项
135
+ * @param bugFixData 缺陷分析数据
136
+ */
137
+ fixBug(projectId: string, issue: IssueItem, bugFixData: BugFixData): Promise<void>;
138
+ /**
139
+ * 将日期字符串解析为时间戳
140
+ * @param dateStr 日期字符串,格式:YYYY-MM-DD
141
+ * @returns 毫秒时间戳,如果解析失败返回 null
142
+ */
143
+ private parseDateToTimestamp;
105
144
  }
@@ -124,7 +124,7 @@ class BusinessService {
124
124
  }
125
125
  const issuesResponse = await this.apiService.getIssues(projectId, {
126
126
  iteration_ids: iterationIds,
127
- tracker_ids: [2], // 2=Task(任务), 7=Story
127
+ tracker_ids: [types_1.IssueTrackerId.TASK], // Task
128
128
  assigned_ids: userIds,
129
129
  limit: 100,
130
130
  offset: 0,
@@ -168,8 +168,10 @@ class BusinessService {
168
168
  };
169
169
  }
170
170
  stats[userId].count++;
171
- // 如果状态是已关闭(id=5),expectedHours 取实际工时,否则取预估工时
172
- const expectedHours = issue.status?.id === 5 ? issue.actual_work_hours || 0 : issue.expected_work_hours || 0;
171
+ // 如果状态是已关闭,expectedHours 取实际工时,否则取预估工时
172
+ const expectedHours = issue.status?.id === types_1.IssueStatusId.CLOSED
173
+ ? issue.actual_work_hours || 0
174
+ : issue.expected_work_hours || 0;
173
175
  stats[userId].expectedHours += expectedHours;
174
176
  stats[userId].actualHours += issue.actual_work_hours || 0;
175
177
  // 累计总工时
@@ -279,7 +281,7 @@ class BusinessService {
279
281
  const issuesResponse = await this.apiService.getIssues(projectId, {
280
282
  iteration_ids: iterationIds,
281
283
  assigned_ids: userIds,
282
- tracker_ids: [7], // 7=Story
284
+ tracker_ids: [types_1.IssueTrackerId.STORY], // Story
283
285
  include_deleted: false,
284
286
  limit: pageSize,
285
287
  offset: offset,
@@ -351,7 +353,7 @@ class BusinessService {
351
353
  // Step 4: 为每个工时记录关联领域信息
352
354
  const enrichedWorkHours = allWorkHours.map((workHour) => {
353
355
  const issue = issueDetailsMap.get(workHour.issue_id);
354
- const isBug = issue?.tracker?.id === 3; // 3=Bug
356
+ const isBug = issue?.tracker?.id === types_1.IssueTrackerId.BUG;
355
357
  const type = isBug ? issue?.tracker?.name || '' : issue?.domain?.name || '未分配领域';
356
358
  return {
357
359
  ...workHour,
@@ -462,5 +464,224 @@ class BusinessService {
462
464
  }
463
465
  return response.data.projects;
464
466
  }
467
+ /**
468
+ * 查询当前用户的所有 Bug
469
+ * @param projectId 项目ID
470
+ * @param options 查询选项
471
+ * @param options.hasIteration 是否有迭代(true: 有迭代, false: 无迭代, undefined: 不过滤)
472
+ * @returns Bug 类型的工作项列表,按创建时间倒序排列
473
+ */
474
+ async getCurrentUserBugs(projectId, options = {}) {
475
+ // Step 1: 获取当前用户信息
476
+ const userInfoResponse = await this.apiService.showCurUserInfo();
477
+ if (!userInfoResponse.success || !userInfoResponse.data) {
478
+ throw new Error(`获取当前用户信息失败: ${userInfoResponse.error || '未知错误'}`);
479
+ }
480
+ const currentUserId = userInfoResponse.data.user_id;
481
+ // Step 2: 分页查询所有 Bug(tracker_id = 3 为 Bug)
482
+ const allBugs = [];
483
+ const pageSize = 100;
484
+ let offset = 0;
485
+ let hasMore = true;
486
+ while (hasMore) {
487
+ const issuesResponse = await this.apiService.getIssues(projectId, {
488
+ assigned_ids: [currentUserId],
489
+ tracker_ids: [types_1.IssueTrackerId.BUG], // Bug
490
+ status_ids: [
491
+ types_1.IssueStatusId.NEW_ISSUE,
492
+ types_1.IssueStatusId.REOPENED,
493
+ types_1.IssueStatusId.NEW_REQUIREMENT,
494
+ ], // 可处理状态
495
+ include_deleted: false,
496
+ limit: pageSize,
497
+ offset: offset,
498
+ });
499
+ if (!issuesResponse.success) {
500
+ throw new Error(`获取Bug列表失败: ${issuesResponse.error || '未知错误'}`);
501
+ }
502
+ const bugs = issuesResponse.data?.issues || [];
503
+ allBugs.push(...bugs);
504
+ // 判断是否还有更多数据
505
+ const total = issuesResponse.data?.total || 0;
506
+ offset += pageSize;
507
+ hasMore = offset < total;
508
+ }
509
+ // Step 3: 按照迭代状态过滤
510
+ let filteredBugs = allBugs;
511
+ if (options.hasIteration !== undefined) {
512
+ filteredBugs = allBugs.filter((bug) => {
513
+ const hasIteration = bug.iteration && bug.iteration.id > 0;
514
+ return options.hasIteration ? hasIteration : !hasIteration;
515
+ });
516
+ }
517
+ // Step 4: 按创建时间倒序排列
518
+ filteredBugs.sort((a, b) => {
519
+ const timeA = new Date(a.created_time).getTime();
520
+ const timeB = new Date(b.created_time).getTime();
521
+ return timeB - timeA; // 倒序
522
+ });
523
+ return filteredBugs;
524
+ }
525
+ /**
526
+ * 根据迭代 ID 和终端类型查询有效 Bug(分页获取全量)
527
+ * @param projectId 项目ID
528
+ * @param iterationIds 迭代 ID 列表
529
+ * @param terminalTypes 终端类型列表(对应 custom_field24),为空则不过滤
530
+ * @returns Bug 类型工作项列表
531
+ */
532
+ async getBugsByIterationsAndTerminals(projectId, iterationIds, terminalTypes) {
533
+ if (iterationIds.length === 0) {
534
+ return [];
535
+ }
536
+ const customFieldsFilter = terminalTypes.length > 0
537
+ ? [{ custom_field: types_1.CustomFieldId.TERMINAL_TYPE, value: terminalTypes.join(',') }]
538
+ : [];
539
+ const allBugs = [];
540
+ const pageSize = 100;
541
+ let offset = 0;
542
+ let hasMore = true;
543
+ while (hasMore) {
544
+ const issuesResponse = await this.apiService.getIssues(projectId, {
545
+ tracker_ids: [types_1.IssueTrackerId.BUG],
546
+ iteration_ids: iterationIds,
547
+ custom_fields: customFieldsFilter.length > 0 ? customFieldsFilter : undefined,
548
+ include_deleted: false,
549
+ limit: pageSize,
550
+ offset,
551
+ });
552
+ if (!issuesResponse.success) {
553
+ throw new Error(`查询 Bug 失败: ${issuesResponse.error || '未知错误'}`);
554
+ }
555
+ const bugs = issuesResponse.data?.issues || [];
556
+ allBugs.push(...bugs);
557
+ const total = issuesResponse.data?.total || 0;
558
+ offset += pageSize;
559
+ hasMore = offset < total;
560
+ }
561
+ return allBugs.filter((bug) => bug.status?.id !== types_1.IssueStatusId.REJECTED);
562
+ }
563
+ /**
564
+ * 批量获取自定义字段的选项
565
+ * @param projectId 项目ID
566
+ * @param customFieldIds 自定义字段ID列表
567
+ * @returns 自定义字段选项映射,key为字段ID,value为选项数组
568
+ */
569
+ async getCustomFieldOptions(projectId, customFieldIds) {
570
+ if (customFieldIds.length === 0) {
571
+ return {};
572
+ }
573
+ const response = await this.apiService.getCustomFields(projectId, customFieldIds);
574
+ if (!response.success || !response.data) {
575
+ throw new Error(`获取自定义字段信息失败: ${response.error || '未知错误'}`);
576
+ }
577
+ // 将自定义字段列表转换为 fieldId -> options 的映射
578
+ const optionsMap = {};
579
+ response.data.datas.forEach((field) => {
580
+ // 如果 options 为 null,返回空数组;否则将逗号分隔的字符串解析为数组
581
+ optionsMap[field.custom_field] = field.options
582
+ ? field.options.split(',').map((option) => option.trim())
583
+ : [];
584
+ });
585
+ return optionsMap;
586
+ }
587
+ /**
588
+ * 修复缺陷工作项
589
+ * 根据填写的缺陷分析信息更新缺陷工作项,仅当问题为缺陷且状态为可处理状态时才更新
590
+ * @param projectId 项目ID
591
+ * @param issue 选中的缺陷工作项
592
+ * @param bugFixData 缺陷分析数据
593
+ */
594
+ async fixBug(projectId, issue, bugFixData) {
595
+ const { defectAnalysis, problemReason, impactScope, introductionStage, releaseDate } = bugFixData;
596
+ // 验证工作项是否为缺陷
597
+ if (issue.tracker?.id !== types_1.IssueTrackerId.BUG) {
598
+ throw new Error('选择的工作项不是缺陷类型');
599
+ }
600
+ // 验证工作项状态是否为可处理状态
601
+ // 可处理状态:17(新问题)、15(重新打开)、1(新需求)
602
+ if (![types_1.IssueStatusId.NEW_ISSUE, types_1.IssueStatusId.REOPENED, types_1.IssueStatusId.NEW_REQUIREMENT].includes(issue.status?.id)) {
603
+ throw new Error('缺陷工作项状态不可处理');
604
+ }
605
+ // 构建更新请求体
606
+ const newCustomFields = [];
607
+ if (defectAnalysis) {
608
+ newCustomFields.push({
609
+ custom_field: 'custom_field32',
610
+ field_name: '缺陷技术分析',
611
+ value: defectAnalysis,
612
+ });
613
+ }
614
+ if (problemReason) {
615
+ newCustomFields.push({
616
+ custom_field: 'custom_field39',
617
+ field_name: '问题原因',
618
+ value: problemReason,
619
+ });
620
+ }
621
+ if (impactScope) {
622
+ newCustomFields.push({
623
+ custom_field: 'custom_field40',
624
+ field_name: '影响范围',
625
+ value: impactScope,
626
+ });
627
+ }
628
+ // 检查缺陷类型是否为客户反馈
629
+ const issueCustomFields = issue.new_custom_fields || [];
630
+ const issueDefectTypeField = issueCustomFields.find((field) => field?.custom_field === 'custom_field36' || field?.field_name === '缺陷类型');
631
+ const issueDefectType = issueDefectTypeField?.value || '';
632
+ const isCustomerFeedback = issueDefectType === '客户反馈';
633
+ if (isCustomerFeedback) {
634
+ if (introductionStage) {
635
+ newCustomFields.push({
636
+ custom_field: 'custom_field29',
637
+ field_name: '引入阶段',
638
+ value: introductionStage,
639
+ });
640
+ }
641
+ if (releaseDate) {
642
+ // 将日期字符串转换为时间戳
643
+ const releaseTimestamp = this.parseDateToTimestamp(releaseDate);
644
+ if (releaseTimestamp !== null) {
645
+ newCustomFields.push({
646
+ custom_field: 'custom_field18',
647
+ field_name: '发布日期',
648
+ value: String(releaseTimestamp),
649
+ });
650
+ }
651
+ }
652
+ }
653
+ // 只有在有自定义字段时才发送更新请求
654
+ if (newCustomFields.length > 0) {
655
+ const updateData = {
656
+ status_id: types_1.IssueStatusId.RESOLVED, // 设置状态为已解决
657
+ new_custom_fields: newCustomFields,
658
+ };
659
+ // 如果处理人不是创建人,则更新开发人员和处理人
660
+ if (issue.assigned_user?.id !== issue.creator?.id) {
661
+ Object.assign(updateData, {
662
+ developer_id: issue.assigned_user?.id, // 开发人员设置为当前处理人
663
+ assigned_id: issue.creator?.id, // 处理人设置为创建人
664
+ });
665
+ }
666
+ await this.apiService.updateIssue(projectId, String(issue.id), updateData);
667
+ }
668
+ }
669
+ /**
670
+ * 将日期字符串解析为时间戳
671
+ * @param dateStr 日期字符串,格式:YYYY-MM-DD
672
+ * @returns 毫秒时间戳,如果解析失败返回 null
673
+ */
674
+ parseDateToTimestamp(dateStr) {
675
+ try {
676
+ const date = new Date(dateStr);
677
+ if (isNaN(date.getTime())) {
678
+ return null;
679
+ }
680
+ return date.getTime();
681
+ }
682
+ catch {
683
+ return null;
684
+ }
685
+ }
465
686
  }
466
687
  exports.BusinessService = BusinessService;
@@ -265,10 +265,38 @@ export interface IssueStatus {
265
265
  id: number;
266
266
  name: string;
267
267
  }
268
+ export declare enum IssueStatusId {
269
+ NEW_REQUIREMENT = 1,// 新需求
270
+ IN_PROGRESS = 2,// 进行中
271
+ RESOLVED = 3,// 已解决
272
+ TESTING = 4,// 测试中
273
+ CLOSED = 5,// 已关闭
274
+ REJECTED = 6,// 已拒绝
275
+ PRODUCT_DESIGN = 7,// 产品设计
276
+ REVIEW_READY = 8,// 可评审
277
+ DEV_POOL = 9,// 开发池
278
+ DEVELOPING = 10,// 开发中
279
+ TEST_READY = 11,// 可提测
280
+ HANDOFF_EXPERIENCE = 12,// 转体验
281
+ ACCEPTED = 13,// 接受处理
282
+ VERIFIED = 14,// 已验证
283
+ REOPENED = 15,// 重新打开
284
+ POSTPONED = 16,// 延期
285
+ NEW_ISSUE = 17,// 新问题
286
+ CONVERTED_TO_REQUIREMENT = 18,// 转需求
287
+ PENDING_TEST = 19
288
+ }
268
289
  export interface IssueTracker {
269
290
  id: number;
270
291
  name: string;
271
292
  }
293
+ export declare enum IssueTrackerId {
294
+ TASK = 2,// 任务
295
+ BUG = 3,// 缺陷
296
+ EPIC = 5,// Epic
297
+ FEATURE = 6,// Feature
298
+ STORY = 7
299
+ }
272
300
  export interface IssueItem {
273
301
  actual_work_hours: number;
274
302
  assigned_cc_user: IssueUser[];
@@ -331,6 +359,26 @@ export interface AddIssueNotesRequest {
331
359
  projectUUId: string;
332
360
  type?: string;
333
361
  }
362
+ export interface UpdateIssueRequest {
363
+ actual_work_hours?: number;
364
+ assigned_id?: number;
365
+ begin_time?: string;
366
+ description?: string;
367
+ developer_id?: number;
368
+ domain_id?: number;
369
+ done_ratio?: number;
370
+ end_time?: string;
371
+ expected_work_hours?: number;
372
+ iteration_id?: number;
373
+ module_id?: number;
374
+ name?: string;
375
+ parent_issue_id?: number;
376
+ priority_id?: number;
377
+ severity_id?: number;
378
+ status_id?: number;
379
+ tracker_id?: number;
380
+ new_custom_fields?: IssueNewCustomField[];
381
+ }
334
382
  export interface ListChildIssuesV4Response {
335
383
  issues: IssueItem[];
336
384
  total: number;
@@ -446,7 +494,32 @@ export interface ListChildIssuesV2Response {
446
494
  /**
447
495
  * 自定义字段类型枚举
448
496
  */
449
- export type CustomFieldType = 'textbox' | 'textarea' | 'checkbox' | 'radio' | 'select' | 'date' | 'number';
497
+ export type CustomFieldType = 'textbox' | 'textarea' | 'checkbox' | 'radio' | 'select' | 'date' | 'number' | 'text' | 'textArea' | 'user' | 'time_date';
498
+ /**
499
+ * 缺陷相关自定义字段ID枚举
500
+ */
501
+ export declare enum CustomFieldId {
502
+ FEEDBACK_PERSON = "custom_field20",// 反馈人
503
+ DEFECT_TECHNICAL_ANALYSIS = "custom_field32",// 缺陷技术分析
504
+ IMPACT_SCOPE = "custom_field40",// 影响范围
505
+ ENVIRONMENT = "custom_field30",// 环境
506
+ TERMINAL_TYPE = "custom_field24",// 终端类型
507
+ DEFECT_TYPE = "custom_field36",// 缺陷类型
508
+ PRODUCT_MODULE = "custom_field33",// 产品模块
509
+ CUSTOMER_FEEDBACK_NO = "custom_field22",// 客户反馈编号
510
+ TEST_CASE_COVERAGE = "custom_field34",// 测试用例覆盖
511
+ TEST_STAGE = "custom_field23",// 测试阶段
512
+ COMPANY_NAME = "custom_field17",// 企业名称
513
+ DEFECT_ROOT_CAUSE = "custom_field28",// 缺陷根源
514
+ PROBLEM_CAUSE_AND_SOLUTION = "custom_field39",// 问题原因及解决办法
515
+ RELEASE_TIME = "custom_field18",// 发布时间
516
+ INTRODUCTION_PHASE = "custom_field29",// 引入阶段
517
+ VERSION = "custom_field37",// 版本
518
+ TESTER = "custom_field26",// 测试人员
519
+ DEVELOPMENT_END = "custom_field16",// 开发端
520
+ AI_RELATED = "custom_field25",// AI相关
521
+ BRIEFING_TIME = "custom_field38"
522
+ }
450
523
  /**
451
524
  * 缺陷技术分析选项枚举
452
525
  * custom_field32(缺陷技术分析)字段的选项值枚举定义
@@ -575,3 +648,36 @@ export interface AddIssueNotesResponse {
575
648
  export interface AddIssueNotesResult {
576
649
  issue: unknown;
577
650
  }
651
+ export interface CurrentUserInfo {
652
+ id: number;
653
+ name: string;
654
+ nick_name: string;
655
+ user_id: string;
656
+ user_num_id: number;
657
+ domain_id: string;
658
+ domain_name: string;
659
+ email?: string;
660
+ phone?: string;
661
+ status?: number;
662
+ }
663
+ export interface CustomFieldOption {
664
+ custom_field: string;
665
+ type: CustomFieldType;
666
+ name: string;
667
+ options: string;
668
+ tracker_ids: number[];
669
+ create_time: string;
670
+ }
671
+ export interface GetCustomFieldsRequest {
672
+ custom_fields: string[];
673
+ }
674
+ export interface GetCustomFieldsResponse {
675
+ datas: CustomFieldOption[];
676
+ }
677
+ export interface BugFixData {
678
+ defectAnalysis?: string;
679
+ problemReason?: string;
680
+ impactScope?: string;
681
+ introductionStage?: string;
682
+ releaseDate?: string;
683
+ }
@@ -1,6 +1,38 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ConfigKey = exports.DefectAnalysisType = exports.IterationStatus = void 0;
3
+ exports.ConfigKey = exports.DefectAnalysisType = exports.CustomFieldId = exports.IterationStatus = exports.IssueTrackerId = exports.IssueStatusId = void 0;
4
+ // 工作项状态ID枚举
5
+ var IssueStatusId;
6
+ (function (IssueStatusId) {
7
+ IssueStatusId[IssueStatusId["NEW_REQUIREMENT"] = 1] = "NEW_REQUIREMENT";
8
+ IssueStatusId[IssueStatusId["IN_PROGRESS"] = 2] = "IN_PROGRESS";
9
+ IssueStatusId[IssueStatusId["RESOLVED"] = 3] = "RESOLVED";
10
+ IssueStatusId[IssueStatusId["TESTING"] = 4] = "TESTING";
11
+ IssueStatusId[IssueStatusId["CLOSED"] = 5] = "CLOSED";
12
+ IssueStatusId[IssueStatusId["REJECTED"] = 6] = "REJECTED";
13
+ IssueStatusId[IssueStatusId["PRODUCT_DESIGN"] = 7] = "PRODUCT_DESIGN";
14
+ IssueStatusId[IssueStatusId["REVIEW_READY"] = 8] = "REVIEW_READY";
15
+ IssueStatusId[IssueStatusId["DEV_POOL"] = 9] = "DEV_POOL";
16
+ IssueStatusId[IssueStatusId["DEVELOPING"] = 10] = "DEVELOPING";
17
+ IssueStatusId[IssueStatusId["TEST_READY"] = 11] = "TEST_READY";
18
+ IssueStatusId[IssueStatusId["HANDOFF_EXPERIENCE"] = 12] = "HANDOFF_EXPERIENCE";
19
+ IssueStatusId[IssueStatusId["ACCEPTED"] = 13] = "ACCEPTED";
20
+ IssueStatusId[IssueStatusId["VERIFIED"] = 14] = "VERIFIED";
21
+ IssueStatusId[IssueStatusId["REOPENED"] = 15] = "REOPENED";
22
+ IssueStatusId[IssueStatusId["POSTPONED"] = 16] = "POSTPONED";
23
+ IssueStatusId[IssueStatusId["NEW_ISSUE"] = 17] = "NEW_ISSUE";
24
+ IssueStatusId[IssueStatusId["CONVERTED_TO_REQUIREMENT"] = 18] = "CONVERTED_TO_REQUIREMENT";
25
+ IssueStatusId[IssueStatusId["PENDING_TEST"] = 19] = "PENDING_TEST";
26
+ })(IssueStatusId || (exports.IssueStatusId = IssueStatusId = {}));
27
+ // 工作项类型ID枚举
28
+ var IssueTrackerId;
29
+ (function (IssueTrackerId) {
30
+ IssueTrackerId[IssueTrackerId["TASK"] = 2] = "TASK";
31
+ IssueTrackerId[IssueTrackerId["BUG"] = 3] = "BUG";
32
+ IssueTrackerId[IssueTrackerId["EPIC"] = 5] = "EPIC";
33
+ IssueTrackerId[IssueTrackerId["FEATURE"] = 6] = "FEATURE";
34
+ IssueTrackerId[IssueTrackerId["STORY"] = 7] = "STORY";
35
+ })(IssueTrackerId || (exports.IssueTrackerId = IssueTrackerId = {}));
4
36
  var IterationStatus;
5
37
  (function (IterationStatus) {
6
38
  IterationStatus["OPEN"] = "open";
@@ -8,6 +40,33 @@ var IterationStatus;
8
40
  IterationStatus["IN_PROGRESS"] = "1";
9
41
  IterationStatus["COMPLETED"] = "2";
10
42
  })(IterationStatus || (exports.IterationStatus = IterationStatus = {}));
43
+ /**
44
+ * 缺陷相关自定义字段ID枚举
45
+ */
46
+ var CustomFieldId;
47
+ (function (CustomFieldId) {
48
+ // Bug专用字段
49
+ CustomFieldId["FEEDBACK_PERSON"] = "custom_field20";
50
+ CustomFieldId["DEFECT_TECHNICAL_ANALYSIS"] = "custom_field32";
51
+ CustomFieldId["IMPACT_SCOPE"] = "custom_field40";
52
+ CustomFieldId["ENVIRONMENT"] = "custom_field30";
53
+ CustomFieldId["TERMINAL_TYPE"] = "custom_field24";
54
+ CustomFieldId["DEFECT_TYPE"] = "custom_field36";
55
+ CustomFieldId["PRODUCT_MODULE"] = "custom_field33";
56
+ CustomFieldId["CUSTOMER_FEEDBACK_NO"] = "custom_field22";
57
+ CustomFieldId["TEST_CASE_COVERAGE"] = "custom_field34";
58
+ CustomFieldId["TEST_STAGE"] = "custom_field23";
59
+ CustomFieldId["COMPANY_NAME"] = "custom_field17";
60
+ CustomFieldId["DEFECT_ROOT_CAUSE"] = "custom_field28";
61
+ CustomFieldId["PROBLEM_CAUSE_AND_SOLUTION"] = "custom_field39";
62
+ CustomFieldId["RELEASE_TIME"] = "custom_field18";
63
+ CustomFieldId["INTRODUCTION_PHASE"] = "custom_field29";
64
+ CustomFieldId["VERSION"] = "custom_field37";
65
+ CustomFieldId["TESTER"] = "custom_field26";
66
+ CustomFieldId["DEVELOPMENT_END"] = "custom_field16";
67
+ CustomFieldId["AI_RELATED"] = "custom_field25";
68
+ CustomFieldId["BRIEFING_TIME"] = "custom_field38";
69
+ })(CustomFieldId || (exports.CustomFieldId = CustomFieldId = {}));
11
70
  /**
12
71
  * 缺陷技术分析选项枚举
13
72
  * custom_field32(缺陷技术分析)字段的选项值枚举定义
@@ -1,29 +1,30 @@
1
1
  import { ConfigMap, HuaweiCloudConfig, OutputFormat } from '../types';
2
2
  /**
3
- * 获取全局配置文件路径
3
+ * 获取配置文件路径
4
4
  */
5
5
  export declare function getConfigPath(): string;
6
6
  /**
7
- * 检查全局配置文件是否存在
7
+ * 检查配置文件是否存在
8
8
  */
9
9
  export declare function configExists(): boolean;
10
10
  /**
11
- * 读取全局配置
11
+ * 读取配置
12
12
  */
13
13
  export declare function readConfig(): Partial<ConfigMap>;
14
14
  /**
15
- * 写入全局配置
15
+ * 写入配置
16
16
  * 支持动态配置项,自动按分组组织配置文件
17
17
  */
18
18
  export declare function writeConfig(config: Partial<ConfigMap>): void;
19
19
  /**
20
- * 删除全局配置
20
+ * 删除配置
21
21
  */
22
22
  export declare function deleteConfig(): void;
23
23
  export interface CliOptions {
24
24
  role?: string;
25
25
  output?: string;
26
26
  report?: boolean;
27
+ outputDir?: string;
27
28
  }
28
29
  export interface LoadedConfig {
29
30
  projectId: string;
@@ -32,7 +33,7 @@ export interface LoadedConfig {
32
33
  outputFormat: OutputFormat;
33
34
  }
34
35
  /**
35
- * 加载配置,优先级:命令行参数 > 全局配置
36
+ * 加载配置,优先级:命令行参数 > 配置文件
36
37
  * @param cliOptions 命令行选项
37
38
  * @returns 加载的配置
38
39
  */
@@ -45,7 +45,7 @@ const os = __importStar(require("os"));
45
45
  const path = __importStar(require("path"));
46
46
  const types_1 = require("../types");
47
47
  /**
48
- * 全局配置管理工具
48
+ * 配置管理工具
49
49
  * 配置文件存储在用户主目录下的 .hecom-codearts 目录
50
50
  */
51
51
  const CONFIG_DIR = path.join(os.homedir(), '.hecom-codearts');
@@ -59,19 +59,19 @@ function ensureConfigDir() {
59
59
  }
60
60
  }
61
61
  /**
62
- * 获取全局配置文件路径
62
+ * 获取配置文件路径
63
63
  */
64
64
  function getConfigPath() {
65
65
  return CONFIG_FILE;
66
66
  }
67
67
  /**
68
- * 检查全局配置文件是否存在
68
+ * 检查配置文件是否存在
69
69
  */
70
70
  function configExists() {
71
71
  return fs.existsSync(CONFIG_FILE);
72
72
  }
73
73
  /**
74
- * 读取全局配置
74
+ * 读取配置
75
75
  */
76
76
  function readConfig() {
77
77
  if (!configExists()) {
@@ -98,7 +98,7 @@ function readConfig() {
98
98
  }
99
99
  }
100
100
  catch (error) {
101
- console.error('读取全局配置文件失败:', error);
101
+ console.error('读取配置文件失败:', error);
102
102
  }
103
103
  return config;
104
104
  }
@@ -124,13 +124,13 @@ const CONFIG_GROUPS = [
124
124
  },
125
125
  ];
126
126
  /**
127
- * 写入全局配置
127
+ * 写入配置
128
128
  * 支持动态配置项,自动按分组组织配置文件
129
129
  */
130
130
  function writeConfig(config) {
131
131
  ensureConfigDir();
132
132
  // 构建配置文件头部
133
- let content = `# Hecom CodeArts 全局配置文件`;
133
+ let content = `# Hecom CodeArts 配置文件`;
134
134
  // 记录已写入的配置项
135
135
  const writtenKeys = new Set();
136
136
  // 按分组写入配置
@@ -155,11 +155,11 @@ function writeConfig(config) {
155
155
  fs.writeFileSync(CONFIG_FILE, content, 'utf-8');
156
156
  }
157
157
  catch (error) {
158
- throw new Error(`写入全局配置文件失败: ${error}`);
158
+ throw new Error(`写入配置文件失败: ${error}`);
159
159
  }
160
160
  }
161
161
  /**
162
- * 删除全局配置
162
+ * 删除配置
163
163
  */
164
164
  function deleteConfig() {
165
165
  if (configExists()) {
@@ -167,19 +167,19 @@ function deleteConfig() {
167
167
  fs.unlinkSync(CONFIG_FILE);
168
168
  }
169
169
  catch (error) {
170
- throw new Error(`删除全局配置文件失败: ${error}`);
170
+ throw new Error(`删除配置文件失败: ${error}`);
171
171
  }
172
172
  }
173
173
  }
174
- // 加载全局配置
174
+ // 加载配置
175
175
  const globalConfig = configExists() ? readConfig() : {};
176
176
  /**
177
- * 加载配置,优先级:命令行参数 > 全局配置
177
+ * 加载配置,优先级:命令行参数 > 配置文件
178
178
  * @param cliOptions 命令行选项
179
179
  * @returns 加载的配置
180
180
  */
181
181
  function loadConfig(cliOptions = {}) {
182
- // 命令行参数 > 全局配置
182
+ // 命令行参数 > 配置文件
183
183
  const projectId = globalConfig[types_1.ConfigKey.PROJECT_ID];
184
184
  const roleIdStr = cliOptions.role || globalConfig[types_1.ConfigKey.ROLE_ID];
185
185
  if (!projectId) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hecom/codearts",
3
- "version": "0.3.2",
3
+ "version": "0.4.1",
4
4
  "description": "华为云 CodeArts 统计分析工具",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -17,7 +17,10 @@
17
17
  "test": "jest --passWithNoTests",
18
18
  "test:coverage": "jest --coverage --passWithNoTests",
19
19
  "prepublishOnly": "npm run build",
20
- "dev": "ts-node src/bin/cli.ts"
20
+ "dev": "ts-node src/bin/cli.ts",
21
+ "minor": "npm version minor -m \"Bump version to %s\"; git push --tags",
22
+ "patch": "npm version patch -m \"Bump version to %s\"; git push --tags",
23
+ "major": "npm version major -m \"Bump version to %s\"; git push --tags"
21
24
  },
22
25
  "keywords": [
23
26
  "huawei-cloud",