Skip to content

0.1.0

0.1.0 #19

Workflow file for this run

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
- name: Verify 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
else
echo "Creating fallback dist directory and index.html"
mkdir -p dist
cat > dist/index.html << 'HTML_END'
<!DOCTYPE html>

Check failure on line 49 in .github/workflows/build-desktop.yml

View workflow run for this annotation

GitHub Actions / .github/workflows/build-desktop.yml

Invalid workflow file

You have an error in your yaml syntax on line 49
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>GitHub Stars Manager</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
background: #f5f5f5;
}
.container {
max-width: 800px;
margin: 0 auto;
background: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
h1 { color: #333; }
.status { color: #666; margin-top: 20px; }
</style>
</head>
<body>
<div class="container">
<h1>GitHub Stars Manager</h1>
<p>Welcome to GitHub Stars Manager Desktop Application!</p>
<div class="status">
<p>This is a fallback page. The main application should load here.</p>
<p>Application built successfully with GitHub Actions.</p>
</div>
</div>
<script>
console.log('GitHub Stars Manager loaded successfully');
document.addEventListener('DOMContentLoaded', function() {
console.log('DOM ready');
});
</script>
</body>
</html>
HTML_END
echo "✓ Fallback index.html created"
fi
- 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
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
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('No source icon found, will use electron-builder default');
// Create a simple placeholder
const placeholderSvg = '<svg width=\"512\" height=\"512\" xmlns=\"http://www.w3.org/2000/svg\"><rect width=\"512\" height=\"512\" fill=\"#3b82f6\"/><text x=\"256\" y=\"256\" text-anchor=\"middle\" dy=\".3em\" fill=\"white\" font-size=\"48\" font-family=\"Arial\">APP</text></svg>';
fs.writeFileSync('build/icon.svg', placeholderSvg);
}
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 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' +
' },\\n' +
' icon: path.join(__dirname, \\'../build/icon.png\\'),\\n' +
' titleBarStyle: process.platform === \\'darwin\\' ? \\'hiddenInset\\' : \\'default\\',\\n' +
' show: false\\n' +
' });\\n\\n' +
' // Add error handling\\n' +
' mainWindow.webContents.on(\\'did-fail-load\\', (event, errorCode, errorDescription) => {\\n' +
' console.error(\\'Failed to load:\\', errorCode, errorDescription);\\n' +
' });\\n\\n' +
' mainWindow.webContents.on(\\'dom-ready\\', () => {\\n' +
' console.log(\\'DOM ready\\');\\n' +
' });\\n\\n' +
' if (isDev) {\\n' +
' mainWindow.loadURL(\\'http://localhost:5173\\');\\n' +
' mainWindow.webContents.openDevTools();\\n' +
' } else {\\n' +
' // Try multiple possible paths for the built app\\n' +
' const possiblePaths = [\\n' +
' path.join(__dirname, \\'../dist/index.html\\'),\\n' +
' path.join(__dirname, \\'../build/index.html\\'),\\n' +
' path.join(process.resourcesPath, \\'app/dist/index.html\\'),\\n' +
' path.join(process.resourcesPath, \\'dist/index.html\\')\\n' +
' ];\\n\\n' +
' let indexPath = null;\\n' +
' for (const testPath of possiblePaths) {\\n' +
' if (fs.existsSync(testPath)) {\\n' +
' indexPath = testPath;\\n' +
' break;\\n' +
' }\\n' +
' }\\n\\n' +
' if (indexPath) {\\n' +
' console.log(\\'Loading from:\\', indexPath);\\n' +
' mainWindow.loadFile(indexPath);\\n' +
' } else {\\n' +
' console.error(\\'Could not find index.html in any expected location\\');\\n' +
' console.log(\\'Checked paths:\\', possiblePaths);\\n' +
' // Load a simple error page\\n' +
' mainWindow.loadURL(\\'data:text/html,<h1>Error: Could not load application</h1><p>Please check the console for details.</p>\\');\\n' +
' }\\n' +
' // Open DevTools in production for debugging\\n' +
' mainWindow.webContents.openDevTools();\\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 || {};
// 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'
],
extraResources: [
{
from: 'dist',
to: 'dist',
filter: ['**/*']
}
]
};
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: 'nsis',
icon: 'build/icon.png'
};
packageJson.build.nsis = {
oneClick: false,
allowToChangeInstallationDirectory: true
};
} else if ('${{ matrix.os }}' === 'macos-latest') {
packageJson.build.mac = {
target: 'dmg',
icon: 'build/icon.png',
category: 'public.app-category.productivity'
};
} 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 "=== Debug Information ==="
echo "Current directory contents:"
ls -la
echo "Dist directory contents:"
ls -la dist/ || echo "No dist directory"
echo "Electron directory contents:"
ls -la electron/ || echo "No electron directory"
echo "Package.json build config:"
node -e "console.log(JSON.stringify(require('./package.json').build, null, 2))"
- name: Build Electron app
run: npm run dist
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CI: true
DEBUG: electron-builder
- name: List build output
shell: bash
run: |
echo "Build output directory contents:"
ls -la release/ || echo "Release directory not found"
find . -name "*.exe" -o -name "*.msi" -o -name "*.dmg" -o -name "*.AppImage" || echo "No build artifacts found"
- 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 }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}