mirror of
https://github.com/AmintaCCCP/GithubStarsManager.git
synced 2025-11-25 02:34:54 +08:00
585 lines
22 KiB
YAML
585 lines
22 KiB
YAML
name: Build Desktop App
|
|
|
|
on:
|
|
push:
|
|
branches: [ main, master ]
|
|
tags: [ 'v*' ]
|
|
pull_request:
|
|
branches: [ main, master ]
|
|
workflow_dispatch:
|
|
|
|
jobs:
|
|
build:
|
|
runs-on: ${{ matrix.os }}
|
|
continue-on-error: false
|
|
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
|
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: '18'
|
|
cache: 'npm'
|
|
|
|
- name: Install dependencies
|
|
run: npm ci
|
|
|
|
- name: Build web app
|
|
run: npm run build
|
|
# env:
|
|
# VITE_BASE_PATH: './'
|
|
|
|
- name: Verify and fix web build
|
|
shell: bash
|
|
run: |
|
|
echo "Checking if dist directory exists and contains files:"
|
|
if [ -d "dist" ] && [ -f "dist/index.html" ]; then
|
|
echo "✓ dist directory and index.html found"
|
|
echo "Contents of dist directory:"
|
|
ls -la dist/ | head -10
|
|
|
|
# 检查 index.html 中的路径并修复
|
|
echo "Checking and fixing asset paths in index.html..."
|
|
if [ -f "dist/index.html" ]; then
|
|
# 确保所有资源路径都是相对路径
|
|
sed -i.bak 's|href="/|href="./|g' dist/index.html
|
|
sed -i.bak 's|src="/|src="./|g' dist/index.html
|
|
sed -i.bak 's|href="\([^"]*\)"|href="./\1"|g' dist/index.html
|
|
sed -i.bak 's|src="\([^"]*\)"|src="./\1"|g' dist/index.html
|
|
# 移除备份文件
|
|
rm -f dist/index.html.bak
|
|
echo "✓ Asset paths fixed in index.html"
|
|
fi
|
|
else
|
|
echo "Creating fallback dist directory and index.html"
|
|
mkdir -p dist
|
|
cp templates/fallback-index.html dist/index.html
|
|
echo "✓ Fallback index.html created from template"
|
|
fi
|
|
|
|
# 显示最终的 index.html 内容(前几行)
|
|
echo "Final index.html content (first 10 lines):"
|
|
head -10 dist/index.html || echo "Could not read index.html"
|
|
|
|
- name: Install sharp for icon generation
|
|
run: npm install sharp --save-dev
|
|
|
|
- name: Create build directory
|
|
shell: bash
|
|
run: |
|
|
node -e "
|
|
const fs = require('fs');
|
|
if (!fs.existsSync('build')) {
|
|
fs.mkdirSync('build', { recursive: true });
|
|
}
|
|
console.log('Build directory created');
|
|
"
|
|
|
|
- name: Generate icons and app resources
|
|
shell: bash
|
|
run: |
|
|
node -e "
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
function generateIcons() {
|
|
const buildDir = 'build';
|
|
if (!fs.existsSync(buildDir)) {
|
|
fs.mkdirSync(buildDir, { recursive: true });
|
|
}
|
|
|
|
// Look for source icon in common locations (优先使用 assets/icon.png)
|
|
let sourceIcon = null;
|
|
const possiblePaths = [
|
|
'assets/icon.png',
|
|
'public/icon.png',
|
|
'src/assets/icon.png',
|
|
'icon.png'
|
|
];
|
|
|
|
for (const iconPath of possiblePaths) {
|
|
if (fs.existsSync(iconPath)) {
|
|
sourceIcon = iconPath;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (sourceIcon) {
|
|
console.log('Using source icon:', sourceIcon);
|
|
fs.copyFileSync(sourceIcon, 'build/icon.png');
|
|
fs.copyFileSync(sourceIcon, 'build/icon-512x512.png');
|
|
} else {
|
|
console.log('Creating default application icon');
|
|
// Create a better default icon
|
|
const iconSvg = \`<svg width=\"512\" height=\"512\" xmlns=\"http://www.w3.org/2000/svg\">
|
|
<defs>
|
|
<linearGradient id=\"grad1\" x1=\"0%\" y1=\"0%\" x2=\"100%\" y2=\"100%\">
|
|
<stop offset=\"0%\" style=\"stop-color:#667eea;stop-opacity:1\" />
|
|
<stop offset=\"100%\" style=\"stop-color:#764ba2;stop-opacity:1\" />
|
|
</linearGradient>
|
|
</defs>
|
|
<rect width=\"512\" height=\"512\" fill=\"url(#grad1)\" rx=\"64\"/>
|
|
<text x=\"256\" y=\"280\" text-anchor=\"middle\" fill=\"white\" font-size=\"120\" font-family=\"Arial, sans-serif\" font-weight=\"bold\">⭐</text>
|
|
<text x=\"256\" y=\"380\" text-anchor=\"middle\" fill=\"white\" font-size=\"32\" font-family=\"Arial, sans-serif\">GitHub</text>
|
|
<text x=\"256\" y=\"420\" text-anchor=\"middle\" fill=\"white\" font-size=\"32\" font-family=\"Arial, sans-serif\">Stars</text>
|
|
</svg>\`;
|
|
fs.writeFileSync('build/icon.svg', iconSvg);
|
|
}
|
|
|
|
console.log('Icon files prepared successfully');
|
|
}
|
|
|
|
generateIcons();
|
|
"
|
|
|
|
- name: Generate Windows ICO file
|
|
if: matrix.os == 'windows-latest'
|
|
shell: bash
|
|
run: |
|
|
# For Windows, electron-builder can handle PNG to ICO conversion
|
|
if [ -f "build/icon.png" ]; then
|
|
cp build/icon.png build/icon.ico
|
|
else
|
|
echo "No icon file found, electron-builder will use default"
|
|
fi
|
|
|
|
- name: Generate macOS ICNS file
|
|
if: matrix.os == 'macos-latest'
|
|
shell: bash
|
|
run: |
|
|
# For macOS, electron-builder can handle PNG to ICNS conversion
|
|
if [ -f "build/icon.png" ]; then
|
|
cp build/icon.png build/icon.icns
|
|
else
|
|
echo "No icon file found, electron-builder will use default"
|
|
fi
|
|
|
|
- name: Install system dependencies (Linux)
|
|
if: matrix.os == 'ubuntu-latest'
|
|
run: |
|
|
sudo apt-get update
|
|
sudo apt-get install -y libnss3-dev libatk-bridge2.0-dev libdrm2 libxcomposite1 libxdamage1 libxrandr2 libgbm1 libxss1 libasound2-dev
|
|
|
|
- name: Install Electron dependencies
|
|
run: npm install --save-dev electron electron-builder
|
|
|
|
- name: Setup Windows build environment
|
|
if: matrix.os == 'windows-latest'
|
|
run: |
|
|
# Install Windows SDK components if needed
|
|
echo "Setting up Windows build environment"
|
|
|
|
- name: Create Electron main process
|
|
shell: bash
|
|
run: |
|
|
node -e "
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
if (!fs.existsSync('electron')) {
|
|
fs.mkdirSync('electron', { recursive: true });
|
|
}
|
|
|
|
const mainJsContent = 'const { app, BrowserWindow, Menu, shell } = require(\\'electron\\');\\n' +
|
|
'const path = require(\\'path\\');\\n' +
|
|
'const fs = require(\\'fs\\');\\n' +
|
|
'const isDev = process.env.NODE_ENV === \\'development\\';\\n\\n' +
|
|
'let mainWindow;\\n\\n' +
|
|
'function createWindow() {\\n' +
|
|
' mainWindow = new BrowserWindow({\\n' +
|
|
' width: 1200,\\n' +
|
|
' height: 800,\\n' +
|
|
' minWidth: 800,\\n' +
|
|
' minHeight: 600,\\n' +
|
|
' webPreferences: {\\n' +
|
|
' nodeIntegration: false,\\n' +
|
|
' contextIsolation: true,\\n' +
|
|
' enableRemoteModule: false,\\n' +
|
|
' webSecurity: false,\\n' +
|
|
' allowRunningInsecureContent: true,\\n' +
|
|
' devTools: isDev // 只在开发模式下启用 DevTools\\n' +
|
|
' },\\n' +
|
|
' icon: path.join(__dirname, \\'../build/icon.png\\'),\\n' +
|
|
' titleBarStyle: \\'default\\', // 使用默认标题栏,避免重叠问题\\n' +
|
|
' show: false,\\n' +
|
|
' autoHideMenuBar: true, // 隐藏菜单栏\\n' +
|
|
' frame: true, // 保持窗口框架\\n' +
|
|
' backgroundColor: \\'#ffffff\\', // 设置背景色,避免白屏闪烁\\n' +
|
|
' titleBarOverlay: false, // 禁用标题栏覆盖\\n' +
|
|
' trafficLightPosition: { x: 20, y: 20 } // macOS 交通灯按钮位置\\n' +
|
|
' });\\n\\n' +
|
|
' // 添加错误处理和加载事件\\n' +
|
|
' mainWindow.webContents.on(\\'did-fail-load\\', (event, errorCode, errorDescription, validatedURL) => {\\n' +
|
|
' console.error(\\'Failed to load:\\', errorCode, errorDescription, validatedURL);\\n' +
|
|
' // 如果主页面加载失败,尝试加载 fallback 页面\\n' +
|
|
' const fallbackPath = path.join(__dirname, \\'../dist/index.html\\');\\n' +
|
|
' if (fs.existsSync(fallbackPath)) {\\n' +
|
|
' console.log(\\'Loading fallback page:\\', fallbackPath);\\n' +
|
|
' mainWindow.loadFile(fallbackPath);\\n' +
|
|
' }\\n' +
|
|
' });\\n\\n' +
|
|
' mainWindow.webContents.on(\\'dom-ready\\', () => {\\n' +
|
|
' if (isDev) console.log(\\'DOM ready\\');\\n' +
|
|
' // 注入一些基础样式,防止白屏\\n' +
|
|
' mainWindow.webContents.insertCSS(\\'body { background-color: #ffffff; }\\');\\n' +
|
|
' });\\n\\n' +
|
|
' mainWindow.webContents.on(\\'did-finish-load\\', () => {\\n' +
|
|
' if (isDev) console.log(\\'Page finished loading\\');\\n' +
|
|
' // 页面加载完成后显示窗口\\n' +
|
|
' if (!mainWindow.isVisible()) {\\n' +
|
|
' mainWindow.show();\\n' +
|
|
' }\\n' +
|
|
' });\\n\\n' +
|
|
' if (isDev) {\\n' +
|
|
' mainWindow.loadURL(\\'http://localhost:5173\\');\\n' +
|
|
' mainWindow.webContents.openDevTools();\\n' +
|
|
' } else {\\n' +
|
|
' // 生产环境:尝试多个可能的路径\\n' +
|
|
' const possiblePaths = [\\n' +
|
|
' path.join(__dirname, \\'../dist/index.html\\'),\\n' +
|
|
' path.join(process.resourcesPath, \\'app.asar/dist/index.html\\'),\\n' +
|
|
' path.join(process.resourcesPath, \\'app/dist/index.html\\'),\\n' +
|
|
' path.join(process.resourcesPath, \\'dist/index.html\\'),\\n' +
|
|
' path.join(__dirname, \\'../build/index.html\\')\\n' +
|
|
' ];\\n\\n' +
|
|
' let indexPath = null;\\n' +
|
|
' for (const testPath of possiblePaths) {\\n' +
|
|
' try {\\n' +
|
|
' if (fs.existsSync(testPath)) {\\n' +
|
|
' indexPath = testPath;\\n' +
|
|
' break;\\n' +
|
|
' }\\n' +
|
|
' } catch (error) {\\n' +
|
|
' // 忽略文件系统错误,继续尝试下一个路径\\n' +
|
|
' continue;\\n' +
|
|
' }\\n' +
|
|
' }\\n\\n' +
|
|
' if (indexPath) {\\n' +
|
|
' console.log(\\'Loading application from:\\', indexPath);\\n' +
|
|
' mainWindow.loadFile(indexPath).catch(error => {\\n' +
|
|
' console.error(\\'Failed to load file:\\', error);\\n' +
|
|
' // 加载失败时显示错误页面\\n' +
|
|
' mainWindow.loadURL(\\'data:text/html,<h1>Application Load Error</h1><p>Could not load the main application. Please restart the app.</p>\\');\\n' +
|
|
' });\\n' +
|
|
' } else {\\n' +
|
|
' console.error(\\'Could not find index.html in any expected location\\');\\n' +
|
|
' console.log(\\'Checked paths:\\', possiblePaths);\\n' +
|
|
' console.log(\\'Current directory:\\', __dirname);\\n' +
|
|
' console.log(\\'Process resources path:\\', process.resourcesPath);\\n' +
|
|
' // 显示详细的错误信息\\n' +
|
|
' const errorHtml = \\'<h1>Application Not Found</h1><p>Could not locate the application files.</p><p>Please reinstall the application.</p>\\';\\n' +
|
|
' mainWindow.loadURL(\\'data:text/html,\\' + encodeURIComponent(errorHtml));\\n' +
|
|
' }\\n' +
|
|
' }\\n\\n' +
|
|
' mainWindow.once(\\'ready-to-show\\', () => {\\n' +
|
|
' mainWindow.show();\\n' +
|
|
' });\\n\\n' +
|
|
' mainWindow.webContents.setWindowOpenHandler(({ url }) => {\\n' +
|
|
' shell.openExternal(url);\\n' +
|
|
' return { action: \\'deny\\' };\\n' +
|
|
' });\\n\\n' +
|
|
' mainWindow.on(\\'closed\\', () => {\\n' +
|
|
' mainWindow = null;\\n' +
|
|
' });\\n' +
|
|
'}\\n\\n' +
|
|
'app.whenReady().then(createWindow);\\n\\n' +
|
|
'app.on(\\'window-all-closed\\', () => {\\n' +
|
|
' if (process.platform !== \\'darwin\\') {\\n' +
|
|
' app.quit();\\n' +
|
|
' }\\n' +
|
|
'});\\n\\n' +
|
|
'app.on(\\'activate\\', () => {\\n' +
|
|
' if (BrowserWindow.getAllWindows().length === 0) {\\n' +
|
|
' createWindow();\\n' +
|
|
' }\\n' +
|
|
'});';
|
|
|
|
fs.writeFileSync('electron/main.js', mainJsContent);
|
|
|
|
const electronPackageJson = {
|
|
name: 'github-stars-manager-desktop',
|
|
version: '1.0.0',
|
|
description: 'GitHub Stars Manager Desktop App',
|
|
main: 'main.js',
|
|
author: 'GitHub Stars Manager',
|
|
license: 'MIT'
|
|
};
|
|
|
|
fs.writeFileSync('electron/package.json', JSON.stringify(electronPackageJson, null, 2));
|
|
console.log('Electron files created successfully');
|
|
"
|
|
|
|
- name: Update main package.json for Electron
|
|
shell: bash
|
|
run: |
|
|
node -e "
|
|
const fs = require('fs');
|
|
const packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8'));
|
|
|
|
packageJson.main = 'electron/main.js';
|
|
packageJson.homepage = './';
|
|
packageJson.scripts = packageJson.scripts || {};
|
|
|
|
// 确保构建脚本使用正确的基础路径
|
|
packageJson.scripts.build = 'vite build --base=./';
|
|
packageJson.scripts['build:electron'] = 'vite build --base=./ && electron-builder';
|
|
packageJson.scripts.dist = 'electron-builder --publish=never';
|
|
|
|
// Ensure proper base path for Electron
|
|
if (!packageJson.build) packageJson.build = {};
|
|
packageJson.build.extraMetadata = {
|
|
main: 'electron/main.js'
|
|
};
|
|
packageJson.scripts.electron = 'electron .';
|
|
packageJson.scripts['electron-dev'] = 'NODE_ENV=development electron .';
|
|
packageJson.scripts.dist = 'electron-builder';
|
|
|
|
packageJson.build = {
|
|
appId: 'com.github-stars-manager.app',
|
|
productName: 'GitHub Stars Manager',
|
|
directories: {
|
|
output: 'release',
|
|
buildResources: 'build'
|
|
},
|
|
files: [
|
|
'dist/**/*',
|
|
'build/**/*',
|
|
'electron/**/*',
|
|
'node_modules/**/*',
|
|
'package.json',
|
|
'!node_modules/.cache/**/*',
|
|
'!**/*.map'
|
|
],
|
|
extraResources: [
|
|
{
|
|
from: 'dist',
|
|
to: 'dist',
|
|
filter: ['**/*']
|
|
}
|
|
],
|
|
compression: 'normal',
|
|
asar: false, // 暂时禁用 ASAR 以简化调试
|
|
publish: null // 确保不会尝试发布
|
|
};
|
|
|
|
fs.writeFileSync('package.json', JSON.stringify(packageJson, null, 2));
|
|
console.log('Package.json updated successfully');
|
|
"
|
|
|
|
- name: Configure platform-specific build settings
|
|
shell: bash
|
|
run: |
|
|
node -e "
|
|
const fs = require('fs');
|
|
const packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8'));
|
|
|
|
if ('${{ matrix.os }}' === 'windows-latest') {
|
|
packageJson.build.win = {
|
|
target: [
|
|
{
|
|
target: 'nsis',
|
|
arch: ['x64']
|
|
}
|
|
],
|
|
icon: 'build/icon.png',
|
|
requestedExecutionLevel: 'asInvoker'
|
|
};
|
|
packageJson.build.nsis = {
|
|
oneClick: false,
|
|
allowToChangeInstallationDirectory: true,
|
|
createDesktopShortcut: true,
|
|
createStartMenuShortcut: true,
|
|
shortcutName: 'GitHub Stars Manager'
|
|
};
|
|
} else if ('${{ matrix.os }}' === 'macos-latest') {
|
|
packageJson.build.mac = {
|
|
target: [
|
|
{
|
|
target: 'dmg',
|
|
arch: ['x64', 'arm64']
|
|
}
|
|
],
|
|
icon: 'build/icon.png',
|
|
category: 'public.app-category.productivity',
|
|
hardenedRuntime: true,
|
|
gatekeeperAssess: false,
|
|
identity: null
|
|
};
|
|
packageJson.build.dmg = {
|
|
title: 'GitHub Stars Manager',
|
|
icon: 'build/icon.png'
|
|
};
|
|
} else {
|
|
packageJson.build.linux = {
|
|
target: 'AppImage',
|
|
icon: 'build/icon-512x512.png',
|
|
category: 'Office'
|
|
};
|
|
}
|
|
|
|
fs.writeFileSync('package.json', JSON.stringify(packageJson, null, 2));
|
|
console.log('Platform-specific settings configured');
|
|
"
|
|
|
|
- name: Debug before build
|
|
shell: bash
|
|
run: |
|
|
echo "=== Pre-Build Debug Information ==="
|
|
echo "Current directory contents:"
|
|
ls -la
|
|
echo ""
|
|
echo "Dist directory contents:"
|
|
ls -la dist/ || echo "No dist directory"
|
|
echo ""
|
|
echo "Electron directory contents:"
|
|
ls -la electron/ || echo "No electron directory"
|
|
echo ""
|
|
echo "Build directory contents:"
|
|
ls -la build/ || echo "No build directory"
|
|
echo ""
|
|
echo "Package.json build config:"
|
|
node -e "console.log(JSON.stringify(require('./package.json').build, null, 2))"
|
|
echo ""
|
|
echo "Checking dist/index.html content:"
|
|
if [ -f "dist/index.html" ]; then
|
|
echo "First 20 lines of dist/index.html:"
|
|
head -20 dist/index.html
|
|
else
|
|
echo "dist/index.html not found"
|
|
fi
|
|
echo ""
|
|
echo "Setting proper permissions:"
|
|
chmod -R 755 dist/ || echo "Could not set dist permissions"
|
|
chmod -R 755 electron/ || echo "Could not set electron permissions"
|
|
chmod -R 755 build/ || echo "Could not set build permissions"
|
|
|
|
- name: Build Electron app
|
|
run: npm run dist
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
CI: true
|
|
DEBUG: electron-builder
|
|
# Linux 特定环境变量
|
|
ELECTRON_BUILDER_ALLOW_UNRESOLVED_DEPENDENCIES: true
|
|
# macOS signing and notarization
|
|
CSC_LINK: ${{ secrets.CSC_LINK }}
|
|
CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }}
|
|
APPLE_ID: ${{ secrets.APPLE_ID }}
|
|
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
|
|
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
|
|
|
- name: List build output
|
|
shell: bash
|
|
run: |
|
|
echo "Build output directory contents:"
|
|
ls -la release/ || echo "Release directory not found"
|
|
echo ""
|
|
echo "Looking for build artifacts:"
|
|
find . -name "*.exe" -o -name "*.msi" -o -name "*.dmg" -o -name "*.AppImage" || echo "No build artifacts found"
|
|
echo ""
|
|
if [ "${{ matrix.os }}" = "ubuntu-latest" ]; then
|
|
echo "Linux specific checks:"
|
|
echo "AppImage files:"
|
|
find . -name "*.AppImage" -exec ls -la {} \; || echo "No AppImage files found"
|
|
echo "Checking AppImage permissions:"
|
|
find . -name "*.AppImage" -exec file {} \; || echo "No AppImage files to check"
|
|
fi
|
|
|
|
- name: Test Electron app (Linux only)
|
|
if: matrix.os == 'ubuntu-latest'
|
|
shell: bash
|
|
run: |
|
|
# Install xvfb for headless testing
|
|
sudo apt-get update
|
|
sudo apt-get install -y xvfb
|
|
|
|
# Test if the app can start (will exit quickly but should not crash)
|
|
echo "Testing Electron app startup..."
|
|
timeout 10s xvfb-run -a npm run electron || echo "App test completed (timeout expected)"
|
|
|
|
- name: Upload artifacts (Windows)
|
|
if: matrix.os == 'windows-latest' && success()
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: windows-app
|
|
path: |
|
|
release/*.exe
|
|
release/*.msi
|
|
if-no-files-found: ignore
|
|
|
|
- name: Upload artifacts (macOS)
|
|
if: matrix.os == 'macos-latest' && success()
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: macos-app
|
|
path: release/*.dmg
|
|
if-no-files-found: ignore
|
|
|
|
- name: Upload artifacts (Linux)
|
|
if: matrix.os == 'ubuntu-latest' && success()
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: linux-app
|
|
path: release/*.AppImage
|
|
if-no-files-found: ignore
|
|
|
|
release:
|
|
needs: build
|
|
runs-on: ubuntu-latest
|
|
if: startsWith(github.ref, 'refs/tags/v') && always()
|
|
permissions:
|
|
contents: write
|
|
|
|
steps:
|
|
- name: Download all artifacts
|
|
uses: actions/download-artifact@v4
|
|
continue-on-error: true
|
|
|
|
- name: List downloaded files
|
|
shell: bash
|
|
run: |
|
|
echo "Downloaded files structure:"
|
|
find . -type f | head -20
|
|
echo "Looking for build artifacts:"
|
|
find . -name "*.exe" -o -name "*.msi" -o -name "*.dmg" -o -name "*.AppImage" | head -20
|
|
|
|
- name: Prepare release files
|
|
shell: bash
|
|
run: |
|
|
mkdir -p release-files
|
|
# Copy all found artifacts to a single directory
|
|
find . -name "*.exe" -exec cp {} release-files/ \; 2>/dev/null || true
|
|
find . -name "*.msi" -exec cp {} release-files/ \; 2>/dev/null || true
|
|
find . -name "*.dmg" -exec cp {} release-files/ \; 2>/dev/null || true
|
|
find . -name "*.AppImage" -exec cp {} release-files/ \; 2>/dev/null || true
|
|
echo "Files prepared for release:"
|
|
ls -la release-files/ || echo "No files found"
|
|
|
|
- name: Create Release
|
|
uses: softprops/action-gh-release@v1
|
|
with:
|
|
files: release-files/*
|
|
draft: false
|
|
prerelease: false
|
|
generate_release_notes: true
|
|
fail_on_unmatched_files: false
|
|
body: |
|
|
## Desktop Application Release
|
|
|
|
This release includes desktop applications for multiple platforms.
|
|
|
|
### Available Downloads:
|
|
- Windows: `.exe` installer
|
|
- macOS: `.dmg` installer
|
|
- Linux: `.AppImage` portable executable
|
|
|
|
Note: Some platform builds may not be available if they failed during the build process.
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |