Skip to content

Commit 8ba749d

Browse files
committed
Add PR change-summary chart workflow
On each pull request, post and keep updated a single comment showing the diff size per file: a Mermaid pie chart of each file's share of the churn plus a collapsible +/- breakdown table. Reads per-file additions/deletions from the PR API via actions/github-script (no checkout, no third-party action) and upserts a marker-tagged comment so it does not spam on pushes.
1 parent 5709795 commit 8ba749d

1 file changed

Lines changed: 96 additions & 0 deletions

File tree

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
name: PR change chart
2+
3+
# Posts (and keeps updated) a single comment on each pull request showing the
4+
# diff size per file: a Mermaid pie chart of each file's share of the churn
5+
# plus a collapsible +/- breakdown table. Uses only first-party actions and
6+
# the PR API, so there is no checkout, no build, and no third-party action.
7+
8+
on:
9+
pull_request:
10+
types: [opened, synchronize, reopened]
11+
12+
permissions:
13+
contents: read
14+
pull-requests: write
15+
16+
jobs:
17+
change-chart:
18+
runs-on: ubuntu-latest
19+
steps:
20+
- name: Build and upsert the change-summary comment
21+
uses: actions/github-script@v7
22+
with:
23+
script: |
24+
// Hidden marker so we can find and update our own comment instead
25+
// of posting a new one on every push.
26+
const MARKER = '<!-- pr-change-chart -->';
27+
const TOP = 15; // cap rows so the chart/table stay readable
28+
const { owner, repo } = context.repo;
29+
const pr = context.payload.pull_request;
30+
31+
// Per-file additions/deletions come straight from the PR API.
32+
const files = await github.paginate(github.rest.pulls.listFiles, {
33+
owner, repo, pull_number: pr.number, per_page: 100,
34+
});
35+
36+
let totalAdd = 0, totalDel = 0;
37+
const rows = files.map(f => {
38+
totalAdd += f.additions;
39+
totalDel += f.deletions;
40+
return { name: f.filename, add: f.additions, del: f.deletions, total: f.changes };
41+
}).sort((a, b) => b.total - a.total);
42+
43+
const shown = rows.slice(0, TOP);
44+
const rest = rows.slice(TOP);
45+
const restTotal = rest.reduce((s, r) => s + r.total, 0);
46+
const churn = totalAdd + totalDel;
47+
48+
// Mermaid pie of churn share per file (GitHub renders Mermaid
49+
// natively). Guarded: a pie with no slices would error, so we skip
50+
// it when the diff is all-binary / zero-line.
51+
let pie = '';
52+
if (churn > 0) {
53+
pie = '```mermaid\npie showData\n';
54+
pie += ` title Lines changed per file (${churn} total)\n`;
55+
for (const r of shown) {
56+
if (r.total <= 0) continue;
57+
const label = r.name.replace(/"/g, "'");
58+
pie += ` "${label}" : ${r.total}\n`;
59+
}
60+
if (restTotal > 0) pie += ` "… ${rest.length} more files" : ${restTotal}\n`;
61+
pie += '```';
62+
}
63+
64+
// Collapsible per-file table with the +/- split.
65+
let table = '| File | + | − | total |\n|---|--:|--:|--:|\n';
66+
for (const r of shown) {
67+
table += `| \`${r.name}\` | ${r.add} | ${r.del} | ${r.total} |\n`;
68+
}
69+
if (rest.length) {
70+
table += `| _… ${rest.length} more files_ | | | ${restTotal} |\n`;
71+
}
72+
table += `| **Total (${files.length} files)** | **${totalAdd}** | **${totalDel}** | **${churn}** |\n`;
73+
74+
const body = [
75+
MARKER,
76+
'### 📊 Change summary',
77+
`**${files.length}** files changed · **+${totalAdd}** / **−${totalDel}** lines`,
78+
'',
79+
pie,
80+
'',
81+
'<details><summary>Per-file breakdown</summary>',
82+
'',
83+
table,
84+
'</details>',
85+
].join('\n');
86+
87+
// Upsert: update our marked comment if it exists, else create it.
88+
const comments = await github.paginate(github.rest.issues.listComments, {
89+
owner, repo, issue_number: pr.number, per_page: 100,
90+
});
91+
const mine = comments.find(c => c.body && c.body.includes(MARKER));
92+
if (mine) {
93+
await github.rest.issues.updateComment({ owner, repo, comment_id: mine.id, body });
94+
} else {
95+
await github.rest.issues.createComment({ owner, repo, issue_number: pr.number, body });
96+
}

0 commit comments

Comments
 (0)