├── .eslintignore ├── .eslintrc.json ├── .github ├── dependabot.yml └── workflows │ └── test.yml ├── .gitignore ├── .prettierignore ├── .prettierrc.json ├── LICENSE ├── README.md ├── action.yml ├── dist └── index.js ├── package-lock.json ├── package.json ├── src └── main.ts └── tsconfig.json /.eslintignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | lib/ 3 | node_modules/ -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["jest", "@typescript-eslint"], 3 | "extends": ["plugin:github/es6"], 4 | "parser": "@typescript-eslint/parser", 5 | "parserOptions": { 6 | "ecmaVersion": 9, 7 | "sourceType": "module", 8 | "project": "./tsconfig.json" 9 | }, 10 | "rules": { 11 | "eslint-comments/no-use": "off", 12 | "import/no-namespace": "off", 13 | "no-unused-vars": "off", 14 | "@typescript-eslint/no-unused-vars": "error", 15 | "@typescript-eslint/explicit-member-accessibility": ["error", {"accessibility": "no-public"}], 16 | "@typescript-eslint/no-require-imports": "error", 17 | "@typescript-eslint/array-type": "error", 18 | "@typescript-eslint/await-thenable": "error", 19 | "@typescript-eslint/ban-ts-ignore": "error", 20 | "camelcase": "off", 21 | "@typescript-eslint/camelcase": "error", 22 | "@typescript-eslint/class-name-casing": "error", 23 | "@typescript-eslint/explicit-function-return-type": ["error", {"allowExpressions": true}], 24 | "@typescript-eslint/func-call-spacing": ["error", "never"], 25 | "@typescript-eslint/generic-type-naming": ["error", "^[A-Z][A-Za-z]*$"], 26 | "@typescript-eslint/no-array-constructor": "error", 27 | "@typescript-eslint/no-empty-interface": "error", 28 | "@typescript-eslint/no-explicit-any": "error", 29 | "@typescript-eslint/no-extraneous-class": "error", 30 | "@typescript-eslint/no-for-in-array": "error", 31 | "@typescript-eslint/no-inferrable-types": "error", 32 | "@typescript-eslint/no-misused-new": "error", 33 | "@typescript-eslint/no-namespace": "error", 34 | "@typescript-eslint/no-non-null-assertion": "warn", 35 | "@typescript-eslint/no-object-literal-type-assertion": "error", 36 | "@typescript-eslint/no-unnecessary-qualifier": "error", 37 | "@typescript-eslint/no-unnecessary-type-assertion": "error", 38 | "@typescript-eslint/no-useless-constructor": "error", 39 | "@typescript-eslint/no-var-requires": "error", 40 | "@typescript-eslint/prefer-for-of": "warn", 41 | "@typescript-eslint/prefer-function-type": "warn", 42 | "@typescript-eslint/prefer-includes": "error", 43 | "@typescript-eslint/prefer-interface": "error", 44 | "@typescript-eslint/prefer-string-starts-ends-with": "error", 45 | "@typescript-eslint/promise-function-async": "error", 46 | "@typescript-eslint/require-array-sort-compare": "error", 47 | "@typescript-eslint/restrict-plus-operands": "error", 48 | "semi": "off", 49 | "@typescript-eslint/semi": ["error", "never"], 50 | "@typescript-eslint/type-annotation-spacing": "error", 51 | "@typescript-eslint/unbound-method": "error" 52 | }, 53 | "env": { 54 | "node": true, 55 | "es6": true, 56 | "jest/globals": true 57 | } 58 | } -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: "action-setup-kube-tools Test" 2 | on: 3 | # Schedule run: Runs at 00:00, only on Mondays (Japan Time) 4 | schedule: 5 | - cron: '0 15 * * 1' 6 | pull_request: 7 | push: 8 | branches: 9 | - master 10 | - 'releases/*' 11 | - 'v*' 12 | 13 | jobs: 14 | build: # make sure build/ci work properly 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v4 18 | - uses: actions/setup-node@v4 19 | with: 20 | node-version: '20.x' 21 | - run: | 22 | npm install 23 | npm run all 24 | test1: 25 | runs-on: ubuntu-latest 26 | steps: 27 | - uses: actions/checkout@v4 28 | - uses: ./ 29 | id: setup 30 | - run: | 31 | kubectl version --client 32 | kustomize version 33 | helm version 34 | kubeval --version 35 | kubeconform -v 36 | conftest --version 37 | yq --version 38 | rancher --version 39 | tilt version 40 | skaffold version 41 | kube-score version 42 | - run: | 43 | kubectl=${{steps.setup.outputs.kubectl-path}} 44 | kustomize=${{steps.setup.outputs.kustomize-path}} 45 | helm=${{steps.setup.outputs.helm-path}} 46 | kubeval=${{steps.setup.outputs.kubeval-path}} 47 | kubeconform=${{steps.setup.outputs.kubeconform-path}} 48 | conftest=${{steps.setup.outputs.conftest-path}} 49 | yq=${{steps.setup.outputs.yq-path}} 50 | rancher=${{steps.setup.outputs.rancher-path}} 51 | tilt=${{steps.setup.outputs.tilt-path}} 52 | skaffold=${{steps.setup.outputs.skaffold-path}} 53 | kubescore=${{steps.setup.outputs.kube-score-path}} 54 | 55 | ${kubectl} version --client 56 | ${kustomize} version 57 | ${helm} version 58 | ${kubeval} --version 59 | ${kubeconform} -v 60 | ${conftest} --version 61 | ${yq} --version 62 | ${rancher} --version 63 | ${tilt} version 64 | ${skaffold} version 65 | ${kubescore} version 66 | 67 | test2: 68 | runs-on: ubuntu-latest 69 | steps: 70 | - uses: actions/checkout@v4 71 | - uses: ./ 72 | with: 73 | kubectl: '1.17.1' 74 | kustomize: '3.7.0' 75 | helm: '3.2.4' 76 | kubeval: '0.16.1' 77 | kubeconform: '0.5.0' 78 | conftest: '0.18.2' 79 | yq: '4.7.1' 80 | rancher: '2.4.10' 81 | tilt: '0.18.11' 82 | skaffold: '1.20.0' 83 | kube-score: '1.10.1' 84 | id: setup 85 | - run: | 86 | kubectl version --client 87 | kustomize version 88 | helm version 89 | kubeval --version 90 | kubeconform -v 91 | conftest --version 92 | yq --version 93 | rancher --version 94 | tilt version 95 | skaffold version 96 | kube-score version 97 | - run: | 98 | kubectl=${{steps.setup.outputs.kubectl-path}} 99 | kustomize=${{steps.setup.outputs.kustomize-path}} 100 | helm=${{steps.setup.outputs.helm-path}} 101 | kubeval=${{steps.setup.outputs.kubeval-path}} 102 | kubeconform=${{steps.setup.outputs.kubeconform-path}} 103 | conftest=${{steps.setup.outputs.conftest-path}} 104 | yq=${{steps.setup.outputs.yq-path}} 105 | rancher=${{steps.setup.outputs.rancher-path}} 106 | tilt=${{steps.setup.outputs.tilt-path}} 107 | skaffold=${{steps.setup.outputs.skaffold-path}} 108 | kubescore=${{steps.setup.outputs.kube-score-path}} 109 | 110 | ${kubectl} version --client 111 | ${kustomize} version 112 | ${helm} version 113 | ${kubeval} --version 114 | ${kubeconform} -v 115 | ${conftest} --version 116 | ${yq} --version 117 | ${rancher} --version 118 | ${tilt} version 119 | ${skaffold} version 120 | ${kubescore} version 121 | 122 | test3: 123 | runs-on: ubuntu-latest 124 | steps: 125 | - uses: actions/checkout@v4 126 | - uses: ./ 127 | with: 128 | arch-type: 'amd64' 129 | setup-tools: | 130 | kubectl 131 | helm 132 | kustomize 133 | skaffold 134 | kubectl: '1.17.1' 135 | helm: '3.2.4' 136 | kustomize: '3.7.0' 137 | skaffold: '1.20.0' 138 | id: setup 139 | - run: | 140 | kubectl version --client 141 | kustomize version 142 | helm version 143 | skaffold version 144 | - run: | 145 | kubectl=${{steps.setup.outputs.kubectl-path}} 146 | kustomize=${{steps.setup.outputs.kustomize-path}} 147 | helm=${{steps.setup.outputs.helm-path}} 148 | kubeval=${{steps.setup.outputs.kubeval-path}} 149 | kubeconform=${{steps.setup.outputs.kubeconform-path}} 150 | conftest=${{steps.setup.outputs.conftest-path}} 151 | yq=${{steps.setup.outputs.yq-path}} 152 | rancher=${{steps.setup.outputs.rancher-path}} 153 | tilt=${{steps.setup.outputs.tilt-path}} 154 | skaffold=${{steps.setup.outputs.skaffold-path}} 155 | kubescore=${{steps.setup.outputs.kube-score-path}} 156 | 157 | if [ ! -z ${kubectl} ]; then 158 | ${kubectl} version --client 159 | fi 160 | if [ ! -z ${kustomize} ]; then 161 | ${kustomize} version 162 | fi 163 | if [ ! -z ${helm} ]; then 164 | ${helm} version 165 | fi 166 | if [ ! -z ${kubeval} ]; then 167 | ${kubeval} --version 168 | fi 169 | if [ ! -z ${kubeconform} ]; then 170 | ${kubeconform} -v 171 | fi 172 | if [ ! -z ${conftest} ]; then 173 | ${conftest} --version 174 | fi 175 | if [ ! -z ${yq} ]; then 176 | ${yq} --version 177 | fi 178 | if [ ! -z ${rancher} ]; then 179 | ${rancher} --version 180 | fi 181 | if [ ! -z ${tilt} ]; then 182 | ${tilt} version 183 | fi 184 | if [ ! -z ${skaffold} ]; then 185 | ${skaffold} version 186 | fi 187 | if [ ! -z ${kubescore} ]; then 188 | ${kubescore} version 189 | fi 190 | 191 | # ARM test 192 | test4: 193 | runs-on: ubuntu-latest 194 | steps: 195 | - uses: actions/checkout@v4 196 | - uses: ./ 197 | with: 198 | arch-type: 'arm64' 199 | id: setup 200 | - run: | 201 | kubectl=${{steps.setup.outputs.kubectl-path}} 202 | kustomize=${{steps.setup.outputs.kustomize-path}} 203 | helm=${{steps.setup.outputs.helm-path}} 204 | kubeval=${{steps.setup.outputs.kubeval-path}} 205 | kubeconform=${{steps.setup.outputs.kubeconform-path}} 206 | conftest=${{steps.setup.outputs.conftest-path}} 207 | yq=${{steps.setup.outputs.yq-path}} 208 | rancher=${{steps.setup.outputs.rancher-path}} 209 | tilt=${{steps.setup.outputs.tilt-path}} 210 | skaffold=${{steps.setup.outputs.skaffold-path}} 211 | kubescore=${{steps.setup.outputs.kube-score-path}} 212 | 213 | if [ ! -z ${kubectl} ]; then 214 | file ${kubectl} 215 | fi 216 | if [ ! -z ${kustomize} ]; then 217 | file ${kustomize} 218 | fi 219 | if [ ! -z ${helm} ]; then 220 | file ${helm} 221 | fi 222 | if [ ! -z ${kubeval} ]; then 223 | file ${kubeval} 224 | fi 225 | if [ ! -z ${kubeconform} ]; then 226 | file ${kubeconform} 227 | fi 228 | if [ ! -z ${conftest} ]; then 229 | file ${conftest} 230 | fi 231 | if [ ! -z ${yq} ]; then 232 | file ${yq} 233 | fi 234 | if [ ! -z ${rancher} ]; then 235 | file ${rancher} 236 | fi 237 | if [ ! -z ${tilt} ]; then 238 | file ${tilt} 239 | fi 240 | if [ ! -z ${skaffold} ]; then 241 | file ${skaffold} 242 | fi 243 | if [ ! -z ${kubescore} ]; then 244 | file ${kubescore} 245 | fi 246 | 247 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Dependency directory 2 | node_modules 3 | 4 | # Rest pulled from https://github.com/github/gitignore/blob/master/Node.gitignore 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | yarn-debug.log* 10 | yarn-error.log* 11 | lerna-debug.log* 12 | 13 | # Diagnostic reports (https://nodejs.org/api/report.html) 14 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 15 | 16 | # Runtime data 17 | pids 18 | *.pid 19 | *.seed 20 | *.pid.lock 21 | 22 | # Directory for instrumented libs generated by jscoverage/JSCover 23 | lib-cov 24 | 25 | # Coverage directory used by tools like istanbul 26 | coverage 27 | *.lcov 28 | 29 | # nyc test coverage 30 | .nyc_output 31 | 32 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 33 | .grunt 34 | 35 | # Bower dependency directory (https://bower.io/) 36 | bower_components 37 | 38 | # node-waf configuration 39 | .lock-wscript 40 | 41 | # Compiled binary addons (https://nodejs.org/api/addons.html) 42 | build/Release 43 | 44 | # Dependency directories 45 | jspm_packages/ 46 | 47 | # TypeScript v1 declaration files 48 | typings/ 49 | 50 | # TypeScript cache 51 | *.tsbuildinfo 52 | 53 | # Optional npm cache directory 54 | .npm 55 | 56 | # Optional eslint cache 57 | .eslintcache 58 | 59 | # Optional REPL history 60 | .node_repl_history 61 | 62 | # Output of 'npm pack' 63 | *.tgz 64 | 65 | # Yarn Integrity file 66 | .yarn-integrity 67 | 68 | # dotenv environment variables file 69 | .env 70 | .env.test 71 | 72 | # parcel-bundler cache (https://parceljs.org/) 73 | .cache 74 | 75 | # next.js build output 76 | .next 77 | 78 | # nuxt.js build output 79 | .nuxt 80 | 81 | # vuepress build output 82 | .vuepress/dist 83 | 84 | # Serverless directories 85 | .serverless/ 86 | 87 | # FuseBox cache 88 | .fusebox/ 89 | 90 | # DynamoDB Local files 91 | .dynamodb/ 92 | 93 | # OS metadata 94 | .DS_Store 95 | Thumbs.db 96 | 97 | # Ignore built ts files 98 | __tests__/runner/* 99 | lib/**/* 100 | 101 | /t/* 102 | /*/t/* 103 | 104 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | lib/ 3 | node_modules/ -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 80, 3 | "tabWidth": 2, 4 | "useTabs": false, 5 | "semi": false, 6 | "singleQuote": true, 7 | "trailingComma": "none", 8 | "bracketSpacing": false, 9 | "arrowParens": "avoid", 10 | "parser": "typescript" 11 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020-2024 Yoichi Kawasaki and contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![action-setup-kube-tools Test](https://github.com/yokawasa/action-setup-kube-tools/actions/workflows/test.yml/badge.svg)](https://github.com/yokawasa/action-setup-kube-tools/actions/workflows/test.yml) 2 | 3 | # action-setup-kube-tools 4 | A GitHub Action that setup Kubernetes tools (kubectl, kustomize, helm, kubeconform, conftest, yq, rancher, tilt, skaffold, kube-score) and cache them on the runner. It is like a typescript version of [stefanprodan/kube-tools](https://github.com/stefanprodan/kube-tools) with no command input param, but as compared with [it](https://github.com/stefanprodan/kube-tools), it's **very fast** as it installs the tools asynchronously. 5 | 6 | ## Usage 7 | 8 | ### Inputs 9 | 10 | |Parameter|Required|Default Value|Description| 11 | |:--:|:--:|:--:|:--| 12 | |`fail-fast`|`false`|`true`| the action immediately fails when it fails to download (ie. due to a bad version) | 13 | |`arch-type`|`false`|`amd64`| The processor architecture type of the tool binary to setup. Supported types are only `amd64` and `arm64`. If a type other than the supported Types is specified, it will be treated as `amd64`.| 14 | |`setup-tools`|`false`|`""`|List of tool name to setup. By default, the action download and setup all supported Kubernetes tools. By specifying `setup-tools` you can choose which tools the action setup. Supported separator is `return` in multi-line string. Supported tools are `kubectl`, `kustomize`, `helm`, `helmv3`, `kubeval`, `conftest`, `yq`, `rancher`, `tilt`, `skaffold`, `kube-score`| 15 | |`kubectl`|`false`|`1.24.10`| kubectl version. kubectl vesion can be found [here](https://github.com/kubernetes/kubernetes/releases)| 16 | |`kustomize`|`false`|`5.0.0`| kustomize version. kustomize vesion can be found [here](https://github.com/kubernetes-sigs/kustomize/releases)| 17 | |`helm`|`false`|`3.11.1`| helm version. helm vesion can be found [here](https://github.com/helm/helm/releases)| 18 | |`kubeval`|`false`|`0.16.1`| kubeval version (must be **0.16.1+**). kubeval vesion can be found [here](https://github.com/instrumenta/kubeval/releases).
NOTE: this parameter is deprecating as `kubeval` is no longer maintained. A good replacement is [kubeconform](https://github.com/yannh/kubeconform). See also [this](https://github.com/instrumenta/kubeval) for more details.| 19 | |`kubeconform`|`false`|`0.5.0`| kubeconform version. kubeconform vesion can be found [here](https://github.com/yannh/kubeconform/releases)| 20 | |`conftest`|`false`|`0.39.0`| conftest version. conftest vesion can be found [here](https://github.com/open-policy-agent/conftest/releases)| 21 | |`yq`|`false`|`4.30.7`| yq version. yq vesion can be found [here](https://github.com/mikefarah/yq/releases/)| 22 | |`rancher`|`false`|`2.7.0`| Rancher CLI version. Rancher CLI vesion can be found [here](https://github.com/rancher/cli/releases)| 23 | |`tilt`|`false`|`0.31.2`| Tilt version. Tilt vesion can be found [here](https://github.com/tilt-dev/tilt/releases)| 24 | |`skaffold`|`false`|`2.1.0`| Skaffold version. Skaffold vesion can be found [here](https://github.com/GoogleContainerTools/skaffold/releases)| 25 | |`kube-score`|`false`|`1.16.1`| kube-score version. kube-score vesion can be found [here](https://github.com/zegl/kube-score/releases)| 26 | 27 | > - Supported Environments: Linux 28 | > - From v0.7.0, the action supports tool version 'v' prefix. Prior to v0.7.0, the action only accept the tool version without 'v' prefix but from v0.7.0 the action automatically add/remove the prefix as necessary 29 | > 30 | ### Outputs 31 | |Parameter|Description| 32 | |:--:|:--| 33 | |`kubectl-path`| kubectl command path if the action setup the tool, otherwise empty string | 34 | |`kustomize-path`| kustomize command path if the action setup the tool, otherwise empty string | 35 | |`helm-path`| helm command path if the action setup the tool, otherwise empty string | 36 | |`kubeval-path`| kubeval command path if the action setup the tool, otherwise empty string | 37 | |`kubeconform-path`| kubeconform command path if the action setup the tool, otherwise empty string | 38 | |`conftest-path`| conftest command path if the action setup the tool, otherwise empty string | 39 | |`yq-path`| yq command path if the action setup the tool, otherwise empty string | 40 | |`rancher-path`| rancher command path if the action setup the tool, otherwise empty string | 41 | |`tilt-path`| rancher command path if the action setup the tool, otherwise empty string | 42 | |`skaffold-path`| rancher command path if the action setup the tool, otherwise empty string | 43 | |`kube-score-path:`| rancher command path if the action setup the tool, otherwise empty string | 44 | 45 | ### Sample Workflow 46 | 47 | Specific versions for the commands can be setup by adding inputs parameters like this: 48 | 49 | ```yaml 50 | test: 51 | runs-on: ubuntu-latest 52 | steps: 53 | - uses: actions/checkout@v2 54 | - uses: yokawasa/action-setup-kube-tools@v0.11.2 55 | with: 56 | kubectl: '1.25' 57 | kustomize: '5.0.0' 58 | helm: '3.11.1' 59 | kubeconform: '0.5.0' 60 | conftest: '0.39.0' 61 | rancher: '2.7.0' 62 | tilt: '0.31.2' 63 | skaffold: '2.1.0' 64 | kube-score: '1.16.1' 65 | - run: | 66 | kubectl version --client 67 | kustomize version 68 | helm version 69 | kubeconform -v 70 | conftest --version 71 | yq --version 72 | rancher --version 73 | tilt version 74 | skaffold version 75 | kube-score version 76 | ``` 77 | 78 | Default versions for the commands will be setup if you don't give any inputs like this: 79 | 80 | ```yaml 81 | test: 82 | runs-on: ubuntu-latest 83 | steps: 84 | - uses: actions/checkout@v2 85 | - uses: yokawasa/action-setup-kube-tools@v0.11.2 86 | - run: | 87 | kubectl version --client 88 | kustomize version 89 | helm version 90 | kubeconform -v 91 | conftest --version 92 | yq --version 93 | rancher --version 94 | tilt version 95 | skaffold version 96 | kube-score version 97 | ``` 98 | 99 | By specifying setup-tools you can choose which tools the action setup. Supported separator is return in multi-line string like this 100 | 101 | ```yaml 102 | test: 103 | runs-on: ubuntu-latest 104 | steps: 105 | - uses: actions/checkout@v2 106 | - uses: yokawasa/action-setup-kube-tools@v0.11.2 107 | with: 108 | setup-tools: | 109 | kubectl 110 | helm 111 | kustomize 112 | skaffold 113 | kubectl: '1.25' 114 | helm: '3.11.1' 115 | kustomize: '5.0.0' 116 | skaffold: '2.1.0' 117 | - run: | 118 | kubectl version --client 119 | kustomize version 120 | helm version 121 | skaffold version 122 | ``` 123 | 124 | By specifying arch-type you can choose the processor architecture type of the tool binary to setup. Supported types are only `amd64`(default) and `arm64`. 125 | 126 | ```yaml 127 | test: 128 | steps: 129 | - uses: actions/checkout@v4 130 | - uses: yokawasa/action-setup-kube-tools@v0.11.2 131 | with: 132 | arch-type: 'arm64' 133 | setup-tools: | 134 | kubectl 135 | helm 136 | kustomize 137 | skaffold 138 | kubectl: '1.25' 139 | helm: '3.11.1' 140 | kustomize: '5.0.0' 141 | skaffold: '2.1.0' 142 | - run: | 143 | kubectl version --client 144 | kustomize version 145 | helm version 146 | skaffold version 147 | ``` 148 | 149 | 150 | ## Developing the action 151 | 152 | Install the dependencies 153 | ```bash 154 | npm install 155 | ``` 156 | 157 | Build the typescript and package it for distribution by running [ncc](https://github.com/zeit/ncc) 158 | ```bash 159 | npm run build && npm run format && npm run lint && npm run pack 160 | ``` 161 | 162 | Finally push the results 163 | ``` 164 | git add dist 165 | git commit -a -m "prod dependencies" 166 | git push origin releases/v0.11.2 167 | ``` 168 | 169 | ## References 170 | 171 | - https://kubernetes.io/releases/ 172 | - https://github.com/kubernetes-sigs/kustomize/releases 173 | - https://github.com/helm/helm/releases 174 | - https://helm.sh/docs/topics/version_skew/ 175 | - https://github.com/instrumenta/kubeval/releases 176 | - https://github.com/open-policy-agent/conftest/releases 177 | - https://github.com/mikefarah/yq/releases 178 | - https://github.com/rancher/cli/releases 179 | - https://github.com/tilt-dev/tilt/releases 180 | - https://github.com/GoogleContainerTools/skaffold/releases 181 | - https://github.com/zegl/kube-score/releases 182 | 183 | ## Contributing 184 | Bug reports and pull requests are welcome on GitHub at https://github.com/yokawasa/action-setup-kube-tools 185 | 186 | ## Changelog 187 | 188 | Please see the [list of releases](https://github.com/yokawasa/action-setup-kube-tools/releases) for information on changes between releases. 189 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: 'Setup Kubernetes Tools' 2 | description: 'Setup Kubernetes tools: kubectl, kustomize, helm, kubeconform, conftest, yq, rancher, tilt, skaffold, kube-score' 3 | author: 'Yoichi Kawasaki @yokawasa' 4 | inputs: 5 | fail-fast: 6 | required: false 7 | default: 'true' 8 | description: 'the action immediately fails when it fails to download (ie. due to a bad version)' 9 | arch-type: 10 | required: false 11 | default: 'amd64' 12 | description: 'The processor architecture type of the tool binary to setup. Supported types are only "amd64" and "arm64". If a type other than the supported Types is specified, it will be treated as "amd64"' 13 | setup-tools: 14 | required: false 15 | default: '' 16 | description: 'List of tool name to setup. By default, the action download and setup all supported Kubernetes tools. By specifying "setup-tools" you can choose which tools the action setup. Supported separator is return in multi-line string. Supported tools are "kubectl", "kustomize", "helm", "helmv3", "kubeval", "conftest", "yq", "rancher", "tilt", "skaffold", "kube-score"' 17 | kubectl: 18 | required: false 19 | default: '1.24.10' 20 | description: 'kubectl version' 21 | kustomize: 22 | required: false 23 | default: '5.0.0' 24 | description: 'kustomize version' 25 | helm: 26 | required: false 27 | default: '3.11.1' 28 | description: 'helm version' 29 | kubeval: 30 | required: false 31 | default: '0.16.1' 32 | description: 'kubeval version' 33 | kubeconform: 34 | required: false 35 | default: '0.5.0' 36 | description: 'kubeconform version' 37 | conftest: 38 | required: false 39 | default: '0.39.0' 40 | description: 'conftest version' 41 | yq: 42 | required: false 43 | default: '4.30.7' 44 | description: 'yq version' 45 | rancher: 46 | required: false 47 | default: '2.7.0' 48 | description: 'rancher cli version' 49 | tilt: 50 | required: false 51 | default: '0.31.2' 52 | description: 'tilt version' 53 | skaffold: 54 | required: false 55 | default: '2.1.0' 56 | description: 'skaffold version' 57 | kube-score: 58 | required: false 59 | default: '1.16.1' 60 | description: 'kube-score version' 61 | outputs: 62 | kubectl-path: 63 | description: 'kubectl command path if the action setup the tool, otherwise empty string' 64 | kustomize-path: 65 | description: 'kustomize command path if the action setup the tool, otherwise empty string' 66 | helm-path: 67 | description: 'helm command path if the action setup the tool, otherwise empty string' 68 | kubeval-path: 69 | description: 'kubeval command path if the action setup the tool, otherwise empty string' 70 | conftest-path: 71 | description: 'conftest command path if the action setup the tool, otherwise empty string' 72 | yq-path: 73 | description: 'yq command path if the action setup the tool, otherwise empty string' 74 | rancher-path: 75 | description: 'rancher cli command path if the action setup the tool, otherwise empty string' 76 | tilt-path: 77 | description: 'tilt command path if the action setup the tool, otherwise empty string' 78 | skaffold-path: 79 | description: 'skaffold command path if the action setup the tool, otherwise empty string' 80 | kube-score-path: 81 | description: 'kube-score command path if the action setup the tool, otherwise empty string' 82 | branding: 83 | icon: 'terminal' 84 | color: 'blue' 85 | runs: 86 | using: 'node20' 87 | main: 'dist/index.js' 88 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "action-setup-kube-tools", 3 | "version": "0.11.2", 4 | "private": true, 5 | "description": "Github Action that install Kubernetes tools (kubectl, kustomize, helm, kubeconform, conftest, yq, etc.) and cache them on the runner", 6 | "main": "lib/main.js", 7 | "scripts": { 8 | "build": "tsc", 9 | "format": "prettier --write **/*.ts", 10 | "format-check": "prettier --check **/*.ts", 11 | "lint": "eslint src/*.ts", 12 | "pack": "ncc build", 13 | "all": "npm run build && npm run format && npm run lint && npm run pack" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "git+https://github.com/yokawasa/action-setup-kube-tools.git" 18 | }, 19 | "keywords": [ 20 | "actions", 21 | "node", 22 | "setup", 23 | "kubernetes", 24 | "kubectl", 25 | "kustomize", 26 | "helm", 27 | "kubeval", 28 | "kubeconform", 29 | "conftest", 30 | "yq", 31 | "rancher", 32 | "tilt", 33 | "skaffold", 34 | "kube-score" 35 | ], 36 | "author": "Yoichi Kawasaki", 37 | "license": "MIT", 38 | "dependencies": { 39 | "@actions/core": "^1.10.0", 40 | "@actions/exec": "^1.1.1", 41 | "@actions/tool-cache": "^2.0.1" 42 | }, 43 | "devDependencies": { 44 | "@types/node": "^12.7.12", 45 | "@typescript-eslint/parser": "^2.8.0", 46 | "@vercel/ncc": "^0.34.0", 47 | "eslint": "^5.16.0", 48 | "eslint-plugin-github": "^2.0.0", 49 | "eslint-plugin-jest": "^22.21.0", 50 | "js-yaml": "^3.13.1", 51 | "prettier": "^1.19.1", 52 | "ts-jest": "^26.1.0", 53 | "typescript": "^3.9.10" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import * as os from 'os' 2 | import * as path from 'path' 3 | import * as util from 'util' 4 | import * as fs from 'fs' 5 | 6 | import * as toolCache from '@actions/tool-cache' 7 | import * as core from '@actions/core' 8 | 9 | const defaultProcessorArchType = 'amd64' 10 | 11 | const defaultKubectlVersion = '1.24.10' 12 | const defaultKustomizeVersion = '5.0.0' 13 | const defaultHelmVersion = '3.11.1' 14 | const defaultKubevalVersion = '0.16.1' 15 | const defaultKubeconformVersion = '0.5.0' 16 | const defaultConftestVersion = '0.39.0' 17 | const defaultYqVersion = '4.30.7' 18 | const defaultRancherVersion = '2.7.0' 19 | const defaultTiltVersion = '0.31.2' 20 | const defaultSkaffoldVersion = '2.1.0' 21 | const defaultKubeScoreVersion = '1.16.1' 22 | 23 | interface Tool { 24 | name: string 25 | defaultVersion: string 26 | isArchived: boolean 27 | supportArm: boolean 28 | commandPathInPackage: string 29 | } 30 | 31 | const Tools: Tool[] = [ 32 | { 33 | name: 'kubectl', 34 | defaultVersion: defaultKubectlVersion, 35 | isArchived: false, 36 | supportArm: true, 37 | commandPathInPackage: 'kubectl' 38 | }, 39 | { 40 | name: 'kustomize', 41 | defaultVersion: defaultKustomizeVersion, 42 | isArchived: true, 43 | supportArm: true, 44 | commandPathInPackage: 'kustomize' 45 | }, 46 | { 47 | name: 'helm', 48 | defaultVersion: defaultHelmVersion, 49 | isArchived: true, 50 | supportArm: true, 51 | commandPathInPackage: 'linux-{arch}/helm' 52 | }, 53 | { 54 | name: 'kubeval', 55 | defaultVersion: defaultKubevalVersion, 56 | isArchived: true, 57 | supportArm: false, 58 | commandPathInPackage: 'kubeval' 59 | }, 60 | { 61 | name: 'kubeconform', 62 | defaultVersion: defaultKubeconformVersion, 63 | isArchived: true, 64 | supportArm: true, 65 | commandPathInPackage: 'kubeconform' 66 | }, 67 | { 68 | name: 'conftest', 69 | defaultVersion: defaultConftestVersion, 70 | isArchived: true, 71 | supportArm: true, 72 | commandPathInPackage: 'conftest' 73 | }, 74 | { 75 | name: 'yq', 76 | defaultVersion: defaultYqVersion, 77 | isArchived: false, 78 | supportArm: true, 79 | commandPathInPackage: 'yq_linux_{arch}' 80 | }, 81 | { 82 | name: 'rancher', 83 | defaultVersion: defaultRancherVersion, 84 | isArchived: true, 85 | supportArm: true, 86 | commandPathInPackage: 'rancher-v{ver}/rancher' 87 | }, 88 | { 89 | name: 'tilt', 90 | defaultVersion: defaultTiltVersion, 91 | isArchived: true, 92 | supportArm: true, 93 | commandPathInPackage: 'tilt' 94 | }, 95 | { 96 | name: 'skaffold', 97 | defaultVersion: defaultSkaffoldVersion, 98 | isArchived: false, 99 | supportArm: true, 100 | commandPathInPackage: 'skaffold-linux-{arch}' 101 | }, 102 | { 103 | name: 'kube-score', 104 | defaultVersion: defaultKubeScoreVersion, 105 | isArchived: false, 106 | supportArm: true, 107 | commandPathInPackage: 'kube-score' 108 | } 109 | ] 110 | 111 | // Replace all {ver} and {arch} placeholders in the source format string with the actual values 112 | function replacePlaceholders( 113 | format: string, 114 | version: string, 115 | archType: string 116 | ): string { 117 | return format.replace(/{ver}|{arch}/g, match => { 118 | return match === '{ver}' ? version : archType 119 | }) 120 | } 121 | 122 | function getDownloadURL( 123 | commandName: string, 124 | version: string, 125 | archType: string 126 | ): string { 127 | let actualArchType = archType 128 | let urlFormat = '' 129 | switch (commandName) { 130 | case 'kubectl': 131 | urlFormat = 'https://dl.k8s.io/release/v{ver}/bin/linux/{arch}/kubectl' 132 | break 133 | case 'kustomize': 134 | urlFormat = 135 | 'https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize%2Fv{ver}/kustomize_v{ver}_linux_{arch}.tar.gz' 136 | break 137 | case 'helm': 138 | urlFormat = 'https://get.helm.sh/helm-v{ver}-linux-{arch}.tar.gz' 139 | break 140 | case 'kubeval': 141 | actualArchType = 'amd64' // kubeval only supports amd64 142 | urlFormat = 143 | 'https://github.com/instrumenta/kubeval/releases/download/v{ver}/kubeval-linux-{arch}.tar.gz' 144 | break 145 | case 'kubeconform': 146 | urlFormat = 147 | 'https://github.com/yannh/kubeconform/releases/download/v{ver}/kubeconform-linux-{arch}.tar.gz' 148 | break 149 | case 'conftest': 150 | actualArchType = archType === 'arm64' ? archType : 'x86_64' 151 | urlFormat = 152 | 'https://github.com/open-policy-agent/conftest/releases/download/v{ver}/conftest_{ver}_Linux_{arch}.tar.gz' 153 | break 154 | case 'yq': 155 | urlFormat = 156 | 'https://github.com/mikefarah/yq/releases/download/v{ver}/yq_linux_{arch}' 157 | break 158 | case 'rancher': 159 | actualArchType = archType === 'arm64' ? 'arm' : archType 160 | urlFormat = 161 | 'https://github.com/rancher/cli/releases/download/v{ver}/rancher-linux-{arch}-v{ver}.tar.gz' 162 | break 163 | case 'tilt': 164 | actualArchType = archType === 'arm64' ? archType : 'x86_64' 165 | urlFormat = 166 | 'https://github.com/tilt-dev/tilt/releases/download/v{ver}/tilt.{ver}.linux.{arch}.tar.gz' 167 | break 168 | case 'skaffold': 169 | urlFormat = 170 | 'https://github.com/GoogleContainerTools/skaffold/releases/download/v{ver}/skaffold-linux-{arch}' 171 | break 172 | case 'kube-score': 173 | urlFormat = 174 | 'https://github.com/zegl/kube-score/releases/download/v{ver}/kube-score_{ver}_linux_{arch}' 175 | break 176 | default: 177 | return '' 178 | } 179 | return replacePlaceholders(urlFormat, version, actualArchType) 180 | } 181 | 182 | async function downloadTool( 183 | version: string, 184 | archType: string, 185 | tool: Tool 186 | ): Promise { 187 | let cachedToolPath = toolCache.find(tool.name, version) 188 | let commandPathInPackage = tool.commandPathInPackage 189 | let commandPath = '' 190 | 191 | if (!cachedToolPath) { 192 | const downloadURL = getDownloadURL(tool.name, version, archType) 193 | 194 | try { 195 | const packagePath = await toolCache.downloadTool(downloadURL) 196 | 197 | if (tool.isArchived) { 198 | const extractTarBaseDirPath = util.format( 199 | '%s_%s', 200 | packagePath, 201 | tool.name 202 | ) 203 | 204 | fs.mkdirSync(extractTarBaseDirPath) 205 | 206 | const extractedDirPath = await toolCache.extractTar( 207 | packagePath, 208 | extractTarBaseDirPath 209 | ) 210 | 211 | commandPathInPackage = replacePlaceholders( 212 | commandPathInPackage, 213 | version, 214 | archType 215 | ) 216 | commandPath = util.format( 217 | '%s/%s', 218 | extractedDirPath, 219 | commandPathInPackage 220 | ) 221 | } else { 222 | commandPath = packagePath 223 | } 224 | } catch (exception) { 225 | throw new Error(`Download ${tool.name} Failed! (url: ${downloadURL})`) 226 | } 227 | cachedToolPath = await toolCache.cacheFile( 228 | commandPath, 229 | tool.name, 230 | tool.name, 231 | version 232 | ) 233 | // eslint-disable-next-line no-console 234 | console.log(`${tool.name} version '${version}' has been cached`) 235 | } else { 236 | // eslint-disable-next-line no-console 237 | console.log(`Found in cache: ${tool.name} version '${version}'`) 238 | } 239 | 240 | const cachedCommand = path.join(cachedToolPath, tool.name) 241 | fs.chmodSync(cachedCommand, '777') 242 | return cachedCommand 243 | } 244 | 245 | // eslint-disable-next-line @typescript-eslint/explicit-function-return-type 246 | async function run() { 247 | if (!os.type().match(/^Linux/)) { 248 | throw new Error('The action only support Linux OS!') 249 | } 250 | 251 | let failFast = true 252 | if (core.getInput('fail-fast', {required: false}).toLowerCase() === 'false') { 253 | failFast = false 254 | } 255 | 256 | let archType = defaultProcessorArchType 257 | if (core.getInput('arch-type', {required: false}).toLowerCase() === 'arm64') { 258 | archType = 'arm64' 259 | } 260 | 261 | let setupToolList: string[] = [] 262 | const setupTools = core.getInput('setup-tools', {required: false}).trim() 263 | if (setupTools) { 264 | setupToolList = setupTools 265 | .split('\n') 266 | .map(function(x) { 267 | return x.trim() 268 | }) 269 | .filter(x => x !== '') 270 | } 271 | 272 | // eslint-disable-next-line github/array-foreach 273 | Tools.forEach(async function(tool) { 274 | let toolPath = '' 275 | // By default, the action setup all supported Kubernetes tools, which mean 276 | // all tools can be setup when setuptools does not have any elements. 277 | if (setupToolList.length === 0 || setupToolList.includes(tool.name)) { 278 | let toolVersion = core 279 | .getInput(tool.name, {required: false}) 280 | .toLowerCase() 281 | if (toolVersion && toolVersion.startsWith('v')) { 282 | toolVersion = toolVersion.substr(1) 283 | } 284 | if (!toolVersion) { 285 | toolVersion = tool.defaultVersion 286 | } 287 | if (archType === 'arm64' && !tool.supportArm) { 288 | // eslint-disable-next-line no-console 289 | console.log( 290 | `The ${tool.name} does not support arm64 architecture, skip it` 291 | ) 292 | return 293 | } 294 | 295 | try { 296 | const cachedPath = await downloadTool(toolVersion, archType, tool) 297 | core.addPath(path.dirname(cachedPath)) 298 | toolPath = cachedPath 299 | } catch (exception) { 300 | if (failFast) { 301 | // eslint-disable-next-line no-console 302 | console.log(`Exiting immediately (fail fast) - [Reason] ${exception}`) 303 | process.exit(1) 304 | } 305 | } 306 | } 307 | core.setOutput(`${tool.name}-path`, toolPath) 308 | }) 309 | } 310 | 311 | run().catch(core.setFailed) 312 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "commonjs", 5 | "outDir": "./lib", 6 | "rootDir": "./src", 7 | "strict": true, 8 | "noImplicitAny": true, 9 | "esModuleInterop": true 10 | }, 11 | "exclude": ["node_modules", "**/*.test.ts"] 12 | } 13 | --------------------------------------------------------------------------------