Accept a Contribute header in readme-check
What does this MR do and why?
GitLab's documentation for component projects says to "Add a ## Contribute section if contributions are welcome" (Write a clear README.md), but check_readme fails any README without a header starting with ## Contributing. A README written to the documentation fails the check.
This MR makes the check accept either name in its first three commits, and in the fourth fixes the check failing on large READMEs that have both headers (#19 (closed)):
- Accept a Contribute header in readme-check.
check_headertakes several names and passes when a##header starts with any of them, and the job asks forContributeorContributing. A README that passed before still passes. A README with neither now getsError: Missing 'Contribute' or 'Contributing' header in file contents. The commit carriesChangelog: Fixed, so the release notes thatgenerate_release_notesbuilds from the changelog API list it. - Describe the headers readme-check asks for. The Readme check section of the README called the
Contributingheader optional, but the check has required it since 33f2a8d3 (January 2024). The section now names the two required headers, with both names the contribution header can take, and links the documentation. - Use the Contribute header in the README. This renames the project's own
## Contributingheader to## Contribute. The project's pipeline runscheck_readmeon its own README throughall-jobs, so the branch pipeline that pushing this branch starts in my fork checks the new name on GitLab itself. The merge request pipeline runs onlygenerate_release_notes, the one job with a rule for merge request events: jobs withoutrules,check_readmeamong them, are left out of merge request pipelines. The section's anchor changes from#contributingto#contribute; nothing in the repository links to it. If you would rather keep the old heading here, I'll drop this commit. - Let grep read the README in readme-check.
check_headerpiped the whole README intogrep -q, which exits at the first match. If the writer still has part of the file to write at that point, it is killed bySIGPIPE, and because GitLab Runner turns onpipefailin BusyBoxsh, the check reports a header the README has as missing. With the default 64 KiB pipes, a README of more than 69,632 bytes with the headers near the top fails every time.grepnow readsREADME.mditself, and thefile_contents=$(cat ./README.md)step, which only fed the pipe, is gone. This commit also carriesChangelog: Fixed. I added it here rather than in a merge request of its own because it changes the lines the first commit rewrites.
Two things I left as they are, for you to decide:
- The contribution header stays required, as 33f2a8d3 made it, although the documentation says to add it "if contributions are welcome". Making it optional again would change what the check enforces, so I did not do it here.
- The same documentation suggests a
## Componentssection, while the check requires## Usage. This MR does not touch that.
References
Closes #6 (closed)
Closes #19 (closed)
How to validate
I ran the check_readme script, as each revision's template has it, against a set of README files, on main and on each of the four commits. The large READMEs have their headers in the first 60 bytes and filler after them.
| README | main |
Commits 1 to 3 | Commit 4 |
|---|---|---|---|
## Usage and ## Contributing |
passes | passes | passes |
## Usage and ## Contribute |
fails: Missing 'Contributing' header |
passes | passes |
## Usage and ## Contribute to this project |
fails: Missing 'Contributing' header |
passes | passes |
## Usage and ## Contributors |
fails | fails: Missing 'Contribute' or 'Contributing' header |
fails: same |
## Usage and ### Contribute (level 3) |
fails | fails: Missing 'Contribute' or 'Contributing' header |
fails: same |
## Usage only |
fails | fails: Missing 'Contribute' or 'Contributing' header |
fails: same |
## Components and ## Contribute, no ## Usage |
fails: Missing 'Usage' header |
fails: Missing 'Usage' header |
fails: same |
no README.md |
fails: Please add a README.md file for your component |
fails: same | fails: same |
this project's README.md at that revision |
passes | passes | passes |
## Usage and ## Contributing, 1,000 bytes |
passes | passes | passes |
## Usage and ## Contributing, 69,633 bytes |
fails: Missing 'Usage' header |
fails: Missing 'Usage' header |
passes |
## Usage and ## Contributing, 177,037 bytes |
fails: Missing 'Usage' header |
fails: Missing 'Usage' header |
passes |
## Usage and ## Contribute, 177,035 bytes |
fails: Missing 'Usage' header |
fails: Missing 'Usage' header |
passes |
## Usage and ## Credits, 177,032 bytes |
fails: Missing 'Usage' header |
fails: Missing 'Usage' header |
fails: Missing 'Contribute' or 'Contributing' header |
## Use and ## Contributing, 177,035 bytes |
fails: Missing 'Usage' header |
fails: Missing 'Usage' header |
fails: Missing 'Usage' header |
The template on main fails the README of the third commit with Missing 'Contributing' header, which is why that commit comes after the fix. On main and on the first three commits every large README fails on its ## Usage header, whatever it contains, which is #19 (closed); on the fourth commit each one passes or fails on the header it has or lacks.
How I ran it
For each revision, I read the check_readme job out of templates/readme-check.yml with Ruby's YAML parser (the second YAML document, as GitLab reads the component) and ran it the way GitLab Runner runs a job script on the Docker executor: the runner's shell detection script as the container command, and the job's script on standard input, each command preceded by the $ ... line the runner prints and wrapped in the lines the runner writes before and after it (pipefail when the shell has it, errexit, noclobber off, the script evaluated in a subshell with standard input from /dev/null). It ran in the busybox image the job names, at the digest busybox:latest points to (busybox@sha256:fd7dc98638c8e305f4dc34e979f1c0fdfdcaeb0fbf8fcff77ae834b6da3d7e6e, the same on 2026-10-11 and 2026-10-13), with no network, in a directory holding the README under test. Each README ran three times on each revision and ten times on the third and fourth commits, and every run with a README ended with the same exit status and the same message. Without one, every run failed, but the error ls writes to standard error sometimes came after the message. The exit status and the last line of output are what the table shows.
I did not run the pipeline on a GitLab instance myself. Pushing this branch starts a branch pipeline in my fork that runs check_readme from this branch on the project's own README, which passed on the third commit; the merge request pipeline does not run it.