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
# CI for tw — https://github.com/markdoc-rs/tw
#
# The gate itself is in `.github/scripts/check.sh`, not here, so release.yml
# runs exactly the same set before it publishes anything. A second list of
# steps drifts, and the half that drifts is always the one nobody watches.
name: CI
on:
push:
branches:
pull_request:
jobs:
check:
name: Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
path: tw
- uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy
- uses: Swatinem/rust-cache@v2
with:
workspaces: tw
- name: check.sh
run: bash tw/.github/scripts/check.sh tw
# The one check that is about a corpus rather than about the code.
#
# Deliberately a corpus built here rather than a fixture in another
# repository: markdoc-lint/examples holds a markdoc-lint.toml and no
# documents, so a run over it indexes zero files and would pass with
# every rule removed. Two files and a known fault cost four lines and
# exercise the config load, the index, the registry, the document
# pass, the JSON envelope and the exit code.
- name: Find a fault in a corpus, and say so in JSON
run: |
set -eu
mkdir -p /tmp/corpus
: > /tmp/corpus/markdoc-lint.toml
printf '# Fine\n\nA paragraph.\n' > /tmp/corpus/ok.md
printf '# Not fine\n\n{%% callout %%}\nbody\n' > /tmp/corpus/bad.md
set +e
./tw/target/release/tw check --no-prose --json --root /tmp/corpus > /tmp/report.json
code=$?
set -e
cat /tmp/report.json
# Exit 1 is "found things", and it is what a hook and a CI step
# both read. A green run on a corpus with a broken tag in it is
# the failure this step exists to catch.
[ "$code" = 1 ] || { echo "::error::tw check exited ${code} on a corpus with an unclosed tag" >&2; exit 1; }
grep -q '"rule": "unclosed-tag"' /tmp/report.json || {
echo "::error::tw check did not report the unclosed tag" >&2; exit 1; }
# The envelope is the contract [[check.external]] rests on: an
# object with a diagnostics array. Anything else and it has moved.
grep -q '"diagnostics"' /tmp/report.json || {
echo "::error::tw check --json printed no diagnostics key" >&2; exit 1; }
echo "tw check finds a fault and reports it as JSON"
# ────────────────────────────────────────────────────────────────────
# tw is a cross-platform CLI and most of the people who run it are on
# Windows. The gate above only proves Linux; this proves the tests pass
# where the path handling, the executable suffix and the self-replace
# rename actually differ.
# ────────────────────────────────────────────────────────────────────
test:
name: test ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
steps:
- uses: actions/checkout@v4
with:
path: tw
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
with:
workspaces: tw
key: test-${{ matrix.os }}
- name: cargo test
working-directory: tw
run: cargo test --all-targets