Skip to content

Commit a876032

Browse files
committed
Updated GH workflow (simpler matrix, better coverage)
1 parent 0023983 commit a876032

File tree

1 file changed

+71
-30
lines changed

1 file changed

+71
-30
lines changed

.github/workflows/ci.yml

Lines changed: 71 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,16 @@ on:
77

88
permissions:
99
contents: read
10+
pull-requests: write
1011

1112
concurrency:
1213
group: ci-${{ github.ref }}
1314
cancel-in-progress: true
1415

1516
jobs:
16-
test:
17-
name: Test (Node ${{ matrix.node }})
17+
ci:
18+
name: Test & Coverage
1819
runs-on: ubuntu-latest
19-
strategy:
20-
fail-fast: false
21-
matrix:
22-
node: [18.x, 20.x, 22.x]
2320
steps:
2421
- uses: actions/checkout@v4
2522

@@ -30,41 +27,21 @@ jobs:
3027

3128
- uses: actions/setup-node@v4
3229
with:
33-
node-version: ${{ matrix.node }}
30+
node-version: 20.x
3431
cache: pnpm
3532

3633
- name: Install dependencies
37-
run: pnpm install --frozen-lockfile
34+
run: pnpm install
3835

3936
- name: Build and test
4037
run: pnpm test:spec
4138

42-
coverage:
43-
name: Coverage (domain suite)
44-
runs-on: ubuntu-latest
45-
needs: test
46-
steps:
47-
- uses: actions/checkout@v4
48-
49-
- uses: pnpm/action-setup@v4
50-
with:
51-
version: 9
52-
run_install: false
53-
54-
- uses: actions/setup-node@v4
55-
with:
56-
node-version: 20.x
57-
cache: pnpm
58-
59-
- name: Install dependencies
60-
run: pnpm install --frozen-lockfile
61-
62-
- name: Run coverage
39+
- name: Run coverage (domain suite)
6340
run: |
6441
set -o pipefail
6542
pnpm test:domain:cov | tee coverage/typecheck/coverage.log
6643
67-
- name: Coverage summary
44+
- name: Coverage summary (job)
6845
run: |
6946
{
7047
echo "## Coverage (domain suite)";
@@ -77,3 +54,67 @@ jobs:
7754
with:
7855
name: coverage-typecheck
7956
path: coverage/typecheck
57+
58+
- name: Comment coverage on PR
59+
if: github.event_name == 'pull_request'
60+
uses: actions/github-script@v7
61+
with:
62+
github-token: ${{ secrets.GITHUB_TOKEN }}
63+
script: |
64+
const fs = require('fs');
65+
const path = 'coverage/typecheck/coverage-final.json';
66+
const coverage = JSON.parse(fs.readFileSync(path, 'utf8'));
67+
68+
const keys = ['lines', 'statements', 'functions', 'branches'];
69+
const totals = Object.values(coverage).reduce((acc, file) => {
70+
for (const key of keys) {
71+
acc[key].total += file[key].total;
72+
acc[key].covered += file[key].covered;
73+
}
74+
return acc;
75+
}, {
76+
lines: { total: 0, covered: 0 },
77+
statements: { total: 0, covered: 0 },
78+
functions: { total: 0, covered: 0 },
79+
branches: { total: 0, covered: 0 },
80+
});
81+
82+
const fmt = ({ covered, total }) =>
83+
total === 0 ? 'n/a' : `${((covered / total) * 100).toFixed(2)}% (${covered}/${total})`;
84+
85+
const header = '## Coverage (domain suite)';
86+
const body = [
87+
header,
88+
'',
89+
`- Lines: ${fmt(totals.lines)}`,
90+
`- Statements: ${fmt(totals.statements)}`,
91+
`- Functions: ${fmt(totals.functions)}`,
92+
`- Branches: ${fmt(totals.branches)}`,
93+
'',
94+
'_Generated by CI_',
95+
].join('\n');
96+
97+
const { data: comments } = await github.rest.issues.listComments({
98+
issue_number: context.issue.number,
99+
owner: context.repo.owner,
100+
repo: context.repo.repo,
101+
});
102+
const existing = comments.find(
103+
(c) => c.user?.login === 'github-actions[bot]' && c.body?.startsWith(header)
104+
);
105+
106+
if (existing) {
107+
await github.rest.issues.updateComment({
108+
comment_id: existing.id,
109+
owner: context.repo.owner,
110+
repo: context.repo.repo,
111+
body,
112+
});
113+
} else {
114+
await github.rest.issues.createComment({
115+
issue_number: context.issue.number,
116+
owner: context.repo.owner,
117+
repo: context.repo.repo,
118+
body,
119+
});
120+
}

0 commit comments

Comments
 (0)