diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..fcdafff --- /dev/null +++ b/.github/workflows/build.yml @@ -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 diff --git a/electron-builder.yml b/electron-builder.yml index c10de27..3bf7a50 100644 --- a/electron-builder.yml +++ b/electron-builder.yml @@ -31,7 +31,6 @@ dmg: linux: target: - AppImage - - snap - deb maintainer: electronjs.org category: Utility diff --git a/electron.vite.config.ts b/electron.vite.config.ts index edd3425..5c7fb12 100644 --- a/electron.vite.config.ts +++ b/electron.vite.config.ts @@ -1,10 +1,27 @@ +import { execSync } from 'child_process' import { defineConfig, externalizeDepsPlugin } from 'electron-vite' import tailwindcss from '@tailwindcss/vite' 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({ main: { - plugins: [externalizeDepsPlugin()] + plugins: [externalizeDepsPlugin()], + define: { + __COMMIT_HASH__: commitHash + } }, preload: { plugins: [externalizeDepsPlugin()] diff --git a/package.json b/package.json index 82f6c95..c753f86 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "1.0.0", "description": "Mirrors Discord Rich Presence (RPC) to multiple running Discord instances", "main": "./out/main/index.js", + "packageManager": "pnpm@10.33.0", "author": "", "private": true, "scripts": { diff --git a/src/main/index.ts b/src/main/index.ts index 68916e8..304e052 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -5,6 +5,8 @@ import { electronApp, optimizer, is } from '@electron-toolkit/utils' import icon from '../../resources/icon.png?asset' import { relay, RelayStatus } from './relay' +declare const __COMMIT_HASH__: string + function settingsPath(): string { return join(app.getPath('userData'), 'settings.json') } @@ -135,6 +137,10 @@ app.whenReady().then(() => { relay.setDisabledMirrors(loadDisabledMirrors()) + ipcMain.handle('relay:get-version', () => ({ + version: app.getVersion(), + commit: __COMMIT_HASH__ + })) ipcMain.handle('relay:get-status', () => relay.getStatus()) ipcMain.handle('relay:start', () => relay.start()) ipcMain.handle('relay:stop', () => relay.stop()) diff --git a/src/preload/index.ts b/src/preload/index.ts index 9a4c13b..061e20b 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -3,6 +3,8 @@ import { electronAPI } from '@electron-toolkit/preload' import type { RelayStatus } from '../main/relay' const api = { + getVersion: (): Promise<{ version: string; commit: string }> => + ipcRenderer.invoke('relay:get-version'), getStatus: (): Promise => ipcRenderer.invoke('relay:get-status'), start: (): Promise => ipcRenderer.invoke('relay:start'), stop: (): Promise => ipcRenderer.invoke('relay:stop'), diff --git a/src/renderer/src/App.tsx b/src/renderer/src/App.tsx index 2e88690..5a62662 100644 --- a/src/renderer/src/App.tsx +++ b/src/renderer/src/App.tsx @@ -103,11 +103,13 @@ export function App(): React.JSX.Element { const [loading, setLoading] = useState(false) const [autostart, setAutostart] = useState(false) const [view, setView] = useState<'main' | 'settings'>('main') + const [appVersion, setAppVersion] = useState<{ version: string; commit: string } | null>(null) useEffect(() => { void (async () => { setStatus(await window.api.getStatus()) setAutostart(await window.api.getAutostart()) + setAppVersion(await window.api.getVersion()) })() return window.api.onStatus(setStatus) @@ -167,6 +169,12 @@ export function App(): React.JSX.Element { + + {appVersion && ( +

+ Version {appVersion.version} ({appVersion.commit}) +

+ )} ) }