feat: Add Docker Compose configurations for Kvrocks and Redis deployments
- Implemented `docker-compose.kvrocks.auth.yml` for Kvrocks with password authentication. - Created `docker-compose.redis.yml` for Redis deployment. - Added Kvrocks configuration file `kvrocks.auth.conf` with necessary settings. - Updated documentation with deployment guidelines for Kvrocks. - Introduced ESLint configuration for code quality. - Developed deployment configuration check script `check-deployment-configs.js`. - Added D1 database initialization script `d1-init.sql` for KatelyaTV. - Created test script `test-kvrocks-deployment.js` to validate Kvrocks deployment. - Implemented fix verification script `verify-kvrocks-fix.js` for password handling. - Updated `wrangler.toml` for Cloudflare deployment configuration.
This commit is contained in:
@@ -0,0 +1,301 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* KatelyaTV 全方案部署状态检查脚本
|
||||
* 检查所有部署方案的配置文件和环境是否完整
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
console.log('🔍 KatelyaTV 部署配置检查开始...\n');
|
||||
|
||||
// 检查结果统计
|
||||
let checkResults = {
|
||||
total: 0,
|
||||
passed: 0,
|
||||
failed: 0,
|
||||
warnings: 0,
|
||||
errors: []
|
||||
};
|
||||
|
||||
// 辅助函数
|
||||
function logCheck(name, status, message = '') {
|
||||
checkResults.total++;
|
||||
if (status === 'PASS') {
|
||||
checkResults.passed++;
|
||||
console.log(`✅ ${name}: PASS ${message}`);
|
||||
} else if (status === 'WARN') {
|
||||
checkResults.warnings++;
|
||||
console.log(`⚠️ ${name}: WARN ${message}`);
|
||||
} else {
|
||||
checkResults.failed++;
|
||||
console.log(`❌ ${name}: FAIL ${message}`);
|
||||
checkResults.errors.push(`${name}: ${message}`);
|
||||
}
|
||||
}
|
||||
|
||||
function fileExists(filePath) {
|
||||
try {
|
||||
return fs.existsSync(filePath);
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function readJsonFile(filePath) {
|
||||
try {
|
||||
const content = fs.readFileSync(filePath, 'utf8');
|
||||
return JSON.parse(content);
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查1:Docker 部署配置
|
||||
function checkDockerConfigs() {
|
||||
console.log('🐳 检查 Docker 部署配置...');
|
||||
|
||||
const dockerConfigs = [
|
||||
{
|
||||
name: 'Docker + Redis 配置',
|
||||
files: ['docker-compose.redis.yml', '.env.redis.example']
|
||||
},
|
||||
{
|
||||
name: 'Docker + Kvrocks 配置(无密码)',
|
||||
files: ['docker-compose.kvrocks.yml', '.env.kvrocks.example']
|
||||
},
|
||||
{
|
||||
name: 'Docker + Kvrocks 配置(密码认证)',
|
||||
files: ['docker-compose.kvrocks.auth.yml']
|
||||
},
|
||||
{
|
||||
name: 'Docker + Kvrocks 本地构建配置',
|
||||
files: ['docker-compose.kvrocks.local.yml']
|
||||
}
|
||||
];
|
||||
|
||||
for (const config of dockerConfigs) {
|
||||
let allFilesExist = true;
|
||||
let missingFiles = [];
|
||||
|
||||
for (const file of config.files) {
|
||||
if (!fileExists(file)) {
|
||||
allFilesExist = false;
|
||||
missingFiles.push(file);
|
||||
}
|
||||
}
|
||||
|
||||
if (allFilesExist) {
|
||||
logCheck(config.name, 'PASS', '所有配置文件存在');
|
||||
} else {
|
||||
logCheck(config.name, 'FAIL', `缺失文件: ${missingFiles.join(', ')}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 检查2:Cloudflare 部署配置
|
||||
function checkCloudflareConfigs() {
|
||||
console.log('\n☁️ 检查 Cloudflare 部署配置...');
|
||||
|
||||
const cloudflareFiles = [
|
||||
'wrangler.toml',
|
||||
'.env.cloudflare.example',
|
||||
'scripts/d1-init.sql'
|
||||
];
|
||||
|
||||
for (const file of cloudflareFiles) {
|
||||
if (fileExists(file)) {
|
||||
logCheck(`Cloudflare 配置文件 ${file}`, 'PASS', '文件存在');
|
||||
} else {
|
||||
logCheck(`Cloudflare 配置文件 ${file}`, 'FAIL', '文件不存在');
|
||||
}
|
||||
}
|
||||
|
||||
// 检查 wrangler.toml 内容
|
||||
if (fileExists('wrangler.toml')) {
|
||||
const content = fs.readFileSync('wrangler.toml', 'utf8');
|
||||
if (content.includes('d1_databases') && content.includes('pages:build')) {
|
||||
logCheck('wrangler.toml 内容', 'PASS', '包含必要配置');
|
||||
} else {
|
||||
logCheck('wrangler.toml 内容', 'WARN', '可能缺少部分配置');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 检查3:Vercel 部署配置
|
||||
function checkVercelConfigs() {
|
||||
console.log('\n▲ 检查 Vercel 部署配置...');
|
||||
|
||||
const vercelFile = 'vercel.json';
|
||||
if (fileExists(vercelFile)) {
|
||||
logCheck('Vercel 配置文件', 'PASS', 'vercel.json 存在');
|
||||
|
||||
const vercelConfig = readJsonFile(vercelFile);
|
||||
if (vercelConfig) {
|
||||
if (vercelConfig.build && vercelConfig.build.env) {
|
||||
logCheck('Vercel 构建配置', 'PASS', '包含环境变量配置');
|
||||
} else {
|
||||
logCheck('Vercel 构建配置', 'WARN', '可能缺少构建环境配置');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logCheck('Vercel 配置文件', 'FAIL', 'vercel.json 不存在');
|
||||
}
|
||||
}
|
||||
|
||||
// 检查4:环境变量示例文件
|
||||
function checkEnvExamples() {
|
||||
console.log('\n⚙️ 检查环境变量示例文件...');
|
||||
|
||||
const envFiles = [
|
||||
'.env.example',
|
||||
'.env.redis.example',
|
||||
'.env.kvrocks.example',
|
||||
'.env.cloudflare.example'
|
||||
];
|
||||
|
||||
for (const envFile of envFiles) {
|
||||
if (fileExists(envFile)) {
|
||||
const content = fs.readFileSync(envFile, 'utf8');
|
||||
const hasStorageType = content.includes('NEXT_PUBLIC_STORAGE_TYPE');
|
||||
const hasAuthConfig = content.includes('NEXTAUTH_SECRET');
|
||||
|
||||
if (hasStorageType && hasAuthConfig) {
|
||||
logCheck(`环境变量文件 ${envFile}`, 'PASS', '包含必要配置');
|
||||
} else {
|
||||
logCheck(`环境变量文件 ${envFile}`, 'WARN', '可能缺少部分配置');
|
||||
}
|
||||
} else {
|
||||
logCheck(`环境变量文件 ${envFile}`, 'FAIL', '文件不存在');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 检查5:package.json 脚本
|
||||
function checkPackageScripts() {
|
||||
console.log('\n📦 检查 package.json 构建脚本...');
|
||||
|
||||
const packageJson = readJsonFile('package.json');
|
||||
if (packageJson && packageJson.scripts) {
|
||||
const requiredScripts = [
|
||||
'dev',
|
||||
'build',
|
||||
'start',
|
||||
'pages:build', // Cloudflare Pages
|
||||
'lint'
|
||||
];
|
||||
|
||||
for (const script of requiredScripts) {
|
||||
if (packageJson.scripts[script]) {
|
||||
logCheck(`package.json 脚本 ${script}`, 'PASS', '脚本存在');
|
||||
} else {
|
||||
logCheck(`package.json 脚本 ${script}`, 'WARN', '脚本不存在或未配置');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logCheck('package.json', 'FAIL', '文件不存在或格式错误');
|
||||
}
|
||||
}
|
||||
|
||||
// 检查6:Kvrocks 配置文件
|
||||
function checkKvrocksConfigs() {
|
||||
console.log('\n🏪 检查 Kvrocks 配置文件...');
|
||||
|
||||
const kvrocksConfigs = [
|
||||
'docker/kvrocks/kvrocks.conf',
|
||||
'docker/kvrocks/kvrocks.auth.conf'
|
||||
];
|
||||
|
||||
for (const configFile of kvrocksConfigs) {
|
||||
if (fileExists(configFile)) {
|
||||
const content = fs.readFileSync(configFile, 'utf8');
|
||||
const hasBasicConfig = content.includes('bind') && content.includes('port');
|
||||
|
||||
if (hasBasicConfig) {
|
||||
logCheck(`Kvrocks 配置 ${path.basename(configFile)}`, 'PASS', '包含基本配置');
|
||||
} else {
|
||||
logCheck(`Kvrocks 配置 ${path.basename(configFile)}`, 'WARN', '可能缺少基本配置');
|
||||
}
|
||||
} else {
|
||||
logCheck(`Kvrocks 配置 ${path.basename(configFile)}`, 'FAIL', '文件不存在');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 检查7:文档文件
|
||||
function checkDocumentation() {
|
||||
console.log('\n📚 检查文档文件...');
|
||||
|
||||
const docFiles = [
|
||||
'README.md',
|
||||
'docs/KVROCKS.md',
|
||||
'docs/KVROCKS_DEPLOYMENT.md',
|
||||
'docs/TVBOX.md',
|
||||
'KVROCKS_FIX_REPORT.md'
|
||||
];
|
||||
|
||||
for (const docFile of docFiles) {
|
||||
if (fileExists(docFile)) {
|
||||
logCheck(`文档文件 ${docFile}`, 'PASS', '文件存在');
|
||||
} else {
|
||||
logCheck(`文档文件 ${docFile}`, 'WARN', '文件不存在');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 主检查函数
|
||||
async function runChecks() {
|
||||
try {
|
||||
await checkDockerConfigs();
|
||||
await checkCloudflareConfigs();
|
||||
await checkVercelConfigs();
|
||||
await checkEnvExamples();
|
||||
await checkPackageScripts();
|
||||
await checkKvrocksConfigs();
|
||||
await checkDocumentation();
|
||||
|
||||
} catch (error) {
|
||||
console.error('检查执行出错:', error);
|
||||
checkResults.failed++;
|
||||
checkResults.errors.push(`检查执行出错: ${error.message}`);
|
||||
}
|
||||
|
||||
// 输出检查结果
|
||||
console.log('\n' + '='.repeat(60));
|
||||
console.log('📊 部署配置检查结果汇总:');
|
||||
console.log(` 总计: ${checkResults.total} 项检查`);
|
||||
console.log(` 通过: ${checkResults.passed} 项 ✅`);
|
||||
console.log(` 警告: ${checkResults.warnings} 项 ⚠️`);
|
||||
console.log(` 失败: ${checkResults.failed} 项 ❌`);
|
||||
|
||||
if (checkResults.failed > 0) {
|
||||
console.log('\n🚨 失败的检查项:');
|
||||
checkResults.errors.forEach((error, index) => {
|
||||
console.log(` ${index + 1}. ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
if (checkResults.warnings > 0) {
|
||||
console.log('\n⚠️ 警告说明:');
|
||||
console.log(' - 警告项目不影响基本功能,但建议完善');
|
||||
console.log(' - 可能影响特定部署方案或高级功能');
|
||||
}
|
||||
|
||||
if (checkResults.failed === 0) {
|
||||
console.log('\n🎉 所有必要配置文件检查通过!');
|
||||
console.log(' 您可以选择以下任意部署方案:');
|
||||
console.log(' 1. 🐳 Docker + Redis (docker-compose.redis.yml)');
|
||||
console.log(' 2. 🏪 Docker + Kvrocks (docker-compose.kvrocks.yml)');
|
||||
console.log(' 3. ☁️ Cloudflare Pages + D1 (wrangler.toml)');
|
||||
console.log(' 4. ▲ Vercel + Upstash (vercel.json)');
|
||||
}
|
||||
|
||||
console.log('='.repeat(60));
|
||||
|
||||
// 退出代码
|
||||
process.exit(checkResults.failed > 0 ? 1 : 0);
|
||||
}
|
||||
|
||||
// 运行检查
|
||||
runChecks().catch(console.error);
|
||||
Reference in New Issue
Block a user