Repository navigation
231 lines (221 loc) · 11.6 KB
/
Copy pathdocs.yml
File metadata and controls
231 lines (221 loc) · 11.6 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: docs
on:
push:
pull_request:
# Daily, for the `versions` job below. The event that invalidates a pinned
# version is a release in *another* repository, so a push/PR-only trigger
# would leave a stale pin undetected until someone happened to touch the
# docs. See spec/009-getting_started_tutorials/design.md § D9.
schedule:
- cron: '17 6 * * *'
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
# pagelint.py --changed derives its strict ranges from the merge-base,
# so the full history has to be here. Present from the first version of
# this file rather than added alongside that step, because a shallow
# clone fails in a way that looks like "no changes" rather than an error.
fetch-depth: 0
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: python3 tools/linkcheck.py
# Repo-wide: banner, heading uniqueness, terminology and language tags are
# errors on every page. Language tags joined that list with spec 011 Task
# 7.2, which tagged the last 34 untagged fences — a rule with no remaining
# debt needs no softer level. The using-directive debt does still have one,
# so it stays a counted warning here and the backlog is visible without
# blocking unrelated work.
- run: python3 tools/pagelint.py
# Spec 018 phase 1, design § Rule 8. Rule 8 (ATTRIBUTE KIND) has one hit in
# the corpus and it is marked, so the step above cannot show the rule still
# fires. These five in-memory plants can: exit 0 only if every one behaves.
- run: python3 tools/pagelint.py --plant
# On a pull request the code rules become errors, but only for blocks that
# overlap the diff. Fixing a typo on a 700-line page therefore obliges
# nothing beyond the typo.
#
# This step must not pass vacuously. pagelint.py exits 2 — not 0 — when it
# cannot resolve the ref or read the diff, so an unusable history fails the
# build rather than reporting "no changed ranges". `fetch-depth: 0` above is
# what makes origin/<base_ref> resolvable.
#
# It also cannot pass *silently* vacuously: spec 010 P2-3, the run opens by
# printing how many files, hunks, pages and code blocks it examined, and
# says so in as many words when the diff reaches no block. That last figure
# is the one to read — the strict rules are per code block, so a diff of a
# hundred prose files makes them strict about nothing. The description
# sweep is the case in point: 149 files and 192 hunks, 5 blocks strict.
#
# base_ref goes through env rather than straight into the command line.
# Git ref names may contain `;`, `&` and `$`, so a `${{ }}` expansion
# inside `run:` is a shell-injection shape even when the value is a
# branch name in this repository.
- if: github.event_name == 'pull_request'
env:
BASE_REF: ${{ github.base_ref }}
run: python3 tools/pagelint.py --changed "origin/$BASE_REF"
# Spec 014 phase 2/3. tools/symbolcheck.py fails the build when a page names a
# symbol on tools/symbolwatch.tsv — a name that is dead in the product at both
# the pinned release and its master.
#
# THIS STEP SHIPS IN THE SAME PR AS THE REPAIRS IT POLICES, and that is the
# rule rather than this instance: a gate and the corpus that satisfies it merge
# together, or the gate merges second. This file triggers `on: push`, so a gate
# merged over a corpus that still violates it turns master red *and* reddens its
# own pull request. The 17 sites this step would have failed on were repaired in
# the commits beside it; the red run itself is preserved in
# spec/014-documentation_workflow/tasks.md § Phase 2 as executed, because a gate
# that has never been seen failing has not been shown to work.
#
# `--verify-list` is deliberately NOT here — see the versions job below. Nothing
# in this job checks out Brighter or Darker, and without them that mode exits 2
# rather than reporting every watched name as dead.
- run: python3 tools/symbolcheck.py
# Spec 010 D3/D7, Q10's answer. Both read only the repository, so neither can
# make the build flaky. `--verify` is deliberately NOT here: it fetches the live
# sitemap, and a check whose failure mode is "the site was slow" teaches people
# to ignore red builds.
#
# --check-shape asserts design §4's S1/S2/S3 — at least 2 pages per section, at
# most 20 top-level entries, at most 4 URL segments — plus that no SUMMARY.md
# heading carries leading whitespace. It was red on the 19-section tree this
# spec replaced (6 singleton sections, 2 sections over 12 entries, and the
# leading space at SUMMARY.md:154), which is how it proved it was not vacuous.
#
# --check-redirects asserts every redirect value resolves to a file that
# exists, every key is a path that no longer publishes, and every byte of
# .gitbook.yaml is printable ASCII. That last one is not a style rule: two
# U+200B zero-width spaces in this repo's `structure:` key meant GitBook never
# read that block, silently, for months — and they came from GitBook's own
# published example, which still carries them.
#
# These gate rather than being run once at merge, because a redirect block that
# is complete at merge and incomplete three PRs later is the same silent
# failure in slow motion.
- run: python3 tools/urlmap.py --check-shape
- run: python3 tools/urlmap.py --check-redirects
# Spec 009 D9. tools/versioncheck.py diffs the versions pinned in tutorial
# prose against the latest non-prerelease on NuGet, per package.
#
# The `if [ -f tools/versioncheck.py ]` guard that stood here until D9 landed
# is GONE, and must stay gone: it existed only to keep the build green while
# the tool was absent, and a guard that outlives its tool silently un-gates
# the check it was protecting.
#
# The invocation is bare for the same reason. versioncheck.py exits 2 when it
# cannot reach NuGet, and an unreachable authority is an unchecked pin rather
# than a pass — so no `|| true`, and no swallowing the exit code in a shell
# pipeline.
#
# This job keeps BOTH triggers. The daily `schedule:` above is not belt and
# braces: the event that invalidates a pin is a release in another
# repository, so a PR-only trigger would leave a stale pin undetected until
# someone happened to touch the docs.
# tools/symbolcheck.py --verify-list joins this job for that same reason, spec 014
# phase 3. It asks of every row in tools/symbolwatch.tsv: is this name still dead?
# A row goes stale when the product brings the name back, deletes its replacement,
# or ships the replacement a page was told to wait for — all three are releases in
# another repository, which is this job's stated trigger and not the `check` job's.
#
# That is also why the three checkouts below are laid out as siblings. symbolcheck
# resolves each row at ../Brighter and ../Darker, and actions/checkout cannot write
# outside the workspace — so this repository goes in Docs/ and the two products
# beside it, rather than at the workspace root. Every step therefore names its
# working-directory.
#
# fetch-depth: 0 and fetch-tags on the products are load-bearing, not caution: the
# rows resolve at a PINNED TAG as well as at origin/master, and a shallow default
# checkout has neither. A missing ref is exit 2 here rather than a row silently
# reading DEAD — `git grep` exits >1 for a bad ref and 1 for an honest zero, and
# resolve() tells those apart.
versions:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
path: Docs
- uses: actions/checkout@v4
with:
repository: BrighterCommand/Brighter
path: Brighter
fetch-depth: 0
fetch-tags: true
- uses: actions/checkout@v4
with:
repository: BrighterCommand/Darker
path: Darker
fetch-depth: 0
fetch-tags: true
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: python3 tools/versioncheck.py
working-directory: Docs
- run: python3 tools/symbolcheck.py --verify-list
working-directory: Docs
# Spec 012 D1/D2. tools/optioncheck diffs every option table in contents/
# against the type its `<!-- optioncheck: -->` marker names, reflecting over
# the packages pinned in tools/optioncheck/optioncheck.csproj.
#
# NO GUARD, and none may be added. The `if [ -f ... ]` that stood in the
# versions job until D9 landed existed only to keep the build green while the
# tool was absent, and a guard that outlives its tool silently un-gates the
# check it was protecting.
#
# NO SCHEDULED RUN, the opposite of the versions job, and it takes an `if:`:
# the `schedule:` at the top of this file triggers every job without a filter.
# AC4's schedule clause was struck at design review
# (design §6.5, §13.2): optioncheck reflects over a PINNED package, so nothing
# outside this repository can change its verdict. A scheduled run can only
# repeat the last PR's answer — or exit 2 because NuGet was briefly
# unreachable, which is a red build caused by the weather.
#
# The invocation is bare for the same reason versioncheck.py's is. Exit 2 is
# "the pinned packages are not in this process", which is an unchecked corpus
# rather than a pass, so no `|| true` and no swallowing the code in a pipeline.
options:
if: github.event_name != 'schedule'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
with:
dotnet-version: '9.0.x'
- run: dotnet run --project tools/optioncheck
# Spec 016. tools/blockcheck.py compiles every C# block in contents/, one
# block per compilation, against the packages pinned in
# tools/blockcheck/refs/refs.csproj, and fails when the blocks that build
# disagree with tools/blockcheck/baseline.tsv in either direction.
#
# NO GUARD, for optioncheck's reason above: a guard that outlives its tool
# silently un-gates the check it was protecting.
#
# NO SCHEDULED RUN (Q8), by an `if:` as for the options job: the `schedule:`
# at the top of this file triggers the whole workflow. The pin is exact (Q9: every PackageReference in refs.csproj names one version),
# so nothing outside this repository can change this job's verdict; a daily
# run could only repeat the last push's answer or go red because NuGet was
# unreachable.
#
# The two builds are separate steps, and before the gate, because without
# them the gate exits 2 -- "nothing was checked" -- rather than failing every
# block. The invocation is bare, rows go to a file and not a pipeline, and
# there is no `|| true`: exit 2 is an unchecked corpus, not a pass.
blocks:
if: github.event_name != 'schedule'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
with:
dotnet-version: '9.0.x'
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: dotnet build tools/blockcheck/refs/refs.csproj -c Release
- run: dotnet build tools/blockcheck/refs-v4/refs-v4.csproj -c Release
- run: dotnet build tools/blockcheck/blockcheck.csproj -c Release
- run: python3 tools/blockcheck.py --report "$RUNNER_TEMP/blockcheck.tsv"