-
Notifications
You must be signed in to change notification settings - Fork 17
Expand file tree
/
Copy pathdeploy-github-actions.js
More file actions
187 lines (162 loc) · 7.15 KB
/
Copy pathdeploy-github-actions.js
File metadata and controls
187 lines (162 loc) · 7.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
#!/usr/bin/env node
// GitHub Actions 专用部署脚本
// 这个脚本确保在 GitHub Actions 环境中正确部署
import { execSync } from 'child_process';
import { readFileSync, writeFileSync } from 'fs';
console.log('🚀 开始 GitHub Actions 部署流程...');
// 数据库配置
const DATABASE_NAME = 'temp_mail_db';
const DATABASE_BINDING = 'temp_mail_db';
async function updateWranglerConfig(databaseId) {
// 检查是否存在 wrangler.toml 文件
try {
const wranglerContent = readFileSync('wrangler.toml', 'utf8');
// 更新数据库绑定信息 - 处理多种可能的格式
let updatedContent = wranglerContent;
// 情况1: 替换具体的数据库ID
updatedContent = updatedContent.replace(
new RegExp(`database_id = \"[a-f0-9-]+\"`, 'g'),
`database_id = "${databaseId}"`
);
// 情况2: 替换环境变量格式
updatedContent = updatedContent.replace(
new RegExp(`database_id = \"\\\${D1_DATABASE_ID}\"`, 'g'),
`database_id = "${databaseId}"`
);
// 情况3: 确保数据库配置存在
if (!updatedContent.includes(`name = "${DATABASE_NAME}"`)) {
// 如果数据库配置不存在,添加完整的配置
const dbConfig = `\n\n[[d1_databases]]\nname = "${DATABASE_NAME}"\ndatabase_id = "${databaseId}"\nbinding = "${DATABASE_BINDING}"`;
updatedContent += dbConfig;
}
writeFileSync('wrangler.toml', updatedContent);
console.log(`✅ 已更新 wrangler.toml 中的数据库绑定: ${databaseId}`);
} catch (error) {
console.log('ℹ️ 未找到 wrangler.toml 文件,创建新的配置文件');
// 创建新的 wrangler.toml 文件
const wranglerConfig = `name = "temp-mail"
main = "worker.js"
compatibility_date = "2024-01-01"
# D1 数据库配置
[[d1_databases]]
name = "${DATABASE_NAME}"
database_id = "${databaseId}"
binding = "${DATABASE_BINDING}"
# 生产环境配置
[env.production]
name = "temp-mail"
# 生产环境D1数据库配置
[[env.production.d1_databases]]
name = "${DATABASE_NAME}"
database_id = "${databaseId}"
binding = "${DATABASE_BINDING}"`;
writeFileSync('wrangler.toml', wranglerConfig);
console.log(`✅ 已创建 wrangler.toml 文件并设置数据库绑定: ${databaseId}`);
}
}
async function getDatabaseId() {
try {
// 移除 --remote 参数,使用默认的本地/远程自动检测
const dbList = execSync('npx wrangler d1 list --json', { encoding: 'utf8' });
const databases = JSON.parse(dbList);
const db = databases.find(d => d.name === DATABASE_NAME);
if (db) {
return db.uuid;
}
} catch (error) {
console.log('⚠️ 无法获取数据库列表:', error.message);
}
return null;
}
try {
console.log('📦 检查 Wrangler 可用性...');
execSync('npx wrangler --version', { stdio: 'inherit' });
console.log('🔐 设置 Cloudflare 认证...');
if (process.env.CLOUDFLARE_API_TOKEN && process.env.CLOUDFLARE_ACCOUNT_ID) {
process.env.CLOUDFLARE_ACCOUNT_ID = process.env.CLOUDFLARE_ACCOUNT_ID;
process.env.CLOUDFLARE_API_TOKEN = process.env.CLOUDFLARE_API_TOKEN;
console.log('✅ Cloudflare 认证已设置');
} else {
console.warn('⚠️ Cloudflare 认证信息未提供,可能无法访问远程资源');
}
console.log('🗄️ 配置 D1 数据库绑定...');
const databaseId = process.env.D1_DATABASE_ID;
if (databaseId) {
await updateWranglerConfig(databaseId);
console.log(`✅ 已使用环境变量 D1_DATABASE_ID 更新数据库绑定: ${databaseId}`);
} else {
console.log('ℹ️ 未提供 D1_DATABASE_ID,跳过数据库绑定更新');
}
console.log('🔧 设置环境变量...');
const envVars = [
// 必需环境变量
{ name: 'ADMIN_PASSWORD', value: process.env.ADMIN_PASSWORD },
{ name: 'GUEST_PASSWORD', value: process.env.GUEST_PASSWORD },
{ name: 'JWT_TOKEN', value: process.env.JWT_TOKEN },
{ name: 'JWT_SECRET', value: process.env.JWT_SECRET },
{ name: 'MAIL_DOMAIN', value: process.env.MAIL_DOMAIN },
{ name: 'D1_DATABASE_ID', value: process.env.D1_DATABASE_ID },
// 可选环境变量(不填写不影响项目正常使用)
{ name: 'ADMIN_NAME', value: process.env.ADMIN_NAME },
{ name: 'ADMIN_USERNAME', value: process.env.ADMIN_USERNAME },
{ name: 'ADMIN_PASS', value: process.env.ADMIN_PASS },
{ name: 'RESEND_API_KEY', value: process.env.RESEND_API_KEY },
{ name: 'RESEND_TOKEN', value: process.env.RESEND_TOKEN },
{ name: 'RESEND', value: process.env.RESEND },
{ name: 'SITE_MODE', value: process.env.SITE_MODE },
{ name: 'SHOW_DEMO_BANNER', value: process.env.SHOW_DEMO_BANNER },
{ name: 'FORWARD_RULES', value: process.env.FORWARD_RULES },
{ name: 'CACHE_TTL', value: process.env.CACHE_TTL },
{ name: 'TELEGRAM_BOT_TOKEN', value: process.env.TELEGRAM_BOT_TOKEN },
{ name: 'TELEGRAM_CHAT_ID', value: process.env.TELEGRAM_CHAT_ID },
{ name: 'MAX_EMAIL_SIZE', value: process.env.MAX_EMAIL_SIZE },
{ name: 'EMAIL_RETENTION_DAYS', value: process.env.EMAIL_RETENTION_DAYS },
{ name: 'GUEST_ENABLED', value: process.env.GUEST_ENABLED }
];
for (const envVar of envVars) {
const hasKey = Object.prototype.hasOwnProperty.call(process.env, envVar.name);
if (hasKey) {
try {
execSync(`npx wrangler secret put ${envVar.name} --env=""`, {
input: String(envVar.value ?? ''),
stdio: ['pipe', 'inherit', 'inherit']
});
console.log(`✅ 已同步环境变量: ${envVar.name}`);
} catch (error) {
console.warn(`⚠️ 同步环境变量 ${envVar.name} 失败:`, error.message);
}
} else {
try {
execSync(`npx wrangler secret delete ${envVar.name} --env=""`, {
input: 'y\n',
stdio: ['pipe', 'inherit', 'inherit']
});
console.log(`🗑️ 已删除 Cloudflare 中多余的环境变量: ${envVar.name}`);
} catch {
console.log(`ℹ️ Cloudflare 中不存在需删除的环境变量: ${envVar.name}`);
}
}
}
// 5. 生成前端环境配置文件 public/env.js(仅包含非敏感开关)
console.log('📝 生成前端环境配置 public/env.js...');
const rawSiteMode = String(process.env.SITE_MODE || '').trim().toLowerCase();
const siteMode = rawSiteMode === 'demo' ? 'demo' : 'selfhost';
const rawGuestEnabled = String(process.env.GUEST_ENABLED || '').trim().toLowerCase();
const guestEnabled = rawGuestEnabled === 'true' || rawGuestEnabled === '1' || rawGuestEnabled === 'yes';
const envJsContent =
`window.__SITE_MODE__ = "${siteMode}";\n` +
`window.__GUEST_ENABLED__ = ${guestEnabled ? 'true' : 'false'};\n`;
writeFileSync('public/env.js', envJsContent, 'utf8');
console.log('✅ 已写入 public/env.js,内容如下(仅非敏感开关):');
console.log(envJsContent);
// 6. 构建项目
console.log('🔨 构建项目...');
execSync('npm run build', { stdio: 'inherit' });
// 7. 部署到 Cloudflare Workers
console.log('☁️ 部署到 Cloudflare Workers...');
execSync('npx wrangler deploy --env=""', { stdio: 'inherit' });
console.log('✅ 部署完成!');
} catch (error) {
console.error('❌ 部署失败:', error.message);
process.exit(1);
}