Skip to content

feat: 支持导出分析报告为 JSON 和 Markdown 格式#19

Open
xx9090950 wants to merge 1 commit into
hellodigua:mainfrom
xx9090950:feat/export-report
Open

feat: 支持导出分析报告为 JSON 和 Markdown 格式#19
xx9090950 wants to merge 1 commit into
hellodigua:mainfrom
xx9090950:feat/export-report

Conversation

@xx9090950
Copy link
Copy Markdown

@xx9090950 xx9090950 commented Apr 29, 2026

总结

  • 响应 issue 能否支持导出 #16 需求,新增报告导出功能
  • 支持 -e, --export <format> 选项(json / markdown)
  • 支持 -o, --output <path> 指定导出路径
  • 单仓库和多仓库模式均支持
  • 导出内容包含:核心结果、工作时间、加班分析、时间分布、月度趋势、团队分析

测试

已通过 TypeScript 类型检查,JSON 和 Markdown 导出均在真实仓库上验证通过。

Summary by Sourcery

Add report export capability for single and multi-repository analyses, supporting JSON and Markdown outputs from the CLI.

New Features:

  • Introduce JSON and Markdown export of analysis reports for single and multi-repo runs via a new exporter utility.
  • Add CLI options -e/--export and -o/--output to control export format and output path, including help text and examples.

Enhancements:

  • Preserve trend and team analysis results during execution so they can be included in exported reports.

响应 issue hellodigua#16 需求,用户可以将分析结果导出为文件,方便分享给其他人
共享各公司的真实工作情况

新增:
- `-e, --export <format>` 选项支持 json 和 markdown 两种导出格式
- `-o, --output <path>` 选项指定导出文件路径
- `src/utils/exporter.ts` 导出工具模块,包含数据序列化和格式转换
- 单仓库和多仓库模式均支持导出
- 导出内容包含核心结果、工作时间、加班分析、时间分布、月度趋势、团队分析
@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented Apr 29, 2026

Reviewer's Guide

Adds a generic report export subsystem that can output single- and multi-repo analysis results as JSON or Markdown, wires it into the analyze/multi CLI commands via new -e/--export and -o/--output options, and threads trend and team analysis results into the export payloads.

Sequence diagram for CLI report export flow (single-repo analyze)

sequenceDiagram
  actor Developer
  participant CLIManager
  participant AnalyzeExecutor
  participant TrendAnalyzer
  participant GitTeamAnalyzer
  participant Exporter as exportReport

  Developer->>CLIManager: run code996 analyze -e json -o report.json
  CLIManager->>AnalyzeExecutor: execute(path, AnalyzeOptions{export,output,...})

  activate AnalyzeExecutor
  AnalyzeExecutor->>TrendAnalyzer: analyzeTrend(path, effectiveSince, effectiveUntil, options)
  TrendAnalyzer-->>AnalyzeExecutor: trendResult

  AnalyzeExecutor->>GitTeamAnalyzer: analyzeTeam(collectOptions, index996, minCommits, maxUsers, false)
  GitTeamAnalyzer-->>AnalyzeExecutor: teamResult

  alt export option is set
    AnalyzeExecutor->>Exporter: exportReport(ExportData{result,parsedData,rawData,trendResult,teamAnalysis}, format, outputPath)
    Exporter-->>AnalyzeExecutor: write file
  end

  AnalyzeExecutor-->>CLIManager: finish
  CLIManager-->>Developer: print summary and export success
Loading

Class diagram for new exporter data structures and functions

classDiagram
  class Exporter {
    +exportReport(data, format, outputPath) void
    -exportToJson(data) string
    -exportToMarkdown(data) string
    -serializeSingleData(data) Record
    -serializeMultiData(data) Record
    -serializeTeamAnalysis(team) Record
    -buildSingleMarkdown(data) string
    -buildMultiMarkdown(data) string
    -formatHour(hour) string
    -getMaxCount(data) number
    -trendLabel(trend) string
  }

  class ExportData {
    +string repoName
    +string repoPath
    +string generatedAt
    +Record~string,unknown~ options
    +Result996 result
    +ParsedGitData parsedData
    +GitLogData rawData
    +ProjectClassificationResult classification
    +TrendAnalysisResult trendResult
    +TeamAnalysis teamAnalysis
  }

  class MultiExportData {
    +string generatedAt
    +Record~string,unknown~ options
    +ExportData[] repos
    +Result996 mergedResult
    +ParsedGitData mergedParsedData
    +GitLogData mergedRawData
    +RepoAnalysisRecord[] repoRecords
    +TrendAnalysisResult trendResult
    +TeamAnalysis teamAnalysis
  }

  class Result996 {
    +number index996
    +string index996Str
    +number overTimeRadio
  }

  class ParsedGitData {
    +any detectedWorkTime
    +any[] hourData
    +any[] dayData
    +any[] workHourPl
    +any[] workWeekPl
    +any weekdayOvertime
    +any weekendOvertime
    +any lateNightAnalysis
  }

  class GitLogData {
    +number totalCommits
    +number contributors
    +string firstCommitDate
    +string lastCommitDate
  }

  class TrendAnalysisResult {
    +any summary
    +any[] monthlyData
  }

  class TeamAnalysis {
    +number totalContributors
    +number totalAnalyzed
    +number baselineEndHour
    +any distribution
    +any statistics
    +any healthAssessment
    +any[] coreContributors
  }

  class RepoAnalysisRecord {
    +string status
    +any repo
    +GitLogData data
    +Result996 result
    +any classification
  }

  class ProjectClassificationResult {
    +string projectType
    +number confidence
  }

  Exporter --> ExportData : uses
  Exporter --> MultiExportData : uses
  ExportData --> Result996 : contains
  ExportData --> ParsedGitData : contains
  ExportData --> GitLogData : contains
  ExportData --> ProjectClassificationResult : optional
  ExportData --> TrendAnalysisResult : optional
  ExportData --> TeamAnalysis : optional

  MultiExportData --> ExportData : contains
  MultiExportData --> Result996 : contains
  MultiExportData --> ParsedGitData : contains
  MultiExportData --> GitLogData : contains
  MultiExportData --> RepoAnalysisRecord : contains
  MultiExportData --> TrendAnalysisResult : optional
  MultiExportData --> TeamAnalysis : optional
