mirror of
https://github.com/Azure/k8s-deploy.git
synced 2026-06-27 15:19:27 +08:00
Migrate to esbuild/Vitest and upgrade @actions/* to ESM-only versions (#492)
* Migrate build toolchain from ncc/Jest to esbuild/Vitest Replace the legacy ncc/Jest/Babel build stack with a modern ESM toolchain: Build: - Replace @vercel/ncc with esbuild (--platform=node --target=node20 --format=esm) - Add createRequire banner for CJS interop in ESM bundle - Add "type": "module" to package.json - Add tsc --noEmit typecheck script (esbuild strips types without checking) - Add typecheck to husky pre-commit hook Dependencies: - Bump @actions/core@3, exec@3, io@3, tool-cache@4 (ESM-only) - Replace jest/ts-jest/@babel/* with vitest@4 Tests: - Convert 29 test files: jest.fn()→vi.fn(), jest.mock()→vi.mock(), jest.spyOn()→vi.spyOn() - Fix vitest 4 compat: mockImplementation requires args, mock call tracking, await .rejects CI: - Update build step from ncc build → npm run build - Update composite action to use npm run build * Switch tsconfig to NodeNext module resolution Change module/moduleResolution from ES2022/bundler to NodeNext/NodeNext and target from ES2022 to ES2020. - Add .js extensions to all relative imports across 59 source/test files (required by NodeNext module resolution) - Add vitest/globals to tsconfig types array for global test API declarations
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import {Kubectl} from '../../types/kubectl'
|
||||
import {Kubectl} from '../../types/kubectl.js'
|
||||
import * as fs from 'fs'
|
||||
import * as yaml from 'js-yaml'
|
||||
import * as core from '@actions/core'
|
||||
@@ -7,15 +7,15 @@ import {
|
||||
isDeploymentEntity,
|
||||
isServiceEntity,
|
||||
KubernetesWorkload
|
||||
} from '../../types/kubernetesTypes'
|
||||
import * as utils from '../../utilities/manifestUpdateUtils'
|
||||
} from '../../types/kubernetesTypes.js'
|
||||
import * as utils from '../../utilities/manifestUpdateUtils.js'
|
||||
import {
|
||||
updateObjectAnnotations,
|
||||
updateObjectLabels,
|
||||
updateSelectorLabels
|
||||
} from '../../utilities/manifestUpdateUtils'
|
||||
import {updateSpecLabels} from '../../utilities/manifestSpecLabelUtils'
|
||||
import {checkForErrors} from '../../utilities/kubectlUtils'
|
||||
} from '../../utilities/manifestUpdateUtils.js'
|
||||
import {updateSpecLabels} from '../../utilities/manifestSpecLabelUtils.js'
|
||||
import {checkForErrors} from '../../utilities/kubectlUtils.js'
|
||||
|
||||
export const CANARY_VERSION_LABEL = 'workflow/version'
|
||||
const BASELINE_SUFFIX = '-baseline'
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
import {vi} from 'vitest'
|
||||
import type {MockInstance} from 'vitest'
|
||||
vi.mock('@actions/core')
|
||||
|
||||
import * as core from '@actions/core'
|
||||
import {Kubectl} from '../../types/kubectl'
|
||||
import {Kubectl} from '../../types/kubectl.js'
|
||||
import {
|
||||
deployPodCanary,
|
||||
calculateReplicaCountForCanary
|
||||
} from './podCanaryHelper'
|
||||
} from './podCanaryHelper.js'
|
||||
|
||||
jest.mock('../../types/kubectl')
|
||||
vi.mock('../../types/kubectl')
|
||||
|
||||
const kc = new Kubectl('')
|
||||
|
||||
@@ -35,18 +39,17 @@ const TIMEOUT_300S = '300s'
|
||||
|
||||
describe('Pod Canary Helper tests', () => {
|
||||
let mockFilePaths: string[]
|
||||
let kubectlApplySpy: jest.SpyInstance
|
||||
let kubectlApplySpy: MockInstance
|
||||
|
||||
beforeEach(() => {
|
||||
//@ts-ignore
|
||||
Kubectl.mockClear()
|
||||
jest.restoreAllMocks()
|
||||
vi.mocked(Kubectl).mockClear()
|
||||
vi.restoreAllMocks()
|
||||
|
||||
mockFilePaths = testManifestFiles
|
||||
kubectlApplySpy = jest.spyOn(kc, 'apply')
|
||||
kubectlApplySpy = vi.spyOn(kc, 'apply')
|
||||
|
||||
// Mock core.getInput with default values
|
||||
jest.spyOn(core, 'getInput').mockImplementation((name: string) => {
|
||||
vi.spyOn(core, 'getInput').mockImplementation((name: string) => {
|
||||
switch (name) {
|
||||
case 'percentage':
|
||||
return VALID_PERCENTAGE.toString()
|
||||
@@ -61,7 +64,7 @@ describe('Pod Canary Helper tests', () => {
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks()
|
||||
vi.restoreAllMocks()
|
||||
kubectlApplySpy.mockClear()
|
||||
})
|
||||
|
||||
@@ -114,7 +117,7 @@ describe('Pod Canary Helper tests', () => {
|
||||
})
|
||||
|
||||
test('should throw error for invalid low percentage', async () => {
|
||||
jest.spyOn(core, 'getInput').mockImplementation((name: string) => {
|
||||
vi.spyOn(core, 'getInput').mockImplementation((name: string) => {
|
||||
if (name === 'percentage') return INVALID_LOW_PERCENTAGE.toString()
|
||||
return ''
|
||||
})
|
||||
@@ -127,7 +130,7 @@ describe('Pod Canary Helper tests', () => {
|
||||
})
|
||||
|
||||
test('should throw error for invalid high percentage', async () => {
|
||||
jest.spyOn(core, 'getInput').mockImplementation((name: string) => {
|
||||
vi.spyOn(core, 'getInput').mockImplementation((name: string) => {
|
||||
if (name === 'percentage') return INVALID_HIGH_PERCENTAGE.toString()
|
||||
return ''
|
||||
})
|
||||
@@ -143,7 +146,7 @@ describe('Pod Canary Helper tests', () => {
|
||||
kubectlApplySpy.mockResolvedValue(mockSuccessResult)
|
||||
|
||||
// Test minimum valid percentage
|
||||
jest.spyOn(core, 'getInput').mockImplementation((name: string) => {
|
||||
vi.spyOn(core, 'getInput').mockImplementation((name: string) => {
|
||||
if (name === 'percentage') return MIN_PERCENTAGE.toString()
|
||||
return ''
|
||||
})
|
||||
@@ -152,7 +155,7 @@ describe('Pod Canary Helper tests', () => {
|
||||
expect(resultMin.execResult).toEqual(mockSuccessResult)
|
||||
|
||||
// Test maximum valid percentage
|
||||
jest.spyOn(core, 'getInput').mockImplementation((name: string) => {
|
||||
vi.spyOn(core, 'getInput').mockImplementation((name: string) => {
|
||||
if (name === 'percentage') return MAX_PERCENTAGE.toString()
|
||||
return ''
|
||||
})
|
||||
@@ -162,7 +165,7 @@ describe('Pod Canary Helper tests', () => {
|
||||
})
|
||||
|
||||
test('should handle force deployment option', async () => {
|
||||
jest.spyOn(core, 'getInput').mockImplementation((name: string) => {
|
||||
vi.spyOn(core, 'getInput').mockImplementation((name: string) => {
|
||||
switch (name) {
|
||||
case 'percentage':
|
||||
return VALID_PERCENTAGE.toString()
|
||||
@@ -186,7 +189,7 @@ describe('Pod Canary Helper tests', () => {
|
||||
})
|
||||
|
||||
test('should handle server-side apply option', async () => {
|
||||
jest.spyOn(core, 'getInput').mockImplementation((name: string) => {
|
||||
vi.spyOn(core, 'getInput').mockImplementation((name: string) => {
|
||||
switch (name) {
|
||||
case 'percentage':
|
||||
return VALID_PERCENTAGE.toString()
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import {Kubectl} from '../../types/kubectl'
|
||||
import {Kubectl} from '../../types/kubectl.js'
|
||||
import * as core from '@actions/core'
|
||||
import * as fs from 'fs'
|
||||
import * as yaml from 'js-yaml'
|
||||
|
||||
import * as fileHelper from '../../utilities/fileUtils'
|
||||
import * as canaryDeploymentHelper from './canaryHelper'
|
||||
import {isDeploymentEntity} from '../../types/kubernetesTypes'
|
||||
import {getReplicaCount} from '../../utilities/manifestUpdateUtils'
|
||||
import {DeployResult} from '../../types/deployResult'
|
||||
import {K8sObject} from '../../types/k8sObject'
|
||||
import {checkForErrors} from '../../utilities/kubectlUtils'
|
||||
import * as fileHelper from '../../utilities/fileUtils.js'
|
||||
import * as canaryDeploymentHelper from './canaryHelper.js'
|
||||
import {isDeploymentEntity} from '../../types/kubernetesTypes.js'
|
||||
import {getReplicaCount} from '../../utilities/manifestUpdateUtils.js'
|
||||
import {DeployResult} from '../../types/deployResult.js'
|
||||
import {K8sObject} from '../../types/k8sObject.js'
|
||||
import {checkForErrors} from '../../utilities/kubectlUtils.js'
|
||||
|
||||
export async function deployPodCanary(
|
||||
filePaths: string[],
|
||||
|
||||
@@ -1,13 +1,34 @@
|
||||
import {vi} from 'vitest'
|
||||
import type {MockInstance} from 'vitest'
|
||||
vi.mock('@actions/core', async (importOriginal) => {
|
||||
const actual: any = await importOriginal()
|
||||
return {
|
||||
...actual,
|
||||
getInput: vi.fn().mockReturnValue(''),
|
||||
debug: vi.fn(),
|
||||
info: vi.fn(),
|
||||
warning: vi.fn(),
|
||||
error: vi.fn(),
|
||||
setFailed: vi.fn(),
|
||||
setOutput: vi.fn(),
|
||||
group: vi
|
||||
.fn()
|
||||
.mockImplementation(
|
||||
async (_name: string, fn: () => Promise<void>) => await fn()
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
import * as core from '@actions/core'
|
||||
import * as fs from 'fs'
|
||||
import {Kubectl} from '../../types/kubectl'
|
||||
import {Kubectl} from '../../types/kubectl.js'
|
||||
import {
|
||||
deploySMICanary,
|
||||
redirectTrafficToCanaryDeployment,
|
||||
redirectTrafficToStableDeployment
|
||||
} from './smiCanaryHelper'
|
||||
} from './smiCanaryHelper.js'
|
||||
|
||||
jest.mock('../../types/kubectl')
|
||||
vi.mock('../../types/kubectl')
|
||||
|
||||
const kc = new Kubectl('')
|
||||
|
||||
@@ -40,22 +61,21 @@ const TIMEOUT_240S = '240s'
|
||||
|
||||
describe('SMI Canary Helper tests', () => {
|
||||
let mockFilePaths: string[]
|
||||
let kubectlApplySpy: jest.SpyInstance
|
||||
let kubectlExecuteCommandSpy: jest.SpyInstance
|
||||
let kubectlApplySpy: MockInstance
|
||||
let kubectlExecuteCommandSpy: MockInstance
|
||||
|
||||
beforeEach(() => {
|
||||
//@ts-ignore
|
||||
Kubectl.mockClear()
|
||||
jest.restoreAllMocks()
|
||||
vi.mocked(Kubectl).mockClear()
|
||||
vi.restoreAllMocks()
|
||||
|
||||
mockFilePaths = testManifestFiles
|
||||
kubectlApplySpy = jest.spyOn(kc, 'apply')
|
||||
kubectlExecuteCommandSpy = jest
|
||||
kubectlApplySpy = vi.spyOn(kc, 'apply')
|
||||
kubectlExecuteCommandSpy = vi
|
||||
.spyOn(kc, 'executeCommand')
|
||||
.mockResolvedValue(mockExecuteCommandResult)
|
||||
|
||||
// Mock core.getInput with default values
|
||||
jest.spyOn(core, 'getInput').mockImplementation((name: string) => {
|
||||
vi.spyOn(core, 'getInput').mockImplementation((name: string) => {
|
||||
switch (name) {
|
||||
case 'percentage':
|
||||
return '50'
|
||||
@@ -72,7 +92,7 @@ describe('SMI Canary Helper tests', () => {
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks()
|
||||
vi.restoreAllMocks()
|
||||
kubectlApplySpy.mockClear()
|
||||
})
|
||||
|
||||
@@ -106,7 +126,7 @@ describe('SMI Canary Helper tests', () => {
|
||||
})
|
||||
|
||||
test('should handle custom replica count from input', async () => {
|
||||
jest.spyOn(core, 'getInput').mockImplementation((name: string) => {
|
||||
vi.spyOn(core, 'getInput').mockImplementation((name: string) => {
|
||||
switch (name) {
|
||||
case 'baseline-and-canary-replicas':
|
||||
return VALID_REPLICA_COUNT.toString()
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
import {Kubectl} from '../../types/kubectl'
|
||||
import {Kubectl} from '../../types/kubectl.js'
|
||||
import * as core from '@actions/core'
|
||||
import * as fs from 'fs'
|
||||
import * as yaml from 'js-yaml'
|
||||
|
||||
import * as fileHelper from '../../utilities/fileUtils'
|
||||
import * as kubectlUtils from '../../utilities/trafficSplitUtils'
|
||||
import * as canaryDeploymentHelper from './canaryHelper'
|
||||
import * as podCanaryHelper from './podCanaryHelper'
|
||||
import {isDeploymentEntity, isServiceEntity} from '../../types/kubernetesTypes'
|
||||
import {checkForErrors} from '../../utilities/kubectlUtils'
|
||||
import {inputAnnotations} from '../../inputUtils'
|
||||
import {DeployResult} from '../../types/deployResult'
|
||||
import {K8sObject} from '../../types/k8sObject'
|
||||
import * as fileHelper from '../../utilities/fileUtils.js'
|
||||
import * as kubectlUtils from '../../utilities/trafficSplitUtils.js'
|
||||
import * as canaryDeploymentHelper from './canaryHelper.js'
|
||||
import * as podCanaryHelper from './podCanaryHelper.js'
|
||||
import {
|
||||
isDeploymentEntity,
|
||||
isServiceEntity
|
||||
} from '../../types/kubernetesTypes.js'
|
||||
import {checkForErrors} from '../../utilities/kubectlUtils.js'
|
||||
import {inputAnnotations} from '../../inputUtils.js'
|
||||
import {DeployResult} from '../../types/deployResult.js'
|
||||
import {K8sObject} from '../../types/k8sObject.js'
|
||||
|
||||
const TRAFFIC_SPLIT_OBJECT_NAME_SUFFIX = '-workflow-rollout'
|
||||
const TRAFFIC_SPLIT_OBJECT = 'TrafficSplit'
|
||||
|
||||
Reference in New Issue
Block a user