openspec-stat 1.1.0 → 1.2.0
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 +16 -0
- package/README.zh-CN.md +16 -0
- package/dist/cjs/formatters.js +147 -1
- package/dist/cjs/i18n/locales/en.json +6 -0
- package/dist/cjs/i18n/locales/zh-CN.json +6 -0
- package/dist/cjs/stats-aggregator.js +25 -0
- package/dist/cjs/types.d.ts +11 -0
- package/dist/esm/formatters.js +222 -37
- package/dist/esm/i18n/locales/en.json +6 -0
- package/dist/esm/i18n/locales/zh-CN.json +6 -0
- package/dist/esm/stats-aggregator.js +29 -0
- package/dist/esm/types.d.ts +11 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,6 +11,7 @@ A CLI tool for tracking team members' OpenSpec proposals and code changes in Git
|
|
|
11
11
|
|
|
12
12
|
- ✅ Track Git commits within specified time ranges
|
|
13
13
|
- ✅ Identify commits containing both OpenSpec proposals and code changes
|
|
14
|
+
- ✅ **Proposal-based statistics summary** - Aggregate statistics by proposal to avoid merge commit bias
|
|
14
15
|
- ✅ Group statistics by author (commits, proposals, code changes)
|
|
15
16
|
- ✅ Support multiple branches and wildcard filtering
|
|
16
17
|
- ✅ Author name mapping (handle multiple Git accounts for the same person)
|
|
@@ -163,6 +164,11 @@ Statistics include:
|
|
|
163
164
|
- **Deletions**: Lines of code deleted
|
|
164
165
|
- **Net Changes**: Additions - Deletions
|
|
165
166
|
|
|
167
|
+
The tool provides two perspectives:
|
|
168
|
+
|
|
169
|
+
1. **Proposal Summary**: Aggregates statistics by proposal, showing total code changes per proposal and all contributors. This avoids statistical bias from merge commits.
|
|
170
|
+
2. **Author Summary**: Groups statistics by contributor, showing individual author contributions.
|
|
171
|
+
|
|
166
172
|
## Output Formats
|
|
167
173
|
|
|
168
174
|
### Table Format (Default)
|
|
@@ -173,6 +179,16 @@ Time Range: 2024-01-01 00:00:00 ~ 2024-01-31 23:59:59
|
|
|
173
179
|
Branches: origin/master
|
|
174
180
|
Total Commits: 15
|
|
175
181
|
|
|
182
|
+
📋 Proposal Summary (by proposal)
|
|
183
|
+
┌──────────────┬─────────┬──────────────────┬────────────┬───────────┬───────────┬─────────────┐
|
|
184
|
+
│ Proposal │ Commits │ Contributors │ Code Files │ Additions │ Deletions │ Net Changes │
|
|
185
|
+
├──────────────┼─────────┼──────────────────┼────────────┼───────────┼───────────┼─────────────┤
|
|
186
|
+
│ feature-123 │ 5 │ John Doe, Jane S.│ 30 │ +890 │ -234 │ +656 │
|
|
187
|
+
│ feature-456 │ 3 │ John Doe │ 15 │ +344 │ -100 │ +244 │
|
|
188
|
+
└──────────────┴─────────┴──────────────────┴────────────┴───────────┴───────────┴─────────────┘
|
|
189
|
+
📊 Total: 2 proposals | 8 commits | 45 files | +1234/-334 lines (net: +900)
|
|
190
|
+
|
|
191
|
+
👥 Author Summary (by contributor)
|
|
176
192
|
┌──────────┬─────────┬──────────────────┬────────────┬───────────┬───────────┬─────────────┐
|
|
177
193
|
│ Author │ Commits │ OpenSpec Proposals│ Code Files │ Additions │ Deletions │ Net Changes │
|
|
178
194
|
├──────────┼─────────┼──────────────────┼────────────┼───────────┼───────────┼─────────────┤
|
package/README.zh-CN.md
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
- ✅ 追踪指定时间范围内的 Git 提交
|
|
13
13
|
- ✅ 识别同时包含 OpenSpec 提案和代码变更的提交
|
|
14
|
+
- ✅ **提案维度统计汇总** - 按提案聚合统计,避免 merge commit 导致的统计偏差
|
|
14
15
|
- ✅ 按作者分组统计(提交数、提案数、代码变更)
|
|
15
16
|
- ✅ 支持多分支和通配符过滤
|
|
16
17
|
- ✅ 作者名称映射(处理同一人的多个 Git 账号)
|
|
@@ -163,6 +164,11 @@ openspec-stat --lang zh-CN --verbose
|
|
|
163
164
|
- **删除行数**:删除的代码行数
|
|
164
165
|
- **净变更**:新增行数 - 删除行数
|
|
165
166
|
|
|
167
|
+
工具提供两个统计视角:
|
|
168
|
+
|
|
169
|
+
1. **提案汇总**:按提案聚合统计,显示每个提案的总代码变更量和所有贡献者,避免 merge commit 导致的统计偏差
|
|
170
|
+
2. **作者汇总**:按贡献者分组统计,显示各个作者的个人贡献情况
|
|
171
|
+
|
|
166
172
|
## 输出格式
|
|
167
173
|
|
|
168
174
|
### 表格格式(默认)
|
|
@@ -173,6 +179,16 @@ openspec-stat --lang zh-CN --verbose
|
|
|
173
179
|
分支:origin/master
|
|
174
180
|
总提交数:15
|
|
175
181
|
|
|
182
|
+
📋 提案汇总(按提案统计)
|
|
183
|
+
┌──────────────┬─────────┬──────────────────┬────────────┬───────────┬───────────┬─────────────┐
|
|
184
|
+
│ 提案 │ 提交数 │ 贡献者 │ 代码文件 │ 新增行数 │ 删除行数 │ 净变更 │
|
|
185
|
+
├──────────────┼─────────┼──────────────────┼────────────┼───────────┼───────────┼─────────────┤
|
|
186
|
+
│ feature-123 │ 5 │ 张三, 李四 │ 30 │ +890 │ -234 │ +656 │
|
|
187
|
+
│ feature-456 │ 3 │ 张三 │ 15 │ +344 │ -100 │ +244 │
|
|
188
|
+
└──────────────┴─────────┴──────────────────┴────────────┴───────────┴───────────┴─────────────┘
|
|
189
|
+
📊 总计:2 个提案 | 8 次提交 | 45 个文件 | +1234/-334 行(净变更:+900)
|
|
190
|
+
|
|
191
|
+
👥 作者汇总(按贡献者统计)
|
|
176
192
|
┌──────────┬─────────┬──────────────────┬────────────┬───────────┬───────────┬─────────────┐
|
|
177
193
|
│ 作者 │ 提交数 │ 提案数 │ 代码文件 │ 新增行数 │ 删除行数 │ 净变更 │
|
|
178
194
|
├──────────┼─────────┼──────────────────┼────────────┼───────────┼───────────┼─────────────┤
|
package/dist/cjs/formatters.js
CHANGED
|
@@ -47,6 +47,59 @@ var OutputFormatter = class {
|
|
|
47
47
|
);
|
|
48
48
|
output += import_chalk.default.gray((0, import_i18n.t)("output.branches", { branches: result.branches.join(", ") }));
|
|
49
49
|
output += import_chalk.default.gray((0, import_i18n.t)("output.totalCommits", { count: String(result.totalCommits) }));
|
|
50
|
+
if (result.proposals.size > 0) {
|
|
51
|
+
output += import_chalk.default.bold.magenta(`
|
|
52
|
+
${(0, import_i18n.t)("output.proposalSummary")}
|
|
53
|
+
`);
|
|
54
|
+
const proposalTable = new import_cli_table3.default({
|
|
55
|
+
head: [
|
|
56
|
+
import_chalk.default.magenta((0, import_i18n.t)("table.proposal")),
|
|
57
|
+
import_chalk.default.magenta((0, import_i18n.t)("table.commits")),
|
|
58
|
+
import_chalk.default.magenta((0, import_i18n.t)("table.contributors")),
|
|
59
|
+
import_chalk.default.magenta((0, import_i18n.t)("table.codeFiles")),
|
|
60
|
+
import_chalk.default.magenta((0, import_i18n.t)("table.additions")),
|
|
61
|
+
import_chalk.default.magenta((0, import_i18n.t)("table.deletions")),
|
|
62
|
+
import_chalk.default.magenta((0, import_i18n.t)("table.netChanges"))
|
|
63
|
+
],
|
|
64
|
+
style: {
|
|
65
|
+
head: [],
|
|
66
|
+
border: []
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
const sortedProposals = Array.from(result.proposals.values()).sort((a, b) => b.netChanges - a.netChanges);
|
|
70
|
+
for (const proposalStats of sortedProposals) {
|
|
71
|
+
const contributors = Array.from(proposalStats.contributors).join(", ");
|
|
72
|
+
proposalTable.push([
|
|
73
|
+
proposalStats.proposal,
|
|
74
|
+
proposalStats.commits.toString(),
|
|
75
|
+
contributors,
|
|
76
|
+
proposalStats.codeFilesChanged.toString(),
|
|
77
|
+
import_chalk.default.green(`+${proposalStats.additions}`),
|
|
78
|
+
import_chalk.default.red(`-${proposalStats.deletions}`),
|
|
79
|
+
proposalStats.netChanges >= 0 ? import_chalk.default.green(`+${proposalStats.netChanges}`) : import_chalk.default.red(`${proposalStats.netChanges}`)
|
|
80
|
+
]);
|
|
81
|
+
}
|
|
82
|
+
output += proposalTable.toString() + "\n";
|
|
83
|
+
const totalProposals = result.proposals.size;
|
|
84
|
+
const totalProposalCommits = Array.from(result.proposals.values()).reduce((sum, p) => sum + p.commits, 0);
|
|
85
|
+
const totalProposalFiles = Array.from(result.proposals.values()).reduce((sum, p) => sum + p.codeFilesChanged, 0);
|
|
86
|
+
const totalProposalAdditions = Array.from(result.proposals.values()).reduce((sum, p) => sum + p.additions, 0);
|
|
87
|
+
const totalProposalDeletions = Array.from(result.proposals.values()).reduce((sum, p) => sum + p.deletions, 0);
|
|
88
|
+
const totalProposalNetChanges = Array.from(result.proposals.values()).reduce((sum, p) => sum + p.netChanges, 0);
|
|
89
|
+
output += import_chalk.default.gray(
|
|
90
|
+
(0, import_i18n.t)("output.proposalTotal", {
|
|
91
|
+
count: totalProposals.toString(),
|
|
92
|
+
commits: totalProposalCommits.toString(),
|
|
93
|
+
files: totalProposalFiles.toString(),
|
|
94
|
+
additions: totalProposalAdditions.toString(),
|
|
95
|
+
deletions: totalProposalDeletions.toString(),
|
|
96
|
+
netChanges: totalProposalNetChanges.toString()
|
|
97
|
+
})
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
output += import_chalk.default.bold.cyan(`
|
|
101
|
+
${(0, import_i18n.t)("output.authorSummary")}
|
|
102
|
+
`);
|
|
50
103
|
const sortedAuthors = Array.from(result.authors.values()).sort((a, b) => b.commits - a.commits);
|
|
51
104
|
for (const stats of sortedAuthors) {
|
|
52
105
|
output += import_chalk.default.bold.cyan(`
|
|
@@ -131,6 +184,26 @@ ${stats.author}
|
|
|
131
184
|
},
|
|
132
185
|
branches: result.branches,
|
|
133
186
|
totalCommits: result.totalCommits,
|
|
187
|
+
proposals: {
|
|
188
|
+
items: Array.from(result.proposals.values()).map((stats) => ({
|
|
189
|
+
proposal: stats.proposal,
|
|
190
|
+
commits: stats.commits,
|
|
191
|
+
contributors: Array.from(stats.contributors),
|
|
192
|
+
contributorCount: stats.contributors.size,
|
|
193
|
+
codeFilesChanged: stats.codeFilesChanged,
|
|
194
|
+
additions: stats.additions,
|
|
195
|
+
deletions: stats.deletions,
|
|
196
|
+
netChanges: stats.netChanges
|
|
197
|
+
})),
|
|
198
|
+
summary: {
|
|
199
|
+
totalProposals: result.proposals.size,
|
|
200
|
+
totalCommits: Array.from(result.proposals.values()).reduce((sum, p) => sum + p.commits, 0),
|
|
201
|
+
totalCodeFiles: Array.from(result.proposals.values()).reduce((sum, p) => sum + p.codeFilesChanged, 0),
|
|
202
|
+
totalAdditions: Array.from(result.proposals.values()).reduce((sum, p) => sum + p.additions, 0),
|
|
203
|
+
totalDeletions: Array.from(result.proposals.values()).reduce((sum, p) => sum + p.deletions, 0),
|
|
204
|
+
totalNetChanges: Array.from(result.proposals.values()).reduce((sum, p) => sum + p.netChanges, 0)
|
|
205
|
+
}
|
|
206
|
+
},
|
|
134
207
|
authors: Array.from(result.authors.values()).map((stats) => {
|
|
135
208
|
var _a;
|
|
136
209
|
return {
|
|
@@ -151,6 +224,42 @@ ${stats.author}
|
|
|
151
224
|
formatCSV(result) {
|
|
152
225
|
var _a;
|
|
153
226
|
const rows = [];
|
|
227
|
+
rows.push(`
|
|
228
|
+
# ${(0, import_i18n.t)("output.proposalSummary")}`);
|
|
229
|
+
rows.push(
|
|
230
|
+
`${(0, import_i18n.t)("table.proposal")},${(0, import_i18n.t)("table.commits")},${(0, import_i18n.t)("table.contributors")},${(0, import_i18n.t)("table.codeFiles")},${(0, import_i18n.t)("table.additions")},${(0, import_i18n.t)("table.deletions")},${(0, import_i18n.t)("table.netChanges")}`
|
|
231
|
+
);
|
|
232
|
+
const sortedProposals = Array.from(result.proposals.values()).sort((a, b) => b.netChanges - a.netChanges);
|
|
233
|
+
for (const stats of sortedProposals) {
|
|
234
|
+
const contributors = Array.from(stats.contributors).join(";");
|
|
235
|
+
rows.push(
|
|
236
|
+
[
|
|
237
|
+
stats.proposal,
|
|
238
|
+
stats.commits,
|
|
239
|
+
`"${contributors}"`,
|
|
240
|
+
stats.codeFilesChanged,
|
|
241
|
+
stats.additions,
|
|
242
|
+
stats.deletions,
|
|
243
|
+
stats.netChanges
|
|
244
|
+
].join(",")
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
const totalProposals = result.proposals.size;
|
|
248
|
+
const totalProposalCommits = Array.from(result.proposals.values()).reduce((sum, p) => sum + p.commits, 0);
|
|
249
|
+
const totalProposalFiles = Array.from(result.proposals.values()).reduce((sum, p) => sum + p.codeFilesChanged, 0);
|
|
250
|
+
const totalProposalAdditions = Array.from(result.proposals.values()).reduce((sum, p) => sum + p.additions, 0);
|
|
251
|
+
const totalProposalDeletions = Array.from(result.proposals.values()).reduce((sum, p) => sum + p.deletions, 0);
|
|
252
|
+
const totalProposalNetChanges = Array.from(result.proposals.values()).reduce((sum, p) => sum + p.netChanges, 0);
|
|
253
|
+
rows.push("");
|
|
254
|
+
rows.push(`# ${(0, import_i18n.t)("output.proposalTotalLabel")}`);
|
|
255
|
+
rows.push(`${(0, import_i18n.t)("table.proposals")},${totalProposals}`);
|
|
256
|
+
rows.push(`${(0, import_i18n.t)("table.commits")},${totalProposalCommits}`);
|
|
257
|
+
rows.push(`${(0, import_i18n.t)("table.codeFiles")},${totalProposalFiles}`);
|
|
258
|
+
rows.push(`${(0, import_i18n.t)("table.additions")},${totalProposalAdditions}`);
|
|
259
|
+
rows.push(`${(0, import_i18n.t)("table.deletions")},${totalProposalDeletions}`);
|
|
260
|
+
rows.push(`${(0, import_i18n.t)("table.netChanges")},${totalProposalNetChanges}`);
|
|
261
|
+
rows.push(`
|
|
262
|
+
# ${(0, import_i18n.t)("output.authorSummary")}`);
|
|
154
263
|
rows.push(
|
|
155
264
|
`${(0, import_i18n.t)("table.author")},${(0, import_i18n.t)("table.period")},${(0, import_i18n.t)("table.commits")},${(0, import_i18n.t)("table.proposalsCount")},${(0, import_i18n.t)("table.proposalsList")},${(0, import_i18n.t)("table.codeFiles")},${(0, import_i18n.t)("table.additions")},${(0, import_i18n.t)("table.deletions")},${(0, import_i18n.t)("table.netChanges")},${(0, import_i18n.t)("table.lastCommitDate")}`
|
|
156
265
|
);
|
|
@@ -183,7 +292,44 @@ ${stats.author}
|
|
|
183
292
|
});
|
|
184
293
|
md += (0, import_i18n.t)("markdown.branches", { branches: result.branches.join(", ") });
|
|
185
294
|
md += (0, import_i18n.t)("markdown.totalCommits", { count: String(result.totalCommits) });
|
|
186
|
-
md +=
|
|
295
|
+
md += `
|
|
296
|
+
## ${(0, import_i18n.t)("output.proposalSummary")}
|
|
297
|
+
|
|
298
|
+
`;
|
|
299
|
+
md += `| ${(0, import_i18n.t)("table.proposal")} | ${(0, import_i18n.t)("table.commits")} | ${(0, import_i18n.t)("table.contributors")} | ${(0, import_i18n.t)("table.codeFiles")} | ${(0, import_i18n.t)("table.additions")} | ${(0, import_i18n.t)("table.deletions")} | ${(0, import_i18n.t)("table.netChanges")} |
|
|
300
|
+
`;
|
|
301
|
+
md += "|--------|---------|-------------|------------|-----------|-----------|-------------|\n";
|
|
302
|
+
const sortedProposals = Array.from(result.proposals.values()).sort((a, b) => b.netChanges - a.netChanges);
|
|
303
|
+
for (const stats of sortedProposals) {
|
|
304
|
+
const contributors = Array.from(stats.contributors).join(", ");
|
|
305
|
+
md += `| ${stats.proposal} | ${stats.commits} | ${contributors} | ${stats.codeFilesChanged} | +${stats.additions} | -${stats.deletions} | ${stats.netChanges >= 0 ? "+" : ""}${stats.netChanges} |
|
|
306
|
+
`;
|
|
307
|
+
}
|
|
308
|
+
const totalProposals = result.proposals.size;
|
|
309
|
+
const totalProposalCommits = Array.from(result.proposals.values()).reduce((sum, p) => sum + p.commits, 0);
|
|
310
|
+
const totalProposalFiles = Array.from(result.proposals.values()).reduce((sum, p) => sum + p.codeFilesChanged, 0);
|
|
311
|
+
const totalProposalAdditions = Array.from(result.proposals.values()).reduce((sum, p) => sum + p.additions, 0);
|
|
312
|
+
const totalProposalDeletions = Array.from(result.proposals.values()).reduce((sum, p) => sum + p.deletions, 0);
|
|
313
|
+
const totalProposalNetChanges = Array.from(result.proposals.values()).reduce((sum, p) => sum + p.netChanges, 0);
|
|
314
|
+
md += `
|
|
315
|
+
**${(0, import_i18n.t)("output.proposalTotalLabel")}**
|
|
316
|
+
`;
|
|
317
|
+
md += `- ${(0, import_i18n.t)("table.proposals")}: ${totalProposals}
|
|
318
|
+
`;
|
|
319
|
+
md += `- ${(0, import_i18n.t)("table.commits")}: ${totalProposalCommits}
|
|
320
|
+
`;
|
|
321
|
+
md += `- ${(0, import_i18n.t)("table.codeFiles")}: ${totalProposalFiles}
|
|
322
|
+
`;
|
|
323
|
+
md += `- ${(0, import_i18n.t)("table.additions")}: +${totalProposalAdditions}
|
|
324
|
+
`;
|
|
325
|
+
md += `- ${(0, import_i18n.t)("table.deletions")}: -${totalProposalDeletions}
|
|
326
|
+
`;
|
|
327
|
+
md += `- ${(0, import_i18n.t)("table.netChanges")}: ${totalProposalNetChanges >= 0 ? "+" : ""}${totalProposalNetChanges}
|
|
328
|
+
`;
|
|
329
|
+
md += `
|
|
330
|
+
## ${(0, import_i18n.t)("output.authorSummary")}
|
|
331
|
+
|
|
332
|
+
`;
|
|
187
333
|
md += `| ${(0, import_i18n.t)("table.author")} | ${(0, import_i18n.t)("table.period")} | ${(0, import_i18n.t)("table.commits")} | ${(0, import_i18n.t)("table.proposals")} | ${(0, import_i18n.t)("table.codeFiles")} | ${(0, import_i18n.t)("table.additions")} | ${(0, import_i18n.t)("table.deletions")} | ${(0, import_i18n.t)("table.netChanges")} |
|
|
188
334
|
`;
|
|
189
335
|
md += "|--------|--------|---------|-----------|------------|-----------|-----------|-------------|\n";
|
|
@@ -48,11 +48,17 @@
|
|
|
48
48
|
"output.branches": "Branches: {{branches}}\n",
|
|
49
49
|
"output.totalCommits": "Total Commits: {{count}}\n\n",
|
|
50
50
|
"output.proposals": " Proposals: {{proposals}}\n",
|
|
51
|
+
"output.proposalSummary": "📋 Proposal Summary (by proposal)",
|
|
52
|
+
"output.proposalTotal": " 📊 Total: {{count}} proposals | {{commits}} commits | {{files}} files | +{{additions}}/-{{deletions}} lines (net: {{netChanges}})\n",
|
|
53
|
+
"output.proposalTotalLabel": "Proposal Summary Total",
|
|
54
|
+
"output.authorSummary": "👥 Author Summary (by contributor)",
|
|
51
55
|
|
|
52
56
|
"table.branch": "Branch",
|
|
53
57
|
"table.period": "Period",
|
|
54
58
|
"table.commits": "Commits",
|
|
55
59
|
"table.proposals": "Proposals",
|
|
60
|
+
"table.proposal": "Proposal",
|
|
61
|
+
"table.contributors": "Contributors",
|
|
56
62
|
"table.codeFiles": "Code Files",
|
|
57
63
|
"table.additions": "Additions",
|
|
58
64
|
"table.deletions": "Deletions",
|
|
@@ -48,11 +48,17 @@
|
|
|
48
48
|
"output.branches": "分支:{{branches}}\n",
|
|
49
49
|
"output.totalCommits": "总提交数:{{count}}\n\n",
|
|
50
50
|
"output.proposals": " 提案:{{proposals}}\n",
|
|
51
|
+
"output.proposalSummary": "📋 提案汇总(按提案统计)",
|
|
52
|
+
"output.proposalTotal": " 📊 总计:{{count}} 个提案 | {{commits}} 次提交 | {{files}} 个文件 | +{{additions}}/-{{deletions}} 行(净变更:{{netChanges}})\n",
|
|
53
|
+
"output.proposalTotalLabel": "提案汇总总计",
|
|
54
|
+
"output.authorSummary": "👥 作者汇总(按贡献者统计)",
|
|
51
55
|
|
|
52
56
|
"table.branch": "分支",
|
|
53
57
|
"table.period": "周期",
|
|
54
58
|
"table.commits": "提交数",
|
|
55
59
|
"table.proposals": "提案数",
|
|
60
|
+
"table.proposal": "提案",
|
|
61
|
+
"table.contributors": "贡献者",
|
|
56
62
|
"table.codeFiles": "代码文件",
|
|
57
63
|
"table.additions": "新增行数",
|
|
58
64
|
"table.deletions": "删除行数",
|
|
@@ -30,6 +30,7 @@ var StatsAggregator = class {
|
|
|
30
30
|
}
|
|
31
31
|
aggregate(analyses, since, until, branches, filterAuthor) {
|
|
32
32
|
const authorStatsMap = /* @__PURE__ */ new Map();
|
|
33
|
+
const proposalStatsMap = /* @__PURE__ */ new Map();
|
|
33
34
|
for (const analysis of analyses) {
|
|
34
35
|
const normalizedAuthor = (0, import_config.normalizeAuthor)(analysis.commit.author, this.config.authorMapping);
|
|
35
36
|
if (this.activeAuthors && !this.activeAuthors.has(normalizedAuthor)) {
|
|
@@ -59,6 +60,29 @@ var StatsAggregator = class {
|
|
|
59
60
|
stats.codeFilesChanged += analysis.codeFiles.length;
|
|
60
61
|
for (const proposal of analysis.openspecProposals) {
|
|
61
62
|
stats.openspecProposals.add(proposal);
|
|
63
|
+
let proposalStats = proposalStatsMap.get(proposal);
|
|
64
|
+
if (!proposalStats) {
|
|
65
|
+
proposalStats = {
|
|
66
|
+
proposal,
|
|
67
|
+
commits: 0,
|
|
68
|
+
contributors: /* @__PURE__ */ new Set(),
|
|
69
|
+
codeFilesChanged: 0,
|
|
70
|
+
additions: 0,
|
|
71
|
+
deletions: 0,
|
|
72
|
+
netChanges: 0,
|
|
73
|
+
commitHashes: /* @__PURE__ */ new Set()
|
|
74
|
+
};
|
|
75
|
+
proposalStatsMap.set(proposal, proposalStats);
|
|
76
|
+
}
|
|
77
|
+
if (!proposalStats.commitHashes.has(analysis.commit.hash)) {
|
|
78
|
+
proposalStats.commitHashes.add(analysis.commit.hash);
|
|
79
|
+
proposalStats.commits++;
|
|
80
|
+
proposalStats.contributors.add(normalizedAuthor);
|
|
81
|
+
proposalStats.codeFilesChanged += analysis.codeFiles.length;
|
|
82
|
+
proposalStats.additions += analysis.totalAdditions;
|
|
83
|
+
proposalStats.deletions += analysis.totalDeletions;
|
|
84
|
+
proposalStats.netChanges += analysis.netChanges;
|
|
85
|
+
}
|
|
62
86
|
}
|
|
63
87
|
if (!stats.lastCommitDate || analysis.commit.date > stats.lastCommitDate) {
|
|
64
88
|
stats.lastCommitDate = analysis.commit.date;
|
|
@@ -112,6 +136,7 @@ var StatsAggregator = class {
|
|
|
112
136
|
timeRange: { since, until },
|
|
113
137
|
branches: actualBranches.size > 0 ? Array.from(actualBranches) : branches,
|
|
114
138
|
authors: authorStatsMap,
|
|
139
|
+
proposals: proposalStatsMap,
|
|
115
140
|
totalCommits: analyses.length
|
|
116
141
|
};
|
|
117
142
|
}
|
package/dist/cjs/types.d.ts
CHANGED
|
@@ -66,6 +66,16 @@ export interface BranchStats {
|
|
|
66
66
|
deletions: number;
|
|
67
67
|
netChanges: number;
|
|
68
68
|
}
|
|
69
|
+
export interface ProposalStats {
|
|
70
|
+
proposal: string;
|
|
71
|
+
commits: number;
|
|
72
|
+
contributors: Set<string>;
|
|
73
|
+
codeFilesChanged: number;
|
|
74
|
+
additions: number;
|
|
75
|
+
deletions: number;
|
|
76
|
+
netChanges: number;
|
|
77
|
+
commitHashes: Set<string>;
|
|
78
|
+
}
|
|
69
79
|
export interface StatsResult {
|
|
70
80
|
timeRange: {
|
|
71
81
|
since: Date;
|
|
@@ -73,5 +83,6 @@ export interface StatsResult {
|
|
|
73
83
|
};
|
|
74
84
|
branches: string[];
|
|
75
85
|
authors: Map<string, AuthorStats>;
|
|
86
|
+
proposals: Map<string, ProposalStats>;
|
|
76
87
|
totalCommits: number;
|
|
77
88
|
}
|
package/dist/esm/formatters.js
CHANGED
|
@@ -34,14 +34,70 @@ export var OutputFormatter = /*#__PURE__*/function () {
|
|
|
34
34
|
output += chalk.gray(t('output.totalCommits', {
|
|
35
35
|
count: String(result.totalCommits)
|
|
36
36
|
}));
|
|
37
|
+
|
|
38
|
+
// Proposal Summary Table
|
|
39
|
+
if (result.proposals.size > 0) {
|
|
40
|
+
output += chalk.bold.magenta("\n".concat(t('output.proposalSummary'), "\n"));
|
|
41
|
+
var proposalTable = new Table({
|
|
42
|
+
head: [chalk.magenta(t('table.proposal')), chalk.magenta(t('table.commits')), chalk.magenta(t('table.contributors')), chalk.magenta(t('table.codeFiles')), chalk.magenta(t('table.additions')), chalk.magenta(t('table.deletions')), chalk.magenta(t('table.netChanges'))],
|
|
43
|
+
style: {
|
|
44
|
+
head: [],
|
|
45
|
+
border: []
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
var sortedProposals = Array.from(result.proposals.values()).sort(function (a, b) {
|
|
49
|
+
return b.netChanges - a.netChanges;
|
|
50
|
+
});
|
|
51
|
+
var _iterator = _createForOfIteratorHelper(sortedProposals),
|
|
52
|
+
_step;
|
|
53
|
+
try {
|
|
54
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
55
|
+
var proposalStats = _step.value;
|
|
56
|
+
var contributors = Array.from(proposalStats.contributors).join(', ');
|
|
57
|
+
proposalTable.push([proposalStats.proposal, proposalStats.commits.toString(), contributors, proposalStats.codeFilesChanged.toString(), chalk.green("+".concat(proposalStats.additions)), chalk.red("-".concat(proposalStats.deletions)), proposalStats.netChanges >= 0 ? chalk.green("+".concat(proposalStats.netChanges)) : chalk.red("".concat(proposalStats.netChanges))]);
|
|
58
|
+
}
|
|
59
|
+
} catch (err) {
|
|
60
|
+
_iterator.e(err);
|
|
61
|
+
} finally {
|
|
62
|
+
_iterator.f();
|
|
63
|
+
}
|
|
64
|
+
output += proposalTable.toString() + '\n';
|
|
65
|
+
|
|
66
|
+
// Proposal summary totals
|
|
67
|
+
var totalProposals = result.proposals.size;
|
|
68
|
+
var totalProposalCommits = Array.from(result.proposals.values()).reduce(function (sum, p) {
|
|
69
|
+
return sum + p.commits;
|
|
70
|
+
}, 0);
|
|
71
|
+
var totalProposalFiles = Array.from(result.proposals.values()).reduce(function (sum, p) {
|
|
72
|
+
return sum + p.codeFilesChanged;
|
|
73
|
+
}, 0);
|
|
74
|
+
var totalProposalAdditions = Array.from(result.proposals.values()).reduce(function (sum, p) {
|
|
75
|
+
return sum + p.additions;
|
|
76
|
+
}, 0);
|
|
77
|
+
var totalProposalDeletions = Array.from(result.proposals.values()).reduce(function (sum, p) {
|
|
78
|
+
return sum + p.deletions;
|
|
79
|
+
}, 0);
|
|
80
|
+
var totalProposalNetChanges = Array.from(result.proposals.values()).reduce(function (sum, p) {
|
|
81
|
+
return sum + p.netChanges;
|
|
82
|
+
}, 0);
|
|
83
|
+
output += chalk.gray(t('output.proposalTotal', {
|
|
84
|
+
count: totalProposals.toString(),
|
|
85
|
+
commits: totalProposalCommits.toString(),
|
|
86
|
+
files: totalProposalFiles.toString(),
|
|
87
|
+
additions: totalProposalAdditions.toString(),
|
|
88
|
+
deletions: totalProposalDeletions.toString(),
|
|
89
|
+
netChanges: totalProposalNetChanges.toString()
|
|
90
|
+
}));
|
|
91
|
+
}
|
|
92
|
+
output += chalk.bold.cyan("\n".concat(t('output.authorSummary'), "\n"));
|
|
37
93
|
var sortedAuthors = Array.from(result.authors.values()).sort(function (a, b) {
|
|
38
94
|
return b.commits - a.commits;
|
|
39
95
|
});
|
|
40
|
-
var
|
|
41
|
-
|
|
96
|
+
var _iterator2 = _createForOfIteratorHelper(sortedAuthors),
|
|
97
|
+
_step2;
|
|
42
98
|
try {
|
|
43
|
-
for (
|
|
44
|
-
var stats =
|
|
99
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
100
|
+
var stats = _step2.value;
|
|
45
101
|
output += chalk.bold.cyan("\n".concat(stats.author, "\n"));
|
|
46
102
|
if (stats.branchStats && stats.branchStats.size > 0) {
|
|
47
103
|
var branchTable = new Table({
|
|
@@ -54,17 +110,17 @@ export var OutputFormatter = /*#__PURE__*/function () {
|
|
|
54
110
|
var sortedBranches = Array.from(stats.branchStats.values()).sort(function (a, b) {
|
|
55
111
|
return b.commits - a.commits;
|
|
56
112
|
});
|
|
57
|
-
var
|
|
58
|
-
|
|
113
|
+
var _iterator3 = _createForOfIteratorHelper(sortedBranches),
|
|
114
|
+
_step3;
|
|
59
115
|
try {
|
|
60
|
-
for (
|
|
61
|
-
var branchStat =
|
|
116
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
117
|
+
var branchStat = _step3.value;
|
|
62
118
|
branchTable.push([branchStat.branch, branchStat.commits.toString(), branchStat.openspecProposals.size.toString(), branchStat.codeFilesChanged.toString(), chalk.green("+".concat(branchStat.additions)), chalk.red("-".concat(branchStat.deletions)), branchStat.netChanges >= 0 ? chalk.green("+".concat(branchStat.netChanges)) : chalk.red("".concat(branchStat.netChanges))]);
|
|
63
119
|
}
|
|
64
120
|
} catch (err) {
|
|
65
|
-
|
|
121
|
+
_iterator3.e(err);
|
|
66
122
|
} finally {
|
|
67
|
-
|
|
123
|
+
_iterator3.f();
|
|
68
124
|
}
|
|
69
125
|
branchTable.push([chalk.bold.yellow(t('table.totalDeduplicated')), chalk.bold(stats.commits.toString()), chalk.bold(stats.openspecProposals.size.toString()), chalk.bold(stats.codeFilesChanged.toString()), chalk.bold.green("+".concat(stats.additions)), chalk.bold.red("-".concat(stats.deletions)), stats.netChanges >= 0 ? chalk.bold.green("+".concat(stats.netChanges)) : chalk.bold.red("".concat(stats.netChanges))]);
|
|
70
126
|
output += branchTable.toString() + '\n';
|
|
@@ -86,9 +142,9 @@ export var OutputFormatter = /*#__PURE__*/function () {
|
|
|
86
142
|
}
|
|
87
143
|
}
|
|
88
144
|
} catch (err) {
|
|
89
|
-
|
|
145
|
+
_iterator2.e(err);
|
|
90
146
|
} finally {
|
|
91
|
-
|
|
147
|
+
_iterator2.f();
|
|
92
148
|
}
|
|
93
149
|
return output;
|
|
94
150
|
}
|
|
@@ -102,6 +158,38 @@ export var OutputFormatter = /*#__PURE__*/function () {
|
|
|
102
158
|
},
|
|
103
159
|
branches: result.branches,
|
|
104
160
|
totalCommits: result.totalCommits,
|
|
161
|
+
proposals: {
|
|
162
|
+
items: Array.from(result.proposals.values()).map(function (stats) {
|
|
163
|
+
return {
|
|
164
|
+
proposal: stats.proposal,
|
|
165
|
+
commits: stats.commits,
|
|
166
|
+
contributors: Array.from(stats.contributors),
|
|
167
|
+
contributorCount: stats.contributors.size,
|
|
168
|
+
codeFilesChanged: stats.codeFilesChanged,
|
|
169
|
+
additions: stats.additions,
|
|
170
|
+
deletions: stats.deletions,
|
|
171
|
+
netChanges: stats.netChanges
|
|
172
|
+
};
|
|
173
|
+
}),
|
|
174
|
+
summary: {
|
|
175
|
+
totalProposals: result.proposals.size,
|
|
176
|
+
totalCommits: Array.from(result.proposals.values()).reduce(function (sum, p) {
|
|
177
|
+
return sum + p.commits;
|
|
178
|
+
}, 0),
|
|
179
|
+
totalCodeFiles: Array.from(result.proposals.values()).reduce(function (sum, p) {
|
|
180
|
+
return sum + p.codeFilesChanged;
|
|
181
|
+
}, 0),
|
|
182
|
+
totalAdditions: Array.from(result.proposals.values()).reduce(function (sum, p) {
|
|
183
|
+
return sum + p.additions;
|
|
184
|
+
}, 0),
|
|
185
|
+
totalDeletions: Array.from(result.proposals.values()).reduce(function (sum, p) {
|
|
186
|
+
return sum + p.deletions;
|
|
187
|
+
}, 0),
|
|
188
|
+
totalNetChanges: Array.from(result.proposals.values()).reduce(function (sum, p) {
|
|
189
|
+
return sum + p.netChanges;
|
|
190
|
+
}, 0)
|
|
191
|
+
}
|
|
192
|
+
},
|
|
105
193
|
authors: Array.from(result.authors.values()).map(function (stats) {
|
|
106
194
|
var _stats$lastCommitDate;
|
|
107
195
|
return {
|
|
@@ -123,23 +211,72 @@ export var OutputFormatter = /*#__PURE__*/function () {
|
|
|
123
211
|
key: "formatCSV",
|
|
124
212
|
value: function formatCSV(result) {
|
|
125
213
|
var rows = [];
|
|
214
|
+
|
|
215
|
+
// Proposal summary section
|
|
216
|
+
rows.push("\n# ".concat(t('output.proposalSummary')));
|
|
217
|
+
rows.push("".concat(t('table.proposal'), ",").concat(t('table.commits'), ",").concat(t('table.contributors'), ",").concat(t('table.codeFiles'), ",").concat(t('table.additions'), ",").concat(t('table.deletions'), ",").concat(t('table.netChanges')));
|
|
218
|
+
var sortedProposals = Array.from(result.proposals.values()).sort(function (a, b) {
|
|
219
|
+
return b.netChanges - a.netChanges;
|
|
220
|
+
});
|
|
221
|
+
var _iterator4 = _createForOfIteratorHelper(sortedProposals),
|
|
222
|
+
_step4;
|
|
223
|
+
try {
|
|
224
|
+
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
|
|
225
|
+
var stats = _step4.value;
|
|
226
|
+
var contributors = Array.from(stats.contributors).join(';');
|
|
227
|
+
rows.push([stats.proposal, stats.commits, "\"".concat(contributors, "\""), stats.codeFilesChanged, stats.additions, stats.deletions, stats.netChanges].join(','));
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Proposal totals
|
|
231
|
+
} catch (err) {
|
|
232
|
+
_iterator4.e(err);
|
|
233
|
+
} finally {
|
|
234
|
+
_iterator4.f();
|
|
235
|
+
}
|
|
236
|
+
var totalProposals = result.proposals.size;
|
|
237
|
+
var totalProposalCommits = Array.from(result.proposals.values()).reduce(function (sum, p) {
|
|
238
|
+
return sum + p.commits;
|
|
239
|
+
}, 0);
|
|
240
|
+
var totalProposalFiles = Array.from(result.proposals.values()).reduce(function (sum, p) {
|
|
241
|
+
return sum + p.codeFilesChanged;
|
|
242
|
+
}, 0);
|
|
243
|
+
var totalProposalAdditions = Array.from(result.proposals.values()).reduce(function (sum, p) {
|
|
244
|
+
return sum + p.additions;
|
|
245
|
+
}, 0);
|
|
246
|
+
var totalProposalDeletions = Array.from(result.proposals.values()).reduce(function (sum, p) {
|
|
247
|
+
return sum + p.deletions;
|
|
248
|
+
}, 0);
|
|
249
|
+
var totalProposalNetChanges = Array.from(result.proposals.values()).reduce(function (sum, p) {
|
|
250
|
+
return sum + p.netChanges;
|
|
251
|
+
}, 0);
|
|
252
|
+
rows.push('');
|
|
253
|
+
rows.push("# ".concat(t('output.proposalTotalLabel')));
|
|
254
|
+
rows.push("".concat(t('table.proposals'), ",").concat(totalProposals));
|
|
255
|
+
rows.push("".concat(t('table.commits'), ",").concat(totalProposalCommits));
|
|
256
|
+
rows.push("".concat(t('table.codeFiles'), ",").concat(totalProposalFiles));
|
|
257
|
+
rows.push("".concat(t('table.additions'), ",").concat(totalProposalAdditions));
|
|
258
|
+
rows.push("".concat(t('table.deletions'), ",").concat(totalProposalDeletions));
|
|
259
|
+
rows.push("".concat(t('table.netChanges'), ",").concat(totalProposalNetChanges));
|
|
260
|
+
|
|
261
|
+
// Author summary section
|
|
262
|
+
rows.push("\n# ".concat(t('output.authorSummary')));
|
|
126
263
|
rows.push("".concat(t('table.author'), ",").concat(t('table.period'), ",").concat(t('table.commits'), ",").concat(t('table.proposalsCount'), ",").concat(t('table.proposalsList'), ",").concat(t('table.codeFiles'), ",").concat(t('table.additions'), ",").concat(t('table.deletions'), ",").concat(t('table.netChanges'), ",").concat(t('table.lastCommitDate')));
|
|
127
264
|
var sortedAuthors = Array.from(result.authors.values()).sort(function (a, b) {
|
|
128
265
|
return b.commits - a.commits;
|
|
129
266
|
});
|
|
130
|
-
var
|
|
131
|
-
|
|
267
|
+
var _iterator5 = _createForOfIteratorHelper(sortedAuthors),
|
|
268
|
+
_step5;
|
|
132
269
|
try {
|
|
133
|
-
for (
|
|
270
|
+
for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
|
|
134
271
|
var _stats$lastCommitDate2;
|
|
135
|
-
var
|
|
136
|
-
var proposals = Array.from(
|
|
137
|
-
rows.push([
|
|
272
|
+
var _stats = _step5.value;
|
|
273
|
+
var proposals = Array.from(_stats.openspecProposals).join(';');
|
|
274
|
+
rows.push([_stats.author, _stats.statisticsPeriod || '-', _stats.commits, _stats.openspecProposals.size, "\"".concat(proposals, "\""), _stats.codeFilesChanged, _stats.additions, _stats.deletions, _stats.netChanges, ((_stats$lastCommitDate2 = _stats.lastCommitDate) === null || _stats$lastCommitDate2 === void 0 ? void 0 : _stats$lastCommitDate2.toISOString()) || ''].join(','));
|
|
138
275
|
}
|
|
139
276
|
} catch (err) {
|
|
140
|
-
|
|
277
|
+
_iterator5.e(err);
|
|
141
278
|
} finally {
|
|
142
|
-
|
|
279
|
+
_iterator5.f();
|
|
143
280
|
}
|
|
144
281
|
return rows.join('\n');
|
|
145
282
|
}
|
|
@@ -162,33 +299,81 @@ export var OutputFormatter = /*#__PURE__*/function () {
|
|
|
162
299
|
md += t('markdown.totalCommits', {
|
|
163
300
|
count: String(result.totalCommits)
|
|
164
301
|
});
|
|
165
|
-
|
|
302
|
+
|
|
303
|
+
// Proposal summary
|
|
304
|
+
md += "\n## ".concat(t('output.proposalSummary'), "\n\n");
|
|
305
|
+
md += "| ".concat(t('table.proposal'), " | ").concat(t('table.commits'), " | ").concat(t('table.contributors'), " | ").concat(t('table.codeFiles'), " | ").concat(t('table.additions'), " | ").concat(t('table.deletions'), " | ").concat(t('table.netChanges'), " |\n");
|
|
306
|
+
md += '|--------|---------|-------------|------------|-----------|-----------|-------------|\n';
|
|
307
|
+
var sortedProposals = Array.from(result.proposals.values()).sort(function (a, b) {
|
|
308
|
+
return b.netChanges - a.netChanges;
|
|
309
|
+
});
|
|
310
|
+
var _iterator6 = _createForOfIteratorHelper(sortedProposals),
|
|
311
|
+
_step6;
|
|
312
|
+
try {
|
|
313
|
+
for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
|
|
314
|
+
var stats = _step6.value;
|
|
315
|
+
var contributors = Array.from(stats.contributors).join(', ');
|
|
316
|
+
md += "| ".concat(stats.proposal, " | ").concat(stats.commits, " | ").concat(contributors, " | ").concat(stats.codeFilesChanged, " | +").concat(stats.additions, " | -").concat(stats.deletions, " | ").concat(stats.netChanges >= 0 ? '+' : '').concat(stats.netChanges, " |\n");
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// Proposal totals
|
|
320
|
+
} catch (err) {
|
|
321
|
+
_iterator6.e(err);
|
|
322
|
+
} finally {
|
|
323
|
+
_iterator6.f();
|
|
324
|
+
}
|
|
325
|
+
var totalProposals = result.proposals.size;
|
|
326
|
+
var totalProposalCommits = Array.from(result.proposals.values()).reduce(function (sum, p) {
|
|
327
|
+
return sum + p.commits;
|
|
328
|
+
}, 0);
|
|
329
|
+
var totalProposalFiles = Array.from(result.proposals.values()).reduce(function (sum, p) {
|
|
330
|
+
return sum + p.codeFilesChanged;
|
|
331
|
+
}, 0);
|
|
332
|
+
var totalProposalAdditions = Array.from(result.proposals.values()).reduce(function (sum, p) {
|
|
333
|
+
return sum + p.additions;
|
|
334
|
+
}, 0);
|
|
335
|
+
var totalProposalDeletions = Array.from(result.proposals.values()).reduce(function (sum, p) {
|
|
336
|
+
return sum + p.deletions;
|
|
337
|
+
}, 0);
|
|
338
|
+
var totalProposalNetChanges = Array.from(result.proposals.values()).reduce(function (sum, p) {
|
|
339
|
+
return sum + p.netChanges;
|
|
340
|
+
}, 0);
|
|
341
|
+
md += "\n**".concat(t('output.proposalTotalLabel'), "**\n");
|
|
342
|
+
md += "- ".concat(t('table.proposals'), ": ").concat(totalProposals, "\n");
|
|
343
|
+
md += "- ".concat(t('table.commits'), ": ").concat(totalProposalCommits, "\n");
|
|
344
|
+
md += "- ".concat(t('table.codeFiles'), ": ").concat(totalProposalFiles, "\n");
|
|
345
|
+
md += "- ".concat(t('table.additions'), ": +").concat(totalProposalAdditions, "\n");
|
|
346
|
+
md += "- ".concat(t('table.deletions'), ": -").concat(totalProposalDeletions, "\n");
|
|
347
|
+
md += "- ".concat(t('table.netChanges'), ": ").concat(totalProposalNetChanges >= 0 ? '+' : '').concat(totalProposalNetChanges, "\n");
|
|
348
|
+
|
|
349
|
+
// Author summary
|
|
350
|
+
md += "\n## ".concat(t('output.authorSummary'), "\n\n");
|
|
166
351
|
md += "| ".concat(t('table.author'), " | ").concat(t('table.period'), " | ").concat(t('table.commits'), " | ").concat(t('table.proposals'), " | ").concat(t('table.codeFiles'), " | ").concat(t('table.additions'), " | ").concat(t('table.deletions'), " | ").concat(t('table.netChanges'), " |\n");
|
|
167
352
|
md += '|--------|--------|---------|-----------|------------|-----------|-----------|-------------|\n';
|
|
168
353
|
var sortedAuthors = Array.from(result.authors.values()).sort(function (a, b) {
|
|
169
354
|
return b.commits - a.commits;
|
|
170
355
|
});
|
|
171
|
-
var
|
|
172
|
-
|
|
356
|
+
var _iterator7 = _createForOfIteratorHelper(sortedAuthors),
|
|
357
|
+
_step7;
|
|
173
358
|
try {
|
|
174
|
-
for (
|
|
175
|
-
var
|
|
176
|
-
md += "| ".concat(
|
|
359
|
+
for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
|
|
360
|
+
var _stats2 = _step7.value;
|
|
361
|
+
md += "| ".concat(_stats2.author, " | ").concat(_stats2.statisticsPeriod || '-', " | ").concat(_stats2.commits, " | ").concat(_stats2.openspecProposals.size, " | ").concat(_stats2.codeFilesChanged, " | +").concat(_stats2.additions, " | -").concat(_stats2.deletions, " | ").concat(_stats2.netChanges >= 0 ? '+' : '').concat(_stats2.netChanges, " |\n");
|
|
177
362
|
}
|
|
178
363
|
} catch (err) {
|
|
179
|
-
|
|
364
|
+
_iterator7.e(err);
|
|
180
365
|
} finally {
|
|
181
|
-
|
|
366
|
+
_iterator7.f();
|
|
182
367
|
}
|
|
183
368
|
md += t('markdown.proposalDetails');
|
|
184
|
-
var
|
|
185
|
-
|
|
369
|
+
var _iterator8 = _createForOfIteratorHelper(sortedAuthors),
|
|
370
|
+
_step8;
|
|
186
371
|
try {
|
|
187
|
-
for (
|
|
188
|
-
var
|
|
189
|
-
if (
|
|
190
|
-
md += "### ".concat(
|
|
191
|
-
for (var _i = 0, _Array$from = Array.from(
|
|
372
|
+
for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) {
|
|
373
|
+
var _stats3 = _step8.value;
|
|
374
|
+
if (_stats3.openspecProposals.size > 0) {
|
|
375
|
+
md += "### ".concat(_stats3.author, "\n\n");
|
|
376
|
+
for (var _i = 0, _Array$from = Array.from(_stats3.openspecProposals); _i < _Array$from.length; _i++) {
|
|
192
377
|
var proposal = _Array$from[_i];
|
|
193
378
|
md += "- ".concat(proposal, "\n");
|
|
194
379
|
}
|
|
@@ -196,9 +381,9 @@ export var OutputFormatter = /*#__PURE__*/function () {
|
|
|
196
381
|
}
|
|
197
382
|
}
|
|
198
383
|
} catch (err) {
|
|
199
|
-
|
|
384
|
+
_iterator8.e(err);
|
|
200
385
|
} finally {
|
|
201
|
-
|
|
386
|
+
_iterator8.f();
|
|
202
387
|
}
|
|
203
388
|
return md;
|
|
204
389
|
}
|
|
@@ -48,11 +48,17 @@
|
|
|
48
48
|
"output.branches": "Branches: {{branches}}\n",
|
|
49
49
|
"output.totalCommits": "Total Commits: {{count}}\n\n",
|
|
50
50
|
"output.proposals": " Proposals: {{proposals}}\n",
|
|
51
|
+
"output.proposalSummary": "📋 Proposal Summary (by proposal)",
|
|
52
|
+
"output.proposalTotal": " 📊 Total: {{count}} proposals | {{commits}} commits | {{files}} files | +{{additions}}/-{{deletions}} lines (net: {{netChanges}})\n",
|
|
53
|
+
"output.proposalTotalLabel": "Proposal Summary Total",
|
|
54
|
+
"output.authorSummary": "👥 Author Summary (by contributor)",
|
|
51
55
|
|
|
52
56
|
"table.branch": "Branch",
|
|
53
57
|
"table.period": "Period",
|
|
54
58
|
"table.commits": "Commits",
|
|
55
59
|
"table.proposals": "Proposals",
|
|
60
|
+
"table.proposal": "Proposal",
|
|
61
|
+
"table.contributors": "Contributors",
|
|
56
62
|
"table.codeFiles": "Code Files",
|
|
57
63
|
"table.additions": "Additions",
|
|
58
64
|
"table.deletions": "Deletions",
|
|
@@ -48,11 +48,17 @@
|
|
|
48
48
|
"output.branches": "分支:{{branches}}\n",
|
|
49
49
|
"output.totalCommits": "总提交数:{{count}}\n\n",
|
|
50
50
|
"output.proposals": " 提案:{{proposals}}\n",
|
|
51
|
+
"output.proposalSummary": "📋 提案汇总(按提案统计)",
|
|
52
|
+
"output.proposalTotal": " 📊 总计:{{count}} 个提案 | {{commits}} 次提交 | {{files}} 个文件 | +{{additions}}/-{{deletions}} 行(净变更:{{netChanges}})\n",
|
|
53
|
+
"output.proposalTotalLabel": "提案汇总总计",
|
|
54
|
+
"output.authorSummary": "👥 作者汇总(按贡献者统计)",
|
|
51
55
|
|
|
52
56
|
"table.branch": "分支",
|
|
53
57
|
"table.period": "周期",
|
|
54
58
|
"table.commits": "提交数",
|
|
55
59
|
"table.proposals": "提案数",
|
|
60
|
+
"table.proposal": "提案",
|
|
61
|
+
"table.contributors": "贡献者",
|
|
56
62
|
"table.codeFiles": "代码文件",
|
|
57
63
|
"table.additions": "新增行数",
|
|
58
64
|
"table.deletions": "删除行数",
|
|
@@ -21,6 +21,7 @@ export var StatsAggregator = /*#__PURE__*/function () {
|
|
|
21
21
|
key: "aggregate",
|
|
22
22
|
value: function aggregate(analyses, since, until, branches, filterAuthor) {
|
|
23
23
|
var authorStatsMap = new Map();
|
|
24
|
+
var proposalStatsMap = new Map();
|
|
24
25
|
var _iterator = _createForOfIteratorHelper(analyses),
|
|
25
26
|
_step;
|
|
26
27
|
try {
|
|
@@ -58,6 +59,33 @@ export var StatsAggregator = /*#__PURE__*/function () {
|
|
|
58
59
|
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
|
|
59
60
|
var _proposal = _step4.value;
|
|
60
61
|
stats.openspecProposals.add(_proposal);
|
|
62
|
+
|
|
63
|
+
// Aggregate by proposal
|
|
64
|
+
var proposalStats = proposalStatsMap.get(_proposal);
|
|
65
|
+
if (!proposalStats) {
|
|
66
|
+
proposalStats = {
|
|
67
|
+
proposal: _proposal,
|
|
68
|
+
commits: 0,
|
|
69
|
+
contributors: new Set(),
|
|
70
|
+
codeFilesChanged: 0,
|
|
71
|
+
additions: 0,
|
|
72
|
+
deletions: 0,
|
|
73
|
+
netChanges: 0,
|
|
74
|
+
commitHashes: new Set()
|
|
75
|
+
};
|
|
76
|
+
proposalStatsMap.set(_proposal, proposalStats);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Only count each commit once per proposal
|
|
80
|
+
if (!proposalStats.commitHashes.has(analysis.commit.hash)) {
|
|
81
|
+
proposalStats.commitHashes.add(analysis.commit.hash);
|
|
82
|
+
proposalStats.commits++;
|
|
83
|
+
proposalStats.contributors.add(normalizedAuthor);
|
|
84
|
+
proposalStats.codeFilesChanged += analysis.codeFiles.length;
|
|
85
|
+
proposalStats.additions += analysis.totalAdditions;
|
|
86
|
+
proposalStats.deletions += analysis.totalDeletions;
|
|
87
|
+
proposalStats.netChanges += analysis.netChanges;
|
|
88
|
+
}
|
|
61
89
|
}
|
|
62
90
|
} catch (err) {
|
|
63
91
|
_iterator4.e(err);
|
|
@@ -167,6 +195,7 @@ export var StatsAggregator = /*#__PURE__*/function () {
|
|
|
167
195
|
},
|
|
168
196
|
branches: actualBranches.size > 0 ? Array.from(actualBranches) : branches,
|
|
169
197
|
authors: authorStatsMap,
|
|
198
|
+
proposals: proposalStatsMap,
|
|
170
199
|
totalCommits: analyses.length
|
|
171
200
|
};
|
|
172
201
|
}
|
package/dist/esm/types.d.ts
CHANGED
|
@@ -66,6 +66,16 @@ export interface BranchStats {
|
|
|
66
66
|
deletions: number;
|
|
67
67
|
netChanges: number;
|
|
68
68
|
}
|
|
69
|
+
export interface ProposalStats {
|
|
70
|
+
proposal: string;
|
|
71
|
+
commits: number;
|
|
72
|
+
contributors: Set<string>;
|
|
73
|
+
codeFilesChanged: number;
|
|
74
|
+
additions: number;
|
|
75
|
+
deletions: number;
|
|
76
|
+
netChanges: number;
|
|
77
|
+
commitHashes: Set<string>;
|
|
78
|
+
}
|
|
69
79
|
export interface StatsResult {
|
|
70
80
|
timeRange: {
|
|
71
81
|
since: Date;
|
|
@@ -73,5 +83,6 @@ export interface StatsResult {
|
|
|
73
83
|
};
|
|
74
84
|
branches: string[];
|
|
75
85
|
authors: Map<string, AuthorStats>;
|
|
86
|
+
proposals: Map<string, ProposalStats>;
|
|
76
87
|
totalCommits: number;
|
|
77
88
|
}
|