From 7b1dac18d4a271b91ea9fa7a0e42df15cdcf444e Mon Sep 17 00:00:00 2001 From: kleap-admin Date: Fri, 16 Jan 2026 10:55:05 +0000 Subject: [PATCH] Update test-vercel-deploy.mjs --- test-vercel-deploy.mjs | 218 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 218 insertions(+) create mode 100644 test-vercel-deploy.mjs diff --git a/test-vercel-deploy.mjs b/test-vercel-deploy.mjs new file mode 100644 index 0000000..033c5eb --- /dev/null +++ b/test-vercel-deploy.mjs @@ -0,0 +1,218 @@ +#!/usr/bin/env node +import { readFileSync, readdirSync, statSync } from 'fs'; +import { join, relative } from 'path'; +import { fileURLToPath } from 'url'; +import { dirname } from 'path'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +const VERCEL_TOKEN = 'RBZ7Ti5xx2n01qugE4bEPuLR'; +const TEAM_ID = 'kleap-ai-apps'; + +// Files to exclude +const EXCLUDE_PATTERNS = [ + 'node_modules', + '.next', + '.git', + '.DS_Store', + 'test-vercel-deploy.mjs', + '.env.local', + 'tsconfig.tsbuildinfo', +]; + +function shouldExclude(path) { + return EXCLUDE_PATTERNS.some(pattern => path.includes(pattern)); +} + +function getAllFiles(dir, baseDir = dir) { + const files = []; + + const items = readdirSync(dir); + + for (const item of items) { + const fullPath = join(dir, item); + const relativePath = relative(baseDir, fullPath); + + if (shouldExclude(relativePath)) continue; + + const stat = statSync(fullPath); + + if (stat.isDirectory()) { + files.push(...getAllFiles(fullPath, baseDir)); + } else if (stat.isFile()) { + files.push({ + path: relativePath, + fullPath: fullPath + }); + } + } + + return files; +} + +function encodeFile(filePath) { + const content = readFileSync(filePath); + return content.toString('base64'); +} + +async function deployToVercel() { + console.log('šŸ“¦ Collecting template files...'); + + const allFiles = getAllFiles(__dirname); + console.log(`šŸ“ Found ${allFiles.length} files`); + + // Prepare files for Vercel + const vercelFiles = allFiles.map(({ path, fullPath }) => { + const data = encodeFile(fullPath); + return { + file: path, + data: data, + encoding: 'base64' + }; + }); + + // Log key files + console.log('šŸ“„ Key files:'); + ['package.json', 'next.config.mjs', 'vercel.json', 'postcss.config.mjs'].forEach(file => { + if (vercelFiles.find(f => f.file === file)) { + console.log(` āœ… ${file}`); + } else { + console.log(` āŒ ${file} MISSING!`); + } + }); + + // Create deployment payload + const payload = { + name: 'kleap-template-test', + files: vercelFiles, + projectSettings: { + framework: 'nextjs', + buildCommand: 'npm run build', + outputDirectory: '.next', + installCommand: 'npm ci --no-audit --no-fund && npm install --platform=linux --arch=x64 tailwindcss@4.1.10 @tailwindcss/postcss@4.1.10 postcss@latest lightningcss-linux-x64-gnu @tailwindcss/oxide-linux-x64-gnu', + }, + target: 'production', + meta: { + test: 'true', + description: 'Testing Next.js 16 + React 19 deployment' + } + }; + + console.log('\nšŸš€ Deploying to Vercel...'); + console.log(` Team: ${TEAM_ID}`); + console.log(` Files: ${vercelFiles.length}`); + + const deployUrl = `https://api.vercel.com/v13/deployments?teamId=${TEAM_ID}`; + + const response = await fetch(deployUrl, { + method: 'POST', + headers: { + 'Authorization': `Bearer ${VERCEL_TOKEN}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify(payload) + }); + + if (!response.ok) { + const error = await response.json(); + console.error('āŒ Deployment failed:', error); + process.exit(1); + } + + const deployment = await response.json(); + console.log('\nāœ… Deployment created!'); + console.log(` ID: ${deployment.id}`); + console.log(` URL: https://${deployment.url}`); + console.log(` Status: ${deployment.readyState || deployment.state || 'QUEUED'}`); + + // Monitor deployment status + console.log('\nā³ Monitoring deployment...'); + await monitorDeployment(deployment.id); +} + +async function monitorDeployment(deploymentId) { + const maxAttempts = 120; // 10 minutes (5 seconds * 120) + let attempts = 0; + + while (attempts < maxAttempts) { + await new Promise(resolve => setTimeout(resolve, 5000)); + attempts++; + + const statusUrl = `https://api.vercel.com/v13/deployments/${deploymentId}?teamId=${TEAM_ID}`; + + try { + const response = await fetch(statusUrl, { + headers: { + 'Authorization': `Bearer ${VERCEL_TOKEN}` + } + }); + + if (!response.ok) continue; + + const data = await response.json(); + const status = data.readyState || data.state || data.status; + + console.log(`[${attempts}/${maxAttempts}] Status: ${status}`); + + if (status === 'READY') { + console.log('\nšŸŽ‰ DEPLOYMENT SUCCESSFUL!'); + console.log(` URL: https://${data.url}`); + console.log(` Status: READY`); + + // Fetch build logs + await fetchBuildLogs(deploymentId); + return; + } + + if (status === 'ERROR' || status === 'FAILED' || status === 'CANCELED') { + console.log('\nāŒ DEPLOYMENT FAILED!'); + console.log(` Status: ${status}`); + await fetchBuildLogs(deploymentId); + process.exit(1); + } + } catch (error) { + console.error('Error checking status:', error.message); + } + } + + console.log('\nā±ļø Timeout - deployment took too long'); +} + +async function fetchBuildLogs(deploymentId) { + console.log('\nšŸ“‹ Fetching build logs...'); + + const logsUrl = `https://api.vercel.com/v3/deployments/${deploymentId}/events?teamId=${TEAM_ID}&builds=1&limit=100&direction=backward`; + + try { + const response = await fetch(logsUrl, { + headers: { + 'Authorization': `Bearer ${VERCEL_TOKEN}` + } + }); + + if (!response.ok) { + console.error('Failed to fetch logs'); + return; + } + + const logs = await response.json(); + + console.log('\n--- BUILD LOGS ---'); + logs.forEach(log => { + const text = log.text || log.payload?.text || ''; + if (text) { + console.log(text); + } + }); + console.log('--- END LOGS ---\n'); + } catch (error) { + console.error('Error fetching logs:', error.message); + } +} + +// Run deployment +deployToVercel().catch(error => { + console.error('Fatal error:', error); + process.exit(1); +});