refactor(launcher): hardcode Gitea channel in lib/baked-gitea-channel.js
- Merge baked base_url/owner/repo/release_tag at load time (no inject script, no fractured-release-channel.json, no CI env for pack). - Fix mergeConfig deep-merge for gitea, patch_manifest, launcher_updates_from_github. - Remove inject-release-channel.js and fractured-release-channel.json. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -38,10 +38,6 @@ jobs:
|
|||||||
cache-dependency-path: tools/fractured-launcher-electron/package-lock.json
|
cache-dependency-path: tools/fractured-launcher-electron/package-lock.json
|
||||||
|
|
||||||
- name: Install and pack (NSIS + portable)
|
- name: Install and pack (NSIS + portable)
|
||||||
env:
|
|
||||||
GITEA_BASE_URL: ${{ secrets.GITEA_BASE_URL }}
|
|
||||||
GITEA_OWNER: ${{ secrets.GITEA_OWNER }}
|
|
||||||
GITEA_REPO: ${{ secrets.GITEA_REPO }}
|
|
||||||
run: |
|
run: |
|
||||||
npm ci
|
npm ci
|
||||||
npm run pack:win
|
npm run pack:win
|
||||||
|
|||||||
@@ -85,14 +85,8 @@ jobs:
|
|||||||
|
|
||||||
- name: Install and pack (NSIS + portable)
|
- name: Install and pack (NSIS + portable)
|
||||||
working-directory: tools/fractured-launcher-electron
|
working-directory: tools/fractured-launcher-electron
|
||||||
env:
|
|
||||||
# Same values as upload step — baked into default-launcher.json (no token).
|
|
||||||
GITEA_BASE_URL: ${{ secrets.GITEA_BASE_URL }}
|
|
||||||
GITEA_OWNER: ${{ secrets.GITEA_OWNER }}
|
|
||||||
GITEA_REPO: ${{ secrets.GITEA_REPO }}
|
|
||||||
run: |
|
run: |
|
||||||
npm ci
|
npm ci
|
||||||
# pack:win runs inject-release-channel.js then electron-builder --publish never
|
|
||||||
npm run pack:win
|
npm run pack:win
|
||||||
|
|
||||||
- name: Stage launcher files for upload
|
- name: Stage launcher files for upload
|
||||||
|
|||||||
@@ -35,14 +35,11 @@ Produces under **`dist/`**:
|
|||||||
| `Fractured-Launcher-${version}-Setup.exe` (NSIS) | **Recommended for players** — supports seamless **auto-update** and restart. |
|
| `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. |
|
| `Fractured-Launcher-${version}-Windows-Portable.exe` | No installer; players replace the file manually. Auto-update is **less reliable** than NSIS. |
|
||||||
|
|
||||||
### Baked Gitea channel (non-token)
|
### Hardcoded Gitea channel (non-token)
|
||||||
|
|
||||||
**`npm run pack:win`** runs **`scripts/inject-release-channel.js`** first. It merges **`gitea.base_url`**, **`owner`**, **`repo`**, and optional **`release_tag`** into **`default-launcher.json`** for that build only (then **electron-builder** packs that file).
|
**`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.
|
||||||
|
|
||||||
- **GitHub Actions** — **Sync release to Gitea** and **Fractured launcher CI** export **`GITEA_BASE_URL`**, **`GITEA_OWNER`**, **`GITEA_REPO`** (same names as your upload secrets) for the pack step, so installers match the repo you sync to. Nothing embeds **`GITEA_TOKEN`**.
|
**`npm run pack:win`** is plain **electron-builder** — no inject step, no extra JSON beside the app.
|
||||||
- **Local packs** — put the same values in **`fractured-release-channel.json`** (committed or personal copy) **or** export those env vars before **`npm run pack:win`**.
|
|
||||||
|
|
||||||
First launch still copies **`default-launcher.json`** → **`launcher.json`** beside the exe, so players get the baked **`gitea.*`** without editing unless they override.
|
|
||||||
|
|
||||||
## Auto-update behaviour
|
## Auto-update behaviour
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"gitea": {
|
|
||||||
"base_url": "",
|
|
||||||
"owner": "",
|
|
||||||
"repo": "",
|
|
||||||
"release_tag": "latest"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Production Gitea mirror (non-secret). Edit here and ship — no inject script,
|
||||||
|
* no fractured-release-channel.json, no CI env needed for these fields.
|
||||||
|
* Token stays in env: GITEA_TOKEN or launcher.json → gitea.token_env.
|
||||||
|
*/
|
||||||
|
module.exports = {
|
||||||
|
base_url: '',
|
||||||
|
owner: '',
|
||||||
|
repo: '',
|
||||||
|
release_tag: 'latest',
|
||||||
|
};
|
||||||
@@ -11,7 +11,13 @@ function mergeConfig(defaults, user) {
|
|||||||
user.update_feed_url != null && user.update_feed_url !== ''
|
user.update_feed_url != null && user.update_feed_url !== ''
|
||||||
? user.update_feed_url
|
? user.update_feed_url
|
||||||
: defaults.update_feed_url,
|
: defaults.update_feed_url,
|
||||||
|
launcher_updates_from_github:
|
||||||
|
user.launcher_updates_from_github != null
|
||||||
|
? user.launcher_updates_from_github
|
||||||
|
: defaults.launcher_updates_from_github,
|
||||||
github: { ...defaults.github, ...(user.github || {}) },
|
github: { ...defaults.github, ...(user.github || {}) },
|
||||||
|
gitea: { ...defaults.gitea, ...(user.gitea || {}) },
|
||||||
|
patch_manifest: { ...defaults.patch_manifest, ...(user.patch_manifest || {}) },
|
||||||
launch: { ...defaults.launch, ...(user.launch || {}) },
|
launch: { ...defaults.launch, ...(user.launch || {}) },
|
||||||
auth: user.auth != null ? { ...defaults.auth, ...user.auth } : defaults.auth,
|
auth: user.auth != null ? { ...defaults.auth, ...user.auth } : defaults.auth,
|
||||||
realmlist: user.realmlist != null ? { ...defaults.realmlist, ...user.realmlist } : defaults.realmlist,
|
realmlist: user.realmlist != null ? { ...defaults.realmlist, ...user.realmlist } : defaults.realmlist,
|
||||||
@@ -19,6 +25,23 @@ function mergeConfig(defaults, user) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Hardcoded Gitea host/repo (see lib/baked-gitea-channel.js). Non-empty baked values win. */
|
||||||
|
function applyBakedGitea(cfg) {
|
||||||
|
let baked;
|
||||||
|
try {
|
||||||
|
baked = require('./baked-gitea-channel');
|
||||||
|
} catch {
|
||||||
|
return cfg;
|
||||||
|
}
|
||||||
|
if (!baked || typeof baked !== 'object') return cfg;
|
||||||
|
cfg.gitea = { ...(cfg.gitea || {}) };
|
||||||
|
for (const k of ['base_url', 'owner', 'repo', 'release_tag']) {
|
||||||
|
const v = baked[k];
|
||||||
|
if (v != null && String(v).trim() !== '') cfg.gitea[k] = String(v).trim();
|
||||||
|
}
|
||||||
|
return cfg;
|
||||||
|
}
|
||||||
|
|
||||||
function getConfigPath(app) {
|
function getConfigPath(app) {
|
||||||
if (process.env.FRACTURED_LAUNCHER_CONFIG) return process.env.FRACTURED_LAUNCHER_CONFIG;
|
if (process.env.FRACTURED_LAUNCHER_CONFIG) return process.env.FRACTURED_LAUNCHER_CONFIG;
|
||||||
if (app && app.isPackaged) {
|
if (app && app.isPackaged) {
|
||||||
@@ -33,11 +56,12 @@ async function loadConfig(app) {
|
|||||||
const defaults = JSON.parse(await fs.readFile(defPath, 'utf8'));
|
const defaults = JSON.parse(await fs.readFile(defPath, 'utf8'));
|
||||||
try {
|
try {
|
||||||
const user = JSON.parse(await fs.readFile(p, 'utf8'));
|
const user = JSON.parse(await fs.readFile(p, 'utf8'));
|
||||||
return { configPath: p, config: mergeConfig(defaults, user) };
|
return { configPath: p, config: applyBakedGitea(mergeConfig(defaults, user)) };
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e.code === 'ENOENT') {
|
if (e.code === 'ENOENT') {
|
||||||
await fs.writeFile(p, JSON.stringify(defaults, null, 2), 'utf8');
|
const initial = applyBakedGitea(mergeConfig(defaults, {}));
|
||||||
return { configPath: p, config: JSON.parse(JSON.stringify(defaults)) };
|
await fs.writeFile(p, JSON.stringify(initial, null, 2), 'utf8');
|
||||||
|
return { configPath: p, config: JSON.parse(JSON.stringify(initial)) };
|
||||||
}
|
}
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
@@ -48,7 +72,7 @@ async function saveGameDir(configPath, gameDir) {
|
|||||||
const defaults = JSON.parse(await fs.readFile(defPath, 'utf8'));
|
const defaults = JSON.parse(await fs.readFile(defPath, 'utf8'));
|
||||||
const user = JSON.parse(await fs.readFile(configPath, 'utf8'));
|
const user = JSON.parse(await fs.readFile(configPath, 'utf8'));
|
||||||
user.game_dir = gameDir;
|
user.game_dir = gameDir;
|
||||||
const merged = mergeConfig(defaults, user);
|
const merged = applyBakedGitea(mergeConfig(defaults, user));
|
||||||
await fs.writeFile(configPath, JSON.stringify(merged, null, 2), 'utf8');
|
await fs.writeFile(configPath, JSON.stringify(merged, null, 2), 'utf8');
|
||||||
return merged;
|
return merged;
|
||||||
}
|
}
|
||||||
@@ -60,4 +84,4 @@ function resolveGameDir(cfg, configPath) {
|
|||||||
return path.normalize(path.join(path.dirname(configPath), gd));
|
return path.normalize(path.join(path.dirname(configPath), gd));
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { getConfigPath, loadConfig, saveGameDir, resolveGameDir, mergeConfig };
|
module.exports = { getConfigPath, loadConfig, saveGameDir, resolveGameDir, mergeConfig, applyBakedGitea };
|
||||||
|
|||||||
@@ -9,8 +9,8 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "electron .",
|
"start": "electron .",
|
||||||
"pack:win": "node scripts/inject-release-channel.js && electron-builder --win nsis portable --x64 --publish never",
|
"pack:win": "electron-builder --win nsis portable --x64 --publish never",
|
||||||
"publish:win": "node scripts/inject-release-channel.js && electron-builder --win nsis portable --x64 --publish never"
|
"publish:win": "electron-builder --win nsis portable --x64 --publish never"
|
||||||
},
|
},
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
@@ -35,6 +35,7 @@
|
|||||||
"renderer.js",
|
"renderer.js",
|
||||||
"styles.css",
|
"styles.css",
|
||||||
"default-launcher.json",
|
"default-launcher.json",
|
||||||
|
"lib/baked-gitea-channel.js",
|
||||||
"lib/gitea-release.js",
|
"lib/gitea-release.js",
|
||||||
"lib/patch-manifest.js",
|
"lib/patch-manifest.js",
|
||||||
"lib/**/*"
|
"lib/**/*"
|
||||||
|
|||||||
@@ -1,77 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Merge Gitea release channel (non-token) into default-launcher.json before pack.
|
|
||||||
* Precedence: env → fractured-release-channel.json → leave existing default-launcher values.
|
|
||||||
*
|
|
||||||
* Env (any of these names):
|
|
||||||
* FRACTURED_LAUNCHER_GITEA_BASE_URL | GITEA_BASE_URL
|
|
||||||
* FRACTURED_LAUNCHER_GITEA_OWNER | GITEA_OWNER
|
|
||||||
* FRACTURED_LAUNCHER_GITEA_REPO | GITEA_REPO
|
|
||||||
* FRACTURED_LAUNCHER_GITEA_RELEASE_TAG | GITEA_RELEASE_TAG
|
|
||||||
*/
|
|
||||||
const fs = require('fs');
|
|
||||||
const path = require('path');
|
|
||||||
|
|
||||||
const root = path.join(__dirname, '..');
|
|
||||||
const defPath = path.join(root, 'default-launcher.json');
|
|
||||||
const channelPath = path.join(root, 'fractured-release-channel.json');
|
|
||||||
|
|
||||||
function pickEnv() {
|
|
||||||
return {
|
|
||||||
base_url: String(
|
|
||||||
process.env.FRACTURED_LAUNCHER_GITEA_BASE_URL || process.env.GITEA_BASE_URL || ''
|
|
||||||
).trim(),
|
|
||||||
owner: String(
|
|
||||||
process.env.FRACTURED_LAUNCHER_GITEA_OWNER || process.env.GITEA_OWNER || ''
|
|
||||||
).trim(),
|
|
||||||
repo: String(
|
|
||||||
process.env.FRACTURED_LAUNCHER_GITEA_REPO || process.env.GITEA_REPO || ''
|
|
||||||
).trim(),
|
|
||||||
release_tag: String(
|
|
||||||
process.env.FRACTURED_LAUNCHER_GITEA_RELEASE_TAG || process.env.GITEA_RELEASE_TAG || ''
|
|
||||||
).trim(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function main() {
|
|
||||||
const cfg = JSON.parse(fs.readFileSync(defPath, 'utf8'));
|
|
||||||
cfg.gitea = cfg.gitea && typeof cfg.gitea === 'object' ? cfg.gitea : {};
|
|
||||||
|
|
||||||
let fileGitea = {};
|
|
||||||
try {
|
|
||||||
const raw = JSON.parse(fs.readFileSync(channelPath, 'utf8'));
|
|
||||||
if (raw && raw.gitea && typeof raw.gitea === 'object') fileGitea = raw.gitea;
|
|
||||||
} catch (e) {
|
|
||||||
if (e.code !== 'ENOENT') throw e;
|
|
||||||
}
|
|
||||||
|
|
||||||
const env = pickEnv();
|
|
||||||
const keys = ['base_url', 'owner', 'repo', 'release_tag'];
|
|
||||||
let changed = false;
|
|
||||||
|
|
||||||
for (const k of keys) {
|
|
||||||
const fromEnv = env[k];
|
|
||||||
const fromFile =
|
|
||||||
fileGitea[k] != null && String(fileGitea[k]).trim() !== '' ? String(fileGitea[k]).trim() : '';
|
|
||||||
const val = (fromEnv && String(fromEnv).trim()) || fromFile;
|
|
||||||
if (!val) continue;
|
|
||||||
if (cfg.gitea[k] !== val) {
|
|
||||||
cfg.gitea[k] = val;
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!changed) {
|
|
||||||
console.log(
|
|
||||||
'inject-release-channel: no overrides (set GITEA_* env and/or fill fractured-release-channel.json)'
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fs.writeFileSync(defPath, `${JSON.stringify(cfg, null, 2)}\n`, 'utf8');
|
|
||||||
console.log('inject-release-channel: wrote gitea.* into default-launcher.json for this build');
|
|
||||||
}
|
|
||||||
|
|
||||||
main();
|
|
||||||
Reference in New Issue
Block a user