-
Notifications
You must be signed in to change notification settings - Fork 2
130 lines (116 loc) · 5.9 KB
/
Copy pathci.yml
File metadata and controls
130 lines (116 loc) · 5.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
name: CI
on:
push:
branches: [main]
pull_request:
concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
test:
name: typecheck · lint · test
runs-on: [self-hosted, macmini]
# Self-hosted runner: never execute a fork PR's code here. Only run for
# direct pushes (already require write access) or PRs from this same repo.
if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository
steps:
- uses: actions/checkout@v7
- uses: pnpm/action-setup@v6
with:
version: 11.5.2
# Self-hosted runners share one $HOME, and the action clears its
# install dir before writing to it. With the default ~/setup-pnpm that
# `rmdir` is shared by every job on the box, so two jobs from
# different refs starting together race and leave it half-removed —
# `ENOTEMPTY ... rmdir .../store/v11/files/03` — after which later
# jobs fail at setup or, once store files are gone, at `pnpm install`
# with ERR_PNPM_ENOENT. All of it before a single test runs.
#
# The workflow's concurrency group is keyed on github.ref, so it
# serialises one branch and does nothing across branches — exactly the
# case that collides.
#
# runner.temp is per-job and cleaned up by the runner, so there is no
# shared directory left to race on. `standalone` additionally avoids
# building the node_modules layout. See #125.
dest: ${{ runner.temp }}/setup-pnpm
standalone: true
# No `cache: pnpm` on purpose. The runner is self-hosted, so the pnpm
# store already persists in $HOME between jobs (see --store-dir below) — actions/cache would
# round-trip a tarball over the network for zero benefit. Measured cost
# when it was enabled: up to 79s in the post-job cache save, longer than
# the test step it was meant to speed up.
- uses: actions/setup-node@v7
with:
node-version: 24
# --store-dir keeps the package cache on a stable path. The install dir
# above is per-job and disposable; the store must not be, or every job
# re-downloads ~1100 packages. A shared content-addressed store is
# pnpm's normal mode and is safe for concurrent readers — it was only
# fragile here because it happened to sit inside the directory the
# action clears.
- run: pnpm install --frozen-lockfile --store-dir ~/.pnpm-store
- run: pnpm typecheck
- run: pnpm lint
# Integration tests start Postgres via testcontainers; Docker runs on the
# self-hosted runner. No secrets required.
- run: pnpm test
mutation:
name: mutation (diff)
runs-on: [self-hosted, macmini]
# Runs only after `test` releases its runner. Mutation is non-blocking, but
# a wide diff can keep Stryker busy for 30+ min (observed on a 9-file diff),
# and while it held the runner the *blocking* typecheck/lint/test jobs of
# every other PR queued behind a job nobody gates on. Ordering it after test
# keeps the blocking checks first without giving up the self-hosted runner.
needs: test
# Self-hosted runner: never execute a fork PR's code here — only PRs from
# this same repo (see the test job's comment for why).
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository
# Diff-scoped: only the source files changed in the PR are mutated, so runs
# take minutes instead of a full cold sweep. Non-blocking (reports only):
# Stryker currently runs just the unit suite, so files covered mainly by
# integration tests score artificially low — a blocking gate would fail
# legitimate PRs. Flip to blocking once the mutation harness also runs the
# integration suite.
continue-on-error: true
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- uses: pnpm/action-setup@v6
with:
version: 11.5.2
# Self-hosted runners share one $HOME, and the action clears its
# install dir before writing to it. With the default ~/setup-pnpm that
# `rmdir` is shared by every job on the box, so two jobs from
# different refs starting together race and leave it half-removed —
# `ENOTEMPTY ... rmdir .../store/v11/files/03` — after which later
# jobs fail at setup or, once store files are gone, at `pnpm install`
# with ERR_PNPM_ENOENT. All of it before a single test runs.
#
# The workflow's concurrency group is keyed on github.ref, so it
# serialises one branch and does nothing across branches — exactly the
# case that collides.
#
# runner.temp is per-job and cleaned up by the runner, so there is no
# shared directory left to race on. `standalone` additionally avoids
# building the node_modules layout. See #125.
dest: ${{ runner.temp }}/setup-pnpm
standalone: true
# No `cache: pnpm` — see the test job for why.
- uses: actions/setup-node@v7
with:
node-version: 24
# --store-dir keeps the package cache on a stable path. The install dir
# above is per-job and disposable; the store must not be, or every job
# re-downloads ~1100 packages. A shared content-addressed store is
# pnpm's normal mode and is safe for concurrent readers — it was only
# fragile here because it happened to sit inside the directory the
# action clears.
- run: pnpm install --frozen-lockfile --store-dir ~/.pnpm-store
- name: Mutation test changed files
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: bash scripts/mutate-diff.sh "$BASE_SHA" "$HEAD_SHA"