mirror of
https://github.com/Azure/k8s-deploy.git
synced 2026-04-07 13:52:16 +08:00
* 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
119 lines
4.3 KiB
TypeScript
119 lines
4.3 KiB
TypeScript
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.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[],
|
|
kubectl: Kubectl,
|
|
onlyDeployStable: boolean = false,
|
|
timeout?: string
|
|
): Promise<DeployResult> {
|
|
const newObjectsList = []
|
|
const percentage = parseInt(core.getInput('percentage', {required: true}))
|
|
|
|
if (percentage < 0 || percentage > 100)
|
|
throw Error('Percentage must be between 0 and 100')
|
|
|
|
for (const filePath of filePaths) {
|
|
try {
|
|
const fileContents = fs.readFileSync(filePath, 'utf8')
|
|
const parsedYaml = yaml.loadAll(fileContents)
|
|
for (const inputObject of parsedYaml) {
|
|
if (
|
|
inputObject &&
|
|
typeof inputObject === 'object' &&
|
|
'metadata' in inputObject &&
|
|
'kind' in inputObject &&
|
|
'spec' in inputObject &&
|
|
typeof inputObject.metadata === 'object' &&
|
|
'name' in inputObject.metadata &&
|
|
typeof inputObject.metadata.name === 'string' &&
|
|
typeof inputObject.kind === 'string'
|
|
) {
|
|
const obj = inputObject as K8sObject
|
|
const name = obj.metadata.name
|
|
const kind = obj.kind
|
|
|
|
if (!onlyDeployStable && isDeploymentEntity(kind)) {
|
|
core.debug('Calculating replica count for canary')
|
|
const canaryReplicaCount = calculateReplicaCountForCanary(
|
|
obj,
|
|
percentage
|
|
)
|
|
core.debug('Replica count is ' + canaryReplicaCount)
|
|
|
|
const newCanaryObject =
|
|
canaryDeploymentHelper.getNewCanaryResource(
|
|
obj,
|
|
canaryReplicaCount
|
|
)
|
|
newObjectsList.push(newCanaryObject)
|
|
|
|
// if there's already a stable object, deploy baseline as well
|
|
const stableObject =
|
|
await canaryDeploymentHelper.fetchResource(
|
|
kubectl,
|
|
kind,
|
|
name
|
|
)
|
|
if (stableObject) {
|
|
core.debug(
|
|
`Stable object found for ${kind} ${name}. Creating baseline objects`
|
|
)
|
|
const newBaselineObject =
|
|
canaryDeploymentHelper.getNewBaselineResource(
|
|
stableObject,
|
|
canaryReplicaCount
|
|
)
|
|
core.debug(
|
|
'New baseline object: ' +
|
|
JSON.stringify(newBaselineObject)
|
|
)
|
|
newObjectsList.push(newBaselineObject)
|
|
}
|
|
} else {
|
|
// deploy non deployment entity or regular deployments for promote as they are
|
|
newObjectsList.push(obj)
|
|
}
|
|
}
|
|
}
|
|
} catch (error) {
|
|
core.error(
|
|
`Failed to parse YAML file at ${filePath}: ${error.message}`
|
|
)
|
|
throw error
|
|
}
|
|
}
|
|
|
|
core.debug('New objects list: ' + JSON.stringify(newObjectsList))
|
|
const manifestFiles = fileHelper.writeObjectsToFile(newObjectsList)
|
|
const forceDeployment = core.getInput('force').toLowerCase() === 'true'
|
|
const serverSideApply = core.getInput('server-side').toLowerCase() === 'true'
|
|
|
|
const execResult = await kubectl.apply(
|
|
manifestFiles,
|
|
forceDeployment,
|
|
serverSideApply,
|
|
timeout
|
|
)
|
|
checkForErrors([execResult])
|
|
return {execResult, manifestFiles}
|
|
}
|
|
|
|
export function calculateReplicaCountForCanary(
|
|
inputObject: any,
|
|
percentage: number
|
|
) {
|
|
const inputReplicaCount = getReplicaCount(inputObject)
|
|
return Math.max(1, Math.round((inputReplicaCount * percentage) / 100))
|
|
}
|