├── examples ├── example1-basic.yaml └── example2-build-deploy-access.yaml ├── .prettierignore ├── .vscode └── settings.json ├── Makefile ├── .github ├── dependabot.yml └── workflows │ ├── auto-tag-latest.yml │ ├── build.yml │ ├── dry-run.yml │ ├── macos-test.yml │ ├── codeql-analysis.yml │ └── test.yml ├── eslint.config.mjs ├── .prettierrc.json ├── jest.config.js ├── src ├── start.ts ├── main.ts ├── inputs.ts ├── download.ts ├── none-driver.ts └── cache.ts ├── __tests__ ├── verify-no-unstaged-changes.sh └── download.test.ts ├── tsconfig.json ├── LICENSE ├── package.json ├── .gitignore ├── action.yml └── README.md /examples/example1-basic.yaml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | lib/ 3 | node_modules/ -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.exclude": { 3 | ".vscode": true, 4 | "node_modules": true 5 | } 6 | } -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | dep: 2 | npm install 3 | 4 | build: 5 | npm run build 6 | npm run pack 7 | all: 8 | npm ci 9 | npm run all 10 | # __tests__/verify-no-unstaged-changes.sh 11 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: 2 3 | updates: 4 | - package-ecosystem: "github-actions" 5 | directory: "/" 6 | schedule: 7 | interval: "weekly" 8 | - package-ecosystem: "npm" 9 | directory: "/" 10 | schedule: 11 | interval: "weekly" 12 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | 3 | import eslint from '@eslint/js'; 4 | import tseslint from 'typescript-eslint'; 5 | import rules from 'typescript-eslint'; 6 | 7 | export default tseslint.config( 8 | eslint.configs.recommended, 9 | tseslint.configs.recommended, 10 | ); -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 80, 3 | "tabWidth": 2, 4 | "useTabs": false, 5 | "semi": false, 6 | "singleQuote": true, 7 | "trailingComma": "es5", 8 | "bracketSpacing": false, 9 | "arrowParens": "always", 10 | "parser": "typescript" 11 | } 12 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | clearMocks: true, 3 | moduleFileExtensions: ['js', 'ts'], 4 | testEnvironment: 'node', 5 | testMatch: ['**/*.test.ts'], 6 | testRunner: 'jest-circus/runner', 7 | transform: { 8 | '^.+\\.ts$': 'ts-jest' 9 | }, 10 | verbose: true 11 | } -------------------------------------------------------------------------------- /.github/workflows/auto-tag-latest.yml: -------------------------------------------------------------------------------- 1 | name: "auto-tag-latest" 2 | permissions: 3 | contents: write 4 | on: 5 | release: 6 | types: [published] 7 | jobs: 8 | # move the "latest" and major version tags to the latest release, e.g., v1, to enable 9 | # consumers to subscribe to the latest reverse-compatible release 10 | auto-tag-latest: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: Actions-R-Us/actions-tagger@v2 14 | with: 15 | publish_latest_tag: true 16 | prefer_branch_releases: false 17 | -------------------------------------------------------------------------------- /src/start.ts: -------------------------------------------------------------------------------- 1 | import {exec} from '@actions/exec' 2 | import {getInput} from '@actions/core' 3 | 4 | import {restoreCaches, saveCaches} from './cache' 5 | import {setArgs} from './inputs' 6 | import {installNoneDriverDeps} from './none-driver' 7 | 8 | export const startMinikube = async (): Promise => { 9 | const args = ['start'] 10 | setArgs(args) 11 | const cacheHits = await restoreCaches() 12 | await installNoneDriverDeps() 13 | const installPath = getInput('install-path') 14 | await exec('minikube', args, {cwd: installPath}) 15 | await saveCaches(cacheHits) 16 | } 17 | -------------------------------------------------------------------------------- /__tests__/verify-no-unstaged-changes.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [[ "$(git status --porcelain)" != "" ]]; then 4 | echo ---------------------------------------- 5 | echo git status 6 | echo ---------------------------------------- 7 | git status 8 | echo ---------------------------------------- 9 | echo git diff 10 | echo ---------------------------------------- 11 | git diff 12 | echo ---------------------------------------- 13 | echo Troubleshooting 14 | echo ---------------------------------------- 15 | echo "::error::Unstaged changes detected. Locally try running: git clean -ffdx && npm ci && npm run all" 16 | exit 1 17 | fi 18 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import {getInput, setFailed} from '@actions/core' 2 | 3 | import {downloadMinikube} from './download' 4 | import {startMinikube} from './start' 5 | 6 | // main thing :) 7 | const run = async (): Promise => { 8 | try { 9 | let minikubeVersion = getInput('minikube-version').toLowerCase() 10 | minikubeVersion = minikubeVersion === 'stable' ? 'latest' : minikubeVersion 11 | const installPath = getInput('install-path') 12 | await downloadMinikube(minikubeVersion, installPath) 13 | if (getInput('start').toLowerCase() === 'true') { 14 | await startMinikube() 15 | } 16 | } catch (error) { 17 | if (error instanceof Error) { 18 | setFailed(error.message) 19 | } 20 | } 21 | } 22 | 23 | run() 24 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: "build" 2 | on: # rebuild any PRs and main branch changes 3 | pull_request: 4 | types: 5 | - opened 6 | - synchronize 7 | - reopened 8 | schedule: 9 | # every 4 hours 10 | - cron: "0 */4 * * *" 11 | push: 12 | branches: 13 | - master 14 | - 'releases/*' 15 | defaults: 16 | run: 17 | shell: bash # set bash as default shell 18 | jobs: 19 | build: # make sure build/ci work properly 20 | strategy: 21 | matrix: 22 | os: 23 | - ubuntu-latest 24 | - ubuntu-24.04-arm 25 | runs-on: ${{ matrix.os }} 26 | steps: 27 | - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 28 | - uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f 29 | with: 30 | node-version: 24 31 | - run: | 32 | npm ci 33 | npm run all 34 | __tests__/verify-no-unstaged-changes.sh 35 | -------------------------------------------------------------------------------- /examples/example2-build-deploy-access.yaml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | - push 4 | - pull_request 5 | jobs: 6 | job1: 7 | runs-on: ubuntu-latest 8 | name: build discover and deploy 9 | steps: 10 | - uses: actions/checkout@v2 11 | - name: Start minikube 12 | uses: medyagh/setup-minikube@latest 13 | # now you can run kubectl to see the pods in the cluster 14 | - name: Try the cluster ! 15 | run: kubectl get pods -A 16 | - name: Build image 17 | run: | 18 | export SHELL=/bin/bash 19 | eval $(minikube -p minikube docker-env) 20 | make build-image 21 | echo -n "verifying images:" 22 | docker images 23 | - name: Deploy to minikube 24 | run: 25 | kubectl apply -f deploy/deploy-minikube.yaml 26 | - name: Test service URLs 27 | run: | 28 | minikube service list 29 | minikube service discover --url 30 | echo -n "------------------opening the service------------------" 31 | curl $(minikube service discover --url)/version 32 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */ 4 | "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ 5 | "outDir": "./lib", /* Redirect output structure to the directory. */ 6 | "rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 7 | "strict": true, /* Enable all strict type-checking options. */ 8 | "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 9 | "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 10 | }, 11 | "exclude": ["node_modules", "**/*.test.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2018 GitHub, Inc. and contributors 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. -------------------------------------------------------------------------------- /src/inputs.ts: -------------------------------------------------------------------------------- 1 | import {getInput} from '@actions/core' 2 | 3 | export const setArgs = (args: string[]) => { 4 | const inputs: {key: string; flag: string}[] = [ 5 | {key: 'addons', flag: '--addons'}, 6 | {key: 'cni', flag: '--cni'}, 7 | {key: 'container-runtime', flag: '--container-runtime'}, 8 | {key: 'cpus', flag: '--cpus'}, 9 | {key: 'driver', flag: '--driver'}, 10 | {key: 'extra-config', flag: '--extra-config'}, 11 | {key: 'feature-gates', flag: '--feature-gates'}, 12 | {key: 'insecure-registry', flag: '--insecure-registry'}, 13 | {key: 'kubernetes-version', flag: '--kubernetes-version'}, 14 | {key: 'listen-address', flag: '--listen-address'}, 15 | {key: 'memory', flag: '--memory'}, 16 | {key: 'mount-path', flag: '--mount-string'}, 17 | {key: 'network-plugin', flag: '--network-plugin'}, 18 | {key: 'nodes', flag: '--nodes'}, 19 | {key: 'wait', flag: '--wait'}, 20 | ] 21 | inputs.forEach((input) => { 22 | const value = getInput(input.key) 23 | if (value !== '') { 24 | args.push(input.flag, value) 25 | } 26 | }) 27 | if (getInput('mount-path') !== '') { 28 | args.push('--mount') 29 | } 30 | const startArgs = getInput('start-args') 31 | if (startArgs !== '') { 32 | args.push(...startArgs.split(' ')) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "minikube-action", 3 | "version": "0.0.18", 4 | "private": true, 5 | "description": "start a kubernetes cluster in github actions", 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 | "test": "jest", 14 | "all": "npm run build && npm run format && npm run lint && npm run pack && npm test" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/medyagh/setup-minikube" 19 | }, 20 | "keywords": [ 21 | "minikube", 22 | "minikube CI", 23 | "test aginst kubernetes", 24 | "test kubernetes", 25 | "kuberentes CI", 26 | "kubernetes", 27 | "kubernetes cluster", 28 | "github", 29 | "actions" 30 | ], 31 | "author": "medyagh", 32 | "license": "MIT", 33 | "dependencies": { 34 | "@actions/cache": "^4.0.3", 35 | "@actions/core": "^1.11.1", 36 | "@actions/exec": "^1.1.1", 37 | "@actions/tool-cache": "^2.0.2" 38 | }, 39 | "devDependencies": { 40 | "@types/jest": "^30.0.0", 41 | "@types/node": "^24.5.2", 42 | "@typescript-eslint/eslint-plugin": "^8.37.0", 43 | "@typescript-eslint/parser": "^8.38.0", 44 | "@vercel/ncc": "^0.38.3", 45 | "eslint": "^9.39.2", 46 | "eslint-config-google": "^0.14.0", 47 | "eslint-plugin-github": "^6.0.0", 48 | "eslint-plugin-jest": "^29.0.1", 49 | "jest": "^30.0.5", 50 | "jest-circus": "^30.0.5", 51 | "js-yaml": "^4.1.1", 52 | "prettier": "^3.6.2", 53 | "ts-jest": "^29.4.6", 54 | "typescript": "^5.9.3" 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /.github/workflows/dry-run.yml: -------------------------------------------------------------------------------- 1 | name: "dry-run" 2 | on: 3 | pull_request: 4 | types: 5 | - opened 6 | - synchronize 7 | - reopened 8 | schedule: 9 | - cron: "0 */4 * * *" 10 | push: 11 | branches: 12 | - master 13 | - 'releases/*' 14 | defaults: 15 | run: 16 | shell: bash 17 | concurrency: 18 | group: dry-run-${{ github.event.pull_request.number || github.ref }} 19 | cancel-in-progress: true 20 | jobs: 21 | dry-run: 22 | strategy: 23 | fail-fast: false 24 | matrix: 25 | os: 26 | - ubuntu-24.04 27 | - ubuntu-22.04 28 | - ubuntu-24.04-arm 29 | - macos-latest 30 | - windows-latest 31 | runs-on: ${{ matrix.os }} 32 | steps: 33 | - id: info-block 34 | uses: medyagh/info-block@main 35 | - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 36 | - name: Install Docker CLI (macOS only) 37 | if: runner.os == 'macOS' 38 | run: | 39 | brew update 40 | brew install docker 41 | - name: install vfkit and tools needed 42 | if: runner.os == 'macOS' 43 | shell: bash 44 | run: | 45 | brew update 46 | brew install vfkit 47 | curl -fsSL https://github.com/minikube-machine/vmnet-helper/releases/latest/download/install.sh | sudo VMNET_INTERACTIVE=0 bash 48 | fw=/usr/libexec/ApplicationFirewall/socketfilterfw 49 | sudo $fw --remove /usr/libexec/bootpd 50 | sudo $fw --add /usr/libexec/bootpd 51 | sudo $fw --unblock /usr/libexec/bootpd 52 | - uses: ./ 53 | with: 54 | start-args: --download-only 55 | - uses: ./ 56 | with: 57 | start-args: --dry-run 58 | -------------------------------------------------------------------------------- /.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/**/* -------------------------------------------------------------------------------- /src/download.ts: -------------------------------------------------------------------------------- 1 | import {addPath} from '@actions/core' 2 | import {exec} from '@actions/exec' 3 | import {mkdirP, cp, rmRF} from '@actions/io' 4 | import {downloadTool} from '@actions/tool-cache' 5 | import {arch, homedir, platform as getPlatform} from 'os' 6 | import {join} from 'path' 7 | 8 | export const getDownloadURL = (version: string): string => { 9 | const osPlat = getPlatform() 10 | const osArch = getMinikubeArch() 11 | const platform = osPlat === 'win32' ? 'windows' : osPlat 12 | const suffix = osPlat === 'win32' ? '.exe' : '' 13 | switch (version) { 14 | case 'latest': 15 | return `https://github.com/kubernetes/minikube/releases/latest/download/minikube-${platform}-${osArch}${suffix}` 16 | case 'head': 17 | return `https://storage.googleapis.com/minikube-builds/master/minikube-${platform}-${osArch}${suffix}` 18 | default: 19 | return `https://github.com/kubernetes/minikube/releases/download/v${version}/minikube-${platform}-${osArch}${suffix}` 20 | } 21 | } 22 | 23 | const getMinikubeArch = (): string => { 24 | switch (arch()) { 25 | case 'x64': 26 | return 'amd64' 27 | break 28 | case 'arm64': 29 | return 'arm64' 30 | break 31 | case 'arm': 32 | return 'arm' 33 | break 34 | case 's390x': 35 | return 's390x' 36 | break 37 | case 'ppc64': 38 | return 'ppc64le' 39 | break 40 | default: 41 | throw new Error( 42 | `Machine is of arch ${arch()}, which isn't supported by minikube.` 43 | ) 44 | } 45 | } 46 | 47 | export const downloadMinikube = async ( 48 | version: string, 49 | installPath?: string 50 | ): Promise => { 51 | const url = getDownloadURL(version) 52 | const downloadPath = await downloadTool(url) 53 | if (!installPath) { 54 | installPath = join(homedir(), 'bin') 55 | } 56 | await mkdirP(installPath) 57 | await exec('chmod', ['+x', downloadPath]) 58 | await cp(downloadPath, join(installPath, 'minikube')) 59 | await rmRF(downloadPath) 60 | addPath(installPath) 61 | } 62 | -------------------------------------------------------------------------------- /.github/workflows/macos-test.yml: -------------------------------------------------------------------------------- 1 | name: "macos-test (flaky)" 2 | on: # rebuild any PRs and main branch changes 3 | pull_request: 4 | types: 5 | - opened 6 | - synchronize 7 | - reopened 8 | schedule: 9 | # every 4 hours 10 | - cron: "0 */4 * * *" 11 | push: 12 | branches: 13 | - master 14 | - 'releases/*' 15 | defaults: 16 | run: 17 | shell: bash # set bash as default shell 18 | concurrency: 19 | group: macos-test-${{ github.event.pull_request.number || github.ref }} 20 | cancel-in-progress: true 21 | jobs: 22 | # test-qemu-driver-start-args-verbose-HEAD: 23 | # runs-on: macos-latest 24 | # steps: 25 | # - id: info-block 26 | # uses: medyagh/info-block@main 27 | # - name: install qemu and tools needed 28 | # shell: bash 29 | # run: | 30 | # brew update 31 | # brew install qemu socket_vmnet 32 | # HOMEBREW=$(which brew) && sudo ${HOMEBREW} services start socket_vmnet 33 | # fw=/usr/libexec/ApplicationFirewall/socketfilterfw 34 | # sudo $fw --remove /usr/libexec/bootpd 35 | # sudo $fw --add /usr/libexec/bootpd 36 | # sudo $fw --unblock /usr/libexec/bootpd 37 | # - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 38 | # - uses: ./ 39 | # with: 40 | # driver: qemu 41 | # start-args: --memory=4gb --alsologtostderr 42 | # minikube-version: HEAD 43 | # - run: | 44 | # minikube profile list 45 | # minikube ssh -- ls -lah 46 | test-vfkit-driver-macos-HEAD: 47 | runs-on: macos-latest 48 | steps: 49 | - id: info-block 50 | uses: medyagh/info-block@main 51 | - name: install vfkit and tools needed 52 | shell: bash 53 | run: | 54 | brew update 55 | brew install vfkit 56 | curl -fsSL https://github.com/minikube-machine/vmnet-helper/releases/latest/download/install.sh | sudo VMNET_INTERACTIVE=0 bash 57 | fw=/usr/libexec/ApplicationFirewall/socketfilterfw 58 | sudo $fw --remove /usr/libexec/bootpd 59 | sudo $fw --add /usr/libexec/bootpd 60 | sudo $fw --unblock /usr/libexec/bootpd 61 | - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 62 | - uses: ./ 63 | with: 64 | driver: vfkit 65 | start-args: --memory=4gb --network vmnet-shared --alsologtostderr --no-kubernetes 66 | minikube-version: HEAD 67 | - run: | 68 | minikube profile list 69 | minikube ssh -- ls -lah 70 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ master ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ master ] 20 | schedule: 21 | - cron: '25 18 * * 0' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'javascript' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 37 | # Learn more about CodeQL language support at https://git.io/codeql-language-support 38 | 39 | steps: 40 | - name: Checkout repository 41 | uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 42 | 43 | # Initializes the CodeQL tools for scanning. 44 | - name: Initialize CodeQL 45 | uses: github/codeql-action/init@c719ec0b337ad8a0f3336d778d54e0f30df35713 46 | with: 47 | languages: ${{ matrix.language }} 48 | # If you wish to specify custom queries, you can do so here or in a config file. 49 | # By default, queries listed here will override any specified in a config file. 50 | # Prefix the list here with "+" to use these queries and those in the config file. 51 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 52 | 53 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 54 | # If this step fails, then you should remove it and run the build manually (see below) 55 | - name: Autobuild 56 | uses: github/codeql-action/autobuild@c719ec0b337ad8a0f3336d778d54e0f30df35713 57 | 58 | # ℹ️ Command-line programs to run using the OS shell. 59 | # 📚 https://git.io/JvXDl 60 | 61 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 62 | # and modify them (or add more) to build your code if your project 63 | # uses a compiled language 64 | 65 | #- run: | 66 | # make bootstrap 67 | # make release 68 | 69 | - name: Perform CodeQL Analysis 70 | uses: github/codeql-action/analyze@c719ec0b337ad8a0f3336d778d54e0f30df35713 71 | -------------------------------------------------------------------------------- /src/none-driver.ts: -------------------------------------------------------------------------------- 1 | import {getInput} from '@actions/core' 2 | import {exec} from '@actions/exec' 3 | import {downloadTool} from '@actions/tool-cache' 4 | 5 | // TODO: automate updating these versions 6 | const cniPluginsVersion = 'v1.6.2' 7 | const criDockerVersion = 'v0.4.0' 8 | const crictlVersion = 'v1.34.0' 9 | 10 | const installCniPlugins = async (): Promise => { 11 | const arch = process.arch === 'arm64' ? 'arm64' : 'amd64' 12 | const cniPluginsURL = `https://github.com/containernetworking/plugins/releases/download/${cniPluginsVersion}/cni-plugins-linux-${arch}-${cniPluginsVersion}.tgz` 13 | const cniPluginsDownload = downloadTool(cniPluginsURL) 14 | await exec('sudo', ['mkdir', '-p', '/opt/cni/bin']) 15 | await exec('sudo', [ 16 | 'tar', 17 | 'zxvf', 18 | await cniPluginsDownload, 19 | '-C', 20 | '/opt/cni/bin', 21 | ]) 22 | } 23 | 24 | const installCriDocker = async (): Promise => { 25 | const arch = process.arch === 'arm64' ? 'arm64' : 'amd64' 26 | const version = criDockerVersion.replace(/^v/, '') 27 | const tgzURL = `https://github.com/Mirantis/cri-dockerd/releases/download/${criDockerVersion}/cri-dockerd-${version}.${arch}.tgz` 28 | const serviceURL = `https://raw.githubusercontent.com/Mirantis/cri-dockerd/${criDockerVersion}/packaging/systemd/cri-docker.service` 29 | const socketURL = `https://raw.githubusercontent.com/Mirantis/cri-dockerd/${criDockerVersion}/packaging/systemd/cri-docker.socket` 30 | 31 | const criDockerArchive = downloadTool(tgzURL) 32 | const criDockerService = downloadTool(serviceURL) 33 | const criDockerSocket = downloadTool(socketURL) 34 | const extractDir = `/tmp/cri-dockerd-${arch}` 35 | 36 | await exec('mkdir', ['-p', extractDir]) 37 | await exec('tar', ['zxvf', await criDockerArchive, '-C', extractDir]) 38 | await exec('sudo', [ 39 | 'mv', 40 | `${extractDir}/cri-dockerd/cri-dockerd`, 41 | '/usr/bin/cri-dockerd', 42 | ]) 43 | await exec('sudo', [ 44 | 'mv', 45 | await criDockerSocket, 46 | '/usr/lib/systemd/system/cri-docker.socket', 47 | ]) 48 | await exec('sudo', [ 49 | 'mv', 50 | await criDockerService, 51 | '/usr/lib/systemd/system/cri-docker.service', 52 | ]) 53 | await exec('sudo', ['chmod', '+x', '/usr/bin/cri-dockerd']) 54 | } 55 | 56 | const installConntrackSocatCriDocker = async (): Promise => { 57 | await exec('sudo', ['apt-get', 'update', '-qq']) 58 | await exec('sudo', ['apt-get', '-qq', '-y', 'install', 'conntrack', 'socat']) 59 | // Install cri-docker after dependency packages 60 | await installCriDocker() 61 | } 62 | 63 | const installCrictl = async (): Promise => { 64 | const arch = process.arch === 'arm64' ? 'arm64' : 'amd64' 65 | const crictlURL = `https://github.com/kubernetes-sigs/cri-tools/releases/download/${crictlVersion}/crictl-${crictlVersion}-linux-${arch}.tar.gz` 66 | const crictlDownload = downloadTool(crictlURL) 67 | await exec('sudo', [ 68 | 'tar', 69 | 'zxvf', 70 | await crictlDownload, 71 | '-C', 72 | '/usr/local/bin', 73 | ]) 74 | } 75 | 76 | const makeCniDirectoryReadable = async (): Promise => { 77 | // created by podman package with 700 root:root 78 | await exec('sudo', ['chmod', '755', '/etc/cni/net.d']) 79 | } 80 | 81 | export const installNoneDriverDeps = async (): Promise => { 82 | const driver = getInput('driver').toLowerCase() 83 | if (driver !== 'none') { 84 | return 85 | } 86 | await Promise.all([ 87 | installCniPlugins(), 88 | installConntrackSocatCriDocker(), 89 | installCrictl(), 90 | makeCniDirectoryReadable(), 91 | ]) 92 | } 93 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: 'setup-minikube' 2 | description: 'test your app against real Kubernetes.' 3 | author: 'Medya Gh' 4 | branding: 5 | icon: 'box' 6 | color: 'blue' 7 | inputs: 8 | start: 9 | description: 'Start minikube after install is complete' 10 | required: false 11 | default: true 12 | cache: 13 | description: 'Cache ISO, kicbase, and preloads to speed up starting minikube' 14 | required: false 15 | default: true 16 | minikube-version: 17 | description: 'Choose a specific version of minikube, "latest" for the latest stable build, or "HEAD" for the latest development build' 18 | required: false 19 | default: 'latest' 20 | driver: 21 | description: 'Choose a specific driver, one of: docker, none, podman, virtualbox, parallels, vmwarefusion, hyperkit, vmware, ssh' 22 | required: false 23 | default: '' 24 | container-runtime: 25 | description: 'Choose a specific container-runtime, one of: docker, containerd, cri-o' 26 | required: false 27 | default: '' 28 | kubernetes-version: 29 | description: 'Choose a specific version of Kubernetes, "stable" for the latest stable build, or "latest" for the latest development build' 30 | required: false 31 | default: '' 32 | cpus: 33 | description: 'Number of CPUs allocated to Kubernetes. Use "max" to use the maximum number of CPUs.' 34 | required: false 35 | default: '' 36 | memory: 37 | description: 'Amount of RAM to allocate to Kubernetes (format: [], where unit = b, k, m or g). Use "max" to use the maximum amount of memory.' 38 | required: false 39 | default: '' 40 | network-plugin: 41 | description: 'Kubelet network plug-in to use (default: auto). Valid options: cni' 42 | required: false 43 | default: '' 44 | cni: 45 | description: 'CNI plug-in to use. Valid options: auto, bridge, calico, cilium, flannel, kindnet, or path to a CNI manifest' 46 | required: false 47 | default: '' 48 | addons: 49 | description: 'Choose optional addons to install. Valid options: ingress, gcp-auth, registry ...' 50 | required: false 51 | default: '' 52 | extra-config: 53 | description: 'Extra configuration (--extra-config) to pass into "minikube start".' 54 | required: false 55 | default: '' 56 | feature-gates: 57 | description: 'Enabling feature gates (--feature-gates) to pass into "minikube start" in a format it accepts it.' 58 | required: false 59 | default: '' 60 | listen-address: 61 | description: 'IP Address to use to expose ports (docker and podman driver only)' 62 | required: false 63 | default: '' 64 | mount-path: 65 | description: 'Mount the source directory from your host into the target directory inside the cluster (format: :)' 66 | required: false 67 | default: '' 68 | nodes: 69 | description: 'The total number of nodes to spin up.' 70 | required: false 71 | default: '' 72 | install-path: 73 | description: 'Path where the executables (minikube) will get installed. Useful when having multiple self-hosted runners on one machine.' 74 | required: false 75 | default: '' 76 | wait: 77 | description: 'comma separated list of Kubernetes components to verify and wait for after starting a cluster. defaults to "apiserver,system_pods", available options: "apiserver,system_pods,default_sa,apps_running,node_ready,kubelet". Other acceptable values are "all" or "none", "true" and "false"' 78 | required: false 79 | default: 'all' 80 | insecure-registry: 81 | description: 'Enable insecure communication with the given registries' 82 | required: false 83 | default: '' 84 | start-args: 85 | description: 'Any flags you would regularly pass into minikube via CLI, seperated by space' 86 | required: false 87 | default: '' 88 | runs: 89 | using: 'node24' 90 | main: 'dist/index.js' 91 | -------------------------------------------------------------------------------- /src/cache.ts: -------------------------------------------------------------------------------- 1 | import { 2 | restoreCache as restoreCacheAction, 3 | saveCache as saveCacheAction, 4 | } from '@actions/cache' 5 | import {info, getInput as getInputAction} from '@actions/core' 6 | import {exec} from '@actions/exec' 7 | import {existsSync} from 'fs' 8 | import {arch, homedir} from 'os' 9 | import {join} from 'path' 10 | 11 | // Catch and log any unhandled exceptions. These exceptions can leak out of the 12 | // uploadChunk method in @actions/toolkit when a failed upload closes the file 13 | // descriptor causing any in-process reads to throw an uncaught exception. 14 | // Instead of failing this action, just warn. 15 | process.on('uncaughtException', (e) => { 16 | info(`[warning]${e.message}`) 17 | }) 18 | 19 | type CacheHits = { 20 | iso: boolean 21 | kic: boolean 22 | preload: boolean 23 | } 24 | 25 | export const restoreCaches = async (): Promise => { 26 | const cacheHits: CacheHits = {iso: true, kic: true, preload: true} 27 | if (!useCache()) { 28 | return cacheHits 29 | } 30 | const minikubeVersion = await getMinikubeVersion() 31 | const isoCacheKey = restoreCache('iso', minikubeVersion) 32 | const kicCacheKey = restoreCache('kic', minikubeVersion) 33 | const preloadCacheKey = restoreCache('preloaded-tarball', minikubeVersion) 34 | cacheHits.iso = typeof (await isoCacheKey) !== 'undefined' 35 | cacheHits.kic = typeof (await kicCacheKey) !== 'undefined' 36 | cacheHits.preload = typeof (await preloadCacheKey) !== 'undefined' 37 | return cacheHits 38 | } 39 | 40 | export const getMinikubeVersion = async (): Promise => { 41 | let version = '' 42 | // const options: any = {} 43 | const options: {listeners: {stdout: (data: Buffer) => void}} = { 44 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 45 | listeners: {stdout: (data: Buffer) => void {}}, 46 | } 47 | 48 | options.listeners = { 49 | stdout: (data: Buffer) => { 50 | version += data.toString() 51 | }, 52 | } 53 | await exec('minikube', ['version', '--short'], options) 54 | return version.trim() 55 | } 56 | 57 | export const saveCaches = async (cacheHits: CacheHits): Promise => { 58 | if (!useCache()) { 59 | return 60 | } 61 | const minikubeVersion = await getMinikubeVersion() 62 | await Promise.all([ 63 | saveCache('iso', cacheHits.iso, minikubeVersion), 64 | saveCache('kic', cacheHits.kic, minikubeVersion), 65 | saveCache('preloaded-tarball', cacheHits.preload, minikubeVersion), 66 | ]) 67 | } 68 | 69 | const restoreCache = async ( 70 | name: string, 71 | minikubeVersion: string 72 | ): Promise => { 73 | return restoreCacheAction( 74 | getCachePaths(name), 75 | getCacheKey(name, minikubeVersion) 76 | ) 77 | } 78 | 79 | const saveCache = async ( 80 | name: string, 81 | cacheHit: boolean, 82 | minikubeVersion: string 83 | ): Promise => { 84 | if (cacheHit) { 85 | return 86 | } 87 | const cachePaths = getCachePaths(name) 88 | if (!existsSync(cachePaths[0])) { 89 | return 90 | } 91 | try { 92 | await saveCacheAction(cachePaths, getCacheKey(name, minikubeVersion)) 93 | } catch (error) { 94 | console.log(name + error) 95 | } 96 | } 97 | 98 | const getCachePaths = (folderName: string): string[] => { 99 | return [join(homedir(), '.minikube', 'cache', folderName)] 100 | } 101 | 102 | const getCacheKey = (name: string, minikubeVersion: string): string => { 103 | let cacheKey = `${name}-${minikubeVersion}-${arch()}` 104 | if (name === 'preloaded-tarball') { 105 | const kubernetesVersion = getInput('kubernetes-version', 'stable') 106 | const containerRuntime = getInput('container-runtime', 'docker') 107 | cacheKey += `-${kubernetesVersion}-${containerRuntime}` 108 | } 109 | return cacheKey 110 | } 111 | 112 | // getInput gets the specified value from the users workflow yaml 113 | // if the value is empty the default value it returned 114 | const getInput = (name: string, defaultValue: string): string => { 115 | const value = getInputAction(name).toLowerCase() 116 | return value !== '' ? value : defaultValue 117 | } 118 | 119 | const useCache = (): boolean => getInputAction('cache').toLowerCase() === 'true' 120 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: "ci" 2 | on: # rebuild any PRs and main branch changes 3 | pull_request: 4 | types: 5 | - opened 6 | - synchronize 7 | - reopened 8 | schedule: 9 | # every 4 hours 10 | - cron: "0 */4 * * *" 11 | push: 12 | branches: 13 | - master 14 | - 'releases/*' 15 | defaults: 16 | run: 17 | shell: bash # set bash as default shell 18 | jobs: 19 | test: 20 | strategy: 21 | fail-fast: false 22 | matrix: 23 | os: 24 | - ubuntu-latest 25 | - ubuntu-24.04-arm 26 | scenario: 27 | - ingress 28 | - extra-options 29 | - nodes 30 | - insecure-registry 31 | - feature-gates 32 | - none-driver 33 | - podman 34 | - minikube-version-HEAD 35 | include: 36 | - scenario: ingress 37 | addons: ingress 38 | - scenario: extra-options 39 | extra_config: kubelet.max-pods=10 40 | - scenario: nodes 41 | nodes: 2 42 | - scenario: insecure-registry 43 | insecure_registry: 192.168.0.0/16 44 | - scenario: feature-gates 45 | feature_gates: SidecarContainers=true 46 | kubernetes_version: 1.31.0 47 | container_runtime: containerd 48 | - scenario: none-driver 49 | driver: none 50 | start_args: --alsologtostderr 51 | - scenario: podman 52 | driver: podman 53 | - scenario: minikube-version-HEAD 54 | minikube_version: HEAD 55 | runs-on: ${{ matrix.os }} 56 | steps: 57 | - id: info-block 58 | uses: medyagh/info-block@main 59 | - name: Install Podman 60 | if: matrix.scenario == 'podman' 61 | run: | 62 | lsb_release -a 63 | sudo apt update 64 | sudo apt install -y podman 65 | echo "--------------------------" 66 | podman version || true 67 | echo "--------------------------" 68 | podman info || true 69 | echo "--------------------------" 70 | podman system df || true 71 | echo "--------------------------" 72 | podman system info --format='{{json .}}'|| true 73 | echo "--------------------------" 74 | podman ps || true 75 | echo "--------------------------" 76 | - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 77 | - uses: ./ 78 | with: 79 | addons: ${{ matrix.addons || '' }} 80 | extra-config: ${{ matrix.extra_config || '' }} 81 | nodes: ${{ matrix.nodes || '' }} 82 | insecure-registry: ${{ matrix.insecure_registry || '' }} 83 | feature-gates: ${{ matrix.feature_gates || '' }} 84 | kubernetes-version: ${{ matrix.kubernetes_version || '' }} 85 | container-runtime: ${{ matrix.container_runtime || '' }} 86 | driver: ${{ matrix.driver || '' }} 87 | start-args: ${{ matrix.start_args || '' }} 88 | - name: Verify ingress addon enabled 89 | if: matrix.scenario == 'ingress' 90 | run: | 91 | minikube addons list | grep 'ingress ' | grep enabled 92 | - name: Verify max pods extra config 93 | if: matrix.scenario == 'extra-options' 94 | run: | 95 | cat ~/.minikube/profiles/minikube/config.json | jq '.KubernetesConfig.ExtraOptions[0].Key' | grep max-pods 96 | - name: Verify node count 97 | if: matrix.scenario == 'nodes' 98 | run: | 99 | if [ $(kubectl get nodes --no-headers | wc -l) -eq 2 ]; then 100 | echo "The cluster has exactly 2 nodes." 101 | else 102 | echo "::error::The cluster does not have 2 nodes." 103 | exit 1 104 | fi 105 | - name: Verify insecure registry configured 106 | if: matrix.scenario == 'insecure-registry' 107 | run: | 108 | minikube ssh cat /lib/systemd/system/docker.service | grep 192.168.0.0/16 109 | - name: Verify feature gates enabled 110 | if: matrix.scenario == 'feature-gates' 111 | run: | 112 | jq -e '(.KubernetesConfig.FeatureGates // "") | tostring | contains("SidecarContainers=true")' ~/.minikube/profiles/minikube/config.json 113 | - name: Wait for CoreDNS rollout 114 | if: matrix.scenario == 'none-driver' || matrix.scenario == 'podman' 115 | run: | 116 | kubectl --namespace=kube-system rollout status deployment/coredns --timeout=60s --watch 117 | - name: Verify DNS resolution 118 | if: matrix.scenario == 'none-driver' || matrix.scenario == 'podman' 119 | run: | 120 | kubectl run \ 121 | --attach \ 122 | --image=docker.io/busybox \ 123 | --restart=Never \ 124 | --rm \ 125 | nslookup \ 126 | -- \ 127 | nslookup kubernetes.default.svc.cluster.local 128 | -------------------------------------------------------------------------------- /__tests__/download.test.ts: -------------------------------------------------------------------------------- 1 | import os from 'os' 2 | 3 | import {getDownloadURL} from '../src/download' 4 | 5 | jest.mock('os') 6 | const mockedOS = jest.mocked(os) 7 | 8 | test('getDownloadURL Linux', () => { 9 | const tests = [ 10 | { 11 | arch: 'x64', 12 | version: 'latest', 13 | expected: 14 | 'https://github.com/kubernetes/minikube/releases/latest/download/minikube-linux-amd64', 15 | }, 16 | { 17 | arch: 'arm64', 18 | version: 'latest', 19 | expected: 20 | 'https://github.com/kubernetes/minikube/releases/latest/download/minikube-linux-arm64', 21 | }, 22 | { 23 | arch: 'arm', 24 | version: 'latest', 25 | expected: 26 | 'https://github.com/kubernetes/minikube/releases/latest/download/minikube-linux-arm', 27 | }, 28 | { 29 | arch: 's390x', 30 | version: 'latest', 31 | expected: 32 | 'https://github.com/kubernetes/minikube/releases/latest/download/minikube-linux-s390x', 33 | }, 34 | { 35 | arch: 'ppc64', 36 | version: 'latest', 37 | expected: 38 | 'https://github.com/kubernetes/minikube/releases/latest/download/minikube-linux-ppc64le', 39 | }, 40 | { 41 | arch: 'x64', 42 | version: 'head', 43 | expected: 44 | 'https://storage.googleapis.com/minikube-builds/master/minikube-linux-amd64', 45 | }, 46 | { 47 | arch: 'arm64', 48 | version: 'head', 49 | expected: 50 | 'https://storage.googleapis.com/minikube-builds/master/minikube-linux-arm64', 51 | }, 52 | { 53 | arch: 'arm', 54 | version: 'head', 55 | expected: 56 | 'https://storage.googleapis.com/minikube-builds/master/minikube-linux-arm', 57 | }, 58 | { 59 | arch: 's390x', 60 | version: 'head', 61 | expected: 62 | 'https://storage.googleapis.com/minikube-builds/master/minikube-linux-s390x', 63 | }, 64 | { 65 | arch: 'ppc64', 66 | version: 'head', 67 | expected: 68 | 'https://storage.googleapis.com/minikube-builds/master/minikube-linux-ppc64le', 69 | }, 70 | { 71 | arch: 'x64', 72 | version: '1.28.0', 73 | expected: 74 | 'https://github.com/kubernetes/minikube/releases/download/v1.28.0/minikube-linux-amd64', 75 | }, 76 | { 77 | arch: 'arm64', 78 | version: '1.28.0', 79 | expected: 80 | 'https://github.com/kubernetes/minikube/releases/download/v1.28.0/minikube-linux-arm64', 81 | }, 82 | { 83 | arch: 'arm', 84 | version: '1.28.0', 85 | expected: 86 | 'https://github.com/kubernetes/minikube/releases/download/v1.28.0/minikube-linux-arm', 87 | }, 88 | { 89 | arch: 's390x', 90 | version: '1.28.0', 91 | expected: 92 | 'https://github.com/kubernetes/minikube/releases/download/v1.28.0/minikube-linux-s390x', 93 | }, 94 | { 95 | arch: 'ppc64', 96 | version: '1.28.0', 97 | expected: 98 | 'https://github.com/kubernetes/minikube/releases/download/v1.28.0/minikube-linux-ppc64le', 99 | }, 100 | ] 101 | 102 | for (const tc of tests) { 103 | mockedOS.arch.mockReturnValue(tc.arch as NodeJS.Architecture) 104 | mockedOS.platform.mockReturnValue('linux') 105 | 106 | const url = getDownloadURL(tc.version) 107 | 108 | expect(url).toBe(tc.expected) 109 | } 110 | }) 111 | 112 | test('getDownloadURL macOS', () => { 113 | const tests = [ 114 | { 115 | arch: 'x64', 116 | version: 'latest', 117 | expected: 118 | 'https://github.com/kubernetes/minikube/releases/latest/download/minikube-darwin-amd64', 119 | }, 120 | { 121 | arch: 'arm64', 122 | version: 'latest', 123 | expected: 124 | 'https://github.com/kubernetes/minikube/releases/latest/download/minikube-darwin-arm64', 125 | }, 126 | { 127 | arch: 'x64', 128 | version: 'head', 129 | expected: 130 | 'https://storage.googleapis.com/minikube-builds/master/minikube-darwin-amd64', 131 | }, 132 | { 133 | arch: 'arm64', 134 | version: 'head', 135 | expected: 136 | 'https://storage.googleapis.com/minikube-builds/master/minikube-darwin-arm64', 137 | }, 138 | { 139 | arch: 'x64', 140 | version: '1.28.0', 141 | expected: 142 | 'https://github.com/kubernetes/minikube/releases/download/v1.28.0/minikube-darwin-amd64', 143 | }, 144 | { 145 | arch: 'arm64', 146 | version: '1.28.0', 147 | expected: 148 | 'https://github.com/kubernetes/minikube/releases/download/v1.28.0/minikube-darwin-arm64', 149 | }, 150 | ] 151 | 152 | for (const tc of tests) { 153 | mockedOS.arch.mockReturnValue(tc.arch as NodeJS.Architecture) 154 | mockedOS.platform.mockReturnValue('darwin') 155 | 156 | const url = getDownloadURL(tc.version) 157 | 158 | expect(url).toBe(tc.expected) 159 | } 160 | }) 161 | 162 | test('getDownloadURL Windows', () => { 163 | const tests = [ 164 | { 165 | arch: 'x64', 166 | version: 'latest', 167 | expected: 168 | 'https://github.com/kubernetes/minikube/releases/latest/download/minikube-windows-amd64.exe', 169 | }, 170 | { 171 | arch: 'x64', 172 | version: 'head', 173 | expected: 174 | 'https://storage.googleapis.com/minikube-builds/master/minikube-windows-amd64.exe', 175 | }, 176 | { 177 | arch: 'x64', 178 | version: '1.28.0', 179 | expected: 180 | 'https://github.com/kubernetes/minikube/releases/download/v1.28.0/minikube-windows-amd64.exe', 181 | }, 182 | ] 183 | 184 | for (const tc of tests) { 185 | mockedOS.arch.mockReturnValue(tc.arch as NodeJS.Architecture) 186 | mockedOS.platform.mockReturnValue('win32') 187 | 188 | const url = getDownloadURL(tc.version) 189 | 190 | expect(url).toBe(tc.expected) 191 | } 192 | }) 193 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # setup-minikube[![CI](https://github.com/medyagh/setup-minikube/actions/workflows/test.yml/badge.svg?branch=master)](https://github.com/medyagh/setup-minikube/actions/workflows/test.yml) 2 | 3 | 4 | - build/deploy/test your application against a certified Kubernetes cluster in GitHub Actions. 5 | - maintained by official minikube maintainers. 6 | 7 | ## Basic Usage 8 | ``` 9 | steps: 10 | - name: start minikube 11 | id: minikube 12 | uses: medyagh/setup-minikube@latest 13 | 14 | ``` 15 | 16 | ## Caching 17 | 18 | By default setup-minikube caches the ISO, kicbase, and preload using GitHub Action Cache, if you'd like to disable this caching add the following to your workflow file. 19 | ``` 20 | - uses: medyagh/setup-minikube@latest 21 | with: 22 | cache: false 23 | ``` 24 | 25 | ## Examples 26 | - [Example 1: Start Kubernetes on pull request](https://github.com/medyagh/setup-minikube#example-1) 27 | 28 | - [Example 2: Start Kubernetes using all configuration options](https://github.com/medyagh/setup-minikube#example-2) 29 | 30 | - [Example 3: Build image and deploy to Kubernetes on pull request](https://github.com/medyagh/setup-minikube#example-3) 31 | - [Real World Examples](https://github.com/medyagh/setup-minikube#Real-World) 32 | 33 | 34 | 35 | ## Configurable Fields 36 | 37 |
38 | start (optional) 39 |
 40 |     - default: true
 41 |     - options:
 42 |       - true
 43 |       - false
 44 |   
