Repository navigation
231 lines (217 loc) · 8.92 KB
/
Copy pathci.yml
File metadata and controls
231 lines (217 loc) · 8.92 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
name: CI
on:
pull_request:
push:
# A glob, not a literal: this filter named draft-18 back when that was the
# default branch (e53c5e0), so when the default moved to draft-19 every push
# to it went unbuilt until someone noticed. draft-* covers the current draft
# branch and the next one without an edit.
#
# Three places still need the literal branch name, so a draft bump has to
# touch all three: the README's CI badge (GitHub badges take one branch and
# no globs), the publish-coverage job below, which must not deploy Pages
# from anything but the default branch, and — outside this repo entirely —
# the github-pages environment's deployment branch policy, in Settings >
# Environments. That last one is not in any file here, so it fails closed
# and only after everything else has gone green:
#
# Branch "draft-NN" is not allowed to deploy to github-pages due to
# environment protection rules.
#
# Update it with:
# gh api -X POST repos/floatdrop/moq-go/environments/github-pages/\
# deployment-branch-policies -f name='draft-NN' -f type='branch'
# then delete the stale policy listed by the same path with GET.
branches: ['draft-*']
# Lets the third-party interop job below be run on demand while it is ungated.
workflow_dispatch:
# Cancel superseded runs on the same ref (e.g. new push to a PR).
concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-go@v7
with:
go-version-file: go.mod
- run: go build ./...
test:
name: Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-go@v7
with:
go-version-file: go.mod
- run: go test ./...
race:
name: Test (race)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-go@v7
with:
go-version-file: go.mod
- run: go test -race ./...
# Measures coverage and builds the report site. Deliberately NOT a gate on
# coverage: there is no floor left to breach, so no drop can fail it. The
# signal is the README badge and the published report, both read by hand. See
# CLAUDE.md "Coverage is measured, not enforced" for the trade-off accepted
# here.
#
# It can still go red, because coverage is measured by running the suite and
# an unmeasurable suite is a failure worth surfacing. When it does, read it as
# a duplicate of the Test job rather than as anything about coverage.
coverage:
name: Coverage report
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-go@v7
with:
go-version-file: go.mod
# Measured with
# -coverpkg, so a package is credited for every line the suite exercises
# rather than only for what its own tests reach; most of wire is driven by
# message/session/relay tests.
# pipefail is load-bearing: the default shell is `bash -e`, which takes a
# pipeline's status from its LAST command, so without it a failed suite
# would exit through tee as a success and this step would pass green.
- name: Measure
run: |
set -o pipefail
make cover-site | tee coverage-summary.txt
# Puts the per-package table on the run's summary page, so a regression is
# visible in the run that caused it without anyone opening the report.
- name: Job summary
run: |
{
echo '### Coverage'
echo '```'
cat coverage-summary.txt
echo '```'
} >>"$GITHUB_STEP_SUMMARY"
- uses: actions/upload-pages-artifact@v5
with:
path: site
# Split from the job above so that one can run on every push and pull request
# while publishing stays on the default branch: a Pages deployment is
# repo-global, so deploying from a branch or a fork's PR would overwrite the
# published report with an unmerged one.
publish-coverage:
name: Publish coverage report
needs: coverage
if: github.event_name == 'push' && github.ref == 'refs/heads/draft-20'
runs-on: ubuntu-latest
# Job-level permissions replace the workflow's `contents: read` outright, so
# it has to be restated alongside the two Pages needs.
permissions:
contents: read
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deploy.outputs.page_url }}
steps:
- id: deploy
uses: actions/deploy-pages@v5
bench:
name: Benchmarks (smoke)
runs-on: ubuntu-latest
# This job is the only thing that runs the sessiontest bufPipe (via
# BenchmarkFanoutBuffered, which the -skip in `make bench` excludes but this
# target deliberately keeps). That is mutex/cond code, so a deadlock here
# would otherwise hang for GitHub's 6h default instead of failing fast.
timeout-minutes: 10
steps:
- uses: actions/checkout@v7
- uses: actions/setup-go@v7
with:
go-version-file: go.mod
# Compile-and-run only, one iteration each (~7s). CI runners are far too
# noisy for timing or allocation assertions, so this asserts nothing about
# the numbers — it only keeps a benchmark from silently rotting into
# something that no longer builds or panics. Regression comparison is the
# local `make bench-quick` / `benchstat` step; see benchmarks/README.md.
- run: make bench-smoke
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-go@v7
with:
go-version-file: go.mod
- name: golangci-lint
uses: golangci/golangci-lint-action@v9
with:
# v2.13.0 is the first release whose staticcheck can parse a go1.27
# field-selector struct key; v2.12.2 panics on one. No release is
# built with go1.27 yet, and a go1.26-built binary refuses a go1.27
# target outright, so build from source with the job's toolchain.
# Revert to the default binary install mode once a release ships
# built with go1.27.
version: v2.13.0
install-mode: goinstall
modernize:
name: Modernize (errorsastype)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-go@v7
with:
go-version-file: go.mod
# v2.13.0's bundled modernize snapshot does ship errorsastype, so the
# lint job already covers it. This runs the analyzer at @latest to catch
# analyzers newer than whatever golangci-lint bundles. See CLAUDE.md.
- run: |
go run golang.org/x/tools/gopls/internal/analysis/modernize/cmd/modernize@latest \
-errorsastype ./...
govulncheck:
name: Vulnerability scan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-go@v7
with:
go-version-file: go.mod
- run: go run golang.org/x/vuln/cmd/govulncheck@latest ./...
# Interop is gated on independent implementations: the unit tests round-trip
# through this codebase's own codec, so a wire-encoding regression (e.g. QUIC
# varints instead of the §1.4.1 leading-ones encoding) passes every unit test
# yet breaks interop. Both jobs use Docker (preinstalled on the runner). The
# advisory `make interop-matrix` is intentionally not gated — it has known
# cross-implementation divergences (see STATUS.md).
# Manual-only: every published third-party client still speaks draft-18, while
# this relay advertises only the "moqt-20" ALPN, so the TLS handshake cannot
# complete and every case fails with "failed to connect to server". Gating on
# it would mean a permanently red required check. Re-enable by deleting the
# `if:` once the interop images move to draft-20 — nothing else about the job
# needs to change. Run it meanwhile from the Actions tab (workflow_dispatch).
interop:
name: Interop (relay ← third-party client)
if: github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v7
# Our relay vs the moq-dev-rs draft-18 client over raw QUIC + WebTransport.
- run: make interop
interop-client:
name: Interop (our client → our relay)
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v7
# Loopback regression guard over BOTH transport mappings: our client and
# relay agree on all six cases via moqt:// and via https://. This is the
# only interop coverage left while the job above is manual, and the only
# thing exercising the relay container's WebTransport path — a stale
# -webtransport flag in entrypoint-relay.sh once broke exactly that.
- run: make interop-loopback