ci: require docs lint when docs change (#25608)

Move docs linting into the required CI umbrella and reuse the existing
`changes` job so docs lint runs when docs or CI files change, plus on
`main` as a backstop.

This is motivated by the docs lint failures on #25601. That PR touched
`.claude/docs/TESTING.md`; the standalone `Docs CI` workflow picked it
up because `docs-ci.yaml` used broad `**.md` matching, but local `pnpm
lint-docs` and `make lint` did not catch the same file because they only
scanned `docs/**` plus root `*.md`. The first failed Docs CI run
reported markdownlint errors in `.claude/docs/TESTING.md` (`MD040` and
`MD031`), and the next run reported a markdown table formatter failure
in the same file.

That mismatch is why this PR exists: prevent unrelated PRs from being
surprised by stale `.claude/docs/**` lint drift only after they happen
to touch one of those files. The local docs scripts now include
`.claude/docs/**`, and the old standalone `Docs CI` workflow is removed
so we do not maintain separate path-filter logic outside the required CI
workflow.

> Generated by mux, but reviewed by a human
This commit is contained in:
Ethan
2026-05-27 12:30:05 +10:00
committed by GitHub
parent 20b50dd4b8
commit e99f7171e4
6 changed files with 115 additions and 160 deletions
+2 -2
View File
@@ -9,7 +9,7 @@ not add new readiness or debug endpoints for these workflows.
`scripts/develop/main.go` defines these base defaults: `scripts/develop/main.go` defines these base defaults:
| Resource | Base default | Override | | Resource | Base default | Override |
|----------|--------------|----------| |--------------------------|--------------|--------------------------------------------------|
| API server | `3000` | `--port`, `CODER_DEV_PORT` | | API server | `3000` | `--port`, `CODER_DEV_PORT` |
| Frontend dev server | `8080` | `--web-port`, `CODER_DEV_WEB_PORT` | | Frontend dev server | `8080` | `--web-port`, `CODER_DEV_WEB_PORT` |
| Workspace proxy | `3010` | `--proxy-port`, `CODER_DEV_PROXY_PORT` | | Workspace proxy | `3010` | `--proxy-port`, `CODER_DEV_PROXY_PORT` |
@@ -38,7 +38,7 @@ The develop script also supports these existing flags and environment
variables: variables:
| Purpose | Flag | Environment variable | | Purpose | Flag | Environment variable |
|---------|------|----------------------| |-----------------------------------|----------------------|------------------------------|
| Per-worktree port offset | `--port-offset` | `CODER_DEV_PORT_OFFSET` | | Per-worktree port offset | `--port-offset` | `CODER_DEV_PORT_OFFSET` |
| Access URL | `--access-url` | `CODER_DEV_ACCESS_URL` | | Access URL | `--access-url` | `CODER_DEV_ACCESS_URL` |
| Admin password | `--password` | `CODER_DEV_ADMIN_PASSWORD` | | Admin password | `--password` | `CODER_DEV_ADMIN_PASSWORD` |
+2 -2
View File
@@ -93,7 +93,7 @@ right column instead. The "Since" column tells you the minimum `go`
directive version required in `go.mod`. directive version required in `go.mod`.
| Old pattern | Modern replacement | Since | | Old pattern | Modern replacement | Since |
|---|---|---| |---------------------------------------------------------------------|-------------------------------------------------------------------------|-----------|
| `interface{}` | `any` | 1.18 | | `interface{}` | `any` | 1.18 |
| `v := v` inside loops | remove it | 1.22 | | `v := v` inside loops | remove it | 1.22 |
| `for i := 0; i < n; i++` | `for i := range n` | 1.22 | | `for i := 0; i < n; i++` | `for i := range n` | 1.22 |
@@ -139,7 +139,7 @@ These enable things that weren't practical before. Reach for them in the
described situations. described situations.
| What | Since | When to use it | | What | Since | When to use it |
|---|---|---| |--------------------------------------------------|-------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `cmp.Or(a, b, c)` | 1.22 | Defaults/fallback chains: returns first non-zero value. Replaces verbose `if a != "" { return a }` cascades. | | `cmp.Or(a, b, c)` | 1.22 | Defaults/fallback chains: returns first non-zero value. Replaces verbose `if a != "" { return a }` cascades. |
| `context.WithoutCancel(ctx)` | 1.21 | Background work that must outlive the request (e.g. async cleanup after HTTP response). Derived context keeps parent's values but ignores cancellation. | | `context.WithoutCancel(ctx)` | 1.21 | Background work that must outlive the request (e.g. async cleanup after HTTP response). Derived context keeps parent's values but ignores cancellation. |
| `context.AfterFunc(ctx, fn)` | 1.21 | Register cleanup that fires on context cancellation without spawning a goroutine that blocks on `<-ctx.Done()`. | | `context.AfterFunc(ctx, fn)` | 1.21 | Register cleanup that fires on context cancellation without spawning a goroutine that blocks on `<-ctx.Done()`. |
+12 -12
View File
@@ -23,48 +23,48 @@
### Testing Issues ### Testing Issues
3. **"package should be X_test"** 1. **"package should be X_test"**
- **Solution**: Use `package_test` naming for test files - **Solution**: Use `package_test` naming for test files
- Example: `identityprovider_test` for black-box testing - Example: `identityprovider_test` for black-box testing
4. **Race conditions in tests** 2. **Race conditions in tests**
- **Solution**: Use unique identifiers instead of hardcoded names - **Solution**: Use unique identifiers instead of hardcoded names
- Example: `fmt.Sprintf("test-client-%s-%d", t.Name(), time.Now().UnixNano())` - Example: `fmt.Sprintf("test-client-%s-%d", t.Name(), time.Now().UnixNano())`
- Never use hardcoded names in concurrent tests - Never use hardcoded names in concurrent tests
5. **Missing newlines** 3. **Missing newlines**
- **Solution**: Ensure files end with newline character - **Solution**: Ensure files end with newline character
- Most editors can be configured to add this automatically - Most editors can be configured to add this automatically
### OAuth2 Issues ### OAuth2 Issues
6. **OAuth2 endpoints returning wrong error format** 1. **OAuth2 endpoints returning wrong error format**
- **Solution**: Ensure OAuth2 endpoints return RFC 6749 compliant errors - **Solution**: Ensure OAuth2 endpoints return RFC 6749 compliant errors
- Use standard error codes: `invalid_client`, `invalid_grant`, `invalid_request` - Use standard error codes: `invalid_client`, `invalid_grant`, `invalid_request`
- Format: `{"error": "code", "error_description": "details"}` - Format: `{"error": "code", "error_description": "details"}`
7. **Resource indicator validation failing** 2. **Resource indicator validation failing**
- **Solution**: Ensure database stores and retrieves resource parameters correctly - **Solution**: Ensure database stores and retrieves resource parameters correctly
- Check both authorization code storage and token exchange handling - Check both authorization code storage and token exchange handling
8. **PKCE tests failing** 3. **PKCE tests failing**
- **Solution**: Verify both authorization code storage and token exchange handle PKCE fields - **Solution**: Verify both authorization code storage and token exchange handle PKCE fields
- Check `CodeChallenge` and `CodeChallengeMethod` field handling - Check `CodeChallenge` and `CodeChallengeMethod` field handling
### RFC Compliance Issues ### RFC Compliance Issues
9. **RFC compliance failures** 1. **RFC compliance failures**
- **Solution**: Verify against actual RFC specifications, not assumptions - **Solution**: Verify against actual RFC specifications, not assumptions
- Use WebFetch tool to get current RFC content for compliance verification - Use WebFetch tool to get current RFC content for compliance verification
- Read the actual RFC specifications before implementation - Read the actual RFC specifications before implementation
10. **Default value mismatches** 2. **Default value mismatches**
- **Solution**: Ensure database migrations match application code defaults - **Solution**: Ensure database migrations match application code defaults
- Example: RFC 7591 specifies `client_secret_basic` as default, not `client_secret_post` - Example: RFC 7591 specifies `client_secret_basic` as default, not `client_secret_post`
### Authorization Issues ### Authorization Issues
11. **Authorization context errors in public endpoints** 1. **Authorization context errors in public endpoints**
- **Solution**: Use `dbauthz.AsSystemRestricted(ctx)` pattern - **Solution**: Use `dbauthz.AsSystemRestricted(ctx)` pattern
- Example: - Example:
@@ -75,17 +75,17 @@
### Authentication Issues ### Authentication Issues
12. **Bearer token authentication issues** 1. **Bearer token authentication issues**
- **Solution**: Check token extraction precedence and format validation - **Solution**: Check token extraction precedence and format validation
- Ensure proper RFC 6750 Bearer Token Support implementation - Ensure proper RFC 6750 Bearer Token Support implementation
13. **URI validation failures** 2. **URI validation failures**
- **Solution**: Support both standard schemes and custom schemes per protocol requirements - **Solution**: Support both standard schemes and custom schemes per protocol requirements
- Native OAuth2 apps may use custom schemes - Native OAuth2 apps may use custom schemes
### General Development Issues ### General Development Issues
14. **Log message formatting errors** 1. **Log message formatting errors**
- **Solution**: Use lowercase, descriptive messages without special characters - **Solution**: Use lowercase, descriptive messages without special characters
- Follow Go logging conventions - Follow Go logging conventions
+26 -1
View File
@@ -53,7 +53,8 @@ jobs:
- "**" - "**"
docs: docs:
- "docs/**" - "docs/**"
- "README.md" - ".claude/docs/**"
- "*.md"
- "examples/web-server/**" - "examples/web-server/**"
- "examples/monitoring/**" - "examples/monitoring/**"
- "examples/lima/**" - "examples/lima/**"
@@ -120,6 +121,28 @@ jobs:
env: env:
FILTER_JSON: ${{ toJSON(steps.filter.outputs) }} FILTER_JSON: ${{ toJSON(steps.filter.outputs) }}
lint-docs:
needs: changes
if: needs.changes.outputs.docs == 'true' || needs.changes.outputs.ci == 'true' || github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- name: Harden Runner
uses: step-security/harden-runner@f808768d1510423e83855289c910610ca9b43176 # v2.17.0
with:
egress-policy: audit
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 1
persist-credentials: false
- name: Setup Node
uses: ./.github/actions/setup-node
- name: Check docs
run: pnpm check-docs
# Disabled due to instability. See: https://github.com/coder/coder/issues/14553 # Disabled due to instability. See: https://github.com/coder/coder/issues/14553
# Re-enable once the flake hash calculation is stable. # Re-enable once the flake hash calculation is stable.
# update-flake: # update-flake:
@@ -1132,6 +1155,7 @@ jobs:
- changes - changes
- fmt - fmt
- lint - lint
- lint-docs
- lint-actions - lint-actions
- gen - gen
- test-go-pg - test-go-pg
@@ -1157,6 +1181,7 @@ jobs:
echo "- changes: ${{ needs.changes.result }}" echo "- changes: ${{ needs.changes.result }}"
echo "- fmt: ${{ needs.fmt.result }}" echo "- fmt: ${{ needs.fmt.result }}"
echo "- lint: ${{ needs.lint.result }}" echo "- lint: ${{ needs.lint.result }}"
echo "- lint-docs: ${{ needs.lint-docs.result }}"
echo "- lint-actions: ${{ needs.lint-actions.result }}" echo "- lint-actions: ${{ needs.lint-actions.result }}"
echo "- gen: ${{ needs.gen.result }}" echo "- gen: ${{ needs.gen.result }}"
echo "- test-go-pg: ${{ needs.test-go-pg.result }}" echo "- test-go-pg: ${{ needs.test-go-pg.result }}"
-71
View File
@@ -1,71 +0,0 @@
name: Docs CI
on:
push:
branches:
- main
# Self-reference removed from both push and pull_request: the `lint`
# and `fmt` steps gate on `tj-actions/changed-files` matching
# `docs/**` or `**.md`, so a workflow-only edit produced an empty
# run. `actionlint` and `make lint/actions` catch YAML problems
# before merge regardless. See DOCS-129.
paths:
- "docs/**"
- "**.md"
pull_request:
# Self-reference removed; see comment under `push:` above.
paths:
- "docs/**"
- "**.md"
permissions:
contents: read
jobs:
docs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Setup Node
uses: ./.github/actions/setup-node
# Per-tool changed-files filters. Each tool gets its own `changed-*`
# step scoped to the files it processes, keeping workflow-level `paths:`
# broad. Adding a tool (e.g. image linter) only needs a new step pair.
- uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v45.0.7
id: changed-md
with:
files: |
**.md
separator: ","
# Both downstream tools take file paths as argv. `tj-actions/changed-files`
# joins paths with `separator: ","`, which the shell does not split on, so
# run the output through `tr ',' '\n' | xargs -d '\n'` to hand each path to
# the tool as a distinct argument. This tolerates filenames containing
# spaces and prevents silent fallbacks: `markdownlint-cli2` would treat a
# comma-joined string as a single non-matching glob, and
# `markdown-table-formatter` would fall back to scanning every `.md` in
# the working tree when invoked with no positional args.
#
# `printf '%s\n'` is used instead of `echo` so a hypothetical leading
# `-e` or `-n` in a path is treated as data, not a bash builtin flag.
- name: lint
if: steps.changed-md.outputs.any_changed == 'true'
run: |
printf '%s\n' "$ALL_CHANGED_FILES" | tr ',' '\n' | xargs -d '\n' pnpm exec markdownlint-cli2
env:
ALL_CHANGED_FILES: ${{ steps.changed-md.outputs.all_changed_files }}
- name: fmt
if: steps.changed-md.outputs.any_changed == 'true'
run: |
printf '%s\n' "$ALL_CHANGED_FILES" | tr ',' '\n' | xargs -d '\n' pnpm exec markdown-table-formatter --check
env:
ALL_CHANGED_FILES: ${{ steps.changed-md.outputs.all_changed_files }}
+3 -2
View File
@@ -4,8 +4,9 @@
"version": "0.0.0", "version": "0.0.0",
"packageManager": "pnpm@10.33.2+sha512.a90faf6feeab71ad6c6e57f94e0fe1a12f5dcc22cd754db40ae9593eb6a3e0b6b12e3540218bb37ae083404b1f2ce6db2a4121e979829b4aff94b99f49da1cf8", "packageManager": "pnpm@10.33.2+sha512.a90faf6feeab71ad6c6e57f94e0fe1a12f5dcc22cd754db40ae9593eb6a3e0b6b12e3540218bb37ae083404b1f2ce6db2a4121e979829b4aff94b99f49da1cf8",
"scripts": { "scripts": {
"format-docs": "markdown-table-formatter $(find docs -name '*.md') *.md", "format-docs": "markdown-table-formatter $(find docs .claude/docs examples/web-server examples/monitoring examples/lima -name '*.md' 2>/dev/null) *.md",
"lint-docs": "markdownlint-cli2 --fix $(find docs -name '*.md') *.md", "lint-docs": "markdownlint-cli2 --fix $(find docs .claude/docs examples/web-server examples/monitoring examples/lima -name '*.md' 2>/dev/null) *.md",
"check-docs": "markdownlint-cli2 $(find docs .claude/docs examples/web-server examples/monitoring examples/lima -name '*.md' 2>/dev/null) *.md && markdown-table-formatter --check $(find docs .claude/docs examples/web-server examples/monitoring examples/lima -name '*.md' 2>/dev/null) *.md",
"storybook": "pnpm run -C site/ storybook" "storybook": "pnpm run -C site/ storybook"
}, },
"devDependencies": { "devDependencies": {