import { execSync } from "node:child_process"; import { createInterface } from "node:readline"; // Configuration const ENV_BRANCH_MAP: Record = { test: "test", stage: "stage", preprod: "prod", prod: "release", }; const args = process.argv.slice(2); const targetEnv = args[0]; // Validate input if (!targetEnv) { console.error("āŒ Error: Please provide an environment."); console.log( `Usage: yarn dlx tsx deploy.ts <${Object.keys(ENV_BRANCH_MAP).join("|")}>` ); process.exit(1); } const targetBranch = ENV_BRANCH_MAP[targetEnv]; if (!targetBranch) { console.error(`āŒ Error: Invalid environment '${targetEnv}'.`); console.log( `Available environments: ${Object.keys(ENV_BRANCH_MAP).join(", ")}` ); process.exit(1); } // Git helper const runGit = ( command: string, options: { stdio?: "inherit" | "ignore" | "pipe" } = {} ) => { return execSync(command, { encoding: "utf-8", ...options }).trim(); }; async function main() { try { // Get current branch const currentBranch = runGit("git rev-parse --abbrev-ref HEAD"); console.log( `\nšŸš€ Preparing to deploy branch '${currentBranch}' to '${targetEnv}' (target branch: '${targetBranch}')` ); // Check for tagging requirement let tagToCreate: string | null = null; const releaseBranchRegex = /^release-(v\d+\.\d+\.\d+)$/; const releaseBranchMatch = currentBranch.match(releaseBranchRegex); if (releaseBranchMatch) { const tagName = releaseBranchMatch[1]; try { // Check if tag already exists locally or remote // Checking local first runGit(`git rev-parse ${tagName}`, { stdio: "ignore" }); console.log(`ā„¹ļø Tag '${tagName}' already exists.`); } catch { // Tag doesn't exist tagToCreate = tagName; console.log(`✨ Will create and push tag: '${tagName}'`); } } if (!releaseBranchMatch && targetEnv === "prod") { console.warn( "āš ļø Warning: Deploying to prod from a non-release branch. No version tag will be created." ); } // Confirmation prompt const rl = createInterface({ input: process.stdin, output: process.stdout, }); const confirmed = await new Promise((resolve) => { rl.question( `\nā“ Are you sure you want to deploy ${currentBranch} to ${targetEnv}? (y/n) `, (answer) => { rl.close(); resolve(answer.toLowerCase() === "y"); } ); }); if (!confirmed) { console.log("🚫 Deployment aborted."); process.exit(0); } console.log("\nšŸ”„ Starting deployment..."); // 1. Create and push tag if needed if (tagToCreate) { console.log(`šŸ·ļø Creating tag ${tagToCreate}...`); runGit(`git tag ${tagToCreate}`); console.log(`ā¬†ļø Pushing tag ${tagToCreate}...`); runGit(`git push origin ${tagToCreate}`); } // 2. Force push to target branch console.log( `šŸ”„ Force pushing '${currentBranch}' to 'origin/${targetBranch}'...` ); runGit( `git push origin ${currentBranch}:${targetBranch} --force-with-lease`, { stdio: "inherit", } ); console.log(`\nāœ… Deployment to ${targetEnv} completed successfully!`); } catch (error) { console.error("\nāŒ Deployment failed."); if (error instanceof Error) { console.error(error.message); } process.exit(1); } } main();