Skip to content

✨ add helm package hook #113

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion .pre-commit-hooks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@
description: golangci-lint is a Go linters aggregator
entry: hooks/golangci-lint.sh
language: script
language: script
files: \.go$
require_serial: true

Expand All @@ -105,6 +104,17 @@
files: \.((ya?ml)|(tpl))$
require_serial: true

- id: helm-package
name: helm-package
description: Run helm package to package helm charts.
entry: hooks/helmpackage.sh
language: script
files: \.((yma?l)|(tpl))$
types:
- "file"
exclude: ^index\.ya?ml$
require_serial: true

- id: markdown-link-check
name: markdown-link-check
description: Run markdown-link-check to check all the relative and absolute links in markdown docs.
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ supported hooks are:
* **golangci-lint**: Automatically run `golangci-lint` on all Golang code (`*.go` files).
* **yapf**: Automatically run [`yapf`](https://github.com/google/yapf) on all python code (`*.py` files).
* **helmlint** Automatically run [`helm lint`](https://helm.sh/docs/helm/helm_lint/) on your Helm chart files. [See caveats here](#helm-lint-caveats).
* **helm-package** Automatically run [`helm package`](https://helm.sh/docs/helm/helm_package/) to package your Helm charts.
* **markdown-link-check** Automatically run [markdown-link-check](https://github.com/tcort/markdown-link-check) on
markdown doc files.
* **sentinel-fmt**: Automatically run `sentinel fmt` on all Sentinel code (`*.sentinel.*` files).
Expand Down
124 changes: 124 additions & 0 deletions hooks/helmpackage.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
#!/usr/bin/env bash

set -e

# Run helm package on the root path.
# A typical helm chart directory structure looks as follows:
#
# root/
# ├─ custom_chart1/
# │ ├─ Chart.yaml
# │ ├─ ...
# ├─ index.yaml
# ├─ README.md
# ├─ charts/
# │ ├─ custom_chart1-0.1.0.tgz
# │ ├─ custom_chart2-1.2.3.tgz
# ├─ custom_chart2/
# │ ├─ Chart.yaml
# │ ├─ ...
#
# The `Chart.yaml` file is metadata that helm uses to index the chart, and is added to the release info. It includes things
# like `name`, `version`, and `maintainers`.
# The `charts` directory are subcharts / dependencies that are deployed with the chart.
# The `templates` directory is what contains the go templates to render the Kubernetes resource yaml. Also includes
# helper template definitions (suffix `.tpl`).
#
# Any time files in `templates` or `charts` changes, we should run `helm lint`. `helm lint` can only be run on the root
# path of a chart, so this pre-commit hook will take the changed files and resolve it to the helm chart path. The helm
# chart path is determined by a heuristic: it is the directory containing the `Chart.yaml` file.
#
# Note that pre-commit will only feed this the files that changed in the commit, so we can't do the filtering at the
# hook setting level (e.g `files: Chart.yaml` will not work if no changes are made in the Chart.yaml file).

# OSX GUI apps do not pick up environment variables the same way as Terminal apps and there are no easy solutions,
# especially as Apple changes the GUI app behavior every release (see https://stackoverflow.com/q/135688/483528). As a
# workaround to allow GitHub Desktop to work, add this (hopefully harmless) setting here.
# Update the PATH environment variable to include the default installation path of helm.
export PATH=$PATH:/usr/local/bin

# Get the absolute path of the current working directory to know when to stop traversing up the directory tree.
readonly cwd_abspath="$(realpath "$PWD")"

readonly charts_path="$cwd_abspath/charts"

# Function to check if an array contains a specific element.
# Usage: contains_element "value_to_find" "${array[@]}"
# Returns: 0 if found, 1 otherwise.
contains_element() {
local -r match="$1"
shift
for e in "$@"; do
if [[ "$e" == "$match" ]]; then
return 0
fi
done
return 1
}

# Function to output debug information only when the PRECOMMIT_DEBUG environment variable is set.
# Outputs to stderr.
debug() {
if [[ ! -z $PRECOMMIT_DEBUG ]]; then
>&2 echo "$@"
fi
}

# Function to recursively find the path of a Helm chart by traversing up from the file location until it finds a Chart.yaml.
# Usage: chart_path "path_of_changed_file"
# Returns: Path of the directory containing Chart.yaml or an empty string if not found.
chart_path() {
local -r changed_file="$1"
local -r changed_file_abspath="$(realpath "$changed_file")"
local -r changed_file_dir="$(dirname "$changed_file_abspath")"

debug "Checking directory $changed_file_abspath and $changed_file_dir for Chart.yaml"

if [[ "$changed_file_abspath" == "$cwd_abspath" ]]; then
debug "No chart path found"
echo ""
return 0
fi

if [[ "$(basename "$changed_file_abspath")" == "Chart.yaml" ]]; then
debug "Chart path found: $changed_file_dir"
echo "$changed_file_dir"
return 0
fi

if [[ -f "$changed_file_abspath/Chart.yaml" ]]; then
debug "Chart path found: $changed_file_abspath"
echo "$changed_file_abspath"
return 0
fi

if [[ -f "$changed_file_dir/Chart.yaml" ]]; then
debug "Chart path found: $changed_file_dir"
echo "$changed_file_dir"
return 0
fi

chart_path "$changed_file_dir"
}

# Array to track which chart directories have already been packaged to avoid duplicate processing.
packaged_chart_paths=()

# Main loop to process each file passed to the script.
for file in "$@"; do
debug "Checking $file"
file_chart_path=$(chart_path "$file")
debug "Resolved $file to chart path $file_chart_path"

if [[ ! -z "$file_chart_path" ]] && ! contains_element "$file_chart_path" "${packaged_chart_paths[@]}"; then
# Package the chart and add its path to the list of packaged charts.
helm package "$file_chart_path" -d $charts_path
packaged_chart_paths+=( "$file_chart_path" )
debug "Packaged $file_chart_path"
fi
done

# After all charts have been packaged, update the index for the repository.
# This assumes that the script is run from the repository root.
helm repo index $cwd_abspath
debug "Repository index updated."