From 68ccdc13a8d57c851924c9c4295fd2fc2d6def35 Mon Sep 17 00:00:00 2001 From: Marc LeBlanc <7050295+marcleblanc2@users.noreply.github.com> Date: Wed, 30 Sep 2026 12:41:54 -0600 Subject: [PATCH 1/5] scripts/helm-docs.sh: POSIX sh, so it runs anywhere a shell and curl exist The script is run by developers, by Buildkite's helm-docs verify step, and (after sourcegraph/sourcegraph#16450) by the release worker, whose wolfi image only has busybox. It required bash for no reason it used: - #!/usr/bin/env bash and set -o pipefail: the script has no pipelines. - mktemp -d -t helm-docs.XXX: not POSIX, and every implementation reads it differently. GNU wants at least three X, busybox wants six (it fails with 'mktemp: : Invalid argument'), and BSD/macOS treats -t as a prefix and does not substitute the X at all. mktemp -d "${TMPDIR:-/tmp}/helm-docs.XXXXXX" behaves the same on all three. - ${0%/*}: fails with 'cd helm-docs.sh' when run as 'sh helm-docs.sh' from inside scripts/. dirname is POSIX and returns '.' in that case. - tar zf FILE -x MEMBER: old-style bunched options. tar -xzf FILE MEMBER is what GNU, BSD, and busybox tar all accept. Also remove the temp dir after extracting, and send the unsupported OS/arch messages to stderr. Verified: dash, macOS /bin/sh (bash 3.2), zsh, and busybox v1.36.1 sh (with PATH limited to busybox applets plus curl) all download once cold, run from cache warm, and work when invoked from inside scripts/. Regenerating the charts leaves git status clean. shellcheck -s sh and checkbashisms are clean. Amp-Thread-ID: https://ampcode.com/threads/T-01a0f388-6a21-7173-93ec-fdd98150d75d Co-authored-by: Amp --- scripts/helm-docs.sh | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/scripts/helm-docs.sh b/scripts/helm-docs.sh index 30cdcd0b..81a4f13e 100755 --- a/scripts/helm-docs.sh +++ b/scripts/helm-docs.sh @@ -1,11 +1,16 @@ -#!/usr/bin/env bash -# Copy from https://github.com/linkerd/linkerd2/blob/main/bin/helm-docs +#!/bin/sh +# Downloads the pinned helm-docs release into target/bin (gitignored) on first +# use, then runs it with any arguments passed to this script. +# +# POSIX sh only (no bash): this runs on developer machines, in Buildkite, and +# in the release worker's busybox-based image. Adapted from +# https://github.com/linkerd/linkerd2/blob/main/bin/helm-docs -set -euf -o pipefail +set -euf helmdocsv=1.14.2 -bindir=$( cd "${0%/*}" && pwd ) # Change to script dir and set bin dir to this -targetbin=$( cd "$bindir"/.. && pwd )/target/bin +bindir=$(cd "$(dirname "$0")" && pwd) +targetbin=$(cd "$bindir/.." && pwd)/target/bin helmdocsbin=$targetbin/helm-docs-$helmdocsv if [ ! -f "$helmdocsbin" ]; then @@ -15,25 +20,28 @@ if [ ! -f "$helmdocsbin" ]; then Darwin) os=Darwin ;; Linux) os=Linux ;; MSYS*|MINGW*|CYGWIN*) os=Windows ;; - *) echo "Unsupported OS: $(uname -s)"; exit 126 ;; + *) echo "Unsupported OS: $(uname -s)" >&2; exit 126 ;; esac case $(uname -m) in x86_64|amd64) arch=x86_64 ;; aarch64|arm64) arch=arm64 ;; armv7l) arch=arm7 ;; armv6l) arch=arm6 ;; - *) echo "Unsupported architecture: $(uname -m)"; exit 126 ;; + *) echo "Unsupported architecture: $(uname -m)" >&2; exit 126 ;; esac helmdocscurl="https://github.com/norwoodj/helm-docs/releases/download/v$helmdocsv/helm-docs_${helmdocsv}_${os}_${arch}.tar.gz" - tmp=$(mktemp -d -t helm-docs.XXX) + + # An explicit template works the same in GNU, BSD/macOS, and busybox mktemp. + tmp=$(mktemp -d "${TMPDIR:-/tmp}/helm-docs.XXXXXX") mkdir -p "$targetbin" ( cd "$tmp" - curl --proto '=https' --tlsv1.2 -sSfL -o "./helm-docs.tar.gz" "$helmdocscurl" - tar zf "./helm-docs.tar.gz" -x "helm-docs" - chmod +x "helm-docs" + curl --proto '=https' --tlsv1.2 -sSfL -o helm-docs.tar.gz "$helmdocscurl" + tar -xzf helm-docs.tar.gz helm-docs + chmod +x helm-docs ) mv "$tmp/helm-docs" "$helmdocsbin" + rm -rf "$tmp" fi -"$helmdocsbin" "$@" \ No newline at end of file +"$helmdocsbin" "$@" From d0ee197644097d85ad43a02cfda15bdde6040f3b Mon Sep 17 00:00:00 2001 From: Marc LeBlanc <7050295+marcleblanc2@users.noreply.github.com> Date: Wed, 30 Sep 2026 14:00:59 -0600 Subject: [PATCH 2/5] scripts/helm-docs.sh: add --check, run from the repo root Buildkite's helm-docs verify step and AGENTS.md each carried their own copy of "regenerate, then fail if the tree changed", both written as bash ([[ -z $(git status -s) ]]). --check moves that into the script: it runs helm-docs, then fails and lists the stale files if any charts/*/README.md differs from the index. It looks only at chart READMEs, so a developer's unrelated uncommitted edits do not fail it. The script now cd's to the repository root first. helm-docs scans the cwd for charts and reads .helmdocsignore from there, so run from anywhere else it found no charts, regenerated nothing, and --check would pass while the READMEs were stale. Verified with dash and macOS /bin/sh: --check passes on a clean tree, fails with exit 1 naming charts/sourcegraph/README.md after a values.yaml change, ignores a dirty values.yaml on its own, and behaves the same from /tmp and from inside scripts/. Arguments still pass through to helm-docs. Amp-Thread-ID: https://ampcode.com/threads/T-01a0f388-6a21-7173-93ec-fdd98150d75d Co-authored-by: Amp --- .buildkite/pipeline.yaml | 5 +---- AGENTS.md | 4 ++-- scripts/helm-docs.sh | 25 +++++++++++++++++++++++-- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/.buildkite/pipeline.yaml b/.buildkite/pipeline.yaml index a72cb237..d4d47773 100644 --- a/.buildkite/pipeline.yaml +++ b/.buildkite/pipeline.yaml @@ -20,10 +20,7 @@ steps: agents: { queue: standard } - label: ":book: Verify helm-docs is up-to-date" - commands: - - "./scripts/helm-docs.sh" - - "echo \"checking for uncommitted changes\"" - - "[[ -z $(git status -s) ]]" + command: "./scripts/helm-docs.sh --check" agents: { queue: standard } - label: "(internal) Release: test" diff --git a/AGENTS.md b/AGENTS.md index 92c9b473..c08bed7a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,10 +2,10 @@ ## After Making Changes -After making changes to any `values.yaml` file, regenerate the helm docs and verify there are no uncommitted changes: +After making changes to any `values.yaml` file, regenerate the helm docs and verify the committed READMEs are current: ```sh -./scripts/helm-docs.sh && [[ -z $(git status -s) ]] +./scripts/helm-docs.sh --check ``` If the README was updated, stage and commit the changes alongside your other modifications. diff --git a/scripts/helm-docs.sh b/scripts/helm-docs.sh index 81a4f13e..cb9f1b75 100755 --- a/scripts/helm-docs.sh +++ b/scripts/helm-docs.sh @@ -2,15 +2,26 @@ # Downloads the pinned helm-docs release into target/bin (gitignored) on first # use, then runs it with any arguments passed to this script. # +# ./scripts/helm-docs.sh regenerate charts/**/README.md +# ./scripts/helm-docs.sh --check regenerate, then fail if any README changed +# # POSIX sh only (no bash): this runs on developer machines, in Buildkite, and # in the release worker's busybox-based image. Adapted from # https://github.com/linkerd/linkerd2/blob/main/bin/helm-docs set -euf +check=false +if [ "${1:-}" = --check ]; then + check=true + shift +fi + helmdocsv=1.14.2 -bindir=$(cd "$(dirname "$0")" && pwd) -targetbin=$(cd "$bindir/.." && pwd)/target/bin +# Run from the repository root regardless of the caller's cwd: helm-docs +# scans the cwd for charts, and it reads .helmdocsignore from there too. +cd "$(dirname "$0")/.." +targetbin=$PWD/target/bin helmdocsbin=$targetbin/helm-docs-$helmdocsv if [ ! -f "$helmdocsbin" ]; then @@ -45,3 +56,13 @@ if [ ! -f "$helmdocsbin" ]; then fi "$helmdocsbin" "$@" + +if [ "$check" = true ]; then + # Only READMEs helm-docs writes, so unrelated local edits don't fail the check. + stale=$(git status --porcelain -- 'charts/*/README.md') + if [ -n "$stale" ]; then + echo "Chart READMEs are out of date. Run ./scripts/helm-docs.sh and commit:" >&2 + echo "$stale" >&2 + exit 1 + fi +fi From 7e8f6054f04595fc3b6d79a7f0c65446a723dde5 Mon Sep 17 00:00:00 2001 From: Marc <7050295+marcleblanc2@users.noreply.github.com> Date: Wed, 30 Sep 2026 15:20:29 -0600 Subject: [PATCH 3/5] Add comments --- scripts/helm-docs.sh | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/scripts/helm-docs.sh b/scripts/helm-docs.sh index cb9f1b75..421fc32b 100755 --- a/scripts/helm-docs.sh +++ b/scripts/helm-docs.sh @@ -1,29 +1,38 @@ #!/bin/sh # Downloads the pinned helm-docs release into target/bin (gitignored) on first -# use, then runs it with any arguments passed to this script. +# use, then runs it with any arguments passed to this script # -# ./scripts/helm-docs.sh regenerate charts/**/README.md -# ./scripts/helm-docs.sh --check regenerate, then fail if any README changed +# Usage: +# ./scripts/helm-docs.sh Regenerate charts/**/README.md after changing a values.yaml file +# ./scripts/helm-docs.sh --check CI check: regenerate, and fail if any changed +# ./scripts/helm-docs.sh [args] Run the helm-docs CLI with args +# ./scripts/helm-docs.sh --check [args] CI check with helm-docs CLI args # -# POSIX sh only (no bash): this runs on developer machines, in Buildkite, and -# in the release worker's busybox-based image. Adapted from -# https://github.com/linkerd/linkerd2/blob/main/bin/helm-docs +# POSIX compliant, so it runs the same anywhere: on developer machines, +# in Buildkite, and in the release worker's busybox image +# +# Adapted from https://github.com/linkerd/linkerd2/blob/main/bin/helm-docs + +# Pinned version of helm-docs +helmdocsversion=1.14.2 set -euf +# Eat the --check positional arg check=false if [ "${1:-}" = --check ]; then check=true shift fi -helmdocsv=1.14.2 # Run from the repository root regardless of the caller's cwd: helm-docs # scans the cwd for charts, and it reads .helmdocsignore from there too. cd "$(dirname "$0")/.." + targetbin=$PWD/target/bin -helmdocsbin=$targetbin/helm-docs-$helmdocsv +helmdocsbin=$targetbin/helm-docs-$helmdocsversion +# Download helm-docs if it doesn't already exist if [ ! -f "$helmdocsbin" ]; then # Release assets are named helm-docs___.tar.gz, # e.g. Darwin_arm64, Linux_x86_64, Windows_x86_64 @@ -31,18 +40,16 @@ if [ ! -f "$helmdocsbin" ]; then Darwin) os=Darwin ;; Linux) os=Linux ;; MSYS*|MINGW*|CYGWIN*) os=Windows ;; - *) echo "Unsupported OS: $(uname -s)" >&2; exit 126 ;; + *) echo "Unsupported host OS: $(uname -s)" >&2; exit 126 ;; esac case $(uname -m) in x86_64|amd64) arch=x86_64 ;; aarch64|arm64) arch=arm64 ;; armv7l) arch=arm7 ;; armv6l) arch=arm6 ;; - *) echo "Unsupported architecture: $(uname -m)" >&2; exit 126 ;; + *) echo "Unsupported host architecture: $(uname -m)" >&2; exit 126 ;; esac - helmdocscurl="https://github.com/norwoodj/helm-docs/releases/download/v$helmdocsv/helm-docs_${helmdocsv}_${os}_${arch}.tar.gz" - - # An explicit template works the same in GNU, BSD/macOS, and busybox mktemp. + helmdocscurl="https://github.com/norwoodj/helm-docs/releases/download/v$helmdocsversion/helm-docs_${helmdocsversion}_${os}_${arch}.tar.gz" tmp=$(mktemp -d "${TMPDIR:-/tmp}/helm-docs.XXXXXX") mkdir -p "$targetbin" ( @@ -55,10 +62,11 @@ if [ ! -f "$helmdocsbin" ]; then rm -rf "$tmp" fi +# Run helm-docs, with any remaining args "$helmdocsbin" "$@" if [ "$check" = true ]; then - # Only READMEs helm-docs writes, so unrelated local edits don't fail the check. + # Only check the READMEs written by helm-docs, so unrelated local edits don't fail this check stale=$(git status --porcelain -- 'charts/*/README.md') if [ -n "$stale" ]; then echo "Chart READMEs are out of date. Run ./scripts/helm-docs.sh and commit:" >&2 From fed1f28ec3edbc48f07c393b113bc20ffae2ad93 Mon Sep 17 00:00:00 2001 From: Marc LeBlanc <7050295+marcleblanc2@users.noreply.github.com> Date: Thu, 1 Oct 2026 01:59:20 -0600 Subject: [PATCH 4/5] scripts/helm-docs.sh: --check compares checksums instead of asking git --check used git status to find READMEs helm-docs rewrote, which tied it to having git installed and a real checkout. Snapshot cksum of every charts/**/README.md before helm-docs runs and compare after; list the paths whose checksum line is missing from the snapshot. find, cksum, and grep -xF are POSIX and busybox applets, so --check now works anywhere the script does, including the release worker's tarball checkout. This also compares against the tree before the run rather than the index, so a developer who has regenerated but not yet committed a README gets a pass instead of a failure until they commit. In CI the tree is clean before the run, so the result is unchanged. Verified with dash and macOS /bin/sh, including a PATH containing no git: clean tree exits 0; one or several values.yaml changes exit 1 listing exactly the affected READMEs; a second run after regeneration exits 0; same results from /tmp. Amp-Thread-ID: https://ampcode.com/threads/T-01a0f388-6a21-7173-93ec-fdd98150d75d Co-authored-by: Amp --- AGENTS.md | 2 +- scripts/helm-docs.sh | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index c08bed7a..32510393 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,7 +2,7 @@ ## After Making Changes -After making changes to any `values.yaml` file, regenerate the helm docs and verify the committed READMEs are current: +After making changes to any `values.yaml` file, regenerate the helm docs; this fails and lists any README it had to rewrite: ```sh ./scripts/helm-docs.sh --check diff --git a/scripts/helm-docs.sh b/scripts/helm-docs.sh index 421fc32b..cb12fb8e 100755 --- a/scripts/helm-docs.sh +++ b/scripts/helm-docs.sh @@ -62,12 +62,22 @@ if [ ! -f "$helmdocsbin" ]; then rm -rf "$tmp" fi +# Checksum every chart README, so --check can tell which ones helm-docs rewrote +# without git (the release worker has neither git nor a checkout) +readme_checksums() { find charts -name README.md -exec cksum {} +; } + +if [ "$check" = true ]; then + before=$(readme_checksums) +fi + # Run helm-docs, with any remaining args "$helmdocsbin" "$@" if [ "$check" = true ]; then - # Only check the READMEs written by helm-docs, so unrelated local edits don't fail this check - stale=$(git status --porcelain -- 'charts/*/README.md') + # Paths whose checksum line isn't in the before snapshot (changed or new) + stale=$(readme_checksums | while read -r line; do + printf '%s\n' "$before" | grep -qxF -- "$line" || echo "${line##* }" + done) if [ -n "$stale" ]; then echo "Chart READMEs are out of date. Run ./scripts/helm-docs.sh and commit:" >&2 echo "$stale" >&2 From 800d3e4350f29057b3b35ad098959290f3278298 Mon Sep 17 00:00:00 2001 From: Marc LeBlanc <7050295+marcleblanc2@users.noreply.github.com> Date: Thu, 1 Oct 2026 02:22:42 -0600 Subject: [PATCH 5/5] helm-docs.sh: print rewritten README paths on stdout The before/after checksum now runs on every invocation, not only under --check, and the paths helm-docs rewrote go to stdout one per line (helm-docs itself logs to stderr, so stdout was empty). The release worker in sourcegraph/sourcegraph can commit exactly those paths instead of keeping its own before/after snapshot of charts/**/README.md. --check is unchanged apart from the hint wording: it still exits 1 when the list is non-empty. Amp-Thread-ID: https://ampcode.com/threads/T-01a0f388-6a21-7173-93ec-fdd98150d75d Co-authored-by: Amp --- scripts/helm-docs.sh | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/scripts/helm-docs.sh b/scripts/helm-docs.sh index cb12fb8e..227c7a66 100755 --- a/scripts/helm-docs.sh +++ b/scripts/helm-docs.sh @@ -1,10 +1,11 @@ #!/bin/sh # Downloads the pinned helm-docs release into target/bin (gitignored) on first -# use, then runs it with any arguments passed to this script +# use, then runs it with any arguments passed to this script. Prints the path +# of every README.md it rewrote, one per line, on stdout # # Usage: # ./scripts/helm-docs.sh Regenerate charts/**/README.md after changing a values.yaml file -# ./scripts/helm-docs.sh --check CI check: regenerate, and fail if any changed +# ./scripts/helm-docs.sh --check CI check: regenerate, and exit 1 if any changed # ./scripts/helm-docs.sh [args] Run the helm-docs CLI with args # ./scripts/helm-docs.sh --check [args] CI check with helm-docs CLI args # @@ -62,25 +63,25 @@ if [ ! -f "$helmdocsbin" ]; then rm -rf "$tmp" fi -# Checksum every chart README, so --check can tell which ones helm-docs rewrote -# without git (the release worker has neither git nor a checkout) +# Checksum every chart README before and after, to report which ones helm-docs +# rewrote. Needs no git: the release worker has neither git nor a checkout readme_checksums() { find charts -name README.md -exec cksum {} +; } +before=$(readme_checksums) -if [ "$check" = true ]; then - before=$(readme_checksums) -fi - -# Run helm-docs, with any remaining args +# Run helm-docs, with any remaining args. Its own log lines go to stderr "$helmdocsbin" "$@" -if [ "$check" = true ]; then - # Paths whose checksum line isn't in the before snapshot (changed or new) - stale=$(readme_checksums | while read -r line; do - printf '%s\n' "$before" | grep -qxF -- "$line" || echo "${line##* }" - done) - if [ -n "$stale" ]; then - echo "Chart READMEs are out of date. Run ./scripts/helm-docs.sh and commit:" >&2 - echo "$stale" >&2 +# Paths whose checksum line isn't in the before snapshot (changed or new) +rewritten=$(readme_checksums | while read -r line; do + printf '%s\n' "$before" | grep -qxF -- "$line" || echo "${line##* }" +done) + +# stdout is only ever this list, one path per line; the release worker +# commits exactly these files +if [ -n "$rewritten" ]; then + echo "$rewritten" + if [ "$check" = true ]; then + echo "The chart READMEs listed above are out of date. Run ./scripts/helm-docs.sh and commit them" >&2 exit 1 fi fi