import { execSync } from 'child_process'; import { resolve } from 'path'; import { fileURLToPath } from 'url'; import { dirname } from 'path'; import process from 'process'; const __dirname = dirname(fileURLToPath(import.meta.url)); const ROOT = resolve(__dirname, '..'); // colors const G = (s) => `\x1b[0;32m${s}\x1b[0m`; const Y = (s) => `\x1b[1;33m${s}\x1b[0m`; const R = (s) => `\x1b[0;31m${s}\x1b[0m`; const log = (msg) => console.log(`${G('[OK]')} ${msg}`); const warn = (msg) => console.warn(`${Y('[WARN]')} ${msg}`); const err = (msg) => { console.error(`${R('[ERR]')} ${msg}`); process.exit(1); }; // ── defaults ── const NAMESPACE = process.env.NAMESPACE || 'app'; const RELEASE = process.env.RELEASE || 'deploy'; const CHART_DIR = process.env.CHART_DIR || resolve(ROOT, 'deploy'); const REGISTRY = process.env.REGISTRY || 'harbor.gitdata.me/gtateam'; const TAG = process.env.TAG || execSync('git rev-parse --short HEAD', { encoding: 'utf8', cwd: ROOT }).trim(); const CONFIG_MAP = process.env.CONFIG_MAP || 'app-env'; const PVC_NAME = process.env.PVC_NAME || 'shared-data'; // ── prereqs ── try { execSync('helm version --short', { stdio: 'pipe' }); } catch { err('helm not found'); } try { execSync('kubectl version --client', { stdio: 'pipe' }); } catch { err('kubectl not found'); } log(execSync('helm version --short', { encoding: 'utf8' }).trim()); log(execSync('kubectl version --client --short 2>/dev/null || kubectl version -o json 2>/dev/null | grep gitVersion', { encoding: 'utf8', shell: true }).trim()); // ── 1. Ensure namespace ── log(`Ensuring namespace ${NAMESPACE} exists...`); execSync(`kubectl create namespace "${NAMESPACE}" --dry-run=client -o yaml | kubectl apply -f -`, { stdio: 'inherit' }); // ── 2. Verify prerequisites ── try { execSync(`kubectl get namespace "${NAMESPACE}"`, { stdio: 'pipe' }); } catch { err(`Namespace '${NAMESPACE}' not found`); } try { execSync(`kubectl get configmap "${CONFIG_MAP}" -n "${NAMESPACE}"`, { stdio: 'pipe' }); } catch { err(`ConfigMap '${CONFIG_MAP}' not found in namespace '${NAMESPACE}'`); } try { execSync(`kubectl get pvc "${PVC_NAME}" -n "${NAMESPACE}"`, { stdio: 'pipe' }); } catch { err(`PVC '${PVC_NAME}' not found in namespace '${NAMESPACE}'`); } // Protect from Helm deletion execSync(`kubectl annotate configmap "${CONFIG_MAP}" -n "${NAMESPACE}" helm.sh/resource-policy=keep --overwrite`, { stdio: 'inherit' }); execSync(`kubectl annotate pvc "${PVC_NAME}" -n "${NAMESPACE}" helm.sh/resource-policy=keep --overwrite`, { stdio: 'inherit' }); // cert-manager ClusterIssuer try { execSync('kubectl get clusterissuer cloudflare-acme-cluster-issuer', { stdio: 'pipe' }); } catch { warn("ClusterIssuer 'cloudflare-acme-cluster-issuer' not found — TLS will fail"); } log('Prerequisites verified'); // ── 3. Lint ── log('Linting Helm chart...'); try { execSync(`helm lint "${CHART_DIR}"`, { stdio: 'inherit' }); } catch { err('Helm lint failed'); } // ── 4. Deploy ── log(`Deploying release ${RELEASE} with tag ${TAG}...`); try { execSync( `helm upgrade --install "${RELEASE}" "${CHART_DIR}"` + ` --namespace "${NAMESPACE}"` + ` --set imageRegistry="${REGISTRY}"` + ` --set imageTag="${TAG}"` + ` --set configMapName="${CONFIG_MAP}"` + ` --set pvcName="${PVC_NAME}"` + ` --timeout 5m`, { stdio: 'inherit' } ); } catch { err(`Deployment FAILED — release preserved for debugging. Debug commands: helm status ${RELEASE} -n ${NAMESPACE} kubectl get pods -n ${NAMESPACE} kubectl logs -n app --previous helm rollback ${RELEASE} -n ${NAMESPACE} (rollback to previous release) helm uninstall ${RELEASE} -n ${NAMESPACE} (remove failed release)`); } log(`Release ${RELEASE} deployed successfully`); // ── 5. Verify ── log('Checking deployment status...'); execSync(`kubectl get deployments -n "${NAMESPACE}" -l app.kubernetes.io/instance="${RELEASE}"`, { stdio: 'inherit' }); execSync(`kubectl get pods -n "${NAMESPACE}" -l app.kubernetes.io/instance="${RELEASE}"`, { stdio: 'inherit' }); execSync(`kubectl get services -n "${NAMESPACE}" -l app.kubernetes.io/instance="${RELEASE}"`, { stdio: 'inherit' }); execSync(`kubectl get ingress -n "${NAMESPACE}"`, { stdio: 'inherit' }); log('Deployment complete');