45 |
46 | 47 |
48 | minikube-version (optional) 49 |
 50 |     - default: latest
 51 |     - options:
 52 |       - version in format of 'X.X.X'
 53 |       - 'latest' for the latest stable release
 54 |       - 'HEAD' for the latest development build
 55 |     - example: 1.24.0
 56 |   
57 |
58 | 59 |
60 | driver (optional) 61 |
 62 |     - default: '' (minikube will auto-select)
 63 |     - options:
 64 |       - docker
 65 |       - none (baremetal)
 66 |       - virtualbox (available on macOS free agents)
 67 |       - also possible if installed on self-hosted agent: podman, parallels, vmwarefusion, hyperkit, vmware, ssh
 68 |   
69 |
70 | 71 |
72 | container-runtime (optional) 73 |
 74 |     - default: docker
 75 |     - options:
 76 |       - docker
 77 |       - containerd
 78 |       - cri-o
 79 |   
80 |
81 | 82 |
83 | kubernetes-version (optional) 84 |
 85 |     - default: stable
 86 |     - options:
 87 |       - 'stable' for the latest stable Kubernetes version
 88 |       - 'latest' for the Newest Kubernetes version
 89 |       - 'vX.X.X'
 90 |     - example: v1.23.1
 91 |   
92 |
93 | 94 |
95 | nodes (optional) 96 |
 97 |     - default: '' (minikube will auto-set)
 98 |     - options:
 99 |       - ''
