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..985e7e5 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) - if [[ -n "${2:-}" ]]; then - command="$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) + -v|--version) if [[ -n "${2:-}" ]]; then - IFS=" " read -r -a docker_args <<< "$2" + version="$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,49 @@ 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") - - if [[ -n "$config" ]]; then - args+=("--volume=$(pwd)/$config:/etc/ct/ct.yaml" ) +install_chart_testing() { + if [[ ! -d "$RUNNER_TOOL_CACHE" ]]; then + echo "Cache directory '$RUNNER_TOOL_CACHE' does not exist" >&2 + exit 1 fi - args=("${args[@]}" "${docker_args[@]}") + local arch + arch=$(uname -m) - args+=("$image" cat) + local cache_dir="$RUNNER_TOOL_CACHE/ct/$version/$arch" + if [[ ! -d "$cache_dir" ]]; then + mkdir -p "$cache_dir" - echo docker "${args[@]}" - docker "${args[@]}" - echo -} + 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 -configure_kube() { - # need to copy full .kube dir for certs, etc: - local confdir - confdir=$(dirname "$kubeconfig") - docker cp "$confdir" ct:/root/.kube -} + echo 'Adding ct directory to PATH...' + echo "$cache_dir" >> "$GITHUB_PATH" -run_ct() { - echo "Running 'ct $command'..." - docker_exec ct "$command" - echo -} + echo 'Setting CT_CONFIG_DIR...' + echo "CT_CONFIG_DIR=$cache_dir/etc" >> "$GITHUB_ENV" -cleanup() { - echo 'Removing ct container...' - docker kill ct > /dev/null 2>&1 - echo 'Done!' -} + 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" -docker_exec() { - echo docker exec --interactive ct "$@" - docker exec --interactive ct "$@" + 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 "$@" 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