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.sh behaves 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

  1. Make sure command -v vale prints nothing, that markdownlint-cli2 is on your PATH, and that Docker (or nerdctl) is running.
  2. Add a page with a Vale error, for example doc/development/documentation/lint_probe_error.md with the front matter of a sibling page and the sentence This page describes the behaviour of the documentation linter. (British spelling, gitlab_base.British, level error).
  3. On master, run scripts/lint-doc.sh doc/development/documentation/lint_probe_error.md. It prints Found docker! Using linting image to run vale..., then Vale's usage text, then Linting passed., and exits 0.
  4. On this branch, run the same command. Vale reports gitlab_base.British on line 8, the script prints vale failed with errors! and lint tests failed!, and exits 1. With a copy, lint_probe_clean.md, that says behavior, Vale prints 0 errors, 0 warnings, and 0 suggestions found in 1 file. and the script exits 0.
  5. 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 prints 0 errors, 0 warnings, and 0 suggestions found in 1 file. and the script exits 0.
  6. Run bundle exec rspec spec/scripts/lint_doc_spec.rb: 10 examples, 0 failures. With the spec on master's script, four of the eight container examples fail, because the Vale command ends at --output=doc/.vale/vale.tmpl and 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 docker branch, and with the nerdctl branch through a nerdctl that forwards to the Docker CLI: on master both 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.sh with 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: on master'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 the docker run, leaving ${files} out of the nerdctl run, appending || true to the docker run, leaving $files out of the local run, mounting the checkout at /gitlab again in the nerdctl or the docker run, and starting the docker run in /gitlab;
  • the same spec with the scripts/lint-doc.sh changes of !264133 (merged) applied, which add a rumdl step before Vale: 10 examples, 0 failures;
  • Tooling::FindTests with tests.yml: scripts/lint-doc.sh selects spec/scripts/lint_doc_spec.rb on this branch and no spec on master; yamllint --strict tests.yml: no problems;
  • bundle exec rubocop spec/scripts/lint_doc_spec.rb: no offenses; scripts/lint/commit_linter.rb on 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 $files in 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 failures

MR 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.

Edited by José M. Requena Plens

Merge request reports

Loading
Loading