-
Notifications
You must be signed in to change notification settings - Fork 130
261 lines (255 loc) · 9.08 KB
/
Copy pathci.yml
File metadata and controls
261 lines (255 loc) · 9.08 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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
name: CI
on:
pull_request:
merge_group:
push:
branches:
- main
# Default to least-privilege for the GITHUB_TOKEN. Individual jobs that
# need to write back to the repo (e.g. posting PR review suggestions)
# widen their own permissions block below.
permissions:
contents: read
jobs:
rubocop:
name: Rubocop
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: ./.github/actions/setup-ruby
- name: Run Rubocop
run: bundle exec rubocop
suggest_lint_changes:
name: 'Suggest lint changes'
runs-on: ubuntu-latest
if: ${{ github.event_name == 'pull_request' }}
# parkerbxyz/suggest-changes posts review comments with suggested
# edits, which requires write access to the PR.
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v7
- uses: ./.github/actions/setup-ruby
- uses: ./.github/actions/setup-node
- name: Run Lint
run: bin/lint -c
- name: Comment suggested changes
uses: parkerbxyz/suggest-changes@v3.1.2
erblint:
name: 'ERB Lint'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: ./.github/actions/setup-ruby
- name: Run erb_lint
run: bin/erb_lint
eslint:
name: ESLint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: ./.github/actions/setup-node
- name: Run ESLint
run: yarn lint
prettier:
name: Prettier
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: ./.github/actions/setup-node
- name: Run Prettier
run: yarn format:check
rspec:
name: RSpec (shard ${{ matrix.shard }}/${{ strategy.job-total }})
runs-on: ubuntu-latest
strategy:
# Don't cancel remaining shards when one fails — we want to see all
# failures in a single run rather than a slow loop of retries.
fail-fast: false
matrix:
# Bumping this number adds more parallel runners. Keep it in sync
# with SHARD_TOTAL below.
shard: [1, 2, 3, 4, 5, 6, 7, 8]
services:
postgres:
image: postgres:15
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
# https://docs.github.com/en/actions/tutorials/use-containerized-services/create-redis-service-containers
redis:
image: redis:latest
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 6379:6379
steps:
- uses: actions/checkout@v7
- uses: ./.github/actions/setup-ruby
- uses: ./.github/actions/setup-node
- uses: ./.github/actions/setup-db
- name: Build Assets
run: yarn build && yarn build:css
- name: Run RSpec
env:
${{ insert }}: ${{ secrets }}
DATABASE_URL: postgres://postgres:postgres@localhost:5432/bank_test
REDIS_URL: redis://localhost:6379
RAILS_ENV: test
CC_TEST_REPORTER_ID: '1' # Force SimpleCov to generate a JSON report
SHARD_INDEX: ${{ matrix.shard }}
SHARD_TOTAL: 8
# Deterministic round-robin split of spec files across shards. We
# sort the file list first so each runner computes the same ordering,
# then `awk` keeps only the files whose 1-based index mod SHARD_TOTAL
# maps to this shard. With 143 spec files over 8 shards, each shard
# runs ~18 files. This is simple and doesn't require extra gems;
# upgrade to a balancer (ci-queue, knapsack_pro) later if shards
# drift apart in wall time.
run: |
specs=$(find spec -name '*_spec.rb' | sort | awk -v i="$SHARD_INDEX" -v n="$SHARD_TOTAL" 'NR % n == (i - 1) % n { print }')
echo "Running $(echo "$specs" | wc -l) spec files on shard $SHARD_INDEX/$SHARD_TOTAL"
seed=$RANDOM
cmd="bundle exec rspec --seed $seed --tag '~skip' $(echo $specs | tr '\n' ' ')"
echo "To reproduce locally, run:"
echo " RAILS_ENV=test bundle exec rails db:drop db:create db:schema:load && \\"
echo " $cmd"
eval "$cmd"
- name: Upload coverage report
uses: actions/upload-artifact@v7
with:
# Each shard generates its own coverage file; name them uniquely
# so the upload action doesn't clash. Merging into a single report
# can be done in a downstream job if needed.
name: simplecov-report-shard-${{ matrix.shard }}
path: coverage/coverage.json
annotate:
name: Annotate
runs-on: ubuntu-latest
services:
postgres:
image: postgres:15
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
steps:
- uses: actions/checkout@v7
- uses: ./.github/actions/setup-ruby
- uses: ./.github/actions/setup-db
- name: Run annotaterb
env:
DATABASE_URL: postgres://postgres:postgres@localhost:5432/bank_test
RAILS_ENV: test
run: bundle exec annotaterb models --frozen
zeitwerk:
name: Zeitwerk
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: ./.github/actions/setup-ruby
- uses: ./.github/actions/setup-node
- name: Run zeitwerk:check
env:
RAILS_ENV: test
run: bundle exec rails zeitwerk:check
reversible_migrations:
name: Reversible Migrations
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
services:
postgres:
image: postgres:15
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- uses: ./.github/actions/setup-ruby
- name: Install postgres client
run: sudo apt-get install libpq-dev
- name: Get new migration versions
id: migrations
run: |
# Get migration files added in this PR compared to main
NEW_MIGRATIONS=$(git diff --name-only --diff-filter=A origin/main...HEAD -- db/migrate/*.rb | sort)
if [ -z "$NEW_MIGRATIONS" ]; then
echo "No new migrations found"
echo "versions=" >> $GITHUB_OUTPUT
else
echo "New migrations found:"
echo "$NEW_MIGRATIONS"
# Extract versions (timestamps) from filenames
VERSIONS=$(echo "$NEW_MIGRATIONS" | sed 's/.*\/\([0-9]*\)_.*/\1/' | tac | tr '\n' ' ')
echo "versions=$VERSIONS" >> $GITHUB_OUTPUT
fi
- name: Setup database
if: steps.migrations.outputs.versions != ''
env:
DATABASE_URL: postgres://postgres:postgres@localhost:5432/bank_test
RAILS_ENV: test
run: bundle exec rails db:create db:schema:load
- name: Test migration reversibility
if: steps.migrations.outputs.versions != ''
env:
DATABASE_URL: postgres://postgres:postgres@localhost:5432/bank_test
RAILS_ENV: test
run: |
VERSIONS="${{ steps.migrations.outputs.versions }}"
# Ensure all migrations are applied first
echo "========================================="
echo "Applying all migrations to get to latest state..."
bundle exec rails db:migrate
# Get the oldest new migration version
OLDEST_NEW=$(echo "$VERSIONS" | awk '{print $NF}')
# Get all migration versions from files, find the one right before OLDEST_NEW
ALL_MIGRATIONS=$(ls db/migrate/*.rb | sed 's/.*\/\([0-9]*\)_.*/\1/' | sort)
ROLLBACK_TO=$(echo "$ALL_MIGRATIONS" | awk -v target="$OLDEST_NEW" '$1 < target {prev=$1} END {print prev}')
echo "========================================="
echo "Rolling back all new migrations..."
if [ -z "$ROLLBACK_TO" ]; then
echo "Rolling back to empty database (no migrations before the new ones)..."
bundle exec rails db:migrate VERSION=0
else
echo "Rolling back to VERSION=$ROLLBACK_TO..."
bundle exec rails db:migrate VERSION=$ROLLBACK_TO
fi
echo "========================================="
echo "Re-applying all migrations..."
bundle exec rails db:migrate
echo "========================================="
echo "✅ All migrations are reversible!"
brakeman:
name: Brakeman
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: ./.github/actions/setup-ruby
- name: Run Brakeman
run: bundle exec brakeman -q