diff --git a/.github/workflows/fractured-launcher-ci.yml b/.github/workflows/fractured-launcher-ci.yml index 2236397..ff97f58 100644 --- a/.github/workflows/fractured-launcher-ci.yml +++ b/.github/workflows/fractured-launcher-ci.yml @@ -22,7 +22,7 @@ concurrency: cancel-in-progress: true jobs: - electron-launcher: + electron-launcher-windows: runs-on: windows-latest timeout-minutes: 45 defaults: @@ -50,3 +50,32 @@ jobs: tools/fractured-launcher-electron/dist/*.exe tools/fractured-launcher-electron/dist/latest.yml tools/fractured-launcher-electron/dist/*.blockmap + + electron-launcher-linux: + runs-on: ubuntu-latest + timeout-minutes: 45 + defaults: + run: + working-directory: tools/fractured-launcher-electron + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: '20' + cache: npm + cache-dependency-path: tools/fractured-launcher-electron/package-lock.json + + - name: Install and pack (AppImage) + run: | + npm ci + npm run pack:linux + + - uses: actions/upload-artifact@v4 + with: + name: fractured-launcher-electron-linux-${{ github.run_id }} + if-no-files-found: warn + path: | + tools/fractured-launcher-electron/dist/*.AppImage + tools/fractured-launcher-electron/dist/*.yml + tools/fractured-launcher-electron/dist/*.blockmap diff --git a/.github/workflows/gitea-release-sync.yml b/.github/workflows/gitea-release-sync.yml index 6033984..07a0884 100644 --- a/.github/workflows/gitea-release-sync.yml +++ b/.github/workflows/gitea-release-sync.yml @@ -13,8 +13,8 @@ # Release on github.com (Releases → Draft/new release → Publish). The workflow # definition must exist on the repo DEFAULT branch (GitHub runs it from there). # -# Steps: build Electron using launcher sources from DEFAULT BRANCH (so tags never miss -# launcher files), checkout tag only for a consistent tree → download release attachments → Gitea. +# Steps: Windows (NSIS+portable) + Linux (AppImage) in parallel, launcher from DEFAULT BRANCH +# overlay on tag checkout → merge with GitHub release assets → upload all to Gitea. # # Secrets: GITEA_BASE_URL, GITEA_TOKEN, GITEA_OWNER, GITEA_REPO # Optional variable: GITEA_TARGET_REF (see tools/fractured-launcher-electron/README.md) @@ -102,11 +102,61 @@ jobs: - uses: actions/upload-artifact@v4 with: - name: electron-dist + name: electron-dist-windows path: launcher-publish/ + build-electron-linux: + needs: meta + if: github.repository == 'Dawnforger/Fractured' + runs-on: ubuntu-latest + timeout-minutes: 45 + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ needs.meta.outputs.tag }} + + - name: Overlay launcher from default branch + shell: bash + run: | + set -euo pipefail + DB="${{ github.event.repository.default_branch }}" + git fetch --no-tags --depth=1 origin "+refs/heads/${DB}:refs/remotes/origin/${DB}" + git checkout "origin/${DB}" -- tools/fractured-launcher-electron + + - uses: actions/setup-node@v4 + with: + node-version: '20' + cache: npm + cache-dependency-path: tools/fractured-launcher-electron/package-lock.json + + - name: Install and pack (AppImage) + working-directory: tools/fractured-launcher-electron + run: | + npm ci + npm run pack:linux + + - name: Stage Linux launcher for upload + shell: bash + run: | + set -euo pipefail + mkdir -p launcher-linux-publish + shopt -s nullglob + cp -f tools/fractured-launcher-electron/dist/*.AppImage launcher-linux-publish/ 2>/dev/null || true + cp -f tools/fractured-launcher-electron/dist/*.yml launcher-linux-publish/ 2>/dev/null || true + cp -f tools/fractured-launcher-electron/dist/*.blockmap launcher-linux-publish/ 2>/dev/null || true + ls -la launcher-linux-publish/ + if ! compgen -G "launcher-linux-publish/*.AppImage" > /dev/null; then + echo "No AppImage under dist/ — electron-builder linux target failed" >&2 + exit 1 + fi + + - uses: actions/upload-artifact@v4 + with: + name: electron-dist-linux + path: launcher-linux-publish/ + sync-gitea: - needs: [meta, build-electron] + needs: [meta, build-electron, build-electron-linux] if: github.repository == 'Dawnforger/Fractured' runs-on: ubuntu-latest env: @@ -126,8 +176,13 @@ jobs: - uses: actions/download-artifact@v4 with: - name: electron-dist - path: /tmp/electron + name: electron-dist-windows + path: /tmp/electron-win + + - uses: actions/download-artifact@v4 + with: + name: electron-dist-linux + path: /tmp/electron-linux - name: Merge GitHub release assets + Electron build env: @@ -150,7 +205,7 @@ jobs: cat /tmp/dl.err || true fi shopt -s nullglob - for f in /tmp/electron/*; do + for f in /tmp/electron-win/* /tmp/electron-linux/*; do if [ -f "$f" ]; then cp -f "$f" combined/ fi diff --git a/tools/fractured-launcher-electron/README.md b/tools/fractured-launcher-electron/README.md index a8c7a86..ef76130 100644 --- a/tools/fractured-launcher-electron/README.md +++ b/tools/fractured-launcher-electron/README.md @@ -1,6 +1,6 @@ # Fractured Launcher (Electron) -Windows launcher with **no extra console window**, **native Browse folder** dialog, **Gitea or GitHub** release assets + GitHub repo file sync, **realmlist**, optional **auth**, **Play**, and **auto-update** (via `electron-updater`). This is the **only** supported client launcher in this repo. +**Windows** and **Linux (AppImage)** launcher with **no extra console window**, **native Browse folder** dialog, **Gitea or GitHub** release assets + GitHub repo file sync, **realmlist**, optional **auth**, **Play**, and **auto-update** (via `electron-updater`). This is the **only** supported client launcher in this repo. ## Requirements @@ -35,6 +35,18 @@ Produces under **`dist/`**: | `Fractured-Launcher-${version}-Setup.exe` (NSIS) | **Recommended for players** — supports seamless **auto-update** and restart. | | `Fractured-Launcher-${version}-Windows-Portable.exe` | No installer; players replace the file manually. Auto-update is **less reliable** than NSIS. | +## Build Linux AppImage + +```bash +cd tools/fractured-launcher-electron +npm install +npm run pack:linux +``` + +Produces **`dist/Fractured-Launcher-${version}-Linux-x86_64.AppImage`**. Same **`lib/baked-gitea-channel.js`** and **`default-launcher.json`** as Windows; run on **Linux** (or use **Fractured launcher CI** / **Sync release to Gitea**, which upload this file to Gitea with the Windows installers). + +**Quick local test (avoids tag snapshot):** from repo root, **`bash tools/fractured-launcher-electron/scripts/manual-pack-linux.sh`** — uses your **current** checkout, then install/run the AppImage from **`dist/`**. + ### Hardcoded Gitea channel (non-token) **`lib/baked-gitea-channel.js`** exports **`base_url`**, **`owner`**, **`repo`**, **`release_tag`**. Set those strings once in the repo (same values you use for CI upload — not secret). At runtime **`config-store`** merges them into **`gitea.*`** so **`launcher.json`** does not need those fields; **`GITEA_TOKEN`** (or **`gitea.token_env`**) is still only for **private** Gitea. Leave a field **`''`** in the baked file to fall back to **`default-launcher.json`** / user **`launcher.json`** for that key. @@ -64,15 +76,15 @@ Produces under **`dist/`**: ### Publishing a new launcher version 1. Bump **`version`** in `package.json` on `main` (or your release branch) and merge. -2. Create a **GitHub release** (tag + attach patches / `Wow.exe` if needed) and click **Publish** — **Sync release to Gitea** builds Windows installers and mirrors everything to Gitea. -3. Local check: `npm run pack:win` then **`scripts/upload-release-to-gitea.sh`** with the same **`GITEA_*`** env vars as CI if you need a manual upload. +2. Create a **GitHub release** (tag + attach patches / `Wow.exe` if needed) and click **Publish** — **Sync release to Gitea** builds **Windows + Linux** launcher artifacts and mirrors everything to Gitea. +3. Local check: **`npm run pack:win`** (on Windows) or **`npm run pack:linux`** / **`scripts/manual-pack-linux.sh`**, then **`scripts/upload-release-to-gitea.sh`** with the same **`GITEA_*`** env vars as CI if you need a manual upload. ## Sync to Gitea (patches + launcher binaries) CI workflow **Sync release to Gitea** (`.github/workflows/gitea-release-sync.yml`) runs on **every published GitHub release** on this repo: 1. Triggers on **release published** on **`Dawnforger/Fractured`** (or **workflow_dispatch** with a tag). -2. Builds the **Electron** app on Windows using **`tools/fractured-launcher-electron` from the repo default branch** (then overlays onto the tag checkout), so older release tags never ship a launcher that’s missing new **`lib/*.js`** files. +2. Builds **Windows** (NSIS + portable) and **Linux** (AppImage) in parallel, each using **`tools/fractured-launcher-electron` from the default branch** (overlaid onto the tag checkout), so older release tags never ship a launcher missing new **`lib/*.js`** files. 3. Downloads **all assets** attached to that **GitHub** release (MPQs, patched `Wow.exe`, etc.). 4. Merges with the built launcher artifacts and uploads everything to a **Gitea release** with the **same tag** (existing attachments on that Gitea release are replaced). @@ -138,9 +150,9 @@ Attach **`patch-manifest.json`** together with the MPQ/exe to the GitHub release ## CI -Workflow **Fractured launcher CI** (`.github/workflows/fractured-launcher-ci.yml`) runs on pushes/PRs under `tools/fractured-launcher-electron/`: Windows pack uses **`electron-builder … --publish never`** (not `npm run pack:win`, so tagged checkouts never require `GH_TOKEN`). **Actions → Fractured launcher CI → Run workflow** runs it manually. +Workflow **Fractured launcher CI** (`.github/workflows/fractured-launcher-ci.yml`) runs on pushes/PRs under `tools/fractured-launcher-electron/`: **Windows** (`npm run pack:win`) and **Linux** (`npm run pack:linux`) jobs, each **`electron-builder … --publish never`**. **Actions → Fractured launcher CI → Run workflow** runs it manually. -**Sync release to Gitea** (`.github/workflows/gitea-release-sync.yml`) uses the same pack command. If you see `GH_TOKEN` / `GitHubPublisher` errors in logs, the job is almost certainly an old **Re-run failed jobs** — open **Actions → Sync release to Gitea → Run workflow**, enter the tag, and start a **new** run instead. +**Sync release to Gitea** (`.github/workflows/gitea-release-sync.yml`) uses the same pack commands. If you see `GH_TOKEN` / `GitHubPublisher` errors in logs, the job is almost certainly an old **Re-run failed jobs** — open **Actions → Sync release to Gitea → Run workflow**, enter the tag, and start a **new** run instead. ## Config diff --git a/tools/fractured-launcher-electron/lib/baked-gitea-channel.js b/tools/fractured-launcher-electron/lib/baked-gitea-channel.js index 1cb2d56..fc1fa7e 100644 --- a/tools/fractured-launcher-electron/lib/baked-gitea-channel.js +++ b/tools/fractured-launcher-electron/lib/baked-gitea-channel.js @@ -6,8 +6,9 @@ * Token stays in env: GITEA_TOKEN or launcher.json → gitea.token_env. */ module.exports = { - base_url: '', - owner: '', - repo: '', + // Scheme optional — gitea-release normalizes to https:// if missing. + base_url: 'https://brassnet.ddns.net:33983', + owner: 'Dawnsorrow', + repo: 'Fractured-Distro', release_tag: 'latest', }; diff --git a/tools/fractured-launcher-electron/lib/gitea-release.js b/tools/fractured-launcher-electron/lib/gitea-release.js index d202462..e2d4a5c 100644 --- a/tools/fractured-launcher-electron/lib/gitea-release.js +++ b/tools/fractured-launcher-electron/lib/gitea-release.js @@ -2,8 +2,15 @@ const { downloadBodyToFile } = require('./http-download'); +function normalizeGiteaBaseUrl(raw) { + let b = String(raw || '').trim().replace(/\/+$/, ''); + if (!b) return ''; + if (!/^https?:\/\//i.test(b)) b = `https://${b}`; + return b; +} + function giteaApiBase(cfg) { - const base = String(cfg.gitea.base_url || '').trim().replace(/\/+$/, ''); + const base = normalizeGiteaBaseUrl(cfg.gitea.base_url); return `${base}/api/v1`; } @@ -87,7 +94,7 @@ async function getGiteaUpdaterFeedBase(cfg) { const rel = await res.json(); const tagName = rel.tag_name; if (!tagName || typeof tagName !== 'string') return null; - const root = String(cfg.gitea.base_url || '').trim().replace(/\/+$/, ''); + const root = normalizeGiteaBaseUrl(cfg.gitea.base_url); const url = `${root}/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/releases/download/${encodeURIComponent(tagName)}/`; return { url, token }; } diff --git a/tools/fractured-launcher-electron/package.json b/tools/fractured-launcher-electron/package.json index 0320aa8..fd8188a 100644 --- a/tools/fractured-launcher-electron/package.json +++ b/tools/fractured-launcher-electron/package.json @@ -1,6 +1,6 @@ { "name": "fractured-launcher-electron", - "version": "1.0.1", + "version": "1.0.2", "description": "Fractured WoW launcher (Electron) — no console window, native folder picker, auto-update", "main": "main.js", "repository": { @@ -10,6 +10,7 @@ "scripts": { "start": "electron .", "pack:win": "electron-builder --win nsis portable --x64 --publish never", + "pack:linux": "electron-builder --linux AppImage --x64 --publish never", "publish:win": "electron-builder --win nsis portable --x64 --publish never" }, "author": "", @@ -59,6 +60,18 @@ }, "portable": { "artifactName": "Fractured-Launcher-${version}-Windows-Portable.${ext}" + }, + "linux": { + "target": [ + { + "target": "AppImage", + "arch": ["x64"] + } + ], + "category": "Game" + }, + "appImage": { + "artifactName": "Fractured-Launcher-${version}-Linux-x86_64.${ext}" } } } diff --git a/tools/fractured-launcher-electron/scripts/manual-pack-linux.sh b/tools/fractured-launcher-electron/scripts/manual-pack-linux.sh new file mode 100755 index 0000000..099f483 --- /dev/null +++ b/tools/fractured-launcher-electron/scripts/manual-pack-linux.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +# Local Linux AppImage build (uses current tree — no tag snapshot). Run from repo root or this dir. +set -euo pipefail +ROOT="$(cd "$(dirname "$0")/.." && pwd)" +cd "$ROOT" +echo "==> npm ci" +npm ci +echo "==> npm run pack:linux (AppImage x64)" +npm run pack:linux +echo "==> dist/:" +ls -la dist/