feat: add deb packaging and Gitea Actions automated release workflow
Build and Release / Build & Release DEB Package (push) Failing after 1m16s
Build and Release / Build & Release DEB Package (push) Failing after 1m16s
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
import os
|
||||
from PIL import Image, ImageDraw
|
||||
|
||||
os.makedirs('build/icons', exist_ok=True)
|
||||
|
||||
size = (512, 512)
|
||||
img = Image.new('RGBA', size, (0, 0, 0, 0))
|
||||
draw = ImageDraw.Draw(img)
|
||||
|
||||
# 1. 绘制带有圆角的深色背景外框 (Tokyo Night 磨砂质感)
|
||||
# 圆角矩形
|
||||
draw.rounded_rectangle([(16, 16), (496, 496)], radius=100, fill=(26, 27, 38, 255), outline=(122, 162, 247, 180), width=6)
|
||||
|
||||
# 2. 内部顶部标题栏装饰小圆点 (macOS / Linux 风格微缩)
|
||||
draw.ellipse([(60, 60), (76, 76)], fill=(247, 118, 142, 255)) # 红
|
||||
draw.ellipse([(92, 60), (108, 76)], fill=(224, 175, 104, 255)) # 黄
|
||||
draw.ellipse([(124, 60), (140, 76)], fill=(158, 206, 106, 255)) # 绿
|
||||
|
||||
# 3. 绘制终端提示符 > (青色发光)
|
||||
points = [
|
||||
(110, 180),
|
||||
(240, 290),
|
||||
(110, 400),
|
||||
(150, 400),
|
||||
(280, 290),
|
||||
(150, 180),
|
||||
]
|
||||
draw.polygon(points, fill=(125, 207, 255, 255))
|
||||
|
||||
# 4. 绘制光标下划线 _ (品红霓虹)
|
||||
draw.rectangle([(300, 360), (410, 395)], fill=(187, 154, 247, 255))
|
||||
|
||||
# 保存 512x512 图标
|
||||
img.save('build/icon.png', 'PNG')
|
||||
img.save('build/icons/512x512.png', 'PNG')
|
||||
|
||||
# 同时也生成常见的 256x256, 128x128, 64x64, 32x32 备用
|
||||
for s in [256, 128, 64, 32]:
|
||||
resized = img.resize((s, s), Image.Resampling.LANCZOS)
|
||||
resized.save(f'build/icons/{s}x{s}.png', 'PNG')
|
||||
|
||||
print('App icons generated successfully!')
|
||||
@@ -0,0 +1,108 @@
|
||||
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';
|
||||
const tag = process.env.GITHUB_REF_NAME || 'v1.0.0';
|
||||
|
||||
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/${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);
|
||||
}
|
||||
|
||||
// 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);
|
||||
});
|
||||
Reference in New Issue
Block a user