👷 ci: Add GitHub Actions workflow for cross-platform builds

This commit is contained in:
2026-06-16 00:14:16 +07:00
parent b8b133c9f2
commit efc810c2e2
7 changed files with 101 additions and 2 deletions
+66
View File
@@ -0,0 +1,66 @@
name: Build
on:
push:
branches:
- main
tags:
- 'v*'
pull_request:
workflow_dispatch:
jobs:
build:
strategy:
fail-fast: false
matrix:
os: [windows-latest, macos-latest, ubuntu-latest]
include:
- os: windows-latest
build-script: build:win
- os: macos-latest
build-script: build:mac
- os: ubuntu-latest
build-script: build:linux
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Setup pnpm
uses: pnpm/action-setup@v5
- name: Setup Node.js
uses: actions/setup-node@v5
with:
node-version: 22
cache: pnpm
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build
run: pnpm ${{ matrix.build-script }}
- name: Set artifact version
id: version
shell: bash
run: |
if [[ "${GITHUB_REF}" == refs/tags/* ]]; then
echo "value=${GITHUB_REF_NAME}" >> "$GITHUB_OUTPUT"
else
echo "value=${GITHUB_SHA::7}" >> "$GITHUB_OUTPUT"
fi
- name: Upload artifacts
uses: actions/upload-artifact@v5
with:
name: ${{ matrix.os }}-${{ steps.version.outputs.value }}
path: |
dist/*.exe
dist/*.dmg
dist/*.AppImage
dist/*.deb
if-no-files-found: error
-1
View File
@@ -31,7 +31,6 @@ dmg:
linux: linux:
target: target:
- AppImage - AppImage
- snap
- deb - deb
maintainer: electronjs.org maintainer: electronjs.org
category: Utility category: Utility
+18 -1
View File
@@ -1,10 +1,27 @@
import { execSync } from 'child_process'
import { defineConfig, externalizeDepsPlugin } from 'electron-vite' import { defineConfig, externalizeDepsPlugin } from 'electron-vite'
import tailwindcss from '@tailwindcss/vite' import tailwindcss from '@tailwindcss/vite'
import react from '@vitejs/plugin-react' import react from '@vitejs/plugin-react'
function getCommitHash(): string {
if (process.env.GITHUB_SHA) return process.env.GITHUB_SHA.slice(0, 7)
try {
const hash = execSync('git rev-parse --short HEAD').toString().trim()
const dirty = execSync('git status --porcelain').toString().trim().length > 0
return dirty ? `${hash}-dirty` : hash
} catch {
return 'unknown'
}
}
const commitHash = JSON.stringify(getCommitHash())
export default defineConfig({ export default defineConfig({
main: { main: {
plugins: [externalizeDepsPlugin()] plugins: [externalizeDepsPlugin()],
define: {
__COMMIT_HASH__: commitHash
}
}, },
preload: { preload: {
plugins: [externalizeDepsPlugin()] plugins: [externalizeDepsPlugin()]
+1
View File
@@ -3,6 +3,7 @@
"version": "1.0.0", "version": "1.0.0",
"description": "Mirrors Discord Rich Presence (RPC) to multiple running Discord instances", "description": "Mirrors Discord Rich Presence (RPC) to multiple running Discord instances",
"main": "./out/main/index.js", "main": "./out/main/index.js",
"packageManager": "pnpm@10.33.0",
"author": "", "author": "",
"private": true, "private": true,
"scripts": { "scripts": {
+6
View File
@@ -5,6 +5,8 @@ import { electronApp, optimizer, is } from '@electron-toolkit/utils'
import icon from '../../resources/icon.png?asset' import icon from '../../resources/icon.png?asset'
import { relay, RelayStatus } from './relay' import { relay, RelayStatus } from './relay'
declare const __COMMIT_HASH__: string
function settingsPath(): string { function settingsPath(): string {
return join(app.getPath('userData'), 'settings.json') return join(app.getPath('userData'), 'settings.json')
} }
@@ -135,6 +137,10 @@ app.whenReady().then(() => {
relay.setDisabledMirrors(loadDisabledMirrors()) relay.setDisabledMirrors(loadDisabledMirrors())
ipcMain.handle('relay:get-version', () => ({
version: app.getVersion(),
commit: __COMMIT_HASH__
}))
ipcMain.handle('relay:get-status', () => relay.getStatus()) ipcMain.handle('relay:get-status', () => relay.getStatus())
ipcMain.handle('relay:start', () => relay.start()) ipcMain.handle('relay:start', () => relay.start())
ipcMain.handle('relay:stop', () => relay.stop()) ipcMain.handle('relay:stop', () => relay.stop())
+2
View File
@@ -3,6 +3,8 @@ import { electronAPI } from '@electron-toolkit/preload'
import type { RelayStatus } from '../main/relay' import type { RelayStatus } from '../main/relay'
const api = { const api = {
getVersion: (): Promise<{ version: string; commit: string }> =>
ipcRenderer.invoke('relay:get-version'),
getStatus: (): Promise<RelayStatus> => ipcRenderer.invoke('relay:get-status'), getStatus: (): Promise<RelayStatus> => ipcRenderer.invoke('relay:get-status'),
start: (): Promise<void> => ipcRenderer.invoke('relay:start'), start: (): Promise<void> => ipcRenderer.invoke('relay:start'),
stop: (): Promise<void> => ipcRenderer.invoke('relay:stop'), stop: (): Promise<void> => ipcRenderer.invoke('relay:stop'),
+8
View File
@@ -103,11 +103,13 @@ export function App(): React.JSX.Element {
const [loading, setLoading] = useState(false) const [loading, setLoading] = useState(false)
const [autostart, setAutostart] = useState(false) const [autostart, setAutostart] = useState(false)
const [view, setView] = useState<'main' | 'settings'>('main') const [view, setView] = useState<'main' | 'settings'>('main')
const [appVersion, setAppVersion] = useState<{ version: string; commit: string } | null>(null)
useEffect(() => { useEffect(() => {
void (async () => { void (async () => {
setStatus(await window.api.getStatus()) setStatus(await window.api.getStatus())
setAutostart(await window.api.getAutostart()) setAutostart(await window.api.getAutostart())
setAppVersion(await window.api.getVersion())
})() })()
return window.api.onStatus(setStatus) return window.api.onStatus(setStatus)
@@ -167,6 +169,12 @@ export function App(): React.JSX.Element {
</div> </div>
<Toggle checked={autostart} onChange={onToggleAutostart} /> <Toggle checked={autostart} onChange={onToggleAutostart} />
</section> </section>
{appVersion && (
<p className="text-xs text-zinc-500 mt-auto">
Version {appVersion.version} ({appVersion.commit})
</p>
)}
</div> </div>
) )
} }