#!/usr/bin/env node /** * Deploy C-----code via Helm * * Usage: * node scripts/deploy.js # Deploy with defaults * node scripts/deploy.js --dry-run # Dry run only * node scripts/deploy.js --migrate # Run migrations first * * Environment: * REGISTRY - Docker registry (default: harbor.gitdata.me/gta_team) * TAG - Image tag (default: latest) * NAMESPACE - Kubernetes namespace (default: gitdata) * RELEASE - Helm release name (default: gitdata) * KUBECONFIG - Path to kubeconfig (default: ~/.kube/config) */ const {execSync} = require('child_process'); const path = require('path'); const fs = require('fs'); const REGISTRY = process.env.REGISTRY || 'harbor.gitdata.me/gta_team'; const TAG = process.env.TAG || process.env.GITHUB_SHA?.substring(0, 8) || 'latest'; const NAMESPACE = process.env.NAMESPACE || 'gitdataai'; const RELEASE = process.env.RELEASE || 'gitdata'; const CHART_PATH = path.join(__dirname, '..', 'deploy'); const KUBECONFIG = process.env.KUBECONFIG || path.join(process.env.HOME || process.env.USERPROFILE, '.kube', 'config'); const args = process.argv.slice(2); const isDryRun = args.includes('--dry-run'); const runMigrate = args.includes('--migrate'); const SERVICES = ['app', 'gitserver', 'email-worker', 'git-hook', 'operator', 'static', 'frontend']; // Validate kubeconfig if (!fs.existsSync(KUBECONFIG)) { console.error(`Error: kubeconfig not found at ${KUBECONFIG}`); console.error('Set KUBECONFIG environment variable or ensure ~/.kube/config exists'); process.exit(1); } console.log(`\n=== Deploy Configuration ===`); console.log(`Registry: ${REGISTRY}`); console.log(`Tag: ${TAG}`); console.log(`Namespace: ${NAMESPACE}`); console.log(`Release: ${RELEASE}`); console.log(`Dry Run: ${isDryRun}`); console.log(`Run Migrate: ${runMigrate}`); console.log(''); // Build helm values override const valuesFile = path.join(CHART_PATH, 'values.yaml'); const userValuesFile = path.join(CHART_PATH, 'values.user.yaml'); const setValues = [ `image.registry=${REGISTRY}`, `app.image.tag=${TAG}`, `gitserver.image.tag=${TAG}`, `emailWorker.image.tag=${TAG}`, `gitHook.image.tag=${TAG}`, `operator.image.tag=${TAG}`, `static.image.tag=${TAG}`, `frontend.image.tag=${TAG}`, ]; if (runMigrate) { setValues.push('migrate.enabled=true'); } const helmArgs = [ 'upgrade', '--install', RELEASE, CHART_PATH, '--namespace', NAMESPACE, '--create-namespace', '-f', valuesFile, ...(fs.existsSync(userValuesFile) ? ['-f', userValuesFile] : []), ...setValues.flatMap(v => ['--set', v]), '--wait', '--timeout', '5m', ]; if (isDryRun) { helmArgs.push('--dry-run'); console.log('==> Dry run mode - no changes will be made\n'); } // Helm upgrade console.log(`==> Running helm upgrade`); console.log(` Command: helm ${helmArgs.join(' ')}\n`); try { execSync(`helm ${helmArgs.join(' ')}`, {stdio: 'inherit', env: {...process.env, KUBECONFIG}}); console.log(`\n[OK] Deployment ${isDryRun ? '(dry-run) ' : ''}complete`); } catch (error) { console.error('\n[FAIL] Deployment failed'); process.exit(1); } // Rollout status if (!isDryRun) { console.log('\n==> Checking rollout status'); for (const service of SERVICES) { const deploymentName = `${RELEASE}-${service}`; console.log(` Checking ${deploymentName}...`); try { execSync( `kubectl rollout status deployment/${deploymentName} -n ${NAMESPACE} --timeout=120s`, {stdio: 'pipe', env: {...process.env, KUBECONFIG}} ); console.log(` [OK] ${deploymentName}`); } catch (error) { console.error(` [WARN] ${deploymentName} rollout timeout or failed`); } } } console.log('\n=== Deploy Complete ===\n');