Loading

File-Level Changes

Change Details Files
Wire export workflow into single-repo analyze command, including passing trend and team analysis results into the export payload.
  • Introduce optional trendResult and teamResult variables so their values can be reused after printing.
  • After main analysis steps, gate export logic on options.export and validate that only json/markdown formats are accepted.
  • Build an ExportData object including repo metadata, options, core Result996, parsed/ raw data, classification, and any available trend/team analysis.
  • Call exportReport with the computed format and output path, defaulting to report.json/report.md.
src/cli/commands/analyze.ts
Wire export workflow into multi-repo analyze command, including aggregation of per-repo export payloads and merged results.
  • Introduce optional trendResult and teamResult variables for multi-repo trend and team analyzers so they can be forwarded to export.
  • When export is requested, re-parse successful repo records to build per-repo ExportData items including parsed and raw data and classification.
  • Assemble a MultiExportData structure that contains generation metadata, options, merged results/parsed/raw data, repo records, and optional trend/team analysis.
  • Invoke exportReport using the selected format and output path for multi-repo exports.
src/cli/commands/multi.ts
Expose new CLI options for exporting reports and propagate them into AnalyzeOptions.
  • Add -e/--export and -o/--output options to the CLI, including help text and examples in the usage output.
  • Merge global export/output values into per-command options so they are available in AnalyzeOptions.
  • Extend AnalyzeOptions with export and output fields used by the analyze and multi commands.
src/cli/index.ts
src/types/git-types.ts
Implement exporter utility that can serialize analysis data into compact JSON or rich Markdown for single and multi-repo runs.
  • Define ExportFormat, ExportData, and MultiExportData types capturing single- and multi-repo export payloads, including trend and team analysis fields.
  • Implement exportReport to ensure the output directory exists, delegate to JSON/Markdown serialization, write the file, and log a success message.
  • Implement JSON serializers that reduce Result996, parsed data, trend data, and team analysis into a structured, consumer-friendly format.
  • Implement Markdown builders for single-repo and multi-repo reports, covering core metrics, working hours, overtime analysis, time distribution, monthly trend, and team analysis, including simple text-based charts and tables.
src/utils/exporter.ts

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've left some high level feedback:

  • 在 Markdown 导出中有多处直接插入可选字段(例如 classification.confidence、trendResult、weekendOvertime 等),当前逻辑会在缺失时输出 undefined 或空结构,建议在生成表格行前做存在性判断或提供合理的 fallback 文本,避免导出的报告出现 undefined
  • 多仓库 Markdown 报告的“各仓库对比”表格里所有仓库状态都写死为 ,同时完全忽略了 repoRecords 中失败或跳过的仓库,建议利用 repoRecords 的 status 字段真实反映成功/失败/跳过,并在表格或单独一节列出未成功分析的仓库。
  • 在 multi 模式导出时,会对每个成功仓库重新调用 GitParser.parseGitData 进行解析,这在大仓库/多仓库场景下可能带来明显的额外开销,建议复用 repoRecords 中已有的解析结果(如果存在)或在分析阶段缓存以避免重复计算。
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- 在 Markdown 导出中有多处直接插入可选字段(例如 classification.confidence、trendResult、weekendOvertime 等),当前逻辑会在缺失时输出 `undefined` 或空结构,建议在生成表格行前做存在性判断或提供合理的 fallback 文本,避免导出的报告出现 `undefined`- 多仓库 Markdown 报告的“各仓库对比”表格里所有仓库状态都写死为 ``,同时完全忽略了 repoRecords 中失败或跳过的仓库,建议利用 repoRecords 的 status 字段真实反映成功/失败/跳过,并在表格或单独一节列出未成功分析的仓库。
- 在 multi 模式导出时,会对每个成功仓库重新调用 GitParser.parseGitData 进行解析,这在大仓库/多仓库场景下可能带来明显的额外开销,建议复用 repoRecords 中已有的解析结果(如果存在)或在分析阶段缓存以避免重复计算。

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@hellodigua
Copy link
Copy Markdown
Owner

hi 可以修复一下AI提出的问题吗,另外目前已支持英文版,要是能一并兼容就好了

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants