Compare commits

..

1 Commits
main ... v4.0.0

Author SHA1 Message Date
GitHub Action
27bfb38730 build 2024-02-13 20:45:12 +00:00
38 changed files with 200322 additions and 2717 deletions

2
.github/CODEOWNERS vendored
View File

@ -1 +1 @@
* @Azure/cloud-native-github-action-owners * @Azure/aks-atlanta

View File

@ -1,18 +0,0 @@
version: 2
updates:
- package-ecosystem: npm
directory: /
schedule:
interval: weekly
groups:
actions:
patterns:
- '*'
- package-ecosystem: github-actions
directory: .github/workflows
schedule:
interval: weekly
groups:
actions:
patterns:
- '*'

View File

@ -1,91 +0,0 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: 'CodeQL Advanced'
on:
push:
branches: ['main']
pull_request:
branches: ['main']
schedule:
- cron: '15 9 * * 0'
jobs:
analyze:
name: Analyze (${{ matrix.language }})
# Runner size impacts CodeQL analysis time. To learn more, please see:
# - https://gh.io/recommended-hardware-resources-for-running-codeql
# - https://gh.io/supported-runners-and-hardware-resources
# - https://gh.io/using-larger-runners (GitHub.com only)
# Consider using larger runners or machines with greater resources for possible analysis time improvements.
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
permissions:
# required for all workflows
security-events: write
# required to fetch internal or private CodeQL packs
packages: read
# only required for workflows in private repositories
actions: read
contents: read
strategy:
fail-fast: false
matrix:
include:
- language: javascript-typescript
build-mode: none
# CodeQL supports the following values keywords for 'language': 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift'
# Use `c-cpp` to analyze code written in C, C++ or both
# Use 'java-kotlin' to analyze code written in Java, Kotlin or both
# Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
# To learn more about changing the languages that are analyzed or customizing the build mode for your analysis,
# see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning.
# If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@c10b8064de6f491fea524254123dbe5e09572f13 # v3.29.5
with:
languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
# If the analyze step fails for one of the languages you are analyzing with
# "We were unable to automatically build your code", modify the matrix above
# to set the build mode to "manual" for that language. Then modify this step
# to build your code.
# Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
- if: matrix.build-mode == 'manual'
shell: bash
run: |
echo 'If you are using a "manual" build mode for one or more of the' \
'languages you are analyzing, replace this with the commands to build' \
'your code, for example:'
echo ' make bootstrap'
echo ' make release'
exit 1
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@c10b8064de6f491fea524254123dbe5e09572f13 # v3.29.5
with:
category: '/language:${{matrix.language}}'

View File

@ -13,7 +13,7 @@ jobs:
# Steps represent a sequence of tasks that will be executed as part of the job # Steps represent a sequence of tasks that will be executed as part of the job
steps: steps:
- uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f # v10.2.0 - uses: actions/stale@v3
name: Setting Issue as Idle name: Setting Issue as Idle
with: with:
repo-token: ${{ secrets.GITHUB_TOKEN }} repo-token: ${{ secrets.GITHUB_TOKEN }}
@ -24,7 +24,7 @@ jobs:
operations-per-run: 100 operations-per-run: 100
exempt-issue-labels: 'backlog' exempt-issue-labels: 'backlog'
- uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f # v10.2.0 - uses: actions/stale@v3
name: Setting PR as Idle name: Setting PR as Idle
with: with:
repo-token: ${{ secrets.GITHUB_TOKEN }} repo-token: ${{ secrets.GITHUB_TOKEN }}

View File

@ -15,7 +15,7 @@ jobs:
steps: steps:
- name: Checkout Source Code - name: Checkout Source Code
id: checkout-code id: checkout-code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v2
- name: Npm Install and Build - name: Npm Install and Build
id: npm-build id: npm-build
run: | run: |

View File

@ -1,4 +1,4 @@
name: 'Run Prettify' name: 'Run prettify'
on: on:
pull_request: pull_request:
push: push:
@ -10,16 +10,9 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout Repository - name: Checkout Repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v2
- name: Setup Node.js - name: Enforce Prettier
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 uses: actionsx/prettier@v2
with: with:
node-version: 'lts/*' args: --check .
cache: 'npm'
- name: Install Dependencies
run: npm ci
- name: Run Prettier Check
run: npx prettier --check .

