Fix Windows installer and build versioning
This commit is contained in:
@@ -21,6 +21,7 @@ const { readLock } = require('../core/locks');
|
|||||||
const CaptureService = require('./capture');
|
const CaptureService = require('./capture');
|
||||||
const { TextIntelService } = require('./text-intel');
|
const { TextIntelService } = require('./text-intel');
|
||||||
const { keepProcessesResponsive } = require('./win-power');
|
const { keepProcessesResponsive } = require('./win-power');
|
||||||
|
const PACKAGE_JSON = require(path.join(__dirname, '..', 'package.json'));
|
||||||
|
|
||||||
const APP_ID = 'com.stepforge.app';
|
const APP_ID = 'com.stepforge.app';
|
||||||
|
|
||||||
@@ -762,6 +763,7 @@ function setupIpc() {
|
|||||||
h('shell:showItemInFolder', ({ target }) => shell.showItemInFolder(target));
|
h('shell:showItemInFolder', ({ target }) => shell.showItemInFolder(target));
|
||||||
h('app:info', () => ({
|
h('app:info', () => ({
|
||||||
version: app.getVersion(),
|
version: app.getVersion(),
|
||||||
|
buildVersion: PACKAGE_JSON.buildVersion || app.getVersion(),
|
||||||
dataDir: store.root,
|
dataDir: store.root,
|
||||||
platform: process.platform,
|
platform: process.platform,
|
||||||
}));
|
}));
|
||||||
|
|||||||
+1
-1
@@ -401,7 +401,7 @@ class StepForgeApp {
|
|||||||
el('div', { style: { fontWeight: 650 } }, folderLabel),
|
el('div', { style: { fontWeight: 650 } }, folderLabel),
|
||||||
q ? el('div.muted', {}, `Search: ${q}`) : el('div.muted', {}, `${this.state.library.guides.length} guides`),
|
q ? el('div.muted', {}, `Search: ${q}`) : el('div.muted', {}, `${this.state.library.guides.length} guides`),
|
||||||
),
|
),
|
||||||
el('div.muted', {}, this.state.info ? `StepForge ${this.state.info.version}` : ''),
|
el('div.muted', {}, this.state.info ? `StepForge ${this.state.info.buildVersion || this.state.info.version}` : ''),
|
||||||
),
|
),
|
||||||
this.domBulkBar = el('div', {}),
|
this.domBulkBar = el('div', {}),
|
||||||
this.domLibraryResults = el('div', {}),
|
this.domLibraryResults = el('div', {}),
|
||||||
|
|||||||
+1
-1
@@ -1,10 +1,10 @@
|
|||||||
!include LogicLib.nsh
|
!include LogicLib.nsh
|
||||||
!include nsDialogs.nsh
|
!include nsDialogs.nsh
|
||||||
|
|
||||||
|
!ifndef BUILD_UNINSTALLER
|
||||||
Var StepForgeDesktopShortcutCheckbox
|
Var StepForgeDesktopShortcutCheckbox
|
||||||
Var StepForgeDesktopShortcutState
|
Var StepForgeDesktopShortcutState
|
||||||
|
|
||||||
!ifndef BUILD_UNINSTALLER
|
|
||||||
; Assisted installer page for the desktop shortcut choice.
|
; Assisted installer page for the desktop shortcut choice.
|
||||||
!macro customInit
|
!macro customInit
|
||||||
StrCpy $StepForgeDesktopShortcutState "true"
|
StrCpy $StepForgeDesktopShortcutState "true"
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "stepforge",
|
"name": "stepforge",
|
||||||
"version": "0.3.2.1",
|
"version": "0.3.2",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "stepforge",
|
"name": "stepforge",
|
||||||
"version": "0.3.2.1",
|
"version": "0.3.2",
|
||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tesseract.js-data/eng": "^1.0.0",
|
"@tesseract.js-data/eng": "^1.0.0",
|
||||||
|
|||||||
+2
-1
@@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "stepforge",
|
"name": "stepforge",
|
||||||
"version": "0.3.2.1",
|
"version": "0.3.2",
|
||||||
|
"buildVersion": "0.3.2.1",
|
||||||
"description": "Fully offline desktop tool for capturing, annotating, and exporting step-by-step guides.",
|
"description": "Fully offline desktop tool for capturing, annotating, and exporting step-by-step guides.",
|
||||||
"main": "app/main.js",
|
"main": "app/main.js",
|
||||||
"author": "StepForge [email protected]",
|
"author": "StepForge [email protected]",
|
||||||
|
|||||||
@@ -20,5 +20,5 @@ fi
|
|||||||
|
|
||||||
node - <<'NODE'
|
node - <<'NODE'
|
||||||
const pkg = require('./package.json');
|
const pkg = require('./package.json');
|
||||||
console.log(`StepForge ${pkg.version} bootstrap OK`);
|
console.log(`StepForge ${pkg.buildVersion || pkg.version} bootstrap OK`);
|
||||||
NODE
|
NODE
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ for (const rel of walk(examplesRoot, examplesRoot)) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const pkg = require(path.join(rootDir, 'package.json'));
|
const pkg = require(path.join(rootDir, 'package.json'));
|
||||||
|
const buildVersion = pkg.buildVersion || pkg.version;
|
||||||
|
|
||||||
const { execSync } = require('node:child_process');
|
const { execSync } = require('node:child_process');
|
||||||
function toolAvailable(cmd) {
|
function toolAvailable(cmd) {
|
||||||
@@ -88,7 +89,8 @@ const toolRows = Object.entries(tools)
|
|||||||
|
|
||||||
const report = `# StepForge Build Report
|
const report = `# StepForge Build Report
|
||||||
|
|
||||||
Version: ${pkg.version}
|
Build version: ${buildVersion}
|
||||||
|
Package version: ${pkg.version}
|
||||||
Generated: ${new Date().toISOString()}
|
Generated: ${new Date().toISOString()}
|
||||||
Host: ${process.platform} ${process.arch} (node ${process.version})
|
Host: ${process.platform} ${process.arch} (node ${process.version})
|
||||||
|
|
||||||
@@ -133,6 +135,7 @@ fs.writeFileSync(manifestFile, JSON.stringify({
|
|||||||
version: 1,
|
version: 1,
|
||||||
generatedAt: new Date().toISOString(),
|
generatedAt: new Date().toISOString(),
|
||||||
packageVersion: pkg.version,
|
packageVersion: pkg.version,
|
||||||
|
buildVersion,
|
||||||
files,
|
files,
|
||||||
}, null, 2) + '\n');
|
}, null, 2) + '\n');
|
||||||
NODE
|
NODE
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
VERSION="$(node -p "require('${ROOT_DIR}/package.json').version" 2>/dev/null || echo 0.0.0)"
|
VERSION="$(node -p "const pkg=require('${ROOT_DIR}/package.json'); pkg.buildVersion || pkg.version" 2>/dev/null || echo 0.0.0)"
|
||||||
OUT_DIR="${STEPFORGE_PACKAGE_DIR:-$ROOT_DIR/build/artifacts}"
|
OUT_DIR="${STEPFORGE_PACKAGE_DIR:-$ROOT_DIR/build/artifacts}"
|
||||||
mkdir -p "$OUT_DIR"
|
mkdir -p "$OUT_DIR"
|
||||||
WORK_DIR="$(mktemp -d "${OUT_DIR%/}/.pkg.XXXXXX")"
|
WORK_DIR="$(mktemp -d "${OUT_DIR%/}/.pkg.XXXXXX")"
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ const { build, Platform } = require('electron-builder');
|
|||||||
const ROOT_DIR = path.resolve(__dirname, '..');
|
const ROOT_DIR = path.resolve(__dirname, '..');
|
||||||
const PACKAGE_JSON = require(path.join(ROOT_DIR, 'package.json'));
|
const PACKAGE_JSON = require(path.join(ROOT_DIR, 'package.json'));
|
||||||
const APP_ID = 'com.stepforge.app';
|
const APP_ID = 'com.stepforge.app';
|
||||||
|
const BUILD_VERSION = PACKAGE_JSON.buildVersion || PACKAGE_JSON.version;
|
||||||
|
|
||||||
function findInstallerExe(dir) {
|
function findInstallerExe(dir) {
|
||||||
if (!fs.existsSync(dir)) return null;
|
if (!fs.existsSync(dir)) return null;
|
||||||
@@ -32,6 +33,7 @@ function createWindowsInstallerConfig(outputDir) {
|
|||||||
return {
|
return {
|
||||||
appId: APP_ID,
|
appId: APP_ID,
|
||||||
productName: 'StepForge',
|
productName: 'StepForge',
|
||||||
|
buildVersion: BUILD_VERSION,
|
||||||
directories: {
|
directories: {
|
||||||
output: outputDir,
|
output: outputDir,
|
||||||
},
|
},
|
||||||
@@ -52,6 +54,7 @@ function createWindowsInstallerConfig(outputDir) {
|
|||||||
createDesktopShortcut: true,
|
createDesktopShortcut: true,
|
||||||
createStartMenuShortcut: true,
|
createStartMenuShortcut: true,
|
||||||
shortcutName: 'StepForge',
|
shortcutName: 'StepForge',
|
||||||
|
artifactName: '${productName} Setup ${buildVersion}.${ext}',
|
||||||
include: 'build/installer.nsh',
|
include: 'build/installer.nsh',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -87,7 +90,7 @@ async function buildWindowsInstaller() {
|
|||||||
const releaseInstaller = path.join(releaseDir, path.basename(builtInstaller));
|
const releaseInstaller = path.join(releaseDir, path.basename(builtInstaller));
|
||||||
fs.copyFileSync(builtInstaller, releaseInstaller);
|
fs.copyFileSync(builtInstaller, releaseInstaller);
|
||||||
|
|
||||||
console.log(`StepForge ${PACKAGE_JSON.version} Windows installer written to ${releaseInstaller}`);
|
console.log(`StepForge ${BUILD_VERSION} Windows installer written to ${releaseInstaller}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (require.main === module) {
|
if (require.main === module) {
|
||||||
|
|||||||
@@ -16,18 +16,25 @@ function stampVersion(rootDir, version) {
|
|||||||
throw new Error('version is required');
|
throw new Error('version is required');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const normalized = version.replace(/^v/i, '');
|
||||||
|
const parts = normalized.split('.');
|
||||||
|
const isFourPartBuild = parts.length === 4 && parts.every((part) => /^\d+$/.test(part));
|
||||||
|
const packageVersion = isFourPartBuild ? parts.slice(0, 3).join('.') : normalized;
|
||||||
|
const buildVersion = normalized;
|
||||||
|
|
||||||
const pkgPath = path.join(rootDir, 'package.json');
|
const pkgPath = path.join(rootDir, 'package.json');
|
||||||
const pkg = readJson(pkgPath);
|
const pkg = readJson(pkgPath);
|
||||||
pkg.version = version;
|
pkg.version = packageVersion;
|
||||||
|
pkg.buildVersion = buildVersion;
|
||||||
writeJson(pkgPath, pkg);
|
writeJson(pkgPath, pkg);
|
||||||
|
|
||||||
const lockPath = path.join(rootDir, 'package-lock.json');
|
const lockPath = path.join(rootDir, 'package-lock.json');
|
||||||
if (!fs.existsSync(lockPath)) return;
|
if (!fs.existsSync(lockPath)) return;
|
||||||
|
|
||||||
const lock = readJson(lockPath);
|
const lock = readJson(lockPath);
|
||||||
lock.version = version;
|
lock.version = packageVersion;
|
||||||
if (lock.packages && lock.packages['']) {
|
if (lock.packages && lock.packages['']) {
|
||||||
lock.packages[''].version = version;
|
lock.packages[''].version = packageVersion;
|
||||||
}
|
}
|
||||||
writeJson(lockPath, lock);
|
writeJson(lockPath, lock);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ test('Windows packaging uses an assisted NSIS installer', (t) => {
|
|||||||
assert.equal(config.nsis.createDesktopShortcut, true);
|
assert.equal(config.nsis.createDesktopShortcut, true);
|
||||||
assert.equal(config.nsis.createStartMenuShortcut, true);
|
assert.equal(config.nsis.createStartMenuShortcut, true);
|
||||||
assert.equal(config.nsis.shortcutName, 'StepForge');
|
assert.equal(config.nsis.shortcutName, 'StepForge');
|
||||||
|
assert.equal(config.buildVersion, '0.3.2.1');
|
||||||
|
assert.equal(config.nsis.artifactName, '${productName} Setup ${buildVersion}.${ext}');
|
||||||
assert.equal(config.nsis.include, 'build/installer.nsh');
|
assert.equal(config.nsis.include, 'build/installer.nsh');
|
||||||
assert.equal(config.asar, true);
|
assert.equal(config.asar, true);
|
||||||
assert.ok(config.files.includes('app/**/*'));
|
assert.ok(config.files.includes('app/**/*'));
|
||||||
@@ -35,7 +37,7 @@ test('Windows packaging uses an assisted NSIS installer', (t) => {
|
|||||||
const tmp = makeTmpDir('windows-installer');
|
const tmp = makeTmpDir('windows-installer');
|
||||||
t.after(() => rmrf(tmp));
|
t.after(() => rmrf(tmp));
|
||||||
fs.mkdirSync(path.join(tmp, 'nested', 'deeper'), { recursive: true });
|
fs.mkdirSync(path.join(tmp, 'nested', 'deeper'), { recursive: true });
|
||||||
const installer = path.join(tmp, 'nested', 'deeper', 'StepForge Setup 0.2.0.exe');
|
const installer = path.join(tmp, 'nested', 'deeper', 'StepForge Setup 0.3.2.1.exe');
|
||||||
fs.writeFileSync(installer, Buffer.from('fake installer'));
|
fs.writeFileSync(installer, Buffer.from('fake installer'));
|
||||||
assert.equal(findInstallerExe(tmp), installer);
|
assert.equal(findInstallerExe(tmp), installer);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -8,13 +8,14 @@ const assert = require('node:assert/strict');
|
|||||||
const { makeTmpDir, rmrf } = require('./helpers');
|
const { makeTmpDir, rmrf } = require('./helpers');
|
||||||
const { stampVersion } = require('../../scripts/stamp-version');
|
const { stampVersion } = require('../../scripts/stamp-version');
|
||||||
|
|
||||||
test('stampVersion updates package metadata without semver validation', () => {
|
test('stampVersion splits build labels into package and build versions', () => {
|
||||||
const root = makeTmpDir('stamp-version');
|
const root = makeTmpDir('stamp-version');
|
||||||
try {
|
try {
|
||||||
fs.writeFileSync(path.join(root, 'package.json'), JSON.stringify({
|
fs.writeFileSync(path.join(root, 'package.json'), JSON.stringify({
|
||||||
name: 'stepforge',
|
name: 'stepforge',
|
||||||
version: '0.1.0',
|
version: '0.1.0',
|
||||||
private: true,
|
private: true,
|
||||||
|
buildVersion: '0.1.0',
|
||||||
}, null, 2));
|
}, null, 2));
|
||||||
|
|
||||||
fs.writeFileSync(path.join(root, 'package-lock.json'), JSON.stringify({
|
fs.writeFileSync(path.join(root, 'package-lock.json'), JSON.stringify({
|
||||||
@@ -35,9 +36,10 @@ test('stampVersion updates package metadata without semver validation', () => {
|
|||||||
const pkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));
|
const pkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));
|
||||||
const lock = JSON.parse(fs.readFileSync(path.join(root, 'package-lock.json'), 'utf8'));
|
const lock = JSON.parse(fs.readFileSync(path.join(root, 'package-lock.json'), 'utf8'));
|
||||||
|
|
||||||
assert.equal(pkg.version, '0.3.2.1');
|
assert.equal(pkg.version, '0.3.2');
|
||||||
assert.equal(lock.version, '0.3.2.1');
|
assert.equal(pkg.buildVersion, '0.3.2.1');
|
||||||
assert.equal(lock.packages[''].version, '0.3.2.1');
|
assert.equal(lock.version, '0.3.2');
|
||||||
|
assert.equal(lock.packages[''].version, '0.3.2');
|
||||||
} finally {
|
} finally {
|
||||||
rmrf(root);
|
rmrf(root);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user