🌳
pt0/deployF/testsF/testdeployActionAI.mts
4import { klusterCtx, type KlusterCfg } from '../k8sF/ctxF/klusterCtxF.mts'
20export type TestdeployConfig = {
21 getTestConfig: () => Promise<RunTestsCoreConfig>
24const getEpPath = () => toPtRelPath(getAppCfg()?.importMetaUrl || '')
26export const mkTestdeploy = (cfg: TestdeployConfig) => {
27 const testdeploy = async () => {
28 const cli = parseCli(testdeployCli)
29 if (cli.history) {
30 printTestHistory({ ep: getAppCfg()?.importMetaUrl, actions: ['runtests', 'apply'] })
31 return
32 }
34 printTestdeployEta(getAppCfg()?.importMetaUrl || '')
36 const { getTestConfig } = cfg
37 const config = await getTestConfig()
38 const epPath = getEpPath()
40 const totalStart = Date.now()
41 const phases: Record<string, number> = {}
43 const t1 = Date.now()
44 const localOpts = defaultRunTestsOpts(config.allSuites, 'testlocal')
45 const localResult = await runTestsCore({ config, opts: localOpts })
46 phases.runtests_local = elapsedSec(t1)
47 if (!localResult.allPassed) {
48 console.log(chalkRed('testlocal failed, aborting'))
49 process.exit(1)
50 }
52 console.log(chalkCyan('apply'))
53 const t2 = Date.now()
55 const appCfg = getAppCfg()
56 assertDefined(appCfg.cluster_name, {appCfg})
57 mutateAppCfg(appCfg, {action: 'apply' as const})
58 actionCtx.enterWith({action: 'apply'}) // ctx:clear
59 klusterCtx.enterWith(appCfg as KlusterCfg) // ctx:clear
60 cliValidatedCtx.enterWith({validated: true}) // ctx:clear
62 await applyAndWaitRollout(appCfg)
65 phases.apply = elapsedSec(t2)
67 if (config.preDeployedTests) await config.preDeployedTests()
69 const t3 = Date.now()
70 const deployedOpts = { ...defaultRunTestsOpts(config.allSuites, 'testprod'), isTestdeploy: true }
71 const deployedResult = await runTestsCore({ config, opts: deployedOpts })
72 phases.runtests_deployed = elapsedSec(t3)
74 if (!deployedResult.allPassed) {
75 console.log(chalkRed('testprod failed'))
76 process.exit(1)
77 }
79 const testsActuallyRan = localResult.totalTests > 0 || deployedResult.totalTests > 0
80 if (testsActuallyRan) {
81 const builder = currentBuilder()
82 const {imageReused} = getAppCfg() as {imageReused?: boolean}
84 ep: epPath,
85 action: 'testdeploy',
86 ts: new Date().toISOString(),
87 durationSec: elapsedSec(totalStart),
88 success: true,
89 gitSha: getGitShaFull(),
90 phases,
91 ptenv: 'testprod',
92 suites: deployedResult.ranSuites,
93 ...(builder !== 'docker' && {builder}),
94 ...(imageReused && {imageReused}),
95 })
96 }
98 console.log(chalkGreen('testdeploy complete'))
99 }
101 testdeploy.cliDescript = testdeployDescript
102 testdeploy.cliSchema = testdeployCli
103 testdeploy.needsLazyDocker = true // prep paths + lazy builder, actual build during apply phase
104 return testdeploy