From eaecd7c596b3517e8827a3ca29cb6b7ed02964e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Reinhard=20N=C3=A4gele?= Date: Sat, 31 Oct 2020 12:34:26 +0100 Subject: [PATCH 1/3] No longer wrap and run ct in Docker container MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With this major change, the action no longer wraps and runs ct in a Docker container but simply installs it directly on the host. Default config files that are part of the distro and Yamale and yamllint are installed as well. With this change, ct is directly exposed to the user with all options directly available. It will be much easier now to integrate custom tools using the new feature to run additional commands introduced in #283. Signed-off-by: Reinhard Nägele --- README.md | 59 +++++++++++++---------- action.yml | 25 ++++------ ct.sh | 134 +++++++---------------------------------------------- main.js | 19 -------- main.sh | 31 ------------- 5 files changed, 59 insertions(+), 209 deletions(-) delete mode 100644 main.js delete mode 100755 main.sh diff --git a/README.md b/README.md index 5708f91..2d22367 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,28 @@ # *chart-testing* Action -A GitHub Action to lint and test Helm charts, using the [helm/chart-testing](https://github.com/helm/chart-testing) CLI tool. - -`master` supports Helm 3 only. -Support for Helm 2 is on branch `dev-v2`. +A GitHub Action for installing the [helm/chart-testing](https://github.com/helm/chart-testing) CLI tool. ## Usage ### Pre-requisites -1. A GitHub repo containing a directory with your Helm charts (eg: `/charts`) -1. Optional: if you want to override the defaults, a [chart-testing config file](https://github.com/helm/chart-testing#configuration) in your GitHub repo (eg. `/ct.yaml`) -1. A workflow YAML file in your `.github/workflows` directory. An [example workflow](#example-workflow) is available below. +1. A GitHub repo containing a directory with your Helm charts (e.g: `charts`) +1. A workflow YAML file in your `.github/workflows` directory. + An [example workflow](#example-workflow) is available below. For more information, reference the GitHub Help Documentation for [Creating a workflow file](https://help.github.com/en/articles/configuring-a-workflow#creating-a-workflow-file) ### Inputs For more information on inputs, see the [API Documentation](https://developer.github.com/v3/repos/releases/#input) -- `image`: The chart-testing Docker image to use (default: `quay.io/helmpack/chart-testing:v3.2.0`) -- `config`: The path to the config file -- `command`: The chart-testing command to run -- `kubeconfig`: The path to the kube config file -- `docker_args`: Additional arguments which should be passed to docker when starting the ct container +- `version`: The chart-testing version to install (default: `v3.2.0`) ### Example Workflow Create a workflow (eg: `.github/workflows/lint-test.yaml`): +Note that Python must be installed as shown below because the action also installs [Yamale](https://github.com/23andMe/Yamale) and [yamllint](https://github.com/adrienverge/yamllint) which require Python. + ```yaml name: Lint and Test Charts @@ -39,28 +34,44 @@ jobs: steps: - name: Checkout uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - uses: actions/setup-python@v2 + with: + python-version: 3.7 - - name: Fetch history - run: git fetch --prune --unshallow + - name: Set up chart-testing + uses: helm/chart-testing-action@v2.0.0 + + - name: Run chart-testing (list-changed) + id: list-changed + run: | + changed=$(ct list-changed) + if [[ -n "$changed" ]]; then + echo "::set-output name=changed::true" + fi - name: Run chart-testing (lint) - id: lint - uses: helm/chart-testing-action@v1.2.0 - with: - command: lint + run: ct lint - name: Create kind cluster uses: helm/kind-action@v1.0.0 - # Only build a kind cluster if there are chart changes to test. - if: steps.lint.outputs.changed == 'true' + if: steps.list-changed.outputs.changed == 'true' - name: Run chart-testing (install) - uses: helm/chart-testing-action@v1.2.0 - with: - command: install + run: ct install ``` -This uses [`@helm/kind-action`](https://www.github.com/helm/kind-action) GitHub Action to spin up a [kind](https://kind.sigs.k8s.io/) Kubernetes cluster, and [`@helm/chart-testing-action`](https://www.github.com/helm/chart-testing-action) to lint and test your charts on every Pull Request. +This uses [`helm/kind-action`](https://www.github.com/helm/kind-action) GitHub Action to spin up a [kind](https://kind.sigs.k8s.io/) Kubernetes cluster, +and [`helm/chart-testing`](https://www.github.com/helm/chart-testing) to lint and test your charts on every pull request. + +## Upgrading from v1.x.x + +v2.0.0 is a major release with breaking changes. +The action no longer wraps the chart-testing tool but simply installs it. +It is no longer run in a Docker container. +All `ct` options are now directly available without the additional abstraction layer. ## Code of conduct diff --git a/action.yml b/action.yml index db91cbe..40240f8 100644 --- a/action.yml +++ b/action.yml @@ -1,24 +1,15 @@ name: "Helm Chart Testing" -description: "Run the Helm chart-testing tool" +description: "Install the Helm chart-testing tool" author: "The Helm authors" branding: color: blue icon: anchor inputs: - image: - description: "The chart-testing Docker image to use (default: quay.io/helmpack/chart-testing:v3.2.0)" - config: - description: "The relative path to the chart-testing config file" - command: - description: "The chart-testing command to run" - required: true - docker_args: - description: "Additional arguments which should be passed to docker when starting the ct container" - kubeconfig: - description: "The path to the kube config file" -outputs: - changed: - description: "Whether or not charts have changed (true/false)" + version: + description: "The chart-testing version to install (default: v3.2.0)" + default: v3.2.0 runs: - using: "node12" - main: "main.js" + using: composite + steps: + - run: "$GITHUB_ACTION_PATH/ct.sh --version ${{ inputs.version }}" + shell: bash diff --git a/ct.sh b/ct.sh index ddd0446..1e45e47 100755 --- a/ct.sh +++ b/ct.sh @@ -4,57 +4,23 @@ set -o errexit set -o nounset set -o pipefail -DEFAULT_IMAGE=quay.io/helmpack/chart-testing:v3.2.0 +DEFAULT_CHART_TESTING_VERSION=v3.2.0 show_help() { cat << EOF Usage: $(basename "$0") -h, --help Display help - -i, --image The chart-testing Docker image to use (default: ${DEFAULT_IMAGE}) - -c, --command The chart-testing command to run - --config The path to the chart-testing config file - --kubeconfig The path to the kube config file - --docker-args Additional arguments which should be passed to docker when starting the ct container + -v, --version The chart-testing version to use (default: $DEFAULT_CHART_TESTING_VERSION)" EOF } main() { - local image="$DEFAULT_IMAGE" - local config= - local command= - local kubeconfig="$HOME/.kube/config" - local docker_args=() + local version="$DEFAULT_CHART_TESTING_VERSION" parse_command_line "$@" - if [[ -z "$command" ]]; then - echo "ERROR: '-c|--command' is required." >&2 - show_help - exit 1 - fi - - run_ct_container - trap cleanup EXIT - - local changed - changed=$(docker_exec ct list-changed) - if [[ -z "$changed" ]]; then - echo 'No chart changes detected.' - echo "::set-output name=changed::false" - return - fi - - # Convenience output for other actions to make use of ct config to check if - # charts changed. - echo "::set-output name=changed::true" - - # All other ct commands require a cluster to be created in a previous step. - if [[ "$command" != "lint" ]] && [[ "$command" != "list-changed" ]]; then - configure_kube - fi - - run_ct + install_chart_testing } parse_command_line() { @@ -64,52 +30,12 @@ parse_command_line() { show_help exit ;; - -i|--image) - if [[ -n "${2:-}" ]]; then - image="$2" - shift - else - echo "ERROR: '-i|--image' cannot be empty." >&2 - show_help - exit 1 - fi - ;; - -c|--command) + -v|--version) if [[ -n "${2:-}" ]]; then - command="$2" + version="$2" shift else - echo "ERROR: '-c|--command' cannot be empty." >&2 - show_help - exit 1 - fi - ;; - --config) - if [[ -n "${2:-}" ]]; then - config="$2" - shift - else - echo "ERROR: '--config' cannot be empty." >&2 - show_help - exit 1 - fi - ;; - --kubeconfig) - if [[ -n "${2:-}" ]]; then - kubeconfig="$2" - shift - else - echo "ERROR: '--kubeconfig' cannot be empty." >&2 - show_help - exit 1 - fi - ;; - --docker-args) - if [[ -n "${2:-}" ]]; then - IFS=" " read -r -a docker_args <<< "$2" - shift - else - echo "ERROR: '--docker-args' cannot be empty." >&2 + echo "ERROR: '-v|--version' cannot be empty." >&2 show_help exit 1 fi @@ -123,45 +49,17 @@ parse_command_line() { done } -run_ct_container() { - echo 'Running ct container...' - local args=(run --rm --interactive --detach --network host --name ct "--volume=$(pwd):/workdir" "--workdir=/workdir") +install_chart_testing() { + echo "Installing chart-testing..." - if [[ -n "$config" ]]; then - args+=("--volume=$(pwd)/$config:/etc/ct/ct.yaml" ) - fi - - args=("${args[@]}" "${docker_args[@]}") - - args+=("$image" cat) - - echo docker "${args[@]}" - docker "${args[@]}" - echo -} - -configure_kube() { - # need to copy full .kube dir for certs, etc: - local confdir - confdir=$(dirname "$kubeconfig") - docker cp "$confdir" ct:/root/.kube -} - -run_ct() { - echo "Running 'ct $command'..." - docker_exec ct "$command" - echo -} - -cleanup() { - echo 'Removing ct container...' - docker kill ct > /dev/null 2>&1 - echo 'Done!' -} + curl -sSLo ct.tar.gz "https://github.com/helm/chart-testing/releases/download/$version/chart-testing_${version#v}_linux_amd64.tar.gz" + tar -xzf ct.tar.gz + sudo mv ct /usr/local/bin/ct + mkdir "$HOME/.ct" + mv etc/* "$HOME/.ct" -docker_exec() { - echo docker exec --interactive ct "$@" - docker exec --interactive ct "$@" + pip install yamllint==1.25.0 + pip install yamale==3.0.4 } main "$@" diff --git a/main.js b/main.js deleted file mode 100644 index d4bef59..0000000 --- a/main.js +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright The Helm Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// # You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// # See the License for the specific language governing permissions and -// limitations under the License. - -const spawnSync = require('child_process').spawnSync; -const path = require("path"); - -const proc = spawnSync('bash', [path.join(__dirname, 'main.sh')], {stdio: 'inherit'}); -process.exit(proc.status) diff --git a/main.sh b/main.sh deleted file mode 100755 index de435eb..0000000 --- a/main.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env bash - -set -o errexit -set -o nounset -set -o pipefail - -SCRIPT_DIR=$(dirname -- "$(readlink -f "${BASH_SOURCE[0]}" || realpath "${BASH_SOURCE[0]}")") - -main() { - args=(--command "${INPUT_COMMAND?'command' is required}") - - if [[ -n "${INPUT_IMAGE:-}" ]]; then - args+=(--image "${INPUT_IMAGE}") - fi - - if [[ -n "${INPUT_CONFIG:-}" ]]; then - args+=(--config "${INPUT_CONFIG}") - fi - - if [[ -n "${INPUT_KUBECONFIG:-}" ]]; then - args+=(--kubeconfig "${INPUT_KUBECONFIG}") - fi - - if [[ -n "${INPUT_DOCKER_ARGS:-}" ]]; then - args+=(--docker-args "${INPUT_DOCKER_ARGS}") - fi - - "$SCRIPT_DIR/ct.sh" "${args[@]}" -} - -main From 2838529c4afbc8117fb247ac5b33f466e2ee81d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Reinhard=20N=C3=A4gele?= Date: Sat, 31 Oct 2020 20:05:40 +0100 Subject: [PATCH 2/3] Use cache dir and virtual env MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Reinhard Nägele --- ct.sh | 45 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/ct.sh b/ct.sh index 1e45e47..c5e9ef4 100755 --- a/ct.sh +++ b/ct.sh @@ -50,16 +50,45 @@ parse_command_line() { } install_chart_testing() { - echo "Installing chart-testing..." + if [[ ! -d "$RUNNER_TOOL_CACHE" ]]; then + echo "Cache directory '$RUNNER_TOOL_CACHE' does not exist" >&2 + exit 1 + fi - curl -sSLo ct.tar.gz "https://github.com/helm/chart-testing/releases/download/$version/chart-testing_${version#v}_linux_amd64.tar.gz" - tar -xzf ct.tar.gz - sudo mv ct /usr/local/bin/ct - mkdir "$HOME/.ct" - mv etc/* "$HOME/.ct" + local cache_dir="$RUNNER_TOOL_CACHE/ct/$version/amd64" + if [[ ! -d "$cache_dir" ]]; then + mkdir -p "$cache_dir" - pip install yamllint==1.25.0 - pip install yamale==3.0.4 + echo "Installing chart-testing..." + curl -sSLo ct.tar.gz "https://github.com/helm/chart-testing/releases/download/$version/chart-testing_${version#v}_linux_amd64.tar.gz" + tar -xzf ct.tar.gz -C "$cache_dir" + rm -f ct.tar.gz + + echo 'Adding ct directory to PATH...' + echo "$cache_dir" >> "$GITHUB_PATH" + + echo 'Setting CT_CONFIG_DIR...' + echo "CT_CONFIG_DIR=$cache_dir/etc" >> "$GITHUB_ENV" + + local venv_dir="$cache_dir/venv" + + echo 'Creating virtual Python environment...' + python3 -m venv "$venv_dir" + + echo 'Activating virtual environment...' + # shellcheck disable=SC1090 + source "$venv_dir/bin/activate" + + echo 'Installing yamllint...' + pip3 install yamllint==1.25.0 + + echo 'Installing Yamale...' + pip3 install yamale==3.0.4 + + echo 'Configuring environment variables for virtual environment for subsequent workflow steps...' + echo "VIRTUAL_ENV=$venv_dir" >> "$GITHUB_ENV" + echo "$venv_dir/bin" >> "$GITHUB_PATH" + fi } main "$@" From a3b508debe90e7aee2531f0a464dd9753ae92286 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Reinhard=20N=C3=A4gele?= Date: Mon, 2 Nov 2020 08:15:46 +0100 Subject: [PATCH 3/3] Look up OS arch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Reinhard Nägele --- ct.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ct.sh b/ct.sh index c5e9ef4..985e7e5 100755 --- a/ct.sh +++ b/ct.sh @@ -55,7 +55,10 @@ install_chart_testing() { exit 1 fi - local cache_dir="$RUNNER_TOOL_CACHE/ct/$version/amd64" + local arch + arch=$(uname -m) + + local cache_dir="$RUNNER_TOOL_CACHE/ct/$version/$arch" if [[ ! -d "$cache_dir" ]]; then mkdir -p "$cache_dir"