Pass the files to Vale in the lint-doc.sh container fallback
What does this MR do and why?
When Vale is not installed, scripts/lint-doc.sh runs it from the documentation linting image with nerdctl or docker (lint-doc.sh#L122-127), but gives the container only Vale's options, not the files to lint. With no input, Vale prints its usage and exits 0, so the script reports Linting passed. without having linted any prose. That is the path the documentation testing page offers to anyone without the linters installed ("A working Docker or containerd installation", testing/_index.md#L270-284), and rake lint:markdown runs this script.
The file list became the third argument of run_locally_or_in_container in !133225 (merged), when the script started to accept files on the command line, and only the local branch ($cmd $args $files, L119) was given it. This MR passes it to both container runs too. It also mounts the checkout in the container at its path on the host rather than at /gitlab, and starts the container there (-v "${PWD}:${PWD}" -w "${PWD}"): an absolute path on the host names no file in a container that has the checkout at /gitlab, and Vale lints an argument that names no file as text, so a page given by its absolute path still passed without being linted (found in review, fixed in the second commit). Vale finds .vale.ini from the working directory the container starts in, as it does when run locally, so no other argument is needed, and the exit status of the container run still decides whether the script fails.
CI is not affected: the docs-lint markdown job runs the script inside the linting image (docs.gitlab-ci.yml#L1-21), where Vale is installed, so it takes the local branch.
The new spec runs the script in a temporary checkout with stand-ins for Vale, nerdctl and docker on PATH, the way spec/scripts/slack_spec.rb stands in for curl, and checks that each of the three branches passes the files to Vale and fails when Vale reports errors, and that each container run mounts the checkout at its own path, so that a file given by its absolute path reaches Vale as that file. tests.yml now maps scripts/lint-doc.sh to the spec, so that a change to the script selects it, as scripts/utils.sh selects spec/scripts/ci/otel_span_shell_function_spec.rb.
What changes for someone without Vale installed: a run with no file arguments, such as rake lint:markdown, now lints doc/ and tooling/docs/api/tags/ in the container, as it does with Vale installed, so it takes as long. Not changed here: with MD_DOC_PATH set and no arguments (the MD_DOC_PATH=path/to/my_doc.md rake lint:markdown form on the testing page), markdownlint lints only those files while Vale still gets the default doc/ tooling/docs/api/tags/ (L106-107), with Vale installed or not.
References
- !133225 (merged) is where the file list became a separate argument that only the local branch received.
- I found this while checking how
scripts/lint-doc.shbehaves on a machine without Vale.
Screenshots or screen recordings
Not applicable: a change to a linting script, with no UI.
How to set up and validate locally
- Make sure
command -v valeprints nothing, thatmarkdownlint-cli2is on yourPATH, and that Docker (or nerdctl) is running. - Add a page with a Vale error, for example
doc/development/documentation/lint_probe_error.mdwith the front matter of a sibling page and the sentenceThis page describes the behaviour of the documentation linter.(British spelling,gitlab_base.British, levelerror). - On
master, runscripts/lint-doc.sh doc/development/documentation/lint_probe_error.md. It printsFound docker! Using linting image to run vale..., then Vale's usage text, thenLinting passed., and exits 0. - On this branch, run the same command. Vale reports
gitlab_base.Britishon line 8, the script printsvale failed with errors!andlint tests failed!, and exits 1. With a copy,lint_probe_clean.md, that saysbehavior, Vale prints0 errors, 0 warnings, and 0 suggestions found in 1 file.and the script exits 0. - On this branch, run it with the page's absolute path,
scripts/lint-doc.sh "$PWD/doc/development/documentation/lint_probe_error.md": the same error, and exit 1. With only the first commit of this branch, Vale prints0 errors, 0 warnings, and 0 suggestions found in 1 file.and the script exits 0. - Run
bundle exec rspec spec/scripts/lint_doc_spec.rb: 10 examples, 0 failures. With the spec onmaster's script, four of the eight container examples fail, because the Vale command ends at--output=doc/.vale/vale.tmpland the checkout is mounted at/gitlab.
What I ran, on master at 16f8dd89 with Docker 29.9.1, the image lint-markdown:alpine-3.24-vale-3.21.0-markdownlint2-0.23.2-lychee-0.24.2-rumdl-0.2.69 the script names, markdownlint-cli2 0.23.2 and no Vale on PATH:
- the steps above with the
dockerbranch, and with thenerdctlbranch through anerdctlthat forwards to the Docker CLI: onmasterboth pages pass, the one with the error included; on this branch the page with the error fails and the clean page passes, named by a relative or an absolute path; with only the first commit, the page with the error passed when named by its absolute path, while a stand-in for an installed Vale (the image's Vale, given the host's paths) reported its error both ways; scripts/lint-doc.shwith no arguments on this branch: markdownlint and Vale lint 3258 files,0 errors, 0 warnings, and 0 suggestions found in 3258 files.,Linting passed.;bundle exec rspec spec/scripts/lint_doc_spec.rb: onmaster's script 10 examples, 4 failures (the file and mount examples of both container branches); with only the first commit, 2 failures (the two mount examples); on this branch 10 examples, 0 failures, with three seeds. Each of these changes to the script makes at least one example fail: quoting"${files}"in thedockerrun, leaving${files}out of thenerdctlrun, appending|| trueto thedockerrun, leaving$filesout of the local run, mounting the checkout at/gitlabagain in thenerdctlor thedockerrun, and starting thedockerrun in/gitlab;- the same spec with the
scripts/lint-doc.shchanges of !264133 (merged) applied, which add arumdlstep before Vale: 10 examples, 0 failures; Tooling::FindTestswithtests.yml:scripts/lint-doc.shselectsspec/scripts/lint_doc_spec.rbon this branch and no spec onmaster;yamllint --strict tests.yml: no problems;bundle exec rubocop spec/scripts/lint_doc_spec.rb: no offenses;scripts/lint/commit_linter.rbon both commits: no findings;- ShellCheck 0.9.0 on the script: the only new findings are two SC2086 notes for the unquoted
${files}, which is split into words on purpose, as${args}beside it and$cmd $args $filesin the local branch are; the second commit adds none.
Red and green output (colors removed, RSpec failures abbreviated)
$ command -v vale || echo none
none
$ scripts/lint-doc.sh doc/development/documentation/lint_probe_error.md # master
INFO Looking for Vale to lint prose, either installed locally or available in documentation linting image...
INFO Found docker! Using linting image to run vale...
vale - A command-line linter for prose.
Usage: vale [options] [input...]
vale myfile.md myfile1.md mydir1
vale --output=JSON [input...]
[...]
INFO Linting passed.
exit status: 0
$ scripts/lint-doc.sh doc/development/documentation/lint_probe_error.md # this branch
INFO Found docker! Using linting image to run vale...
doc/development/documentation/lint_probe_error.md:
Line 8, position 25 (rule gitlab_base.British)
error: Use the US spelling 'behavior' instead of the British 'behaviour'.
More information: https://docs.gitlab.com/development/documentation/styleguide/#language
1 errors, 0 warnings, and 0 suggestions found in 1 file.
ERROR vale failed with errors!
INFO Checking for restricted directory names...
ERROR lint tests failed! Review the log carefully to see full listing.
exit status: 1
$ scripts/lint-doc.sh doc/development/documentation/lint_probe_clean.md # this branch
INFO Found docker! Using linting image to run vale...
0 errors, 0 warnings, and 0 suggestions found in 1 file.
INFO Checking for restricted directory names...
INFO Linting passed.
exit status: 0
$ scripts/lint-doc.sh "$PWD/doc/development/documentation/lint_probe_error.md" # first commit only
INFO Found docker! Using linting image to run vale...
0 errors, 0 warnings, and 0 suggestions found in 1 file.
INFO Checking for restricted directory names...
INFO Linting passed.
exit status: 0
$ scripts/lint-doc.sh "$PWD/doc/development/documentation/lint_probe_error.md" # this branch (checkout path shortened)
INFO Found docker! Using linting image to run vale...
/path/to/gitlab/doc/development/documentation/lint_probe_error.md:
Line 8, position 25 (rule gitlab_base.British)
error: Use the US spelling 'behavior' instead of the British 'behaviour'.
More information: https://docs.gitlab.com/development/documentation/styleguide/#language
1 errors, 0 warnings, and 0 suggestions found in 1 file.
ERROR vale failed with errors!
INFO Checking for restricted directory names...
ERROR lint tests failed! Review the log carefully to see full listing.
exit status: 1
$ bundle exec rspec spec/scripts/lint_doc_spec.rb # spec on master's script
1) scripts/lint-doc.sh when Vale is not installed and docker is available behaves like runs Vale on the files it is given passes the files to Vale
expected: ["vale", "--minAlertLevel", "error", "--output=doc/.vale/vale.tmpl", "doc/first.md", "doc/second.md"]
got: ["--rm", "registry.gitlab.com/gitlab-org/technical-writing/docs-gitlab-com/lint-markdown:alpine-3.24-...3.2-lychee-0.24.2-rumdl-0.2.69", "vale", "--minAlertLevel", "error", "--output=doc/.vale/vale.tmpl"]
2) scripts/lint-doc.sh when Vale is not installed and nerdctl is available behaves like runs Vale on the files it is given passes the files to Vale
expected: ["vale", "--minAlertLevel", "error", "--output=doc/.vale/vale.tmpl", "doc/first.md", "doc/second.md"]
got: ["--rm", "registry.gitlab.com/gitlab-org/technical-writing/docs-gitlab-com/lint-markdown:alpine-3.24-...3.2-lychee-0.24.2-rumdl-0.2.69", "vale", "--minAlertLevel", "error", "--output=doc/.vale/vale.tmpl"]
3) and 4) for docker and nerdctl: mounts the checkout at its own path, so an absolute path names the same file in the container
expected [["run", "-t"], ["-t", "-v"], ["-v", "/tmp/d20261023-...:/gitlab"], [...]] to include ["-v", "/tmp/d20261023-...:/tmp/d20261023-..."] and ["-w", "/tmp/d20261023-..."]
10 examples, 4 failures
$ bundle exec rspec spec/scripts/lint_doc_spec.rb # spec on the first commit's script
1) and 2) for docker and nerdctl: mounts the checkout at its own path, so an absolute path names the same file in the container
expected [["run", "-t"], ["-t", "-v"], ["-v", "/tmp/d20261023-...:/gitlab"], [...]] to include ["-v", "/tmp/d20261023-...:/tmp/d20261023-..."] and ["-w", "/tmp/d20261023-..."]
10 examples, 2 failures
$ bundle exec rspec spec/scripts/lint_doc_spec.rb # this branch
10 examples, 0 failures
$ bundle exec rspec spec/scripts/lint_doc_spec.rb # this branch, with the lint-doc.sh changes of !264133
10 examples, 0 failuresMR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.