View File

@ -13,6 +13,6 @@ jobs:
permissions: permissions:
actions: read actions: read
contents: write contents: write
uses: Azure/action-release-workflows/.github/workflows/release_js_project.yaml@v1 uses: Azure/action-release-workflows/.github/workflows/release_js_project.yaml@a705b2ab6a3ee889f2b0d925ad0bd2f9eb733ce6
with: with:
changelogPath: ./CHANGELOG.md changelogPath: ./CHANGELOG.md

View File

@ -13,7 +13,7 @@ jobs:
unit-test: unit-test:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/checkout@v1
- name: Run Unit Tests - name: Run Unit Tests
run: | run: |
npm install npm install

1
.gitignore vendored
View File

@ -331,4 +331,3 @@ node_modules
coverage coverage
# Transpiled JS # Transpiled JS
lib/

View File

@ -1,7 +0,0 @@
npm test
npm run format-check || {
echo ""
echo "❌ Formatting check failed."
echo "💡 Run 'npm run format' or 'prettier --write .' to fix formatting issues."
exit 1
}

View File

@ -1,15 +1,5 @@
# Change Log # Change Log
## [4.0.2] - 2025-11-13
- #[164](https://github.com/Azure/k8s-set-context/pull/164) Adding optional kubeconfig encoding variable
- Dependabot updates
## [4.0.1] - 2024-09-06
- #90 update dev dependencies with Typescript to 5
- #89 Adding dependabot
## [4.0.0] - 2024-02-13 ## [4.0.0] - 2024-02-13
- #83 update to node20 as node16 is deprecated - #83 update to node20 as node16 is deprecated

View File

