Files
hatty/scripts/gitea-release.mjs
T
zzzjy 5212de32f2
Build and Release / Build & Release DEB Package (push) Successful in 3m8s
fix(ci): remove redundant icon generation and enhance Gitea release script
2026-09-23 01:51:43 +08:00

136 lines
4.6 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import fs from 'fs';
import path from 'path';
async function main() {
const serverUrl = process.env.GITHUB_SERVER_URL || process.env.GITEA_SERVER_URL || 'https://git.zzzjy.cloud';
const token = process.env.GITHUB_TOKEN || process.env.GITEA_TOKEN;
const repo = process.env.GITHUB_REPOSITORY || 'zzzjy/hatty';
let tag = process.env.GITHUB_REF_NAME || 'v1.0.0';
// 规范化 tag 名称(移除可能的 refs/tags/ 前缀)
tag = tag.replace(/^refs\/tags\//, '');
if (!token) {
console.error('Error: GITHUB_TOKEN or GITEA_TOKEN is required.');
process.exit(1);
}
const [owner, repoName] = repo.split('/');
const apiBase = `${serverUrl.replace(/\/+$/, '')}/api/v1/repos/${owner}/${repoName}`;
console.log(`Connecting to Gitea at ${serverUrl} for repository ${repo}...`);
// 1. 检查或创建 Release
let releaseId = null;
const tagCheckRes = await fetch(`${apiBase}/releases/tags/${encodeURIComponent(tag)}`, {
headers: {
Authorization: `token ${token}`,
Accept: 'application/json',
},
});
if (tagCheckRes.ok) {
const existing = await tagCheckRes.json();
releaseId = existing.id;
console.log(`Found existing release for tag ${tag} (id: ${releaseId})`);
} else {
console.log(`Creating new release for tag ${tag}...`);
const createRes = await fetch(`${apiBase}/releases`, {
method: 'POST',
headers: {
Authorization: `token ${token}`,
'Content-Type': 'application/json',
Accept: 'application/json',
},
body: JSON.stringify({
tag_name: tag,
name: `hatty ${tag}`,
body: `### ⚡ hatty ${tag} 现代化 Linux 终端新版本发布\n\n- **架构**:Electron + xterm.js (WebGL 硬件加速) + Linux PTY\n- **特性**:无边框磨砂毛玻璃、5 套现代暗黑主题、多标签页、灵活多窗格分屏\n- **安装说明**:下载下方附件 \`.deb\` 文件,在终端运行 \`sudo dpkg -i hatty_*.deb\` 即可完成安装。`,
draft: false,
prerelease: false,
}),
});
if (!createRes.ok) {
const errText = await createRes.text();
console.error(`Failed to create release: ${createRes.status} ${errText}`);
process.exit(1);
}
const created = await createRes.json();
releaseId = created.id;
console.log(`Release created successfully with id ${releaseId}`);
}
// 2. 查找 dist/ 下的 .deb 安装包
const distDir = path.resolve('dist');
if (!fs.existsSync(distDir)) {
console.error('dist directory does not exist.');
process.exit(1);
}
const files = fs.readdirSync(distDir).filter((f) => f.endsWith('.deb') || f.endsWith('.AppImage'));
if (files.length === 0) {
console.error('No .deb or .AppImage files found in dist directory.');
process.exit(1);
}
// 检查已存在的附件,若同名则先删除以支持重试
try {
const assetsRes = await fetch(`${apiBase}/releases/${releaseId}/assets`, {
headers: {
Authorization: `token ${token}`,
Accept: 'application/json',
},
});
if (assetsRes.ok) {
const existingAssets = await assetsRes.json();
for (const asset of existingAssets) {
if (files.includes(asset.name)) {
console.log(`Deleting existing asset ${asset.name} (id: ${asset.id}) to replace...`);
await fetch(`${apiBase}/releases/${releaseId}/assets/${asset.id}`, {
method: 'DELETE',
headers: { Authorization: `token ${token}` },
});
}
}
}
} catch (e) {
console.warn('Checking existing assets notice:', e.message);
}
// 3. 上传安装包到 Release 附件
for (const fileName of files) {
const filePath = path.join(distDir, fileName);
const fileStat = fs.statSync(filePath);
console.log(`Uploading ${fileName} (${(fileStat.size / (1024 * 1024)).toFixed(2)} MB)...`);
const fileBuffer = fs.readFileSync(filePath);
const formData = new FormData();
const blob = new Blob([fileBuffer], { type: 'application/octet-stream' });
formData.append('attachment', blob, fileName);
const uploadRes = await fetch(`${apiBase}/releases/${releaseId}/assets?name=${encodeURIComponent(fileName)}`, {
method: 'POST',
headers: {
Authorization: `token ${token}`,
},
body: formData,
});
if (uploadRes.ok) {
console.log(`✔ Successfully uploaded ${fileName}`);
} else {
const err = await uploadRes.text();
console.warn(`Warning: Upload ${fileName} returned status ${uploadRes.status}: ${err}`);
}
}
console.log('All release operations completed successfully!');
}
main().catch((err) => {
console.error('Unexpected error:', err);
process.exit(1);
});