mirror of
https://github.com/coder/coder.git
synced 2026-09-01 14:53:15 +08:00
feat: wire Vale prose linter into docs CI (#25467)
Wires Vale into docs CI as an advisory (non-blocking) prose-lint step. Closes [DOCS-40](https://linear.app/codercom/issue/DOCS-40). > **Integration update (rebased onto `main`).** Since this branch was opened, `main` consolidated docs linting into the **required** `lint-docs` job in `ci.yaml` and removed the standalone `docs-ci.yaml` ([#25608](https://github.com/coder/coder/pull/25608)). This PR adds Vale to that `lint-docs` job instead of resurrecting `docs-ci.yaml`, and the `docs/.style/` scaffold defers to the merged [#25466](https://github.com/coder/coder/pull/25466) (DOCS-180). Vale stays advisory. > **Post-review refactor.** Following the Coder Agents review, Vale is now invoked through `mise exec "aqua:errata-ai/vale"` (the same pattern as `actionlint`/`zizmor`) instead of a bespoke `curl`/`tar` download. This removed the GNU-only `grep -oP` version extraction and `uname`/arch mapping that broke on macOS BSD grep, and the prose step now skips paths a PR deletes. See the resolved review threads for CRF-17/19/20/21/22. A sample of what this check does is as follows: <img width="1443" height="1293" alt="image" src="https://github.com/user-attachments/assets/cf68dbf9-d9df-49ba-8dbf-200875bc289e" /> ## What changes - `.vale.ini` at the repo root: Google base + Coder (custom, empty in v1) + curated write-good. `alex` rules are pulled in a la carte. Inline comments justify every enable/disable. - `mise.toml`: pin Vale `3.7.1` via aqua. `mise.lock`: lock that pin across all platforms so `mise install --locked` (used by `build_image`) resolves it. - `Makefile`: a `docs/.style/.vale-synced` sentinel that gates `vale sync`, and a `lint/prose` target that runs `vale --no-exit`. Both invoke Vale via `mise exec "aqua:errata-ai/vale" -- vale ...`, so mise owns the version and the OS/arch download (no hand-rolled install path). - `.github/workflows/ci.yaml`: append Vale steps to the existing required `lint-docs` job: `Detect changed Markdown`, `Restore Vale styles`, `Prepare Vale styles` (`make docs/.style/.vale-synced`), `Vale prose lint`, and a default-branch-only `Save Vale styles`. They lint only changed Markdown under `docs/` that still exists on disk, with a problem matcher for inline PR annotations. - `.github/vale-problem-matcher.json`: parses `vale --output=line` so alerts surface as annotations on the Files Changed tab. - `.gitignore` and the workflow cache `path:`: use `docs/.style/styles/*` plus a `!docs/.style/styles/Coder` negation so adding a package does not require parallel edits. - `.markdownlint-cli2.jsonc`: ignore the synced styles so `make lint/markdown` does not lint upstream READMEs. Scaffold prose under `docs/.style/` and `.claude/docs/DOCS_STYLE_GUIDE.md` / `AGENTS.md` come from the merged DOCS-180; this PR no longer touches them. Net diff against `main` is the 8 Vale-wiring files only. ## Severity policy (v1) Rule severity reflects two things together: the rule's false-positive rate against real Coder docs and the gravity of the rule. Low FPs plus high gravity argues for `error`; lower gravity or more judgment calls argue for `warning` or `suggestion`. v1 lands most rules at `warning` and the wordiness rules at `suggestion`. A rule promotes to `error` only when (a) its false-positive rate against real content is effectively zero and (b) the existing-content violation count for that rule is also zero. Vale exits non-zero only on error-level alerts regardless of `MinAlertLevel`; the Makefile and CI invoke Vale with `--no-exit` so the baseline error count from un-overridden Google rules does not fail the build while real failures (bad config, missing files) still propagate. ## CI integration Vale runs as steps appended to the required `lint-docs` job in `ci.yaml`, gated on changed Markdown: 1. **`Detect changed Markdown`** (`tj-actions/changed-files`) scopes to changed `**.md`; the prose step re-filters to `docs/` (the `docs/**.md` glob silently skips dot-prefixed dirs and would miss `docs/.style/style-guide.md`). 2. **`Restore Vale styles`** (`actions/cache/restore`), keyed off `hashFiles('.vale.ini', 'mise.toml', 'docs/.style/styles/Coder/**')`. mise manages the Vale binary, so only the synced styles are cached. 3. **`Prepare Vale styles`** runs `make docs/.style/.vale-synced` (`mise exec ... vale sync`). 4. **`Vale prose lint`** filters the changed set to `docs/` paths still present on disk, then runs `mise exec ... vale --no-exit --output=line`, emitting inline annotations via the problem matcher. 5. **`Save Vale styles`** writes the cache, gated to `refs/heads/main` only so PR runs cannot poison the cache other branches restore from (the zizmor `cache-poisoning` concern). **Every Vale step is `continue-on-error: true`.** This is a deliberate change from the original standalone-workflow design: now that Vale lives inside the *required* `lint-docs` job, a transient `vale sync` network failure (or first-use `mise` install blip) would otherwise block merges. `continue-on-error` keeps Vale advisory, so only the markdownlint / table-formatter checks above (`pnpm check-docs`) remain merge-blocking. `vale --no-exit` additionally keeps the baseline error count from un-overridden Google rules from failing the step. ## Verification - `actionlint` clean on `ci.yaml` (local + `make lint/actions/actionlint`); `zizmor --persona regular` reports no findings. - `make lint/prose` on the full `docs/` corpus: ~406 errors, ~5,346 warnings, ~7,928 suggestions across 461 files, exit 0 (`--no-exit`), Vale `3.7.1` installed by mise. - Net diff vs `main` is the 8 Vale-wiring files only; the `docs/.style/` scaffold already matches `main`. <details> <summary>Implementation plan and decision log</summary> ### Why this rule set The Vale evaluation against the full docs corpus (measured 2026-05-18) produced ~43,940 raw violations across six candidate base styles. The selection here drops Microsoft and RedHat (overlap with Google, and RedHat's Spacing rule hammers technical IDs), and proselint (Annotations rule treats `> [!NOTE]` admonitions as TODO markers). Within the kept styles: - **Google** is the base. Disables: `EmDash` (conflicts with `make lint/emdash`), `Latin` (i.e./e.g. are fine for our audience), `Spacing` (4,500 errors on `codersdk.SomeType` patterns in the auto-generated API reference). Softened: `Parens` to `suggestion`, `WordList` to `warning`. - **write-good** is the base, with `Passive` and `E-Prime` off. `TooWordy` and `ThereIs` are suggestions; `Weasel` is a warning. - **alex** is cherry-picked (not in `BasedOnStyles`): `Ablist`, `Condescending`, `LGBTQ`, `ProfanityLikely`, `Race`, `Suicide` at warning. The `ProfanityMaybe`/`ProfanityUnlikely` rules trip on `execute`, `kill`, `failed`, and `attack`, which read as technical vocabulary in our context. - **Coder** is in `BasedOnStyles` but the directory is empty in v1. Rules land through the per-rule tickets in the [Docs style guide](https://linear.app/codercom/project/docs-style-guide-7828445b9afc) project. ### Why `mise exec` instead of a download block Vale is pinned in `mise.toml` like `actionlint` and `zizmor`, so invoking it via `mise exec "aqua:errata-ai/vale" -- vale ...` makes the pin the single source of truth and lets mise handle the OS/arch-specific download. This replaced an earlier ~30-line `curl`/`tar` block whose GNU-only `grep -oP ...\K` version extraction returned empty on macOS BSD grep. Note: the bare `vale` short name in `mise exec` ignores the pin and resolves to the latest release, so the full aqua key is required. ### Why `vale sync` instead of vendoring The three style packages weigh ~272 KB combined, so vendoring is cheap. But Vale's ecosystem treats `Packages = ` + `vale sync` as canonical, the upstream LICENSE files are not in the package tarballs (would need to be added manually), and the CI cache makes the sync nearly free after the first run. Sticking with the canonical pattern keeps the repo lean and the upgrade path obvious. ### Why `lint/prose` is not in `lint:` or `lint-light:` Vale on the full docs corpus takes ~20s on cold caches. Forcing every pre-commit through that would be aggressive for a feature that ships as warnings. `make lint/typos` follows the same pattern (it is in `lint-light` but not `lint`; CI invokes it directly). v1 keeps Vale opt-in locally and CI-only by default; promote to `lint:` once the rule set stabilizes. ### Exit-code handling Two mechanisms combine, and the choice changed when the step moved into the required `lint-docs` job: - `vale --no-exit` suppresses Vale's non-zero exit on alerts, so the baseline error-level violations from un-overridden Google rules do not fail the step while the cleanup PRs land. Real failures (config invalid, file missing) still exit non-zero. - `continue-on-error: true` on every Vale step. Because the steps now run inside the *required* `lint-docs` job, a `vale sync` download/network blip must not block merges. The original (standalone, non-required) design rejected `continue-on-error` for showing a misleading yellow badge; in a required job that tradeoff flips, and advisory-yellow is strictly preferable to merge-blocking-red on an infrastructure flake. `|| true` in the Makefile was also rejected: it swallows missing-config failures indiscriminately. ### Pre-mortem - **Generated docs noise**: `docs/reference/` is dominated by auto-generated content (clidocgen, apidocgen, auditdocgen, metricsdocgen). The architectural decision is to fix the generators, not exclude paths in Vale. Google.Spacing is the only rule silenced specifically to defer the generator fix; everything else surfaces as warnings. - **First-run cost**: `mise` installs the pinned Vale (a single small binary) and `vale sync` pulls the style packages on a cold run. The Actions cache keyed off `hashFiles('.vale.ini', 'mise.toml', 'docs/.style/styles/Coder/**')` makes subsequent runs near-instant; the `Coder/**` hash is defense-in-depth against [actions/toolkit#713](https://github.com/actions/toolkit/issues/713) so a future cache release that regresses path-negation cannot serve a stale `Coder/` from cache. - **Required-job blast radius**: moving Vale into the required `lint-docs` job means any Vale step failure would gate merges. Mitigated by `continue-on-error` on all Vale steps plus a clean skip when no changed `docs/` Markdown remains on disk, so only `pnpm check-docs` stays blocking. - **Cross-platform install**: handled by mise (aqua backend) rather than a hand-rolled `uname`/arch map, which removes the macOS BSD-grep break the review flagged. - **Deleted files**: `all_changed_files` is ACMRD and lists paths a PR removes; the prose step filters to files still present on disk so Vale does not error on a missing file. - **Local-vs-CI parity**: CI lints changed files only; local `make lint/prose` lints the full tree. This mirrors `make lint/markdown` (full tree) vs the changed-files CI step. Acceptable for v1. </details> --- *Filed via [Coder Agents](https://coder.com/docs/ai-coder/agents) on Nick's behalf.*
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"problemMatcher": [
|
||||
{
|
||||
"owner": "vale",
|
||||
"severity": "warning",
|
||||
"pattern": [
|
||||
{
|
||||
"regexp": "^(.+):(\\d+):(\\d+):([^:]+):(.+)$",
|
||||
"file": 1,
|
||||
"line": 2,
|
||||
"column": 3,
|
||||
"code": 4,
|
||||
"message": 5
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -162,6 +162,96 @@ jobs:
|
||||
- name: Check docs
|
||||
run: pnpm check-docs
|
||||
|
||||
# Vale prose linter, advisory only. Scoped to changed Markdown under
|
||||
# docs/. Every Vale step is `continue-on-error` so this section can
|
||||
# never block the required `lint-docs` job: a `vale sync` network
|
||||
# blip or a baseline rule violation surfaces as an annotation, not a
|
||||
# merge gate. Only markdownlint/table-formatter above stay blocking.
|
||||
# `vale --no-exit` additionally keeps the baseline error count from
|
||||
# un-overridden upstream Google rules from failing the step. Lives
|
||||
# here rather than a standalone workflow so docs lint stays in the
|
||||
# single required CI umbrella (see #25608). See DOCS-40.
|
||||
- name: Detect changed Markdown
|
||||
id: changed-md
|
||||
continue-on-error: true
|
||||
uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v45.0.7
|
||||
with:
|
||||
files: |
|
||||
**.md
|
||||
separator: ","
|
||||
|
||||
# `**.md` (not `docs/**.md`) because the action's globber collapses a
|
||||
# `**` adjacent to `.md` to a single path segment, so `docs/**.md`
|
||||
# only matches top-level docs/*.md and misses nested pages such as
|
||||
# docs/.style/style-guide.md. The prose step below re-filters to
|
||||
# docs/ paths.
|
||||
# Cache split into restore + conditional save to avoid letting PR
|
||||
# runs populate a cache that other branches restore from (the
|
||||
# zizmor `cache-poisoning` concern). Only pushes to the default
|
||||
# branch may write the cache; PRs may only read it.
|
||||
- name: Restore Vale styles
|
||||
id: vale-cache
|
||||
if: steps.changed-md.outputs.any_changed == 'true'
|
||||
continue-on-error: true
|
||||
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||
with:
|
||||
# Negation excludes the hand-authored Coder rules from the cache;
|
||||
# the key also hashes them so a rule change always invalidates it.
|
||||
# mise manages the Vale binary, so only the synced styles cache.
|
||||
path: |
|
||||
docs/.style/styles/*
|
||||
!docs/.style/styles/Coder
|
||||
docs/.style/.vale-synced
|
||||
key: vale-${{ hashFiles('.vale.ini', 'mise.toml', 'docs/.style/styles/Coder/**') }}
|
||||
restore-keys: |
|
||||
vale-
|
||||
|
||||
- name: Prepare Vale styles
|
||||
if: steps.changed-md.outputs.any_changed == 'true'
|
||||
continue-on-error: true
|
||||
env:
|
||||
# Non-interactive: let mise auto-install the pinned Vale on first use.
|
||||
MISE_YES: "1"
|
||||
run: make docs/.style/.vale-synced
|
||||
|
||||
- name: Vale prose lint
|
||||
if: steps.changed-md.outputs.any_changed == 'true'
|
||||
continue-on-error: true
|
||||
env:
|
||||
ALL_CHANGED_FILES: ${{ steps.changed-md.outputs.all_changed_files }}
|
||||
# Non-interactive: let mise auto-install the pinned Vale on first use.
|
||||
MISE_YES: "1"
|
||||
run: |
|
||||
# all_changed_files is ACMRD and so lists paths this PR deleted.
|
||||
# Vale errors on a missing file (--no-exit only suppresses alert
|
||||
# exits, not runtime errors), so keep only docs/ paths still on
|
||||
# disk. See DOCS-40.
|
||||
files=$(printf '%s\n' "$ALL_CHANGED_FILES" \
|
||||
| tr ',' '\n' \
|
||||
| grep -E '^docs/' \
|
||||
| while IFS= read -r f; do [ -f "$f" ] && printf '%s\n' "$f"; done || true)
|
||||
if [ -z "$files" ]; then
|
||||
echo "No changed Markdown files under docs/ on disk; skipping Vale."
|
||||
exit 0
|
||||
fi
|
||||
echo "::add-matcher::.github/vale-problem-matcher.json"
|
||||
printf '%s\n' "$files" | xargs -d '\n' mise exec "aqua:errata-ai/vale" -- vale --no-exit --output=line
|
||||
echo "::remove-matcher owner=vale::"
|
||||
|
||||
- name: Save Vale styles
|
||||
# Only the default branch is trusted to write the cache, so PR
|
||||
# runs cannot poison the cache that subsequent runs restore from.
|
||||
# Skip when the cache already had an exact key hit (no new content).
|
||||
if: github.ref == 'refs/heads/main' && steps.changed-md.outputs.any_changed == 'true' && steps.vale-cache.outputs.cache-hit != 'true'
|
||||
continue-on-error: true
|
||||
uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||
with:
|
||||
path: |
|
||||
docs/.style/styles/*
|
||||
!docs/.style/styles/Coder
|
||||
docs/.style/.vale-synced
|
||||
key: ${{ steps.vale-cache.outputs.cache-primary-key }}
|
||||
|
||||
# Disabled due to instability. See: https://github.com/coder/coder/issues/14553
|
||||
# Re-enable once the flake hash calculation is stable.
|
||||
# update-flake:
|
||||
|
||||
@@ -13,6 +13,14 @@ node_modules/
|
||||
vendor/
|
||||
yarn-error.log
|
||||
|
||||
# Vale (prose linter) pulls package contents into docs/.style/styles/ on
|
||||
# `vale sync`. Each synced package directory and the sync sentinel are
|
||||
# gitignored. The Coder/ directory next to them is tracked because it
|
||||
# holds our custom rules.
|
||||
docs/.style/.vale-synced
|
||||
docs/.style/styles/*/
|
||||
!docs/.style/styles/Coder/
|
||||
|
||||
# Test output files
|
||||
test-output/
|
||||
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
{
|
||||
"ignores": ["PLAN.md"],
|
||||
"ignores": [
|
||||
"PLAN.md",
|
||||
// Synced Vale packages (pulled by `vale sync`). Keep aligned with the
|
||||
// Packages directive in .vale.ini so markdownlint never lints upstream
|
||||
// style files we did not author.
|
||||
"docs/.style/styles/Google/**",
|
||||
"docs/.style/styles/alex/**",
|
||||
"docs/.style/styles/write-good/**"
|
||||
],
|
||||
}
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
# Vale configuration for Coder documentation.
|
||||
#
|
||||
# Curated cherry-pick of Google's developer-docs style, write-good (wordiness),
|
||||
# and a hand-picked subset of alex (inclusive-language). The choice of base
|
||||
# styles and disabled rules is documented in DOCS-40 and reproducible via
|
||||
# `make lint/prose`.
|
||||
#
|
||||
# Severity policy. Rules sit at a level that reflects two things
|
||||
# together: false-positive rate against real Coder docs and the gravity of
|
||||
# the rule. Low FPs plus high gravity argues for `error`; lower gravity or
|
||||
# more judgment calls argue for `warning` or `suggestion`. v1 lands most
|
||||
# rules at `warning` and the wordiness rules at `suggestion`. Promote a
|
||||
# rule to `error` only when (a) its false-positive rate against real
|
||||
# content is effectively zero and (b) the existing-content violation count
|
||||
# for that rule is also zero.
|
||||
#
|
||||
# About Vale's exit code: Vale exits non-zero only when error-level alerts
|
||||
# are found, regardless of `MinAlertLevel`. The Makefile invokes Vale with
|
||||
# `--no-exit` to suppress that exit while the un-overridden Google
|
||||
# error-level rules still produce a baseline error count. Real failures
|
||||
# (bad config, missing files) still propagate. See
|
||||
# DOCS-40 for the rollout plan.
|
||||
#
|
||||
# The styles themselves live under docs/.style/styles/ after `vale sync`,
|
||||
# which the Makefile target invokes once per .vale.ini change. They are
|
||||
# gitignored to keep the repo lean.
|
||||
|
||||
StylesPath = docs/.style/styles
|
||||
MinAlertLevel = suggestion
|
||||
|
||||
# Packages drives `vale sync`. Pin upstream tags here when reproducibility
|
||||
# matters more than getting upstream fixes; the unpinned form pulls the
|
||||
# latest release of each package on `vale sync`.
|
||||
Packages = Google, alex, write-good
|
||||
|
||||
[*.md]
|
||||
BasedOnStyles = Google, write-good, Coder
|
||||
|
||||
# --- Google curation -------------------------------------------------------
|
||||
# Google.EmDash conflicts with our em-dash ban (see scripts/check_emdash.sh
|
||||
# and DOCS-44). The repo-level ban covers Unicode U+2014/U+2013 plus the
|
||||
# ` -- ` ASCII fallback; Google.EmDash would double-flag and use prose
|
||||
# different from our policy.
|
||||
Google.EmDash = NO
|
||||
|
||||
# Google.Latin flags i.e. and e.g. for non-native readers. Coder docs assume
|
||||
# a technical audience that reads these fluently; leaving the rule on
|
||||
# produces noise without value.
|
||||
Google.Latin = NO
|
||||
|
||||
# Soften two high-volume Google rules. The signal-to-noise ratio is low
|
||||
# at the default warning level.
|
||||
Google.Parens = suggestion
|
||||
Google.WordList = warning
|
||||
|
||||
# Google.Spacing flags fully-qualified Go type names like
|
||||
# `codersdk.WorkspaceAgent` as "should have one space." It produces ~4,500
|
||||
# errors against `docs/reference/api/schemas.md` alone (measured
|
||||
# 2026-05-18) because codersdk type names match the pattern. The
|
||||
# architectural decision for generated content is to fix the upstream
|
||||
# Go generators (clidocgen, apidocgen, auditdocgen, metricsdocgen)
|
||||
# rather than add Vale path exclusions; this disable buys time until
|
||||
# those generator changes land. Re-enable then, ideally promoted to
|
||||
# `error`.
|
||||
Google.Spacing = NO
|
||||
|
||||
# --- write-good curation ---------------------------------------------------
|
||||
# Passive voice is contextually correct often enough that flagging every
|
||||
# instance teaches nothing. E-Prime forbids forms of "to be" entirely,
|
||||
# which is incompatible with normal technical writing.
|
||||
write-good.Passive = NO
|
||||
write-good.E-Prime = NO
|
||||
|
||||
# Keep the three rules that catch real wordiness problems. Wordiness and
|
||||
# ThereIs are judgment calls (suggestion); Weasel is sharper (warning).
|
||||
write-good.TooWordy = suggestion
|
||||
write-good.Weasel = warning
|
||||
write-good.ThereIs = suggestion
|
||||
|
||||
# --- alex curation ---------------------------------------------------------
|
||||
# alex is loaded a la carte rather than via BasedOnStyles. ProfanityMaybe
|
||||
# and ProfanityUnlikely fire on technical terms like `execute`, `kill`,
|
||||
# `failed`, and `attack`; ProfanityLikely is much more conservative and
|
||||
# safe to keep on.
|
||||
alex.Ablist = warning
|
||||
alex.Condescending = warning
|
||||
alex.LGBTQ = warning
|
||||
alex.ProfanityLikely = warning
|
||||
alex.Race = warning
|
||||
alex.Suicide = warning
|
||||
@@ -825,6 +825,35 @@ lint/typos:
|
||||
typos --config .github/workflows/typos.toml
|
||||
.PHONY: lint/typos
|
||||
|
||||
# Vale (prose linter).
|
||||
#
|
||||
# Invoked through `mise exec` like actionlint and zizmor above, so the
|
||||
# version pinned in mise.toml ("aqua:errata-ai/vale") is the single source
|
||||
# of truth and mise downloads the right OS/arch build. Always pass the full
|
||||
# aqua key: the bare `vale` short name ignores the pin and resolves to the
|
||||
# latest release.
|
||||
|
||||
# `vale sync` pulls the packages listed in .vale.ini's Packages directive
|
||||
# into StylesPath (docs/.style/styles/). The .vale-synced sentinel makes
|
||||
# sync idempotent across `make lint/prose` calls and lets warm checkouts
|
||||
# skip the re-sync entirely. Make rebuilds this target when `.vale.ini`
|
||||
# changes.
|
||||
docs/.style/.vale-synced: .vale.ini
|
||||
@echo "$(GREEN)==>$(RESET) $(BOLD)vale sync$(RESET)"
|
||||
mise exec "aqua:errata-ai/vale" -- vale sync
|
||||
@touch $@
|
||||
|
||||
# Vale exits non-zero only on error-level alerts. `--no-exit` keeps the
|
||||
# target green while the un-overridden Google error-level rules still
|
||||
# produce a baseline error count; real failures (bad config, missing
|
||||
# files) still propagate. Once the baseline error count reaches zero, drop
|
||||
# `--no-exit` and surface error-level violations as real failures. See
|
||||
# DOCS-40.
|
||||
lint/prose: docs/.style/.vale-synced
|
||||
@echo "$(GREEN)==>$(RESET) $(BOLD)lint/prose$(RESET)"
|
||||
mise exec "aqua:errata-ai/vale" -- vale --no-exit docs/
|
||||
.PHONY: lint/prose
|
||||
|
||||
# pre-commit and pre-push mirror CI checks locally.
|
||||
#
|
||||
# pre-commit runs checks that don't need external services (Docker,
|
||||
|
||||
@@ -18,8 +18,8 @@ elsewhere (blog, changelog, Support KB, etc.).
|
||||
|
||||
See [`style-guide.md`](style-guide.md) for the prose style guide. The
|
||||
`styles/Coder/` directory holds the custom Vale rules that enforce parts
|
||||
of the guide; Vale's `StylesPath` in the repo-root `.vale.ini` (added in
|
||||
a follow-up PR) points at `docs/.style/styles/`.
|
||||
of the guide; Vale's `StylesPath` in the repo-root `.vale.ini` points at
|
||||
`docs/.style/styles/`.
|
||||
|
||||
## Why a hidden directory
|
||||
|
||||
@@ -56,8 +56,9 @@ directory from the surgical-reindex payload on mixed commits.
|
||||
`markdownlint-cli2 --fix $(find docs -name '*.md')`.
|
||||
- `make fmt/markdown` (markdown-table-formatter) reflows tables here for
|
||||
the same reason.
|
||||
- Vale, once `.vale.ini` lands in a follow-up PR, lints the entire
|
||||
`docs/**/*.md` set including `docs/.style/style-guide.md`.
|
||||
- Vale lints the entire `docs/**/*.md` set, including
|
||||
`docs/.style/style-guide.md`. See the repo-root `.vale.ini` for the
|
||||
active configuration; run `make lint/prose` locally to reproduce.
|
||||
|
||||
## What does not run against this directory
|
||||
|
||||
|
||||
@@ -76,7 +76,8 @@ The repo-root `.vale.ini` configures Vale to read styles from
|
||||
- Coder-specific custom rules in `docs/.style/styles/Coder/`
|
||||
|
||||
The rationale for the cherry-picked base styles and the severity
|
||||
policy lives in the follow-up PR that lands `.vale.ini`.
|
||||
policy lives in `.vale.ini`'s inline comments. Run `make lint/prose`
|
||||
to reproduce the baseline locally.
|
||||
|
||||
## Editor setup
|
||||
|
||||
|
||||
@@ -32,8 +32,17 @@ following third-party references:
|
||||
|
||||
## Tools
|
||||
|
||||
The following are tools that you can use to edit your writing. However, take the
|
||||
suggestions provided with a grain of salt.
|
||||
This repository runs [Vale](https://vale.sh/) on `docs/` as part of CI to
|
||||
enforce prose style. The configuration is the repo-root `.vale.ini`, and
|
||||
the curated rule set is documented in
|
||||
[`docs/.style/style-guide.md`](../../.style/style-guide.md). Run the same
|
||||
checks locally with `make lint/prose`. Vale runs in advisory mode in
|
||||
this iteration: warnings surface as inline PR annotations, but they don't
|
||||
block the build.
|
||||
|
||||
The following external tools can also help when drafting. Take their
|
||||
suggestions with a grain of salt because they aren't tuned for Coder's
|
||||
voice or product names:
|
||||
|
||||
- [alex.js](https://alexjs.com/)
|
||||
- [Grammarly](https://app.grammarly.com/)
|
||||
|
||||
@@ -144,6 +144,54 @@ url = "https://github.com/crate-ci/typos/releases/download/v1.46.1/typos-v1.46.1
|
||||
checksum = "sha256:a7b042fc79bf7b73b00ece054ec3109858e001136c2642f28004544b571d37a2"
|
||||
url = "https://github.com/crate-ci/typos/releases/download/v1.46.1/typos-v1.46.1-x86_64-pc-windows-msvc.zip"
|
||||
|
||||
[[tools."aqua:errata-ai/vale"]]
|
||||
version = "3.7.1"
|
||||
backend = "aqua:errata-ai/vale"
|
||||
|
||||
[tools."aqua:errata-ai/vale"."platforms.linux-arm64"]
|
||||
checksum = "sha256:c485582de0dea90cded2e4b5c560d6129b3b2f160139af2195020a284f8a1670"
|
||||
url = "https://github.com/vale-cli/vale/releases/download/v3.7.1/vale_3.7.1_Linux_arm64.tar.gz"
|
||||
|
||||
[tools."aqua:errata-ai/vale"."platforms.linux-arm64-musl"]
|
||||
checksum = "sha256:c485582de0dea90cded2e4b5c560d6129b3b2f160139af2195020a284f8a1670"
|
||||
url = "https://github.com/vale-cli/vale/releases/download/v3.7.1/vale_3.7.1_Linux_arm64.tar.gz"
|
||||
|
||||
[tools."aqua:errata-ai/vale"."platforms.linux-x64"]
|
||||
checksum = "sha256:ba4924bf2c5884499f09b02a6eb3318b29df40a3e81701c0804b9b1aefcd9483"
|
||||
url = "https://github.com/vale-cli/vale/releases/download/v3.7.1/vale_3.7.1_Linux_64-bit.tar.gz"
|
||||
|
||||
[tools."aqua:errata-ai/vale"."platforms.linux-x64-baseline"]
|
||||
checksum = "sha256:ba4924bf2c5884499f09b02a6eb3318b29df40a3e81701c0804b9b1aefcd9483"
|
||||
url = "https://github.com/vale-cli/vale/releases/download/v3.7.1/vale_3.7.1_Linux_64-bit.tar.gz"
|
||||
|
||||
[tools."aqua:errata-ai/vale"."platforms.linux-x64-musl"]
|
||||
checksum = "sha256:ba4924bf2c5884499f09b02a6eb3318b29df40a3e81701c0804b9b1aefcd9483"
|
||||
url = "https://github.com/vale-cli/vale/releases/download/v3.7.1/vale_3.7.1_Linux_64-bit.tar.gz"
|
||||
|
||||
[tools."aqua:errata-ai/vale"."platforms.linux-x64-musl-baseline"]
|
||||
checksum = "sha256:ba4924bf2c5884499f09b02a6eb3318b29df40a3e81701c0804b9b1aefcd9483"
|
||||
url = "https://github.com/vale-cli/vale/releases/download/v3.7.1/vale_3.7.1_Linux_64-bit.tar.gz"
|
||||
|
||||
[tools."aqua:errata-ai/vale"."platforms.macos-arm64"]
|
||||
checksum = "sha256:88c9e562bc0bb614f11fa2933a430ca087f9e4d949bd3968f49258617765c79f"
|
||||
url = "https://github.com/vale-cli/vale/releases/download/v3.7.1/vale_3.7.1_macOS_arm64.tar.gz"
|
||||
|
||||
[tools."aqua:errata-ai/vale"."platforms.macos-x64"]
|
||||
checksum = "sha256:878775cbebffe93ad2381779e964428f38822dfba32625885d899a0cef429d8b"
|
||||
url = "https://github.com/vale-cli/vale/releases/download/v3.7.1/vale_3.7.1_macOS_64-bit.tar.gz"
|
||||
|
||||
[tools."aqua:errata-ai/vale"."platforms.macos-x64-baseline"]
|
||||
checksum = "sha256:878775cbebffe93ad2381779e964428f38822dfba32625885d899a0cef429d8b"
|
||||
url = "https://github.com/vale-cli/vale/releases/download/v3.7.1/vale_3.7.1_macOS_64-bit.tar.gz"
|
||||
|
||||
[tools."aqua:errata-ai/vale"."platforms.windows-x64"]
|
||||
checksum = "sha256:9f14a2552c9efe65e0ab5ef8e45cf01ce89733b436687d68faef7b147c5cfc71"
|
||||
url = "https://github.com/vale-cli/vale/releases/download/v3.7.1/vale_3.7.1_Windows_64-bit.zip"
|
||||
|
||||
[tools."aqua:errata-ai/vale"."platforms.windows-x64-baseline"]
|
||||
checksum = "sha256:9f14a2552c9efe65e0ab5ef8e45cf01ce89733b436687d68faef7b147c5cfc71"
|
||||
url = "https://github.com/vale-cli/vale/releases/download/v3.7.1/vale_3.7.1_Windows_64-bit.zip"
|
||||
|
||||
[[tools."aqua:jj-vcs/jj"]]
|
||||
version = "0.41.0"
|
||||
backend = "aqua:jj-vcs/jj"
|
||||
|
||||
Reference in New Issue
Block a user