@ -4,6 +4,6 @@ This project has adopted the [Microsoft Open Source Code of Conduct](https://ope
Resources: Resources:
- [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/)
- [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
- Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns

View File

@ -6,9 +6,9 @@ It is a requirement to use [`azure/login`](https://github.com/Azure/login/tree/m
There are three approaches for specifying the deployment target: There are three approaches for specifying the deployment target:
- Kubeconfig file provided as input to the action - Kubeconfig file provided as input to the action
- Service account approach where the secret associated with the service account is provided as input to the action - Service account approach where the secret associated with the service account is provided as input to the action
- Service principal approach (only applicable for arc cluster) where service principal provided with 'creds' is used as input to action - Service principal approach (only applicable for arc cluster) where service principal provided with 'creds' is used as input to action
In all these approaches it is recommended to store these contents (kubeconfig file content or secret content) in a [secret](https://docs.github.com/en/actions/security-guides/encrypted-secrets/). In all these approaches it is recommended to store these contents (kubeconfig file content or secret content) in a [secret](https://docs.github.com/en/actions/security-guides/encrypted-secrets/).
@ -19,7 +19,7 @@ Refer to the [action metadata file](./action.yml) for details about inputs. Note
### Kubeconfig approach ### Kubeconfig approach
```yaml ```yaml
- uses: azure/k8s-set-context@v4 - uses: azure/k8s-set-context@v3
with: with:
method: kubeconfig method: kubeconfig
kubeconfig: <your kubeconfig> kubeconfig: <your kubeconfig>
@ -50,7 +50,7 @@ Please refer to documentation on fetching [kubeconfig for any generic K8s cluste
### Service account approach ### Service account approach
```yaml ```yaml
- uses: azure/k8s-set-context@v4 - uses: azure/k8s-set-context@v3
with: with:
method: service-account method: service-account
k8s-url: <URL of the cluster's API server> k8s-url: <URL of the cluster's API server>
@ -74,7 +74,7 @@ kubectl get secret <service-account-secret-name> -n <namespace> -o yaml
### Service account approach for arc cluster ### Service account approach for arc cluster
```yaml ```yaml
- uses: azure/k8s-set-context@v4 - uses: azure/k8s-set-context@v3
with: with:
method: service-account method: service-account
cluster-type: arc cluster-type: arc
@ -86,7 +86,7 @@ kubectl get secret <service-account-secret-name> -n <namespace> -o yaml
### Service principal approach for arc cluster ### Service principal approach for arc cluster
```yaml ```yaml
- uses: azure/k8s-set-context@v4 - uses: azure/k8s-set-context@v3
with: with:
method: service-principal method: service-principal
cluster-type: arc cluster-type: arc

View File

@ -14,13 +14,13 @@ You should receive a response within 24 hours. If for some reason you do not, pl
Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
- Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) - Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
- Full paths of source file(s) related to the manifestation of the issue - Full paths of source file(s) related to the manifestation of the issue
- The location of the affected source code (tag/branch/commit or direct URL) - The location of the affected source code (tag/branch/commit or direct URL)
- Any special configuration required to reproduce the issue - Any special configuration required to reproduce the issue
- Step-by-step instructions to reproduce the issue - Step-by-step instructions to reproduce the issue
- Proof-of-concept or exploit code (if possible) - Proof-of-concept or exploit code (if possible)
- Impact of the issue, including how an attacker might exploit the issue - Impact of the issue, including how an attacker might exploit the issue
This information will help us triage your report more quickly. This information will help us triage your report more quickly.

View File

@ -13,10 +13,6 @@ inputs:
kubeconfig: kubeconfig:
description: 'Contents of kubeconfig file' description: 'Contents of kubeconfig file'
required: false required: false
kubeconfig-encoding:
description: 'Encoding of the kubeconfig input. Accepts "plaintext" (default) or "base64".'
required: false
default: 'plaintext'
context: context:
description: 'If your kubeconfig has multiple contexts, use this field to use a specific context, otherwise the default one would be chosen' description: 'If your kubeconfig has multiple contexts, use this field to use a specific context, otherwise the default one would be chosen'
required: false required: false
@ -39,5 +35,5 @@ inputs:
branding: branding:
color: 'blue' color: 'blue'
runs: runs:
using: 'node24' using: 'node20'
main: 'lib/index.js' main: 'lib/index.js'

20
jest.config.js Normal file
View File

@ -0,0 +1,20 @@
module.exports = {
restoreMocks: true,
clearMocks: true,
resetMocks: true,
moduleFileExtensions: ['js', 'ts'],
testEnvironment: 'node',
testMatch: ['**/*.test.ts'],
transform: {
'^.+\\.ts$': 'ts-jest'
},
verbose: true,
coverageThreshold: {
global: {
branches: 0,
functions: 40,
lines: 22,
statements: 22
}
}
}

39
lib/exec-child.js Normal file
View File

@ -0,0 +1,39 @@
if (require.main !== module) {
throw new Error('This file should not be required');
}
var childProcess = require('child_process');
var fs = require('fs');
var paramFilePath = process.argv[2];
var serializedParams = fs.readFileSync(paramFilePath, 'utf8');
var params = JSON.parse(serializedParams);
var cmd = params.command;
var execOptions = params.execOptions;
var pipe = params.pipe;
var stdoutFile = params.stdoutFile;
var stderrFile = params.stderrFile;
var c = childProcess.exec(cmd, execOptions, function (err) {
if (!err) {
process.exitCode = 0;
} else if (err.code === undefined) {
process.exitCode = 1;
} else {
process.exitCode = err.code;
}
});
var stdoutStream = fs.createWriteStream(stdoutFile);
var stderrStream = fs.createWriteStream(stderrFile);
c.stdout.pipe(stdoutStream);
c.stderr.pipe(stderrStream);
c.stdout.pipe(process.stdout);
c.stderr.pipe(process.stderr);
if (pipe) {
c.stdin.end(pipe);
}

192191
lib/index.js Normal file

File diff suppressed because one or more lines are too long

10323
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,17 +1,15 @@
{ {
"name": "k8s-set-context-action", "name": "k8s-set-context-action",
"version": "4.0.2", "version": "4.0.0",
"private": true, "private": true,
"main": "lib/index.js", "main": "lib/index.js",
"type": "module",
"scripts": { "scripts": {
"build": "tsc --noEmit && esbuild src/run.ts --bundle --platform=node --target=node20 --format=esm --outfile=lib/index.js --banner:js=\"import { createRequire } from 'module';const require = createRequire(import.meta.url);\"", "prebuild": "npm i @vercel/ncc",
"typecheck": "tsc --noEmit", "build": "ncc build src/run.ts -o lib",
"test": "vitest run", "test": "jest",
"test-coverage": "vitest run --coverage", "test-coverage": "jest --coverage",
"format": "prettier --write .", "format": "prettier --write .",
"format-check": "prettier --check .", "format-check": "prettier --check ."
"prepare": "husky"
}, },
"keywords": [ "keywords": [
"actions", "actions",
@ -21,19 +19,20 @@
"author": "GitHub", "author": "GitHub",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@actions/core": "^3.0.0", "@actions/core": "^1.10.0",
"@actions/exec": "^3.0.0", "@actions/exec": "^1.0.0",
"@actions/io": "^3.0.2", "@actions/io": "^1.1.2",
"@kubernetes/client-node": "^1.4.0", "@kubernetes/client-node": "^0.16.0",
"husky": "^9.1.7", "js-yaml": "^4.1.0"
"js-yaml": "^4.1.1"
}, },
"devDependencies": { "devDependencies": {
"@types/js-yaml": "^4.0.9", "@types/jest": "^28.1.2",
"@types/node": "^25.0.9", "@types/js-yaml": "^4.0.4",
"esbuild": "^0.27.4", "@types/node": "^16.0.0",
"prettier": "^3.8.0", "@vercel/ncc": "^0.34.0",
"typescript": "^6.0.2", "jest": "^28.1.1",
"vitest": "^4.1.1" "prettier": "2.7.1",
"ts-jest": "^28.0.5",
"typescript": "4.7.4"
} }
} }

View File

@ -1,9 +1,7 @@
import {vi, describe, it, expect} from 'vitest' import {getRequiredInputError} from '../tests/util'
import {getRequiredInputError} from '../tests/util.js' import {run} from './action'
import {run} from './action.js' import fs from 'fs'
import * as utils from './utils'
vi.mock('fs')
vi.mock('./utils.js')
describe('Run', () => { describe('Run', () => {
it('throws error without cluster type', async () => { it('throws error without cluster type', async () => {
@ -11,23 +9,22 @@ describe('Run', () => {
}) })
it('writes kubeconfig and sets context', async () => { it('writes kubeconfig and sets context', async () => {
const {getKubeconfig, setContext} = await import('./utils.js')
const fs = await import('fs')
const kubeconfig = 'kubeconfig' const kubeconfig = 'kubeconfig'
process.env['INPUT_CLUSTER-TYPE'] = 'default' process.env['INPUT_CLUSTER-TYPE'] = 'default'
process.env['RUNNER_TEMP'] = '/sample/path' process.env['RUNNER_TEMP'] = '/sample/path'
vi.mocked(getKubeconfig).mockResolvedValue(kubeconfig) jest
vi.mocked(setContext).mockReturnValue(kubeconfig) .spyOn(utils, 'getKubeconfig')
vi.mocked(fs.writeFileSync).mockImplementation(() => {}) .mockImplementation(async () => kubeconfig)
vi.mocked(fs.chmodSync).mockImplementation(() => {}) jest.spyOn(fs, 'writeFileSync').mockImplementation(() => {})
jest.spyOn(fs, 'chmodSync').mockImplementation(() => {})
jest.spyOn(utils, 'setContext').mockImplementation(() => kubeconfig)
await run() expect(await run())
expect(utils.getKubeconfig).toHaveBeenCalled()
expect(getKubeconfig).toHaveBeenCalled()
expect(fs.writeFileSync).toHaveBeenCalled() expect(fs.writeFileSync).toHaveBeenCalled()
expect(fs.chmodSync).toHaveBeenCalled() expect(fs.chmodSync).toHaveBeenCalled()
expect(setContext).toHaveBeenCalled() expect(utils.setContext).toHaveBeenCalled()
}) })
}) })

View File

@ -1,8 +1,8 @@
import * as core from '@actions/core' import * as core from '@actions/core'
import * as path from 'path' import * as path from 'path'
import * as fs from 'fs' import * as fs from 'fs'
import {Cluster, parseCluster} from './types/cluster.js' import {Cluster, parseCluster} from './types/cluster'
import {setContext, getKubeconfig} from './utils.js' import {setContext, getKubeconfig} from './utils'
/** /**
* Sets the Kubernetes context based on supplied action inputs * Sets the Kubernetes context based on supplied action inputs
@ -14,7 +14,7 @@ export async function run() {
required: true required: true
}) })
) )
const runnerTempDirectory: string = process.env['RUNNER_TEMP'] ?? '' const runnerTempDirectory: string = process.env['RUNNER_TEMP']
const kubeconfigPath: string = path.join( const kubeconfigPath: string = path.join(
runnerTempDirectory, runnerTempDirectory,
`kubeconfig_${Date.now()}` `kubeconfig_${Date.now()}`

View File

@ -1,11 +1,8 @@
import {vi, describe, test, it, expect, beforeEach} from 'vitest' import * as actions from '@actions/exec'
import * as io from '@actions/io' import * as io from '@actions/io'
import {getRequiredInputError} from '../../tests/util.js' import {getRequiredInputError} from '../../tests/util'
import {getArcKubeconfig, KUBECONFIG_LOCATION} from './arc.js' import {getArcKubeconfig, KUBECONFIG_LOCATION} from './arc'
import * as az from './azCommands.js' import * as az from './azCommands'
vi.mock('@actions/io')
vi.mock('./azCommands.js')
describe('Arc kubeconfig', () => { describe('Arc kubeconfig', () => {
test('it throws error without resource group', async () => { test('it throws error without resource group', async () => {
@ -31,11 +28,11 @@ describe('Arc kubeconfig', () => {
process.env['INPUT_RESOURCE-GROUP'] = group process.env['INPUT_RESOURCE-GROUP'] = group
process.env['INPUT_CLUSTER-NAME'] = name process.env['INPUT_CLUSTER-NAME'] = name
vi.mocked(io.which).mockResolvedValue(path) jest.spyOn(io, 'which').mockImplementation(async () => path)
vi.mocked(az.runAzCliCommand).mockResolvedValue(undefined) jest.spyOn(az, 'runAzCliCommand').mockImplementation(async () => {})
vi.mocked(az.runAzKubeconfigCommandBlocking).mockResolvedValue( jest
kubeconfig .spyOn(az, 'runAzKubeconfigCommandBlocking')
) .mockImplementation(async () => kubeconfig)
}) })
it('throws an error without method', async () => { it('throws an error without method', async () => {

View File

@ -1,8 +1,8 @@
import * as core from '@actions/core' import * as core from '@actions/core'
import * as io from '@actions/io' import * as io from '@actions/io'
import {Method, parseMethod} from '../types/method.js' import {Method, parseMethod} from '../types/method'
import * as path from 'path' import * as path from 'path'
import {runAzCliCommand, runAzKubeconfigCommandBlocking} from './azCommands.js' import {runAzCliCommand, runAzKubeconfigCommandBlocking} from './azCommands'
const RUNNER_TEMP: string = process.env['RUNNER_TEMP'] || '' const RUNNER_TEMP: string = process.env['RUNNER_TEMP'] || ''
export const KUBECONFIG_LOCATION: string = path.join( export const KUBECONFIG_LOCATION: string = path.join(

View File

@ -1,17 +1,14 @@
import {vi, describe, test, expect, beforeEach} from 'vitest'
import * as actions from '@actions/exec' import * as actions from '@actions/exec'
import {runAzCliCommand} from './azCommands.js' import {runAzCliCommand} from './azCommands'
vi.mock('@actions/exec')
describe('Az commands', () => { describe('Az commands', () => {
test('it runs an az cli command', async () => { test('it runs an az cli command', async () => {
const path = 'path' const path = 'path'
const args = ['args'] const args = ['args']
vi.mocked(actions.exec).mockResolvedValue(0) jest.spyOn(actions, 'exec').mockImplementation(async () => 0)
await runAzCliCommand(path, args) expect(await runAzCliCommand(path, args))
expect(actions.exec).toHaveBeenCalledWith(path, args, {}) expect(actions.exec).toBeCalledWith(path, args, {})
}) })
}) })

View File

@ -1,5 +1,6 @@
import * as fs from 'fs' import * as fs from 'fs'
import {ExecOptions, exec} from '@actions/exec' import {ExecOptions} from '@actions/exec/lib/interfaces'
import {exec} from '@actions/exec'
import {spawn} from 'child_process' import {spawn} from 'child_process'
const AZ_TIMEOUT_SECONDS: number = 120 const AZ_TIMEOUT_SECONDS: number = 120

View File

@ -1,7 +1,6 @@
import {vi, describe, test, expect, beforeEach, afterEach} from 'vitest'
import * as fs from 'fs' import * as fs from 'fs'
import {getRequiredInputError} from '../../tests/util.js' import {getRequiredInputError} from '../../tests/util'
import {createKubeconfig, getDefaultKubeconfig} from './default.js' import {createKubeconfig, getDefaultKubeconfig} from './default'
describe('Default kubeconfig', () => { describe('Default kubeconfig', () => {
test('it creates a kubeconfig with proper format', () => { test('it creates a kubeconfig with proper format', () => {
@ -51,11 +50,6 @@ describe('Default kubeconfig', () => {
process.env['INPUT_METHOD'] = 'default' process.env['INPUT_METHOD'] = 'default'
}) })
afterEach(() => {
delete process.env['INPUT_KUBECONFIG']
delete process.env['INPUT_KUBECONFIG-ENCODING']
})
test('it throws error without kubeconfig', () => { test('it throws error without kubeconfig', () => {
expect(() => getDefaultKubeconfig()).toThrow( expect(() => getDefaultKubeconfig()).toThrow(
getRequiredInputError('kubeconfig') getRequiredInputError('kubeconfig')
@ -68,33 +62,6 @@ describe('Default kubeconfig', () => {
expect(getDefaultKubeconfig()).toBe(kc) expect(getDefaultKubeconfig()).toBe(kc)
}) })
test('returns kubeconfig as plaintext when encoding is plaintext', () => {
const kc = 'example kc'
process.env['INPUT_KUBECONFIG'] = kc
process.env['INPUT_KUBECONFIG-ENCODING'] = 'plaintext'
expect(getDefaultKubeconfig()).toBe(kc)
})
test('it gets default config through base64 kubeconfig input', () => {
const kc = 'example kc'
const base64Kc = Buffer.from(kc, 'utf-8').toString('base64')
process.env['INPUT_KUBECONFIG'] = base64Kc
process.env['INPUT_KUBECONFIG-ENCODING'] = 'base64'
expect(getDefaultKubeconfig()).toBe(kc)
})
test('it throws error for unknown kubeconfig-encoding', () => {
const kc = 'example kc'
process.env['INPUT_KUBECONFIG'] = kc
process.env['INPUT_KUBECONFIG-ENCODING'] = 'foobar'
expect(() => getDefaultKubeconfig()).toThrow(
"Invalid kubeconfig-encoding: 'foobar'. Must be 'plaintext' or 'base64'."
)
})
}) })
test('it defaults to default method', () => { test('it defaults to default method', () => {

View File

@ -1,8 +1,8 @@
import * as core from '@actions/core' import * as core from '@actions/core'
import * as jsyaml from 'js-yaml' import * as jsyaml from 'js-yaml'
import {KubeConfig} from '@kubernetes/client-node' import {KubeConfig} from '@kubernetes/client-node'
import {K8sSecret, parseK8sSecret} from '../types/k8sSecret.js' import {K8sSecret, parseK8sSecret} from '../types/k8sSecret'
import {Method, parseMethod} from '../types/method.js' import {Method, parseMethod} from '../types/method'
/** /**
* Gets the kubeconfig based on provided method for a default Kubernetes cluster * Gets the kubeconfig based on provided method for a default Kubernetes cluster
@ -44,27 +44,7 @@ export function getDefaultKubeconfig(): string {
} }
default: { default: {
core.debug('Setting context using kubeconfig') core.debug('Setting context using kubeconfig')
enum Encoding { return core.getInput('kubeconfig', {required: true})
Base64 = 'base64',
Plaintext = 'plaintext'
}
const rawKubeconfig = core.getInput('kubeconfig', {required: true})
const encoding =
core.getInput('kubeconfig-encoding')?.toLowerCase() ||
Encoding.Plaintext
if (encoding !== Encoding.Base64 && encoding !== Encoding.Plaintext) {
throw new Error(
`Invalid kubeconfig-encoding: '${encoding}'. Must be 'plaintext' or 'base64'.`
)
}
const kubeconfig =
encoding === Encoding.Base64
? Buffer.from(rawKubeconfig, 'base64').toString('utf-8')
: rawKubeconfig
return kubeconfig
} }
} }
} }

View File

@ -1,4 +1,4 @@
import {run} from './action.js' import {run} from './action'
import * as core from '@actions/core' import * as core from '@actions/core'
// Run the application // Run the application

View File

@ -1,9 +1,8 @@
import {describe, test, expect} from 'vitest' import {Cluster, parseCluster} from './cluster'
import {Cluster, parseCluster} from './cluster.js'
describe('Cluster type', () => { describe('Cluster type', () => {
test('it has required values', () => { test('it has required values', () => {
const vals = Object.values(Cluster) as string[] const vals = <any>Object.values(Cluster)
expect(vals.includes('arc')).toBe(true) expect(vals.includes('arc')).toBe(true)
expect(vals.includes('generic')).toBe(true) expect(vals.includes('generic')).toBe(true)
}) })

View File

@ -8,10 +8,9 @@ export enum Cluster {
* @param str The cluster type (case insensitive) * @param str The cluster type (case insensitive)
* @returns The Cluster enum or undefined if it can't be parsed * @returns The Cluster enum or undefined if it can't be parsed
*/ */
export const parseCluster = (str: string): Cluster | undefined => { export const parseCluster = (str: string): Cluster | undefined =>
const key = Object.keys(Cluster).find( Cluster[
(k) => Object.keys(Cluster).filter(
Cluster[k as keyof typeof Cluster].toLowerCase() === str.toLowerCase() (k) => Cluster[k].toString().toLowerCase() === str.toLowerCase()
) as keyof typeof Cluster | undefined )[0] as keyof typeof Cluster
return key !== undefined ? Cluster[key] : undefined ]
}

View File

@ -1,5 +1,4 @@
import {describe, test, expect} from 'vitest' import {parseK8sSecret, K8sSecret} from './k8sSecret'
import {parseK8sSecret} from './k8sSecret.js'
describe('K8sSecret type', () => { describe('K8sSecret type', () => {
describe('Parsing from any', () => { describe('Parsing from any', () => {

View File

@ -1,9 +1,8 @@
import {describe, test, expect} from 'vitest' import {Method, parseMethod} from './method'
import {Method, parseMethod} from './method.js'
describe('Method type', () => { describe('Method type', () => {
test('it has required values', () => { test('it has required values', () => {
const vals = Object.values(Method) as string[] const vals = <any>Object.values(Method)
expect(vals.includes('kubeconfig')).toBe(true) expect(vals.includes('kubeconfig')).toBe(true)
expect(vals.includes('service-account')).toBe(true) expect(vals.includes('service-account')).toBe(true)
expect(vals.includes('service-principal')).toBe(true) expect(vals.includes('service-principal')).toBe(true)

View File

@ -9,10 +9,9 @@ export enum Method {
* @param str The method (case insensitive) * @param str The method (case insensitive)
* @returns The Method enum or undefined if it can't be parsed * @returns The Method enum or undefined if it can't be parsed
*/ */
export const parseMethod = (str: string): Method | undefined => { export const parseMethod = (str: string): Method | undefined =>
const key = Object.keys(Method).find( Method[
(k) => Object.keys(Method).filter(
Method[k as keyof typeof Method].toLowerCase() === str.toLowerCase() (k) => Method[k].toString().toLowerCase() === str.toLowerCase()
) as keyof typeof Method | undefined )[0] as keyof typeof Method
return key !== undefined ? Method[key] : undefined ]
}

View File

@ -1,26 +1,25 @@
import {vi, describe, test, expect} from 'vitest'
import fs from 'fs' import fs from 'fs'
import * as arc from './kubeconfigs/arc.js' import * as arc from './kubeconfigs/arc'
import * as def from './kubeconfigs/default.js' import * as def from './kubeconfigs/default'
import {Cluster} from './types/cluster.js' import {Cluster} from './types/cluster'
import {getKubeconfig, setContext} from './utils.js' import {getKubeconfig, setContext} from './utils'
describe('Utils', () => { describe('Utils', () => {
describe('get kubeconfig', () => { describe('get kubeconfig', () => {
test('it gets arc kubeconfig when type is arc', async () => { test('it gets arc kubeconfig when type is arc', async () => {
const arcKubeconfig = 'arckubeconfig' const arcKubeconfig = 'arckubeconfig'
vi.spyOn(arc, 'getArcKubeconfig').mockImplementation( jest
async () => arcKubeconfig .spyOn(arc, 'getArcKubeconfig')
) .mockImplementation(async () => arcKubeconfig)
expect(await getKubeconfig(Cluster.ARC)).toBe(arcKubeconfig) expect(await getKubeconfig(Cluster.ARC)).toBe(arcKubeconfig)
}) })
test('it defaults to default kubeconfig', async () => { test('it defaults to default kubeconfig', async () => {
const defaultKubeconfig = 'arckubeconfig' const defaultKubeconfig = 'arckubeconfig'
vi.spyOn(def, 'getDefaultKubeconfig').mockImplementation( jest
() => defaultKubeconfig .spyOn(def, 'getDefaultKubeconfig')
) .mockImplementation(() => defaultKubeconfig)
expect(await getKubeconfig(undefined)).toBe(defaultKubeconfig) expect(await getKubeconfig(undefined)).toBe(defaultKubeconfig)
expect(await getKubeconfig(Cluster.GENERIC)).toBe(defaultKubeconfig) expect(await getKubeconfig(Cluster.GENERIC)).toBe(defaultKubeconfig)

View File

@ -1,9 +1,9 @@
import * as core from '@actions/core' import * as core from '@actions/core'
import * as fs from 'fs' import * as fs from 'fs'
import {KubeConfig} from '@kubernetes/client-node' import {KubeConfig} from '@kubernetes/client-node'
import {getDefaultKubeconfig} from './kubeconfigs/default.js' import {getDefaultKubeconfig} from './kubeconfigs/default'
import {getArcKubeconfig} from './kubeconfigs/arc.js' import {getArcKubeconfig} from './kubeconfigs/arc'
import {Cluster} from './types/cluster.js' import {Cluster} from './types/cluster'
/** /**
* Gets the kubeconfig based on Kubernetes cluster type * Gets the kubeconfig based on Kubernetes cluster type

View File

@ -1,14 +1,8 @@
{ {
"compilerOptions": { "compilerOptions": {
"target": "ES2020", "target": "ES6",
"module": "NodeNext", "module": "commonjs",
"moduleResolution": "NodeNext", "esModuleInterop": true
"rootDir": "./src",
"outDir": "./lib",
"noImplicitAny": false,
"skipLibCheck": true,
"noEmit": true,
"types": ["node", "vitest/globals"]
}, },
"exclude": ["node_modules", "**/*.test.ts", "vitest.config.ts", "tests/"] "exclude": ["node_modules", "tests", "src/**/*.test.ts"]
} }

View File

@ -1,10 +0,0 @@
import {defineConfig} from 'vitest/config'
export default defineConfig({
test: {
globals: true,
environment: 'node',
include: ['**/*.test.ts'],
clearMocks: true
}
})