100 |     - example: 4
101 |   
102 |
103 | 104 |
105 | cpus (optional) 106 |
107 |     - default: '' (minikube will auto-set)
108 |     - options:
109 |       - ''
110 |       - 'max' to use the maximum available CPUs
111 |     - example: 4
112 |   
113 |
114 | 115 |
116 | memory (optional) 117 |
118 |     - default: '' (minikube will auto-set)
119 |     - options:
120 |       - '' where unit = b, k, m or g
121 |       - 'max' to use the maximum available memory
122 |     - example: 4000m
123 |   
124 |
125 | 126 |
127 | network-plugin (optional) 128 |
129 |     - default: auto
130 |     - options:
131 |       - cni
132 |   
133 |
134 | 135 |
136 | cni (optional) 137 |
138 |     - default: '' (auto)
139 |     - options:
140 |       - bridge
141 |       - calico
142 |       - cilium
143 |       - flannel
144 |       - kindnet
145 |       - (path to a CNI manifest)
146 |   
147 |
148 | 149 |
150 | wait (optional) 151 |
152 |     - default: all
153 |     - options:
154 |       - comma separated list of Kubernetes components (e.g. apiserver,system_pods,default_sa,apps_running,node_ready,kubelet)
155 |       - all
156 |       - none
157 |       - true
158 |       - false
159 |   
160 |
161 | 162 |
163 | addons (optional) 164 |
165 |     - default: ''
166 |     - options:
167 |       - ambassador
168 |       - auto-pause
169 |       - csi-hostpath-driver
170 |       - dashboard
171 |       - default-storageclass
172 |       - efk
173 |       - freshpod
174 |       - gcp-auth
175 |       - gvisor
176 |       - headlamp
177 |       - helm-tiller
178 |       - inaccel
179 |       - ingress
180 |       - ingress-dns
181 |       - istio
182 |       - istio-provisioner
183 |       - kong
184 |       - kubevirt
185 |       - logviewer
186 |       - metallb
187 |       - metrics-server
188 |       - nvidia-driver-installer
189 |       - nvidia-gpu-device-plugin
190 |       - olm
191 |       - pod-security-policy
192 |       - portainer
193 |       - registry
194 |       - registry-aliases
195 |       - registry-creds
196 |       - storage-provisioner
197 |       - storage-provisioner-gluster
198 |       - volumesnapshots
199 |       - (minikube addons list)
200 |     - example: ingress,registry
201 |   
202 |
203 | 204 |
205 | extra-config (optional) 206 |
207 |     - default: ''
208 |     - value: Any extra config fields (see [docs](https://minikube.sigs.k8s.io/docs/handbook/config/#kubernetes-configuration))
209 |   
210 |
211 | 212 |
213 | feature-gates (optional) 214 |
215 |     - default: ''
216 |     - value: Enable feature gates in API service (see [docs](https://minikube.sigs.k8s.io/docs/handbook/config/#enabling-feature-gates))
217 |   
218 |
219 | 220 |
221 | listen-address (optional) 222 |
223 |     - default: ''
224 |     - value: IP Address to use to expose ports (docker and podman driver only)
225 |   
226 |
227 | 228 |
229 | mount-path (optional) 230 |
231 |     - default: ''
232 |     - value: Mount the source directory from your host into the target directory inside the cluster (format: :)
233 |   
234 |
235 | 236 |
237 | install-path (optional) 238 |
239 |     - default: ''
240 |     - value: Path where the executables (minikube) will get installed. Useful when having multiple self-hosted runners on one machine.
241 |   
242 |
243 | 244 |
245 | insecure-registry (optional) 246 |
247 |     - default: ''
248 |     - value: Any container registry address which is insecure
249 |     - example: localhost:5000,10.0.0.0/24
250 |   
251 |
252 | 253 |
254 | start-args (optional) 255 |
256 |     - default: ''
257 |     - value: Any flags you would regularly pass into minikube via CLI
258 |     - example: --delete-on-failure --subnet 192.168.50.0
259 |   
260 |
261 | 262 | ## Example 1: 263 | #### Start Kubernetes on pull request 264 | 265 | ``` 266 | name: CI 267 | on: 268 | - pull_request 269 | jobs: 270 | job1: 271 | runs-on: ubuntu-latest 272 | name: job1 273 | steps: 274 | - name: start minikube 275 | id: minikube 276 | uses: medyagh/setup-minikube@latest 277 | # now you can run kubectl to see the pods in the cluster 278 | - name: kubectl 279 | run: kubectl get pods -A 280 | ``` 281 | 282 | ## Example 2 283 | ### Start Kubernetes using all configuration options 284 | 285 | ``` 286 | name: CI 287 | on: 288 | - pull_request 289 | jobs: 290 | job1: 291 | runs-on: ubuntu-latest 292 | name: job1 293 | steps: 294 | - name: start minikube 295 | uses: medyagh/setup-minikube@latest 296 | id: minikube 297 | with: 298 | cache: false 299 | minikube-version: 1.24.0 300 | driver: docker 301 | container-runtime: containerd 302 | kubernetes-version: v1.22.3 303 | nodes: 2 304 | cpus: 4 305 | memory: 4000m 306 | cni: bridge 307 | addons: registry,ingress 308 | extra-config: 'kubelet.max-pods=10' 309 | feature-gates: 'DownwardAPIHugePages=true' 310 | mount-path: '/Users/user1/test-files:/testdata' 311 | wait: false 312 | insecure-registry: 'localhost:5000,10.0.0.0/24' 313 | start-args: '--delete-on-failure --subnet 192.168.50.0' 314 | # now you can run kubectl to see the pods in the cluster 315 | - name: kubectl 316 | run: kubectl get pods -A 317 | ``` 318 | 319 | ## Example 3: 320 | ### Build image and deploy to Kubernetes on pull request 321 | ``` 322 | name: CI 323 | on: 324 | - push 325 | - pull_request 326 | jobs: 327 | job1: 328 | runs-on: ubuntu-latest 329 | name: build discover and deploy 330 | steps: 331 | - uses: actions/checkout@v4 332 | with: 333 | repository: medyagh/local-dev-example-with-minikube 334 | - name: Start minikube 335 | uses: medyagh/setup-minikube@latest 336 | # now you can run kubectl to see the pods in the cluster 337 | - name: Try the cluster! 338 | run: kubectl get pods -A 339 | - name: Build image 340 | run: | 341 | minikube image build -t local/devex:v1 . 342 | - name: Deploy to minikube 343 | run: | 344 | kubectl apply -f deploy/k8s.yaml 345 | kubectl wait --for=condition=ready pod -l app=local-devex 346 | - name: Test service URLs 347 | run: | 348 | minikube service list 349 | minikube service local-devex-svc --url 350 | echo -n "------------------opening the service------------------" 351 | curl $(minikube service local-devex-svc --url)/version 352 | ``` 353 | ## Real World: 354 | #### Add your own repo here: 355 | - [medyagh/test-minikube-example](https://github.com/medyagh/test-minikube-example) 356 | - [AET-DevOps25/team-404-name-not-found](https://github.com/AET-DevOps25/team-404-name-not-found) 357 | - [More examples](https://github.com/medyagh/setup-minikube/tree/master/examples) 358 | 359 | ## About Author 360 | 361 | Medya Ghazizadeh, Follow me on [twitter](https://twitter.com/medya_dev) for my dev news! 362 | --------------------------------------------------------------------------------