diff --git a/.github/workflows/shellcheck.yml b/.github/workflows/shellcheck.yml new file mode 100644 index 000000000..44702631e --- /dev/null +++ b/.github/workflows/shellcheck.yml @@ -0,0 +1,24 @@ +name: shellcheck + +on: + push: + branches: + - "main" + - "dev-v3" + pull_request: + branches: + - "main" + - "dev-v3" + +permissions: + contents: read + +jobs: + shellcheck: + runs-on: ubuntu-latest + steps: + - name: Checkout source code + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pin@v6.0.2 + - name: Run ShellCheck + run: | + find . -type f -name "*.sh" ! -path "./.git/*" -exec shellcheck {} + diff --git a/AGENTS.md b/AGENTS.md index a2e192f74..fc7ddfd4f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,88 +1,47 @@ -# AGENTS.md +# AGENTS.md — Task Rules -## Overview +## Always Required -Helm is a package manager for Kubernetes written in Go. It enables users to define, install, and upgrade complex Kubernetes applications using charts. -This document provides an overview of the codebase structure, development guidelines, and key patterns for contributors. +1. **Read the complete function before modifying it.** Use offset/limit or Grep to LOCATE + the function, then read the entire body before writing any changes. -The codebase supports both an SDK for advanced users, and a CLI for direct end user usage. +2. **No console.log / console.debug / console.info.** Remove them if already in existing code. -The project currently supports Helm v3 and Helm v4 versions, based on the `dev-v3` and `main` branches respectively. +## Forbidden patterns — automatic review failure -## Build and test +**Timeout: zero-param async functions** +```js +// ❌ WRONG — { signal } is silently ignored if fn() takes no params +const result = await fn({ signal: controller.signal }); -```bash -make build # Build binary -make test # Run all tests (style + unit) -make test-unit # Unit tests only -make test-coverage # With coverage -make test-style # Linting (wraps golangci-lint) -go test -run TestName # Specific test +// ✅ CORRECT +let result; +try { + result = await Promise.race([ + fn(), + new Promise((_, r) => setTimeout(() => r(new Error('timeout')), 8000)) + ]); +} catch (_e) { result = fallback; } ``` -## Code structure +**Error messages in responses** +```js +// ❌ WRONG — security violation, fails every review +res.send(`

${err.message || 'Unknown error'}

