子仓库提交
This commit is contained in:
387
crop-x-new/scripts/build.cjs
Normal file
387
crop-x-new/scripts/build.cjs
Normal file
@@ -0,0 +1,387 @@
|
||||
/**
|
||||
* 统一构建脚本
|
||||
*
|
||||
* 整合环境设置、API生成和Next.js构建的完整构建流程
|
||||
* 支持多环境构建:dev, test, uat, prod
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { execSync, spawn } = require('child_process');
|
||||
|
||||
// ANSI 颜色代码
|
||||
const colors = {
|
||||
reset: '\x1b[0m',
|
||||
red: '\x1b[31m',
|
||||
green: '\x1b[32m',
|
||||
yellow: '\x1b[33m',
|
||||
blue: '\x1b[34m',
|
||||
cyan: '\x1b[36m',
|
||||
white: '\x1b[37m'
|
||||
};
|
||||
|
||||
// 日志函数
|
||||
function log(message, color = 'white') {
|
||||
console.log(`${colors[color]}${message}${colors.reset}`);
|
||||
}
|
||||
|
||||
function logSuccess(message) {
|
||||
log(`✓ ${message}`, 'green');
|
||||
}
|
||||
|
||||
function logError(message) {
|
||||
log(`✗ ${message}`, 'red');
|
||||
}
|
||||
|
||||
function logInfo(message) {
|
||||
log(`ℹ ${message}`, 'blue');
|
||||
}
|
||||
|
||||
function logStep(message) {
|
||||
log(`🔄 ${message}`, 'cyan');
|
||||
}
|
||||
|
||||
function logWarning(message) {
|
||||
log(`⚠ ${message}`, 'yellow');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取命令行参数中的环境
|
||||
*/
|
||||
function getEnvironmentFromArgs() {
|
||||
const args = process.argv.slice(2);
|
||||
|
||||
// 查找 --env 参数
|
||||
const envArg = args.find(arg => arg.startsWith('--env='));
|
||||
if (envArg) {
|
||||
return envArg.split('=')[1];
|
||||
}
|
||||
|
||||
// 查找直接的参数
|
||||
const directEnv = args[0];
|
||||
if (['dev', 'test', 'uat', 'prod'].includes(directEnv)) {
|
||||
return directEnv;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证环境名称
|
||||
*/
|
||||
function validateEnvironment(env) {
|
||||
const validEnvs = ['dev', 'test', 'uat', 'prod'];
|
||||
if (!validEnvs.includes(env)) {
|
||||
logError(`无效的环境名称: ${env}`);
|
||||
logInfo(`支持的环境: ${validEnvs.join(', ')}`);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制环境配置文件
|
||||
*/
|
||||
function copyEnvironmentConfig(env) {
|
||||
logStep(`设置 ${env} 环境配置`);
|
||||
|
||||
const envDir = path.join(process.cwd(), 'env');
|
||||
const sourceFile = path.join(envDir, `.env.${env}`);
|
||||
const targetFile = path.join(process.cwd(), '.env.local');
|
||||
|
||||
// 检查源文件是否存在
|
||||
if (!fs.existsSync(sourceFile)) {
|
||||
logError(`环境配置文件不存在: ${sourceFile}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
// 复制文件
|
||||
fs.copyFileSync(sourceFile, targetFile);
|
||||
logSuccess(`已复制环境配置: ${env}`);
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
logError(`复制环境配置文件失败: ${error.message}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理缓存目录
|
||||
*/
|
||||
function cleanCache() {
|
||||
logStep('清理缓存目录');
|
||||
|
||||
const dirsToClean = ['.next', 'node_modules/.cache'];
|
||||
|
||||
dirsToClean.forEach(dir => {
|
||||
const dirPath = path.join(process.cwd(), dir);
|
||||
if (fs.existsSync(dirPath)) {
|
||||
try {
|
||||
fs.rmSync(dirPath, { recursive: true, force: true });
|
||||
logSuccess(`已清理: ${dir}`);
|
||||
} catch (error) {
|
||||
logWarning(`清理 ${dir} 失败: ${error.message}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成API客户端代码
|
||||
*/
|
||||
function generateApi(env) {
|
||||
logStep('生成API客户端代码');
|
||||
|
||||
try {
|
||||
// 设置环境变量
|
||||
const apiBaseUrl = getApiBaseUrl(env);
|
||||
process.env.API_BASE_URL = apiBaseUrl;
|
||||
|
||||
logInfo(`API服务器: ${apiBaseUrl}`);
|
||||
|
||||
// 执行API生成脚本
|
||||
execSync('node scripts/generate-api.cjs', {
|
||||
stdio: 'inherit',
|
||||
cwd: process.cwd()
|
||||
});
|
||||
|
||||
logSuccess('API客户端代码生成完成');
|
||||
return true;
|
||||
} catch (error) {
|
||||
logError(`API生成失败: ${error.message}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从环境配置文件中读取配置
|
||||
*/
|
||||
function getEnvConfigFromFile(env) {
|
||||
try {
|
||||
// 读取对应环境配置文件
|
||||
const envFilePath = path.join(process.cwd(), 'env', `.env.${env}`);
|
||||
|
||||
if (!fs.existsSync(envFilePath)) {
|
||||
logWarning(`环境配置文件不存在: ${envFilePath}`);
|
||||
return {
|
||||
FRONTEND_BASE_URL: 'http://localhost:3000',
|
||||
BACKEND_BASE_URL: 'http://localhost:8080',
|
||||
ENV_DESCRIPTION: `${env}环境`
|
||||
};
|
||||
}
|
||||
|
||||
const envContent = fs.readFileSync(envFilePath, 'utf8');
|
||||
const lines = envContent.split('\n');
|
||||
|
||||
const config = {
|
||||
FRONTEND_BASE_URL: 'http://localhost:3000',
|
||||
BACKEND_BASE_URL: 'http://localhost:8080',
|
||||
ENV_DESCRIPTION: `${env}环境`
|
||||
};
|
||||
|
||||
// 解析配置文件
|
||||
for (const line of lines) {
|
||||
if (line.startsWith('FRONTEND_BASE_URL=')) {
|
||||
config.FRONTEND_BASE_URL = line.split('=')[1].trim();
|
||||
} else if (line.startsWith('BACKEND_BASE_URL=')) {
|
||||
config.BACKEND_BASE_URL = line.split('=')[1].trim();
|
||||
logInfo(`从 ${envFilePath} 读取到后端地址: ${config.BACKEND_BASE_URL}`);
|
||||
} else if (line.startsWith('ENV_DESCRIPTION=')) {
|
||||
config.ENV_DESCRIPTION = line.split('=')[1].trim();
|
||||
}
|
||||
}
|
||||
|
||||
return config;
|
||||
} catch (error) {
|
||||
logError(`读取环境配置失败: ${error.message}`);
|
||||
return {
|
||||
FRONTEND_BASE_URL: 'http://localhost:3000',
|
||||
BACKEND_BASE_URL: 'http://localhost:8080',
|
||||
ENV_DESCRIPTION: `${env}环境`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取API基础URL - 从环境配置文件中读取
|
||||
*/
|
||||
function getApiBaseUrl(env) {
|
||||
const config = getEnvConfigFromFile(env);
|
||||
return config.BACKEND_BASE_URL;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取前端基础URL - 从环境配置文件中读取
|
||||
*/
|
||||
function getFrontendUrl(env) {
|
||||
const config = getEnvConfigFromFile(env);
|
||||
return config.FRONTEND_BASE_URL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Next.js 构建
|
||||
*/
|
||||
function buildNext(env) {
|
||||
logStep('执行 Next.js 构建');
|
||||
|
||||
try {
|
||||
// 设置环境变量
|
||||
process.env.NODE_ENV = 'production'; // 所有构建都使用 production 模式
|
||||
process.env.NEXT_PUBLIC_ENV = env;
|
||||
|
||||
// 执行构建
|
||||
execSync('npm run build', {
|
||||
stdio: 'inherit',
|
||||
cwd: process.cwd()
|
||||
});
|
||||
|
||||
logSuccess('Next.js 构建完成');
|
||||
return true;
|
||||
} catch (error) {
|
||||
logError(`Next.js 构建失败: ${error.message}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示构建信息
|
||||
*/
|
||||
function showBuildInfo(env, totalTime) {
|
||||
const envConfig = getEnvConfigFromFile(env);
|
||||
|
||||
log('='.repeat(60), 'green');
|
||||
logSuccess(`构建完成!总耗时: ${totalTime}ms`);
|
||||
logSuccess(`环境: ${envConfig.ENV_DESCRIPTION} (${env})`);
|
||||
logSuccess(`前端地址: ${envConfig.FRONTEND_BASE_URL}`);
|
||||
logSuccess(`后端地址: ${envConfig.BACKEND_BASE_URL}`);
|
||||
logSuccess('构建产物: .next 目录');
|
||||
log('='.repeat(60), 'green');
|
||||
|
||||
logInfo('部署建议:');
|
||||
logInfo(` 将 .next 目录和 package.json 部署到 ${envConfig.ENV_DESCRIPTION}`);
|
||||
if (env !== 'dev') {
|
||||
logInfo(` 确保环境变量 NODE_ENV=production 和 NEXT_PUBLIC_ENV=${env}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示帮助信息
|
||||
*/
|
||||
function showHelp() {
|
||||
log('用法: node scripts/build.cjs [环境] [选项]', 'cyan');
|
||||
log('');
|
||||
log('环境:', 'yellow');
|
||||
log(' dev 开发环境', 'white');
|
||||
log(' test 测试环境', 'white');
|
||||
log(' uat UAT 环境', 'white');
|
||||
log(' prod 生产环境', 'white');
|
||||
log('');
|
||||
log('选项:', 'yellow');
|
||||
log(' --env=<environment> 指定环境 (与直接指定环境等效)', 'white');
|
||||
log(' --clean 构建前清理缓存', 'white');
|
||||
log(' --skip-api 跳过API生成', 'white');
|
||||
log(' --skip-build 跳过Next.js构建(仅设置环境)', 'white');
|
||||
log(' --help 显示此帮助信息', 'white');
|
||||
log('');
|
||||
log('示例:', 'yellow');
|
||||
log(' node scripts/build.cjs dev # 开发环境完整构建', 'white');
|
||||
log(' node scripts/build.cjs test --clean # 测试环境清理缓存后构建', 'white');
|
||||
log(' node scripts/build.cjs prod --skip-api # 生产环境跳过API生成构建', 'white');
|
||||
log(' node scripts/build.cjs uat --skip-build # UAT环境仅设置环境和API生成', 'white');
|
||||
log('');
|
||||
}
|
||||
|
||||
/**
|
||||
* 主函数
|
||||
*/
|
||||
function main() {
|
||||
const startTime = Date.now();
|
||||
|
||||
log('='.repeat(60), 'cyan');
|
||||
log('统一构建脚本', 'cyan');
|
||||
log('整合环境设置、API生成和Next.js构建', 'cyan');
|
||||
log('='.repeat(60), 'cyan');
|
||||
|
||||
// 检查帮助参数
|
||||
if (process.argv.includes('--help') || process.argv.includes('-h')) {
|
||||
showHelp();
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// 获取环境参数
|
||||
let env = getEnvironmentFromArgs();
|
||||
if (!env) {
|
||||
logError('请指定环境参数');
|
||||
logInfo('使用 --help 查看帮助信息');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// 验证环境
|
||||
if (!validateEnvironment(env)) {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// 解析选项
|
||||
const shouldClean = process.argv.includes('--clean');
|
||||
const skipApi = process.argv.includes('--skip-api');
|
||||
const skipBuild = process.argv.includes('--skip-build');
|
||||
|
||||
logInfo(`目标环境: ${env}`);
|
||||
logInfo(`工作目录: ${process.cwd()}`);
|
||||
|
||||
try {
|
||||
// 1. 设置环境配置
|
||||
const envSuccess = copyEnvironmentConfig(env);
|
||||
if (!envSuccess) {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// 2. 清理缓存(可选)
|
||||
if (shouldClean) {
|
||||
cleanCache();
|
||||
}
|
||||
|
||||
// 3. 生成API客户端(可选)
|
||||
if (!skipApi) {
|
||||
const apiSuccess = generateApi(env);
|
||||
if (!apiSuccess) {
|
||||
process.exit(1);
|
||||
}
|
||||
} else {
|
||||
logInfo('跳过API生成');
|
||||
}
|
||||
|
||||
// 4. Next.js 构建(可选)
|
||||
if (!skipBuild) {
|
||||
const buildSuccess = buildNext(env);
|
||||
if (!buildSuccess) {
|
||||
process.exit(1);
|
||||
}
|
||||
} else {
|
||||
logInfo('跳过Next.js构建');
|
||||
}
|
||||
|
||||
const totalTime = Date.now() - startTime;
|
||||
showBuildInfo(env, totalTime);
|
||||
|
||||
} catch (error) {
|
||||
const totalTime = Date.now() - startTime;
|
||||
logError(`构建失败 (${totalTime}ms): ${error.message}`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// 执行主函数
|
||||
if (require.main === module) {
|
||||
main();
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
copyEnvironmentConfig,
|
||||
generateApi,
|
||||
buildNext,
|
||||
validateEnvironment,
|
||||
getEnvironmentFromArgs
|
||||
};
|
||||
44
crop-x-new/scripts/deploy.js
Normal file
44
crop-x-new/scripts/deploy.js
Normal file
@@ -0,0 +1,44 @@
|
||||
import axios from 'axios';
|
||||
var data = JSON.stringify({
|
||||
"namespace": "argo",
|
||||
"template_name": "repo-runtime-workflow",
|
||||
"parameters": {
|
||||
"git-schema": "http",
|
||||
"git-domain": "gitea-service-http.cropflow-dev.svc.cluster.local:3000",
|
||||
"git-user": "cavin",
|
||||
"git-repo": "smart-crop-ui",
|
||||
"git-revision": "main",
|
||||
"git-pat": "b6c02bf1aec73d7bbbfbe590ea37564a29c4bd5d",
|
||||
"docker-image-domain": "172.16.102.3:30648",
|
||||
"docker-dockerfile-path": "./Dockerfile.crop-x",
|
||||
"resource-cpu-limit": "500m",
|
||||
"resource-memory-limit": "512Mi",
|
||||
"resource-gpu-mem-limit": "",
|
||||
"resource-mount-path": "/data",
|
||||
"resource-mount-capacity": "",
|
||||
"app-namespace": "argo",
|
||||
"app-env-vars": "",
|
||||
"app-ingress-host": ".dev.maimaiag.com",
|
||||
"app-container-port": "3000",
|
||||
"security-scan-enabled": "false"
|
||||
}
|
||||
});
|
||||
|
||||
var config = {
|
||||
method: 'post',
|
||||
url: 'https://gitea-admin-argo-workflow-api-app.dev.maimaiag.com/api/v1/workflows/from-template',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
data : data
|
||||
};
|
||||
|
||||
axios(config)
|
||||
.then(function (response) {
|
||||
|
||||
let url = `https://gitea-admin-argo-workflow-api-app.dev.maimaiag.com/api/v1/workflows/${response.data.name}/log`
|
||||
console.log(`打开 ${url} 查看日志`);
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
388
crop-x-new/scripts/generate-api.cjs
Normal file
388
crop-x-new/scripts/generate-api.cjs
Normal file
@@ -0,0 +1,388 @@
|
||||
/**
|
||||
* 简化的 API 生成脚本
|
||||
*
|
||||
* 这个脚本现在主要负责:
|
||||
* 1. 使用 @hey-api/openapi-ts 命令生成客户端代码
|
||||
* 2. 环境配置通过 openapi-ts.config.ts 处理
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
// 从环境配置文件中读取 API_BASE_URL
|
||||
function getApiBaseUrl() {
|
||||
try {
|
||||
// 首先尝试从 env/.env.dev 文件读取
|
||||
const envDevPath = path.join(process.cwd(), 'env', '.env.dev');
|
||||
if (fs.existsSync(envDevPath)) {
|
||||
const envContent = fs.readFileSync(envDevPath, 'utf8');
|
||||
const apiBaseUrlMatch = envContent.match(/API_BASE_URL=([^\r\n]+)/);
|
||||
|
||||
if (apiBaseUrlMatch && apiBaseUrlMatch[1]) {
|
||||
return apiBaseUrlMatch[1].trim();
|
||||
}
|
||||
}
|
||||
|
||||
// 如果上面的文件不存在,尝试从 TypeScript 环境配置文件读取
|
||||
const envConfigPath = path.join(process.cwd(), 'src', 'env', 'index.ts');
|
||||
if (fs.existsSync(envConfigPath)) {
|
||||
const envContent = fs.readFileSync(envConfigPath, 'utf8');
|
||||
const devConfigMatch = envContent.match(/dev:\s*\{[\s\S]*?BACKEND_BASE_URL:\s*['"`]([^'"`]+)['"`]/);
|
||||
|
||||
if (devConfigMatch && devConfigMatch[1]) {
|
||||
return devConfigMatch[1].trim();
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error('无法找到 API_BASE_URL 或 BACKEND_BASE_URL 配置');
|
||||
} catch (error) {
|
||||
console.log(`读取环境配置失败: ${error.message}`);
|
||||
return 'http://localhost:8080'; // 默认值
|
||||
}
|
||||
}
|
||||
|
||||
// 获取 API 基础 URL
|
||||
const API_BASE_URL = getApiBaseUrl();
|
||||
|
||||
// 设置环境变量供后续使用
|
||||
process.env.API_BASE_URL = API_BASE_URL;
|
||||
|
||||
// ANSI 颜色代码
|
||||
const colors = {
|
||||
reset: '\x1b[0m',
|
||||
red: '\x1b[31m',
|
||||
green: '\x1b[32m',
|
||||
yellow: '\x1b[33m',
|
||||
blue: '\x1b[34m',
|
||||
magenta: '\x1b[35m',
|
||||
cyan: '\x1b[36m',
|
||||
white: '\x1b[37m'
|
||||
};
|
||||
|
||||
// 日志函数
|
||||
function log(message, color = 'white') {
|
||||
console.log(`${colors[color]}${message}${colors.reset}`);
|
||||
}
|
||||
|
||||
function logSuccess(message) {
|
||||
log(`✓ ${message}`, 'green');
|
||||
}
|
||||
|
||||
function logError(message) {
|
||||
log(`✗ ${message}`, 'red');
|
||||
}
|
||||
|
||||
function logWarning(message) {
|
||||
log(`⚠ ${message}`, 'yellow');
|
||||
}
|
||||
|
||||
function logInfo(message) {
|
||||
log(`ℹ ${message}`, 'blue');
|
||||
}
|
||||
|
||||
// 显示环境配置信息
|
||||
logInfo(`当前环境: ${process.env.NODE_ENV || 'development'}`);
|
||||
logInfo(`API 服务器: ${API_BASE_URL}`);
|
||||
logInfo(`已从 env/.env.dev 读取 API_BASE_URL 配置`);
|
||||
|
||||
/**
|
||||
* 检查自定义文件是否存在
|
||||
* 如果某些文件已经被自定义,我们不希望覆盖它们
|
||||
*/
|
||||
function checkCustomFiles() {
|
||||
const customFiles = [
|
||||
'client.gen.ts' // 客户端文件通常是自定义的
|
||||
];
|
||||
|
||||
const outputDir = path.join(process.cwd(), 'src', 'lib', 'api');
|
||||
const existingCustomFiles = [];
|
||||
|
||||
for (const file of customFiles) {
|
||||
const filePath = path.join(outputDir, file);
|
||||
if (fs.existsSync(filePath)) {
|
||||
// 检查文件是否包含自定义内容的标识
|
||||
const content = fs.readFileSync(filePath, 'utf8');
|
||||
|
||||
// 检查是否有自定义配置的标识
|
||||
const customIndicators = [
|
||||
'getBaseUrl',
|
||||
'createDynamicClient',
|
||||
'getCurrentClientConfig',
|
||||
// 可以添加更多自定义标识
|
||||
];
|
||||
|
||||
const hasCustomContent = customIndicators.some(indicator =>
|
||||
content.includes(indicator)
|
||||
);
|
||||
|
||||
if (hasCustomContent) {
|
||||
existingCustomFiles.push(file);
|
||||
logWarning(`检测到自定义文件: ${file}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return existingCustomFiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* 备份自定义文件
|
||||
*/
|
||||
function backupCustomFiles(customFiles) {
|
||||
if (customFiles.length === 0) return;
|
||||
|
||||
logInfo('备份自定义文件...');
|
||||
const outputDir = path.join(process.cwd(), 'src', 'lib', 'api');
|
||||
const backupDir = path.join(process.cwd(), 'src', 'lib', 'api', 'backup');
|
||||
|
||||
// 创建备份目录
|
||||
if (!fs.existsSync(backupDir)) {
|
||||
fs.mkdirSync(backupDir, { recursive: true });
|
||||
}
|
||||
|
||||
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
||||
const timestampedBackupDir = path.join(backupDir, `backup-${timestamp}`);
|
||||
fs.mkdirSync(timestampedBackupDir);
|
||||
|
||||
for (const file of customFiles) {
|
||||
const srcPath = path.join(outputDir, file);
|
||||
const destPath = path.join(timestampedBackupDir, file);
|
||||
fs.copyFileSync(srcPath, destPath);
|
||||
logInfo(` 备份: ${file} -> backup/${timestamp}/${file}`);
|
||||
}
|
||||
|
||||
logSuccess(`自定义文件已备份到: backup/${timestamp}/`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 恢复自定义文件
|
||||
*/
|
||||
function restoreCustomFiles(customFiles) {
|
||||
if (customFiles.length === 0) return;
|
||||
|
||||
logInfo('恢复自定义文件...');
|
||||
const outputDir = path.join(process.cwd(), 'src', 'lib', 'api');
|
||||
const backupDir = path.join(process.cwd(), 'src', 'lib', 'api', 'backup');
|
||||
|
||||
// 找到最新的备份目录
|
||||
const backupDirs = fs.existsSync(backupDir)
|
||||
? fs.readdirSync(backupDir)
|
||||
.filter(name => name.startsWith('backup-'))
|
||||
.sort()
|
||||
.reverse()
|
||||
: [];
|
||||
|
||||
if (backupDirs.length === 0) {
|
||||
logWarning('没有找到备份文件,跳过恢复');
|
||||
return;
|
||||
}
|
||||
|
||||
const latestBackupDir = path.join(backupDir, backupDirs[0]);
|
||||
|
||||
for (const file of customFiles) {
|
||||
const srcPath = path.join(latestBackupDir, file);
|
||||
const destPath = path.join(outputDir, file);
|
||||
|
||||
if (fs.existsSync(srcPath)) {
|
||||
fs.copyFileSync(srcPath, destPath);
|
||||
logInfo(` 恢复: ${file}`);
|
||||
}
|
||||
}
|
||||
|
||||
logSuccess('自定义文件已恢复');
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载并保存 openapi.json 文件到本地
|
||||
*/
|
||||
function downloadOpenApiJson() {
|
||||
return new Promise((resolve, reject) => {
|
||||
const https = require('https');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const fileUrl = `${API_BASE_URL}/openapi.json`;
|
||||
const outputPath = path.join(process.cwd(), 'scripts', 'openapi.json');
|
||||
|
||||
logInfo(`下载 OpenAPI 规范文件: ${fileUrl}`);
|
||||
|
||||
const startTime = Date.now();
|
||||
|
||||
// 创建 HTTPS 代理(如果需要,可以忽略 SSL 证书验证)
|
||||
const agent = new https.Agent({
|
||||
rejectUnauthorized: false // 跳过 SSL 证书验证
|
||||
});
|
||||
|
||||
https.get(fileUrl, { agent }, (response) => {
|
||||
if (response.statusCode !== 200) {
|
||||
reject(new Error(`HTTP ${response.statusCode}: ${response.statusMessage}`));
|
||||
return;
|
||||
}
|
||||
|
||||
let data = '';
|
||||
|
||||
response.on('data', (chunk) => {
|
||||
data += chunk;
|
||||
});
|
||||
|
||||
response.on('end', () => {
|
||||
try {
|
||||
// 验证 JSON 格式
|
||||
JSON.parse(data);
|
||||
|
||||
// 写入文件
|
||||
fs.writeFileSync(outputPath, data, 'utf8');
|
||||
const executionTime = Date.now() - startTime;
|
||||
logSuccess(`OpenAPI 规范已保存到: scripts/openapi.json (${executionTime}ms)`);
|
||||
resolve();
|
||||
} catch (error) {
|
||||
reject(new Error(`JSON 格式错误: ${error.message}`));
|
||||
}
|
||||
});
|
||||
}).on('error', (error) => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用 openapi-ts 命令生成客户端代码
|
||||
*/
|
||||
function generateWithOpenApiTS() {
|
||||
return new Promise((resolve, reject) => {
|
||||
logInfo('使用 @hey-api/openapi-ts 生成客户端代码...');
|
||||
|
||||
const { exec } = require('child_process');
|
||||
const command = 'npx @hey-api/openapi-ts';
|
||||
|
||||
logInfo(`执行命令: ${command}`);
|
||||
|
||||
const startTime = Date.now();
|
||||
|
||||
exec(command, { cwd: process.cwd() }, (error, stdout, stderr) => {
|
||||
const executionTime = Date.now() - startTime;
|
||||
|
||||
if (error) {
|
||||
logError(`openapi-ts 执行失败 (${executionTime}ms)`);
|
||||
logError(`错误信息: ${error.message}`);
|
||||
if (stderr) {
|
||||
logError(`stderr: ${stderr}`);
|
||||
}
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (stderr) {
|
||||
logWarning(`stderr: ${stderr}`);
|
||||
}
|
||||
|
||||
logSuccess(`openapi-ts 执行成功 (${executionTime}ms)`);
|
||||
if (stdout) {
|
||||
logInfo(`输出: ${stdout}`);
|
||||
}
|
||||
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证生成的文件
|
||||
*/
|
||||
function validateGeneratedFiles() {
|
||||
try {
|
||||
logInfo('验证生成的文件...');
|
||||
const outputDir = path.join(process.cwd(), 'src', 'lib', 'api');
|
||||
|
||||
if (!fs.existsSync(outputDir)) {
|
||||
throw new Error('输出目录不存在');
|
||||
}
|
||||
|
||||
const files = fs.readdirSync(outputDir);
|
||||
logInfo(`输出目录包含 ${files.length} 个文件:`);
|
||||
|
||||
const requiredFiles = ['types.gen.ts', 'sdk.gen.ts', 'index.ts'];
|
||||
const generatedFiles = [];
|
||||
|
||||
for (const file of files) {
|
||||
const filePath = path.join(outputDir, file);
|
||||
const stats = fs.statSync(filePath);
|
||||
|
||||
// 只显示文件,不显示目录
|
||||
if (stats.isFile()) {
|
||||
const size = (stats.size / 1024).toFixed(2);
|
||||
logInfo(` 📄 ${file} (${size} KB)`);
|
||||
generatedFiles.push(file);
|
||||
}
|
||||
}
|
||||
|
||||
// 检查必要文件
|
||||
const missingFiles = requiredFiles.filter(file => !generatedFiles.includes(file));
|
||||
if (missingFiles.length > 0) {
|
||||
logWarning(`缺少期望的文件: ${missingFiles.join(', ')}`);
|
||||
} else {
|
||||
logSuccess('所有期望的文件都已生成');
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
logError(`验证生成的文件失败: ${error.message}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 主函数
|
||||
*/
|
||||
async function main() {
|
||||
const startTime = Date.now();
|
||||
|
||||
log('='.repeat(60), 'cyan');
|
||||
log('API 客户端代码生成脚本', 'cyan');
|
||||
log('基于 @hey-api/openapi-ts', 'cyan');
|
||||
log('='.repeat(60), 'cyan');
|
||||
|
||||
try {
|
||||
// 检查是否有自定义文件
|
||||
const customFiles = checkCustomFiles();
|
||||
|
||||
if (customFiles.length > 0) {
|
||||
logInfo('检测到自定义文件,将在生成前进行备份');
|
||||
backupCustomFiles(customFiles);
|
||||
}
|
||||
|
||||
// 下载 openapi.json 文件到本地
|
||||
await downloadOpenApiJson();
|
||||
|
||||
// 使用 openapi-ts 生成代码
|
||||
await generateWithOpenApiTS();
|
||||
|
||||
// 恢复自定义文件
|
||||
if (customFiles.length > 0) {
|
||||
restoreCustomFiles(customFiles);
|
||||
}
|
||||
|
||||
// 验证生成的文件
|
||||
if (!validateGeneratedFiles()) {
|
||||
logWarning('文件验证发现问题,但生成过程已完成');
|
||||
}
|
||||
|
||||
const totalTime = Date.now() - startTime;
|
||||
logSuccess(`API 客户端代码生成完成!总耗时: ${totalTime}ms`);
|
||||
logSuccess('生成的文件位于 src/lib/api/ 目录');
|
||||
|
||||
if (customFiles.length > 0) {
|
||||
logInfo('自定义文件已保持不变,避免覆盖手动配置');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
const totalTime = Date.now() - startTime;
|
||||
logError(`脚本执行失败 (${totalTime}ms): ${error.message}`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// 执行主函数
|
||||
if (require.main === module) {
|
||||
main();
|
||||
}
|
||||
1
crop-x-new/scripts/openapi.json
Normal file
1
crop-x-new/scripts/openapi.json
Normal file
File diff suppressed because one or more lines are too long
70
crop-x-new/scripts/setup-dev-tools.js
Normal file
70
crop-x-new/scripts/setup-dev-tools.js
Normal file
@@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
// 读取开发工具配置
|
||||
const configPath = path.join(__dirname, '../.dev-tools-config.json');
|
||||
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
||||
|
||||
// 获取命令行参数
|
||||
const args = process.argv.slice(2);
|
||||
const enableAll = args.includes('--enable');
|
||||
const disableAll = args.includes('--disable');
|
||||
|
||||
console.log('🔧 开发工具设置脚本');
|
||||
console.log('====================');
|
||||
|
||||
// 更新配置文件
|
||||
function updateConfig(config) {
|
||||
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
||||
console.log('✅ 配置文件已更新');
|
||||
}
|
||||
|
||||
// 检查工具状态
|
||||
function checkToolStatus(toolName, toolConfig) {
|
||||
return toolConfig.enabled ? '✅ 已启用' : '❌ 已禁用';
|
||||
}
|
||||
|
||||
// 设置工具状态
|
||||
function setToolStatus(toolName, enabled) {
|
||||
config.tools[toolName].enabled = enabled;
|
||||
const status = enabled ? '启用' : '禁用';
|
||||
console.log(`${enabled ? '✅' : '❌'} ${toolName}: ${status}`);
|
||||
}
|
||||
|
||||
// 主逻辑
|
||||
if (enableAll) {
|
||||
console.log('🔓 启用所有开发工具...');
|
||||
Object.keys(config.tools).forEach(toolName => {
|
||||
setToolStatus(toolName, true);
|
||||
});
|
||||
updateConfig(config);
|
||||
console.log('\n🎉 所有开发工具已启用!运行以下命令使用:');
|
||||
console.log(' npm run lint # ESLint检查');
|
||||
console.log(' npm run lint:fix # ESLint自动修复');
|
||||
console.log(' npm run format # Prettier格式化');
|
||||
console.log(' npm run format:check # Prettier检查');
|
||||
} else if (disableAll) {
|
||||
console.log('🔒 禁用所有开发工具...');
|
||||
Object.keys(config.tools).forEach(toolName => {
|
||||
setToolStatus(toolName, false);
|
||||
});
|
||||
updateConfig(config);
|
||||
console.log('\n🛌 所有开发工具已禁用!');
|
||||
} else {
|
||||
console.log('📊 当前开发工具状态:');
|
||||
Object.entries(config.tools).forEach(([toolName, toolConfig]) => {
|
||||
console.log(` ${checkToolStatus(toolName, toolConfig)} ${toolName} - ${toolConfig.description}`);
|
||||
});
|
||||
|
||||
console.log('\n📖 使用说明:');
|
||||
console.log(' npm run scripts:setup # 查看当前状态');
|
||||
console.log(' npm run scripts:enable # 启用所有工具');
|
||||
console.log(' npm run scripts:disable # 禁用所有工具');
|
||||
console.log('\n💡 提示:也可以直接编辑 .dev-tools-config.json 文件来单独控制每个工具');
|
||||
}
|
||||
Reference in New Issue
Block a user