1import { appCfgCtx } from '../../deployF/k8sF/ctxF/appCfgCtxF.mts'2import { read1File } from '../../serverF/libFs/read1FileF.mts'3import { allPromCalls } from '../../sharedF/moDashF/promF/allPromCallsF.mts'4import { betLog } from '../../sharedF/betterConsLogF.mts'5import { getPubEnv } from '../../serverF/getPubEnvF.mts'6import { ptDir } from '../../serverF/ptDirF.mts'7import { tsAbsPath, type absFileDirPath } from '../../ptDirF.mts'8import * as _ from 'lodash-es'9import { applyAndWaitRollout } from './mkNextDeploymentF.mts'10import { resourcesActionNames, resourcesActionsH } from '../../deployF/k8sF/isActionSupportedF.mts'11import { resourceActionWins } from '../../deployF/k8sF/resourceActionWinsAI.mts'12import { doSetProcessEnv } from '../../deployF/libF/doSetEnvF.mts'13import { mergeConcatA } from '../../sharedF/moDashF/mergeConcatAF.mts'14import { mutateAppCfg } from '../../deployF/mutateAppCfgF.mts'15import fs from 'fs'16import { toEnvLocal } from './toEnvLocalF.mts'17import { guardProdAction } from '../../deployF/readlineF/guardPromptF.mts'18import { reorderActionNames } from '../../deployF/cliF/cliHelpF.mts'19import { k8sCli } from '../../deployF/k8sF/cliF.mts'20import { buildNextDf } from './buildNextDfF.mts'21import { buildEnvConf } from '../../deployF/buildEnvConfF.mts'22import { deployActionGensDf, deployActionNeedsLazyDocker, deployActionBuildsDf } from '../../deployF/dockerF/deployActionGensDfF.mts'23import { decAppCfgResGitSha } from '../../deployF/decAppCfgResGitShaF.mts'24import { getDefaultEnv, getIsDevAction } from '../../deployF/getDefaultEnvF.mts'25import { isOcWeb } from '../../sharedF/isDevPcF.mts'26import { nextAppPaths } from './nextAppPathsF.mts'27import { epsToPathsGitCached } from '../../deployF/dockerF/dfFromMadgeF.mts'28import { getDeployNextCtx } from './deployNextF.mts'29import { getDeployActions } from '../../deployF/ptDeployActions/doPtDeployActionF.mts'30import { getPtDeployActionNames } from '../../deployF/ptDeployActions/getPtDeployActionNamesF.mts'31import { doPtDeployAction, tryDispatchAction } from '../../deployF/ptDeployActions/do1PtDeployActionF.mts'32import { ptDeployActionsCtx } from '../../deployF/ptDeployActions/doPtDeployActionF.mts'33import { doBuildSw } from '../../deployF/devpconlyF/doBuildSwF.mts'34import { doBuildWorker } from '../../deployF/devpconlyF/doBuildWorkerF.mts'36import { module1ToObj } from '../../sharedF/objF.mts'37import { generic3DeploymentTmpl } from '../../deployF/k8sF/genericDeploymentF.mts'38import { nextContCtx } from '../../deployF/libF/nextContCtxF.mts'39import { getNextSvcPortNo } from '../../serverF/getReqEnvConfItemF.mts'41import { devActionNames } from './devActionNamesF.mts'42import { doDevAction } from './doDevActionF.mts'43import * as devActions from './devActionsF.mts'44import { assertDefined } from '../../sharedF/assertsF/assertDefinedF.mts'45import { getHeadGitSha } from '../../deployF/libF/gitF/gitRepoF.mts'46import { nextDeployCtx } from '../../deployF/dockerF/dockerUtilsF.mts'47import { availActionsCtx } from '../../deployF/ctxF/availActionsCtxF.mts'48import { getAction } from '../../deployF/ctxF/actionCtxF.mts'49import { getCfProxied } from '../../deployF/k8sF/get1NonWcDnsF.mts'50import { initCliTimer } from '../../deployF/cliF/cliTimerCtxF.mts'51import { applyHistoryGuard } from '../../deployF/testsF/recordTestResultAI.mts'52import { isDeployAction } from '../../deployF/testsF/actionResultsAI.mts'53import { deriveDbNodePorts } from '../../deployF/deriveDbNodePortsAI.mts'54import { guardPendingMigrations } from '../../deployF/dbF/guardPendingMigrationsAI.mts'55import { parseCli } from '../../serverF/cliArgAI.mts'56import { applyCli } from '../../deployF/cliF/cliSchemaSetsF.mts'58const doSetEnvLocal = ({envLocal, envConf}: {envLocal: Record<string, string>, envConf: Record<string, unknown>}) => {59 const envLocalPath = [process.cwd(), '.env.local'].join('/')61 const envLocalS = toEnvLocal(envLocal)63 console.log({envLocal, envConf})65 fs.writeFileSync(envLocalPath, envLocalS)66}68// IMPORTANT: All appConfig mutations must happen BEFORE nextDeployCtx.enterWith69// because enterWith spreads a snapshot. Later mutations to appConfig won't70// be visible to code reading from getReqNextDeployCtx().71export const syncBuildDeployNextApp = async ({...appConfig}) => {73 if (isDeployAction(appConfig.action)) deriveDbNodePorts(appConfig)75 // Derive cfProxied before entering context (needed for docker build env)76 if (_.isUndefined(appConfig.cfProxied)) {77 const hostname = appConfig.nonWcHostname || appConfig.kube_extHostname78 if (hostname) appConfig.cfProxied = getCfProxied(hostname)79 }81 nextDeployCtx.enterWith({...appConfig})83 let {84 appPath, name, action, cluster_name,85 envConf={}, envLocal, dockerEnv, prebuildEnvConfH,86 cfProxied, dbQsCfg,87 } = appConfig89 if (action === 'apply') {91 if (cli.history) {92 const statsRows = appConfig.deployHistoryStatsF ? await appConfig.deployHistoryStatsF({ep: appConfig.importMetaUrl, appConfig}) : undefined93 await applyHistoryGuard(appConfig.importMetaUrl, statsRows, appConfig.deployHistoryStatsLabel)94 return appConfig95 }97 }98 const isDevAction = getIsDevAction({action})99 if ((!isDevAction || isOcWeb) && name && cluster_name) {100 envConf = buildEnvConf({envConf, action, cluster_name, name, importMetaUrl: appConfig.importMetaUrl})101 }103 const {gpIsProd} = dbQsCfg || {}104 if (gpIsProd) await guardProdAction({gpIsProd, action, name})105 let git_sha = 'devvv'106 if (!isDevAction && appPath) {107 git_sha = await getHeadGitSha()108 }109 mutateAppCfg(appConfig, {git_sha, getVirtualPathsFnc: () => nextAppPaths({inclServer: true, inclClient: true})})111 const nextIsDev = _.includes(['setprocenv', 'devserver'], action)112 if (nextIsDev) {113 prebuildEnvConfH.nextCfgH ||= {}114 }116 if (appConfig.extraActions) {117 ptDeployActionsCtx.enterWith({...ptDeployActionsCtx.getStore(), ...appConfig.extraActions})118 availActionsCtx.enterWith({...availActionsCtx.getStore(), ...appConfig.extraActions})119 }120 appCfgCtx.enterWith(appConfig)121 // Handle extraActions (rotatewchn, etc) early before docker setup122 // Only dispatch if action came from argv (not overridden by caller like setDevPcEnv)123 if (action === getAction() && await tryDispatchAction()) return appConfig124 const defaultEnv = getDefaultEnv()125 Object.assign(defaultEnv, {126 NODE_ENV: nextIsDev ? 'development' : 'production' // necessary fix for next.js, not .mjs?127 })129 if (cfProxied) envConf = {...envConf, cfProxied}130 const {svcPortNo=3000} = appConfig131 envConf = {...envConf, nextSvcPortNo: svcPortNo, nextIsDev}133 dockerEnv = _.merge(defaultEnv, dockerEnv)134 envLocal = _.merge(defaultEnv, envLocal)136 doSetProcessEnv({envLocal, envConf})137 mutateAppCfg(appConfig, {envConf, envLocal})139 if (isDeployAction(action)) await guardPendingMigrations({appCfg: appConfig})141 const needsDocker = deployActionGensDf({action})142 const needsLazyDocker = deployActionNeedsLazyDocker({action})144 if (needsDocker || needsLazyDocker) {146 const needsSwBuild = deployActionBuildsDf({action})147 if (needsSwBuild) {149 if (builtSwFilename) {151 }152 if (builtWorkerFilename) {153 await doBuildWorker()154 const workerPtPath = `${appPath}/public/${builtWorkerFilename}`156 if (fs.existsSync(workerAbsPath)) {157 const workerContent = fs.readFileSync(workerAbsPath, 'utf8')158 appConfig.inclContentH ??= {}159 appConfig.inclContentH[workerPtPath] = workerContent160 }161 }162 }164 const epPtPathsA = await nextAppPaths()166 mutateAppCfg(appConfig, {epPtPathsA})167 const afterYarnInstallDockPathsA = await epsToPathsGitCached({epPtPathsA})168 const buildSha = isDevAction ? 'devvv' : await getHeadGitSha({filterPathList: afterYarnInstallDockPathsA})169 mutateAppCfg(appConfig, {buildSha})171 const {getBoundaryDir} = getDeployNextCtx()172 const clientDockPaths = _.filter(afterYarnInstallDockPathsA, (path) => ['componentsF', 'sharedF'].includes(getBoundaryDir(path)))174 // pubEnvKeyA computation - needed for apply action175 const computePubEnvKeyA = async () => {176 const {transTokensHToPlain, transTokenFromPlain} = getDeployNextCtx()177 const {envConf: {gpMaybePubEnvH}} = appConfig178 const maybePubEnvH = transTokensHToPlain(gpMaybePubEnvH) 179 const seenTokensByPathH = _.chain(await allPromCalls(clientDockPaths, async (path: string) => {181 const foundPubEnvKeysA = _.chain(maybePubEnvH).keys().filter((pubEnvKey) => {182 return _.includes(contents, pubEnvKey)183 }).value()184 if (foundPubEnvKeysA.length == 0) return185 return [path, foundPubEnvKeysA]186 })).compact().fromPairs().value()187 const pubEnvKeyA = _.chain(seenTokensByPathH).values().flatten().uniq().map((orig) => {188 return transTokenFromPlain({orig, prebuildEnvConfH})189 }).value()190 Object.assign(appConfig.envConf, {pubEnvKeyA})191 }193 if (needsDocker && !needsLazyDocker) {194 // immediate build195 mutateAppCfg(appConfig, {dockerFilesA: await buildNextDf({action, dockerEnv, git_sha, buildSha, afterYarnInstallDockPathsA: afterYarnInstallDockPathsA as absFileDirPath[]})})196 } else {197 // lazy build - store builder function, invoked by imageFromAppCfg when needed198 const dockerBuilder = async () => {199 return await buildNextDf({action: 'apply', dockerEnv, git_sha, buildSha, afterYarnInstallDockPathsA: afterYarnInstallDockPathsA as absFileDirPath[]})200 }201 mutateAppCfg(appConfig, {dockerBuilder})202 }203 if (!isDevAction) await computePubEnvKeyA()204 }206 if (action == 'setprocenv') {207 return appConfig208 }210 if (action == 'setenv') {211 doSetEnvLocal({envLocal, envConf})212 return appConfig213 }215 mutateAppCfg(appConfig, {resourceTmpl: generic3DeploymentTmpl({name})})216 appConfig = await decAppCfgResGitSha({appConfig})218 nextContCtx.enterWith({...nextContCtx.getStore(), 219 name: 'nextcont',220 livenessProbe: {221 initialDelaySeconds: 3,222 periodSeconds: 3,223 timeoutSeconds: 5,224 failureThreshold: 5,225 httpGet: {226 path: '/health/liveness',227 port: getNextSvcPortNo(),228 }229 },230 })231 // composed action (extraActions) owns ordering: its testlocal phase must run before any docker build232 if (action === getAction() && getDeployActions()[action] && await doPtDeployAction()) return appConfig233 await applyAndWaitRollout(appConfig)235 if (resourceActionWins(action)) {236 return appConfig237 }239 appCfgCtx.enterWith(appConfig)240 if (await doPtDeployAction()) return appConfig242 if (getIsDevAction({action})) {243 await doDevAction()244 return appConfig245 }247 const actionsH = {...resourcesActionsH(), ...module1ToObj(getDeployActions()), ...devActions}248 const actionNames = [249 ...resourcesActionNames(),250 ...devActionNames,251 'help',252 ...getPtDeployActionNames(),253 ]254 k8sCli({actionNames: reorderActionNames(actionNames, actionsH as any), actionsH: actionsH as any})256 return appConfig257}