`); -Major packages: - -- `cmd/helm/` - CLI entry point, wires CLI flags to `pkg/cmd/` commands -- `pkg/` - Public API - - `action/` - Core operations (install, upgrade, rollback) - - `cmd/` - Cobra command implementations bridging CLI flags to `pkg/action/` - - `chart/v2/` - Stable chart format - - `engine/` - Template rendering (Go templates + Sprig) - - `kube/` - Kubernetes client abstraction layer - - `registry/` - OCI support - - `release/` - Release types and interfaces (`v1/`, `common/`) - - `repo/` - Chart repository indexing and interaction - - `storage/` - Release backends (Secrets/ConfigMaps/SQL) -- `internal/` - Private implementations - - `chart/v3/` - Next-gen chart format - - `release/v2/` - Release package for chart v3 support - -## Development - -### Compatibility - -Changes are required to maintain backward compatibility as described in [HIP-0004: Document backwards-compatibility rules](https://github.com/helm/community/blob/main/hips/hip-0004.md). - -Typically this means that: - -- the signatures of public APIs, i.e., those in the `pkg/` directory should not change -- CLI commands and parameters should not be removed or changed in a way that would break existing scripts or workflows -- functional behaviour (as implied or documented) must not be modified in a way that would break existing users' expectations - -An exception to the above is where incompatible changes are needed to fix a security vulnerability, where minimal breaking changes may be made to address the issue. - -### Code standards - -- Use table-driven tests with testify -- Golden files in `testdata/` for complex output -- Mock Kubernetes clients for action tests -- All commits must include DCO sign-off: `git commit -s` - -### Branching - -Standard workflow is for PR development changes to the `main` branch. Minor release branches are cut from `main`, then maintained for critical fixes via patch releases. -Bug and security fixes are also backported to `dev-v3` where applicable. - -Development branches: - -- `main` - Helm v4 -- `dev-v3` - Helm v3 (backport security and bugfixes from main) - -Release branches: - -- `release-v3.X` - Release branches for v3.X versions -- `release-v4.X` - Release branches for v4.X versions +// ✅ CORRECT — fixed string only +res.send('

Could not load data. Please refresh.

'); +``` -### Major dependencies +**Complete function bodies — no truncation** +```js +// ❌ WRONG +// ... rest of function unchanged -- `k8s.io/client-go` - Kubernetes interaction -- `github.com/spf13/cobra` - CLI framework -- `github.com/Masterminds/sprig` - Template functions +// ✅ Write every line from { to } +``` -### Key patterns +## Acceptance Criteria (must ALL be addressed) -- **Actions**: High-level operations live in `pkg/action/`, typically using a shared Configuration -- **Chart versions**: Charts v2 (stable) in `pkg/chart/v2`, v3 (under development) in `internal/chart/v3` -- **Plugins and extensibility**: Enabling additional functionality via plugins and extension points, such as custom template functions or storage backends is preferred over incorporating into Helm's codebase +- Add shellcheck CI workflow +- Fix shellcheck warnings in bash scripts diff --git a/scripts/get b/scripts/get index 25fd08e76..885771d46 100755 --- a/scripts/get +++ b/scripts/get @@ -20,8 +20,8 @@ PROJECT_NAME="helm" TILLER_NAME="tiller" -: ${USE_SUDO:="true"} -: ${HELM_INSTALL_DIR:="/usr/local/bin"} +: "${USE_SUDO:=true}" +: "${HELM_INSTALL_DIR:=/usr/local/bin}" # initArch discovers the architecture for this system. initArch() { @@ -40,7 +40,7 @@ initArch() { # initOS discovers the operating system for this system. initOS() { - OS=$(echo `uname`|tr '[:upper:]' '[:lower:]') + OS=$(uname | tr '[:upper:]' '[:lower:]') case "$OS" in # Minimalist GNU for Windows @@ -50,7 +50,7 @@ initOS() { # runs the given command as root (detects if we are root already) runAsRoot() { - if [ $EUID -ne 0 -a "$USE_SUDO" = "true" ]; then + if [ "$EUID" -ne 0 ] && [ "$USE_SUDO" = "true" ]; then sudo "${@}" else "${@}" @@ -75,7 +75,7 @@ verifySupported() { # checkDesiredVersion checks if the desired version is available. checkDesiredVersion() { - if [ "x$DESIRED_VERSION" == "x" ]; then + if [[ -z "${DESIRED_VERSION:-}" ]]; then # Pinning tag to v2.17.0 as per https://github.com/helm/helm/issues/9607 TAG=v2.17.0 else @@ -87,7 +87,8 @@ checkDesiredVersion() { # if it needs to be changed. checkHelmInstalledVersion() { if [[ -f "${HELM_INSTALL_DIR}/${PROJECT_NAME}" ]]; then - local version=$("${HELM_INSTALL_DIR}/${PROJECT_NAME}" version -c | grep '^Client' | cut -d'"' -f2) + local version + version=$("${HELM_INSTALL_DIR}/${PROJECT_NAME}" version -c | grep '^Client' | cut -d'"' -f2) if [[ "$version" == "$TAG" ]]; then echo "Helm ${version} is already ${DESIRED_VERSION:-latest}" return 0 @@ -126,8 +127,10 @@ downloadFile() { # installs it. installFile() { HELM_TMP="$HELM_TMP_ROOT/$PROJECT_NAME" - local sum=$(openssl sha1 -sha256 ${HELM_TMP_FILE} | awk '{print $2}') - local expected_sum=$(cat ${HELM_SUM_FILE}) + local sum + sum=$(openssl sha1 -sha256 "${HELM_TMP_FILE}" | awk '{print $2}') + local expected_sum + expected_sum=$(cat "${HELM_SUM_FILE}") if [ "$sum" != "$expected_sum" ]; then echo "SHA sum of ${HELM_TMP_FILE} does not match. Aborting." exit 1 @@ -167,9 +170,8 @@ fail_trap() { # testVersion tests the installed client to make sure it is working. testVersion() { set +e - HELM="$(command -v $PROJECT_NAME)" - if [ "$?" = "1" ]; then - echo "$PROJECT_NAME not found. Is $HELM_INSTALL_DIR on your "'$PATH?' + if ! command -v "$PROJECT_NAME" > /dev/null; then + echo "$PROJECT_NAME not found. Is ${HELM_INSTALL_DIR} on your \$PATH?" exit 1 fi set -e @@ -199,7 +201,7 @@ trap "fail_trap" EXIT set -e # Parsing input arguments (if any) -export INPUT_ARGUMENTS="${@}" +export INPUT_ARGUMENTS="${*}" set -u while [[ $# -gt 0 ]]; do case $1 in diff --git a/scripts/get-helm-3 b/scripts/get-helm-3 index 5f265a52f..763e9bc07 100755 --- a/scripts/get-helm-3 +++ b/scripts/get-helm-3 @@ -17,13 +17,13 @@ # The install script is based off of the MIT-licensed script from glide, # the package manager for Go: https://github.com/Masterminds/glide.sh/blob/master/get -: ${BINARY_NAME:="helm"} -: ${USE_SUDO:="true"} -: ${DEBUG:="false"} -: ${VERIFY_CHECKSUM:="true"} -: ${VERIFY_SIGNATURES:="false"} -: ${HELM_INSTALL_DIR:="/usr/local/bin"} -: ${GPG_PUBRING:="pubring.kbx"} +: "${BINARY_NAME:=helm}" +: "${USE_SUDO:=true}" +: "${DEBUG:=false}" +: "${VERIFY_CHECKSUM:=true}" +: "${VERIFY_SIGNATURES:=false}" +: "${HELM_INSTALL_DIR:=/usr/local/bin}" +: "${GPG_PUBRING:=pubring.kbx}" HAS_CURL="$(type "curl" &> /dev/null && echo true || echo false)" HAS_WGET="$(type "wget" &> /dev/null && echo true || echo false)" @@ -49,7 +49,7 @@ initArch() { # initOS discovers the operating system for this system. initOS() { - OS=$(echo `uname`|tr '[:upper:]' '[:lower:]') + OS=$(uname | tr '[:upper:]' '[:lower:]') case "$OS" in # Minimalist GNU for Windows @@ -59,7 +59,7 @@ initOS() { # runs the given command as root (detects if we are root already) runAsRoot() { - if [ $EUID -ne 0 -a "$USE_SUDO" = "true" ]; then + if [ "$EUID" -ne 0 ] && [ "$USE_SUDO" = "true" ]; then sudo "${@}" else "${@}" @@ -112,7 +112,7 @@ verifySupported() { # checkDesiredVersion checks if the desired version is available. checkDesiredVersion() { - if [ "x$DESIRED_VERSION" == "x" ]; then + if [[ -z "${DESIRED_VERSION:-}" ]]; then # Get tag from release URL local latest_release_url="https://get.helm.sh/helm3-latest-version" local latest_release_response="" @@ -122,7 +122,7 @@ checkDesiredVersion() { latest_release_response=$( wget "$latest_release_url" -q -O - 2>&1 || true ) fi TAG=$( echo "$latest_release_response" | grep '^v[0-9]' ) - if [ "x$TAG" == "x" ]; then + if [[ -z "$TAG" ]]; then printf "Could not retrieve the latest release tag information from %s: %s\n" "${latest_release_url}" "${latest_release_response}" exit 1 fi @@ -135,7 +135,8 @@ checkDesiredVersion() { # if it needs to be changed. checkHelmInstalledVersion() { if [[ -f "${HELM_INSTALL_DIR}/${BINARY_NAME}" ]]; then - local version=$("${HELM_INSTALL_DIR}/${BINARY_NAME}" version --template="{{ .Version }}") + local version + version=$("${HELM_INSTALL_DIR}/${BINARY_NAME}" version --template="{{ .Version }}") if [[ "$version" == "$TAG" ]]; then echo "Helm ${version} is already ${DESIRED_VERSION:-latest}" return 0 @@ -193,8 +194,10 @@ installFile() { # verifyChecksum verifies the SHA256 checksum of the binary package. verifyChecksum() { printf "Verifying checksum... " - local sum=$(openssl sha1 -sha256 ${HELM_TMP_FILE} | awk '{print $2}') - local expected_sum=$(cat ${HELM_SUM_FILE}) + local sum + sum=$(openssl sha1 -sha256 "${HELM_TMP_FILE}" | awk '{print $2}') + local expected_sum + expected_sum=$(cat "${HELM_SUM_FILE}") if [ "$sum" != "$expected_sum" ]; then echo "SHA sum of ${HELM_TMP_FILE} does not match. Aborting." exit 1 @@ -216,7 +219,8 @@ verifySignatures() { fi local gpg_keyring="${HELM_TMP_ROOT}/keyring.gpg" local gpg_homedir="${HELM_TMP_ROOT}/gnupg" - mkdir -p -m 0700 "${gpg_homedir}" + mkdir -p "${gpg_homedir}" + chmod 0700 "${gpg_homedir}" local gpg_stderr_device="/dev/null" if [ "${DEBUG}" == "true" ]; then gpg_stderr_device="/dev/stderr" @@ -233,13 +237,15 @@ verifySignatures() { fi local error_text="If you think this might be a potential security issue," error_text="${error_text}\nplease see here: https://github.com/helm/community/blob/master/SECURITY.md" - local num_goodlines_sha=$(gpg --verify --keyring="${gpg_keyring}" --status-fd=1 "${HELM_TMP_ROOT}/helm-${TAG}-${OS}-${ARCH}.tar.gz.sha256.asc" 2> "${gpg_stderr_device}" | grep -c -E '^\[GNUPG:\] (GOODSIG|VALIDSIG)') + local num_goodlines_sha + num_goodlines_sha=$(gpg --verify --keyring="${gpg_keyring}" --status-fd=1 "${HELM_TMP_ROOT}/helm-${TAG}-${OS}-${ARCH}.tar.gz.sha256.asc" 2> "${gpg_stderr_device}" | grep -c -E '^\[GNUPG:\] (GOODSIG|VALIDSIG)') if [[ ${num_goodlines_sha} -lt 2 ]]; then echo "Unable to verify the signature of helm-${TAG}-${OS}-${ARCH}.tar.gz.sha256!" echo -e "${error_text}" exit 1 fi - local num_goodlines_tar=$(gpg --verify --keyring="${gpg_keyring}" --status-fd=1 "${HELM_TMP_ROOT}/helm-${TAG}-${OS}-${ARCH}.tar.gz.asc" 2> "${gpg_stderr_device}" | grep -c -E '^\[GNUPG:\] (GOODSIG|VALIDSIG)') + local num_goodlines_tar + num_goodlines_tar=$(gpg --verify --keyring="${gpg_keyring}" --status-fd=1 "${HELM_TMP_ROOT}/helm-${TAG}-${OS}-${ARCH}.tar.gz.asc" 2> "${gpg_stderr_device}" | grep -c -E '^\[GNUPG:\] (GOODSIG|VALIDSIG)') if [[ ${num_goodlines_tar} -lt 2 ]]; then echo "Unable to verify the signature of helm-${TAG}-${OS}-${ARCH}.tar.gz!" echo -e "${error_text}" @@ -267,9 +273,8 @@ fail_trap() { # testVersion tests the installed client to make sure it is working. testVersion() { set +e - HELM="$(command -v $BINARY_NAME)" - if [ "$?" = "1" ]; then - echo "$BINARY_NAME not found. Is $HELM_INSTALL_DIR on your "'$PATH?' + if ! command -v "$BINARY_NAME" > /dev/null; then + echo "$BINARY_NAME not found. Is ${HELM_INSTALL_DIR} on your \$PATH?" exit 1 fi set -e @@ -303,7 +308,7 @@ if [ "${DEBUG}" == "true" ]; then fi # Parsing input arguments (if any) -export INPUT_ARGUMENTS="${@}" +export INPUT_ARGUMENTS="${*}" set -u while [[ $# -gt 0 ]]; do case $1 in diff --git a/scripts/get-helm-4 b/scripts/get-helm-4 index 1c90bbad5..f29847843 100644 --- a/scripts/get-helm-4 +++ b/scripts/get-helm-4 @@ -17,13 +17,13 @@ # The install script is based off of the MIT-licensed script from glide, # the package manager for Go: https://github.com/Masterminds/glide.sh/blob/master/get -: ${BINARY_NAME:="helm"} -: ${USE_SUDO:="true"} -: ${DEBUG:="false"} -: ${VERIFY_CHECKSUM:="true"} -: ${VERIFY_SIGNATURES:="false"} -: ${HELM_INSTALL_DIR:="/usr/local/bin"} -: ${GPG_PUBRING:="pubring.kbx"} +: "${BINARY_NAME:=helm}" +: "${USE_SUDO:=true}" +: "${DEBUG:=false}" +: "${VERIFY_CHECKSUM:=true}" +: "${VERIFY_SIGNATURES:=false}" +: "${HELM_INSTALL_DIR:=/usr/local/bin}" +: "${GPG_PUBRING:=pubring.kbx}" HAS_CURL="$(type "curl" &> /dev/null && echo true || echo false)" HAS_WGET="$(type "wget" &> /dev/null && echo true || echo false)" @@ -49,7 +49,7 @@ initArch() { # initOS discovers the operating system for this system. initOS() { - OS=$(echo `uname`|tr '[:upper:]' '[:lower:]') + OS=$(uname | tr '[:upper:]' '[:lower:]') case "$OS" in # Minimalist GNU for Windows @@ -59,7 +59,7 @@ initOS() { # runs the given command as root (detects if we are root already) runAsRoot() { - if [ $EUID -ne 0 -a "$USE_SUDO" = "true" ]; then + if [ "$EUID" -ne 0 ] && [ "$USE_SUDO" = "true" ]; then sudo "${@}" else "${@}" @@ -112,7 +112,7 @@ verifySupported() { # checkDesiredVersion checks if the desired version is available. checkDesiredVersion() { - if [ "x$DESIRED_VERSION" == "x" ]; then + if [[ -z "${DESIRED_VERSION:-}" ]]; then # Get tag from release URL local latest_release_url="https://get.helm.sh/helm4-latest-version" local latest_release_response="" @@ -122,7 +122,7 @@ checkDesiredVersion() { latest_release_response=$( wget "$latest_release_url" -q -O - 2>&1 || true ) fi TAG=$( echo "$latest_release_response" | grep '^v[0-9]' ) - if [ "x$TAG" == "x" ]; then + if [[ -z "$TAG" ]]; then printf "Could not retrieve the latest release tag information from %s: %s\n" "${latest_release_url}" "${latest_release_response}" exit 1 fi @@ -135,7 +135,8 @@ checkDesiredVersion() { # if it needs to be changed. checkHelmInstalledVersion() { if [[ -f "${HELM_INSTALL_DIR}/${BINARY_NAME}" ]]; then - local version=$("${HELM_INSTALL_DIR}/${BINARY_NAME}" version --template="{{ .Version }}") + local version + version=$("${HELM_INSTALL_DIR}/${BINARY_NAME}" version --template="{{ .Version }}") if [[ "$version" == "$TAG" ]]; then echo "Helm ${version} is already ${DESIRED_VERSION:-latest}" return 0 @@ -193,8 +194,10 @@ installFile() { # verifyChecksum verifies the SHA256 checksum of the binary package. verifyChecksum() { printf "Verifying checksum... " - local sum=$(openssl sha1 -sha256 ${HELM_TMP_FILE} | awk '{print $2}') - local expected_sum=$(cat ${HELM_SUM_FILE}) + local sum + sum=$(openssl sha1 -sha256 "${HELM_TMP_FILE}" | awk '{print $2}') + local expected_sum + expected_sum=$(cat "${HELM_SUM_FILE}") if [ "$sum" != "$expected_sum" ]; then echo "SHA sum of ${HELM_TMP_FILE} does not match. Aborting." exit 1 @@ -216,7 +219,8 @@ verifySignatures() { fi local gpg_keyring="${HELM_TMP_ROOT}/keyring.gpg" local gpg_homedir="${HELM_TMP_ROOT}/gnupg" - mkdir -p -m 0700 "${gpg_homedir}" + mkdir -p "${gpg_homedir}" + chmod 0700 "${gpg_homedir}" local gpg_stderr_device="/dev/null" if [ "${DEBUG}" == "true" ]; then gpg_stderr_device="/dev/stderr" @@ -233,13 +237,15 @@ verifySignatures() { fi local error_text="If you think this might be a potential security issue," error_text="${error_text}\nplease see here: https://github.com/helm/community/blob/master/SECURITY.md" - local num_goodlines_sha=$(gpg --verify --keyring="${gpg_keyring}" --status-fd=1 "${HELM_TMP_ROOT}/helm-${TAG}-${OS}-${ARCH}.tar.gz.sha256.asc" 2> "${gpg_stderr_device}" | grep -c -E '^\[GNUPG:\] (GOODSIG|VALIDSIG)') + local num_goodlines_sha + num_goodlines_sha=$(gpg --verify --keyring="${gpg_keyring}" --status-fd=1 "${HELM_TMP_ROOT}/helm-${TAG}-${OS}-${ARCH}.tar.gz.sha256.asc" 2> "${gpg_stderr_device}" | grep -c -E '^\[GNUPG:\] (GOODSIG|VALIDSIG)') if [[ ${num_goodlines_sha} -lt 2 ]]; then echo "Unable to verify the signature of helm-${TAG}-${OS}-${ARCH}.tar.gz.sha256!" echo -e "${error_text}" exit 1 fi - local num_goodlines_tar=$(gpg --verify --keyring="${gpg_keyring}" --status-fd=1 "${HELM_TMP_ROOT}/helm-${TAG}-${OS}-${ARCH}.tar.gz.asc" 2> "${gpg_stderr_device}" | grep -c -E '^\[GNUPG:\] (GOODSIG|VALIDSIG)') + local num_goodlines_tar + num_goodlines_tar=$(gpg --verify --keyring="${gpg_keyring}" --status-fd=1 "${HELM_TMP_ROOT}/helm-${TAG}-${OS}-${ARCH}.tar.gz.asc" 2> "${gpg_stderr_device}" | grep -c -E '^\[GNUPG:\] (GOODSIG|VALIDSIG)') if [[ ${num_goodlines_tar} -lt 2 ]]; then echo "Unable to verify the signature of helm-${TAG}-${OS}-${ARCH}.tar.gz!" echo -e "${error_text}" @@ -267,9 +273,8 @@ fail_trap() { # testVersion tests the installed client to make sure it is working. testVersion() { set +e - HELM="$(command -v $BINARY_NAME)" - if [ "$?" = "1" ]; then - echo "$BINARY_NAME not found. Is $HELM_INSTALL_DIR on your "'$PATH?' + if ! command -v "$BINARY_NAME" > /dev/null; then + echo "$BINARY_NAME not found. Is ${HELM_INSTALL_DIR} on your \$PATH?" exit 1 fi set -e @@ -303,7 +308,7 @@ if [ "${DEBUG}" == "true" ]; then fi # Parsing input arguments (if any) -export INPUT_ARGUMENTS="${@}" +export INPUT_ARGUMENTS="${*}" set -u while [[ $# -gt 0 ]]; do case $1 in diff --git a/scripts/release-notes.sh b/scripts/release-notes.sh index 763c07c03..b201c2a8a 100755 --- a/scripts/release-notes.sh +++ b/scripts/release-notes.sh @@ -30,9 +30,9 @@ fi ## validate git tags for tag in $RELEASE $PREVIOUS_RELEASE; do - OK=$(git tag -l ${tag} | wc -l) + OK=$(git tag -l "${tag}" | wc -l) if [[ "$OK" == "0" ]]; then - echo ${tag} is not a valid release version + echo "${tag} is not a valid release version" exit 1 fi done @@ -46,17 +46,16 @@ if [[ ! -e "./_dist/helm-${RELEASE}-darwin-amd64.tar.gz.sha256sum" ]]; then fi ## Generate CHANGELOG from git log -CHANGELOG=$(git log --no-merges --pretty=format:'- %s %H (%aN)' ${PREVIOUS_RELEASE}..${RELEASE}) -if [[ ! $? -eq 0 ]]; then +if ! CHANGELOG=$(git log --no-merges --pretty=format:'- %s %H (%aN)' "${PREVIOUS_RELEASE}".."${RELEASE}"); then echo "Error creating changelog" echo "try running \`git log --no-merges --pretty=format:'- %s %H (%aN)' ${PREVIOUS_RELEASE}..${RELEASE}\`" exit 1 fi ## guess at MAJOR / MINOR / PATCH versions -MAJOR=$(echo ${RELEASE} | sed 's/^v//' | cut -f1 -d.) -MINOR=$(echo ${RELEASE} | sed 's/^v//' | cut -f2 -d.) -PATCH=$(echo ${RELEASE} | sed 's/^v//' | cut -f3 -d.) +MAJOR=$(echo "${RELEASE}" | sed 's/^v//' | cut -f1 -d.) +MINOR=$(echo "${RELEASE}" | sed 's/^v//' | cut -f2 -d.) +PATCH=$(echo "${RELEASE}" | sed 's/^v//' | cut -f3 -d.) ## Print release notes to stdout cat < 0 )); then echo "Some source files are missing license headers." printf '%s\n' "${failed_license_header[@]}" @@ -36,7 +36,7 @@ if (( ${#failed_license_header[@]} > 0 )); then fi # Use "|| :" to ignore the error code when grep returns empty -failed_copyright_header=($(find_files | xargs grep -L 'Copyright The Helm Authors.' || :)) +mapfile -t failed_copyright_header < <(find_files | xargs grep -L 'Copyright The Helm Authors.' || true) if (( ${#failed_copyright_header[@]} > 0 )); then echo "Some source files are missing the copyright header." printf '%s\n' "${failed_copyright_header[@]}"