Repository navigation
477 lines (431 loc) · 18.4 KB
/
Copy pathpr.yml
File metadata and controls
477 lines (431 loc) · 18.4 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
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
name: Pull Request Tests
# tools/stb is a standalone project with its own gate (stb_tests.yml). We must
# NOT skip this workflow for stb-only changes via a trigger-level `paths`
# filter: these jobs are REQUIRED status checks, and a required check that is
# path-filtered at the trigger never reports — leaving stb-only PRs stuck on
# "Expected — waiting for status". Instead we always trigger and skip each job
# with a `changes`-gated `if:`; a job skipped by `if:` reports success and so
# satisfies the required check without running the Stratos build. See #5528.
on:
pull_request:
branches:
- main
- develop
- 'angular**'
- 'release/**'
push:
branches:
- develop
- main
- 'release/**'
# One live run per ref: a push to a PR branch (or develop/main) cancels the
# in-flight run for the same ref, so overlapping runs never contend for
# runners and only the newest commit is gated.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
# pull-requests: read is required by dorny/paths-filter, which lists a
# PR's changed files through the API.
permissions:
contents: read
pull-requests: read
env:
NODE_OPTIONS: --max-old-space-size=5500
NODE_VERSION: '24'
GO_VERSION: '1.27'
BUN_VERSION: '1.3.14'
jobs:
# Decide whether this PR touches anything outside tools/stb. All the real
# jobs below gate on `non_stb` so stb-only PRs skip them (→ success) while
# every other PR runs the full suite. Always runs; cheap.
changes:
name: Detect non-stb changes
runs-on: ubuntu-latest
outputs:
non_stb: ${{ steps.filter.outputs.non_stb }}
docs: ${{ steps.filter.outputs.docs }}
website: ${{ steps.filter.outputs.website }}
booklets: ${{ steps.filter.outputs.booklets }}
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
persist-credentials: false
- uses: dorny/paths-filter@d1c1ffe0248fe513906c8e24db8ea791d46f8590 # v3.0.3
id: filter
with:
# A file counts only if it matches EVERY pattern — required for the
# '!' exclusions below; the default 'some' lets '**' match anything,
# making the exclusions dead letters.
predicate-quantifier: 'every'
filters: |
# non_stb = the code path: skip the heavy suite when a PR only
# touches stb tooling, docs/, or website/ (each has its own gate).
non_stb:
- '**'
- '!tools/stb/**'
- '!docs/**'
- '!website/**'
- '!README.md'
docs:
- 'docs/**'
website:
- 'website/**'
booklets:
- 'docs/booklets/**'
# Enforce the GFM-intersection markdown subset on docs/ so every page
# renders identically on GitHub and in the website generator. Not a
# required check yet; job-level `if:` keeps it green-when-skipped if it
# ever becomes one (same pattern as the stb gate above).
docs-lint:
name: Docs Lint
runs-on: ubuntu-latest
needs: changes
if: needs.changes.outputs.docs == 'true'
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
persist-credentials: false
- uses: oven-sh/setup-bun@f4d14e03ff726c06358e5557344e1da148b56cf7 # v1.2.2
with:
bun-version: ${{ env.BUN_VERSION }}
- run: bun scripts/lint-docs.mjs
# The website previously had no PR coverage on develop: the legacy docs
# workflow (since removed) only triggered on master, so a website change
# (e.g. a dependency bump with a stale bun.lock) could merge green
# without ever being built. Frozen-lockfile install + full build
# catches both.
website-build:
name: Website Build
runs-on: ubuntu-latest
needs: changes
if: needs.changes.outputs.website == 'true'
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
persist-credentials: false
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: ${{ env.NODE_VERSION }}
- uses: oven-sh/setup-bun@f4d14e03ff726c06358e5557344e1da148b56cf7 # v1.2.2
with:
bun-version: ${{ env.BUN_VERSION }}
- name: Install dependencies
run: cd website && bun install --frozen-lockfile
- name: Build website
run: cd website && bun run build
# Booklets are offline epub/PDF renderings of docs/ (see docs/booklets/).
# Rendered on any docs or booklets change; the outputs are uploaded
# as a PR artifact for eyeballing, not published anywhere.
booklets-build:
name: Booklets Build
runs-on: ubuntu-latest
needs: changes
if: needs.changes.outputs.docs == 'true' || needs.changes.outputs.booklets == 'true'
timeout-minutes: 15
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
persist-credentials: false
- uses: quarto-dev/quarto-actions/setup@8a96df13519ee81fd526f2dfca5962811136661b # v2.2.0
with:
version: 1.9.38
# Mermaid diagrams render through chrome-headless-shell; without it
# preinstalled, quarto render blocks on an interactive install
# prompt and the job hangs until the timeout.
- name: Install chrome-headless-shell
run: quarto install chrome-headless-shell --no-prompt
- name: Render booklets
run: docs/booklets/render.sh
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: booklets
path: |
dist/booklets/
!dist/booklets/.work/**
retention-days: 14
# Advisory: names the e2e specs that cover the components a PR changes,
# derived from data-test hooks and element selectors (scripts/
# e2e-impact.mjs). Never gates — the e2e suite needs a live CF endpoint,
# so it cannot run here; this puts the scoped-run command in the job
# summary so reviewers know exactly which specs the change touches.
e2e-impact:
name: E2E Impact (advisory)
runs-on: ubuntu-latest
needs: changes
if: github.event_name == 'pull_request' && needs.changes.outputs.non_stb == 'true'
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
persist-credentials: false
fetch-depth: 0
- uses: oven-sh/setup-bun@f4d14e03ff726c06358e5557344e1da148b56cf7 # v1.2.2
with:
bun-version: ${{ env.BUN_VERSION }}
- name: Report covering specs
env:
BASE: ${{ github.base_ref }}
# Lets the impact script harvest tokens of components DELETED in
# the PR from the base ref, so their stranded specs still surface.
IMPACT_BASE: origin/${{ github.base_ref }}
run: |
# pipefail: a failing git diff must fail the job, not feed bun an
# empty stdin that reads as a green "no frontend changes".
set -o pipefail
{
echo '```'
git diff --name-only "origin/${BASE}...HEAD" | bun scripts/e2e-impact.mjs
echo '```'
} | tee -a "${GITHUB_STEP_SUMMARY}"
lint:
name: Lint Check
runs-on: ubuntu-latest
needs: changes
if: needs.changes.outputs.non_stb == 'true'
steps:
- name: Checkout code
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
persist-credentials: false
- name: Setup Go
uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0
with:
go-version: ${{ env.GO_VERSION }}
cache-dependency-path: src/jetstream/go.sum
- name: Setup Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: ${{ env.NODE_VERSION }}
- name: Setup Bun
uses: oven-sh/setup-bun@f4d14e03ff726c06358e5557344e1da148b56cf7 # v1.2.2
with:
bun-version: ${{ env.BUN_VERSION }}
- name: Get Bun cache directory
id: bun-cache-dir
shell: bash
run: echo "dir=$(bun pm cache)" >> ${GITHUB_OUTPUT}
- name: Cache Bun dependencies
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: ${{ steps.bun-cache-dir.outputs.dir }}
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }}
restore-keys: |
${{ runner.os }}-bun-
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Run linting
# `make check lint` is what runs locally: ESLint plus go fmt, go vet
# and golangci-lint over every backend module. Running `bun run lint`
# here instead left the Go linters out of CI entirely.
run: make check lint
test-frontend:
name: Frontend Tests
runs-on: ubuntu-latest
needs: changes
# Gate at STEP level, not job level: the per-package names below are
# required status checks, and a job-level skip collapses the matrix so
# those contexts never report ("expected" forever). With step-level
# gating each shard still spins up, no-ops, and reports success.
strategy:
fail-fast: false
matrix:
package: [core, store, cloud-foundry, kubernetes, cf-autoscaler, git, shared, extension]
steps:
- name: Checkout code
if: needs.changes.outputs.non_stb == 'true'
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
persist-credentials: false
- name: Setup Node.js
if: needs.changes.outputs.non_stb == 'true'
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: ${{ env.NODE_VERSION }}
- name: Setup Bun
if: needs.changes.outputs.non_stb == 'true'
uses: oven-sh/setup-bun@f4d14e03ff726c06358e5557344e1da148b56cf7 # v1.2.2
with:
bun-version: ${{ env.BUN_VERSION }}
- name: Get Bun cache directory
if: needs.changes.outputs.non_stb == 'true'
id: bun-cache-dir
shell: bash
run: echo "dir=$(bun pm cache)" >> ${GITHUB_OUTPUT}
- name: Cache Bun dependencies
if: needs.changes.outputs.non_stb == 'true'
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: ${{ steps.bun-cache-dir.outputs.dir }}
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }}
restore-keys: |
${{ runner.os }}-bun-
- name: Install dependencies
if: needs.changes.outputs.non_stb == 'true'
run: bun install --frozen-lockfile
- name: Generate build info
if: needs.changes.outputs.non_stb == 'true'
run: make stamp frontend
- name: Run ${{ matrix.package }} tests
if: needs.changes.outputs.non_stb == 'true'
# TODO: Remove --dangerouslyIgnoreUnhandledErrors once test mocks are fixed (FWT-872)
run: bun run vitest run --dangerouslyIgnoreUnhandledErrors --project=${{ matrix.package }} --passWithNoTests
test-backend:
name: Backend Tests
runs-on: ubuntu-latest
needs: changes
if: needs.changes.outputs.non_stb == 'true'
steps:
- name: Checkout code
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
persist-credentials: false
- name: Setup Go
uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0
with:
go-version: ${{ env.GO_VERSION }}
cache-dependency-path: src/jetstream/go.sum
- name: Setup Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: ${{ env.NODE_VERSION }}
- name: Setup Bun
uses: oven-sh/setup-bun@f4d14e03ff726c06358e5557344e1da148b56cf7 # v1.2.2
with:
bun-version: ${{ env.BUN_VERSION }}
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Create extra_plugins.go
run: |
cat > src/jetstream/extra_plugins.go << 'EOF'
package main
// This file is auto-generated - DO NOT EDIT
import _ "github.com/cloudfoundry/stratos/src/jetstream/plugins/autoscaler"
import _ "github.com/cloudfoundry/stratos/src/jetstream/plugins/cloudfoundry"
import _ "github.com/cloudfoundry/stratos/src/jetstream/plugins/cfapppush"
import _ "github.com/cloudfoundry/stratos/src/jetstream/plugins/cfappssh"
import _ "github.com/cloudfoundry/stratos/src/jetstream/plugins/userinvite"
import _ "github.com/cloudfoundry/stratos/src/jetstream/plugins/analysis"
import _ "github.com/cloudfoundry/stratos/src/jetstream/plugins/kubernetes"
import _ "github.com/cloudfoundry/stratos/src/jetstream/plugins/monocular"
EOF
- name: Run backend tests
run: make test backend
build-check:
name: Build Check
runs-on: ubuntu-latest
needs: [changes, lint, test-frontend, test-backend]
if: needs.changes.outputs.non_stb == 'true'
steps:
- name: Checkout code
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
persist-credentials: false
- name: Setup Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: ${{ env.NODE_VERSION }}
- name: Setup Bun
uses: oven-sh/setup-bun@f4d14e03ff726c06358e5557344e1da148b56cf7 # v1.2.2
with:
bun-version: ${{ env.BUN_VERSION }}
- name: Setup Go
uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0
with:
go-version: ${{ env.GO_VERSION }}
cache-dependency-path: src/jetstream/go.sum
- name: Get Bun cache directory
id: bun-cache-dir
shell: bash
run: echo "dir=$(bun pm cache)" >> ${GITHUB_OUTPUT}
- name: Cache Bun dependencies
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: ${{ steps.bun-cache-dir.outputs.dir }}
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }}
restore-keys: |
${{ runner.os }}-bun-
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Create extra_plugins.go
run: |
cat > src/jetstream/extra_plugins.go << 'EOF'
package main
// This file is auto-generated - DO NOT EDIT
import _ "github.com/cloudfoundry/stratos/src/jetstream/plugins/autoscaler"
import _ "github.com/cloudfoundry/stratos/src/jetstream/plugins/cloudfoundry"
import _ "github.com/cloudfoundry/stratos/src/jetstream/plugins/cfapppush"
import _ "github.com/cloudfoundry/stratos/src/jetstream/plugins/cfappssh"
import _ "github.com/cloudfoundry/stratos/src/jetstream/plugins/userinvite"
import _ "github.com/cloudfoundry/stratos/src/jetstream/plugins/analysis"
import _ "github.com/cloudfoundry/stratos/src/jetstream/plugins/kubernetes"
import _ "github.com/cloudfoundry/stratos/src/jetstream/plugins/monocular"
EOF
- name: Build frontend
run: make build frontend
- name: Build backend
run: make build backend
- name: Upload frontend artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: frontend-dist
path: dist/
retention-days: 1
- name: Upload backend artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: backend-binary
path: dist/bin/jetstream
retention-days: 1
# Advisory only, and deliberately NOT in pr-success's needs: a hard failure
# here would fire on pipeline fixes, docs-only changes, reverts and bumps,
# and a gate with that false-positive rate gets routed around rather than
# obeyed. A ::warning:: renders inline on the Files tab; a plain log line
# would be invisible once the check goes green.
#
# Dependabot is exempt because it cannot act on the advice — it never runs
# release-notes.sh. Its bumps are picked up instead by
# `release-notes.sh check` at `make stamp tag` time, off the commit log.
changelog-fragment:
name: Changelog Fragment (advisory)
runs-on: ubuntu-latest
if: github.event_name == 'pull_request' && github.actor != 'dependabot[bot]'
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
fetch-depth: 0
persist-credentials: false
- name: Check for a release-notes fragment
env:
BASE: ${{ github.event.pull_request.base.sha }}
run: |
# AM, not A: appending to an existing fragment is how a change joins
# a note that is already there — a dependency bump landing after the
# fragment that covers its group, for instance.
if git diff --name-only --diff-filter=AM "$BASE...HEAD" \
| grep -qE '^changelog\.d/[0-9]+-.*\.md$'; then
echo "✅ Release-notes fragment present."
exit 0
fi
echo "::warning title=No release-notes fragment::This PR neither adds nor updates a changelog.d fragment, so it will not appear in the release notes. Run ./build/release-notes.sh new — or ignore this if the change needs no note."
pr-success:
name: PR Quality Gate
runs-on: ubuntu-latest
needs: [lint, test-frontend, test-backend, build-check, website-build, booklets-build]
if: always()
steps:
- name: Check all jobs
# A stb-only PR skips every job above; "skipped" is an acceptable
# outcome here (the Stratos suite is genuinely N/A), only "failure"
# or "cancelled" should fail the gate.
run: |
for res in "${{ needs.lint.result }}" \
"${{ needs.test-frontend.result }}" \
"${{ needs.test-backend.result }}" \
"${{ needs.build-check.result }}" \
"${{ needs.website-build.result }}" \
"${{ needs.booklets-build.result }}"; do
if [ "$res" != "success" ] && [ "$res" != "skipped" ]; then
echo "❌ One or more required checks failed (result: $res)"
exit 1
fi
done
echo "✅ All PR checks passed!"