fix(updater): show header action only when update is available
Hide the header update action until a newer release is confirmed. Register update notifications before renderer initialization so startup cannot miss them. Refresh the public product screenshot and release metadata for v2.0.7.
This commit is contained in:
@@ -15,7 +15,7 @@ Multi-Hoster-Upload is a Windows desktop app for managing large file batches acr
|
|||||||
- Control per-hoster concurrency, bandwidth limits, retries, folder monitoring, notifications, and completed-item cleanup.
|
- Control per-hoster concurrency, bandwidth limits, retries, folder monitoring, notifications, and completed-item cleanup.
|
||||||
- Keep local upload history and copy completed links in bulk.
|
- Keep local upload history and copy completed links in bulk.
|
||||||
- Transfer accounts and settings with a 75-character encrypted online key while encryption and decryption stay on the client.
|
- Transfer accounts and settings with a 75-character encrypted online key while encryption and decryption stay on the client.
|
||||||
- Check for updates from the header and install available releases from an accessible update dialog.
|
- Check for updates from Settings or Help; when a newer release is available, install it from the header update action and accessible update dialog.
|
||||||
|
|
||||||
## Supported hosters
|
## Supported hosters
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 46 KiB |
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "multi-hoster-uploader",
|
"name": "multi-hoster-uploader",
|
||||||
"version": "2.0.6",
|
"version": "2.0.7",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "multi-hoster-uploader",
|
"name": "multi-hoster-uploader",
|
||||||
"version": "2.0.6",
|
"version": "2.0.7",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chokidar": "^3.6.0",
|
"chokidar": "^3.6.0",
|
||||||
"undici": "^7.29.0",
|
"undici": "^7.29.0",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "multi-hoster-uploader",
|
"name": "multi-hoster-uploader",
|
||||||
"version": "2.0.6",
|
"version": "2.0.7",
|
||||||
"description": "Upload files to doodstream, voe, vidmoly, byse simultaneously",
|
"description": "Upload files to doodstream, voe, vidmoly, byse simultaneously",
|
||||||
"main": "main.js",
|
"main": "main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
+3
-4
@@ -369,10 +369,6 @@ async function init() {
|
|||||||
if (versionLabel) versionLabel.textContent = `v${version}`;
|
if (versionLabel) versionLabel.textContent = `v${version}`;
|
||||||
} catch {}
|
} catch {}
|
||||||
|
|
||||||
// Update listeners
|
|
||||||
window.api.onUpdateAvailable(showUpdateBanner);
|
|
||||||
window.api.onUpdateProgress(handleUpdateProgress);
|
|
||||||
|
|
||||||
window.api.onUploadProgress((data) => {
|
window.api.onUploadProgress((data) => {
|
||||||
handleProgress(data);
|
handleProgress(data);
|
||||||
});
|
});
|
||||||
@@ -660,6 +656,7 @@ function _syncHeaderUpdateState() {
|
|||||||
? `Update v${version || 'unbekannt'} verfügbar. Klicken zum Installieren.`
|
? `Update v${version || 'unbekannt'} verfügbar. Klicken zum Installieren.`
|
||||||
: 'Nach Aktualisierungen suchen';
|
: 'Nach Aktualisierungen suchen';
|
||||||
if (button) {
|
if (button) {
|
||||||
|
button.hidden = !available;
|
||||||
button.classList.toggle('update-available', available);
|
button.classList.toggle('update-available', available);
|
||||||
button.classList.toggle('is-checking', _updateCheckBusy);
|
button.classList.toggle('is-checking', _updateCheckBusy);
|
||||||
button.disabled = _updateCheckBusy;
|
button.disabled = _updateCheckBusy;
|
||||||
@@ -6734,6 +6731,8 @@ function updateStatsPanel() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// --- Start ---
|
// --- Start ---
|
||||||
|
window.api.onUpdateAvailable(showUpdateBanner);
|
||||||
|
window.api.onUpdateProgress(handleUpdateProgress);
|
||||||
window.api.onPrepareClose(prepareForWindowClose);
|
window.api.onPrepareClose(prepareForWindowClose);
|
||||||
init().then(() => {
|
init().then(() => {
|
||||||
window.api.signalCloseHandshakeReady();
|
window.api.signalCloseHandshakeReady();
|
||||||
|
|||||||
+1
-1
@@ -53,7 +53,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="header-spacer" aria-hidden="true"></div>
|
<div class="header-spacer" aria-hidden="true"></div>
|
||||||
<div class="header-cluster header-utilities">
|
<div class="header-cluster header-utilities">
|
||||||
<button class="header-update-button" id="headerUpdateBtn" title="Nach Aktualisierungen suchen" aria-label="Nach Aktualisierungen suchen" data-tooltip="Nach Aktualisierungen suchen">
|
<button class="header-update-button" id="headerUpdateBtn" title="Nach Aktualisierungen suchen" aria-label="Nach Aktualisierungen suchen" data-tooltip="Nach Aktualisierungen suchen" hidden>
|
||||||
<svg class="header-action-icon" aria-hidden="true"><use href="#icon-download"></use></svg>
|
<svg class="header-action-icon" aria-hidden="true"><use href="#icon-download"></use></svg>
|
||||||
<span class="header-update-label">Update</span>
|
<span class="header-update-label">Update</span>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -1772,6 +1772,10 @@ select.hs-input { max-width: none; width: auto; min-width: 140px; }
|
|||||||
transition: background-color .14s, transform .14s;
|
transition: background-color .14s, transform .14s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.header-update-button[hidden] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.header-update-button::after {
|
.header-update-button::after {
|
||||||
content: attr(data-tooltip);
|
content: attr(data-tooltip);
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ function createStage() {
|
|||||||
return stage;
|
return stage;
|
||||||
}
|
}
|
||||||
|
|
||||||
function verify(stage, version = '2.0.6') {
|
function verify(stage, version = '2.0.7') {
|
||||||
return spawnSync(process.execPath, ['scripts/verify-public-release.mjs', '--source-only', '--version', version], {
|
return spawnSync(process.execPath, ['scripts/verify-public-release.mjs', '--source-only', '--version', version], {
|
||||||
cwd: stage,
|
cwd: stage,
|
||||||
encoding: 'utf8'
|
encoding: 'utf8'
|
||||||
|
|||||||
+46
-13
@@ -32,7 +32,13 @@ const ConfigStore = require(path.join(process.cwd(), 'lib', 'config-store'));
|
|||||||
const updaterModule = require(path.join(process.cwd(), 'lib', 'updater'));
|
const updaterModule = require(path.join(process.cwd(), 'lib', 'updater'));
|
||||||
let preparedUpdateMockCalls = 0;
|
let preparedUpdateMockCalls = 0;
|
||||||
let launchedUpdateMockCalls = 0;
|
let launchedUpdateMockCalls = 0;
|
||||||
updaterModule.checkForUpdate = async () => ({ available: false });
|
let updateCheckMockCalls = 0;
|
||||||
|
updaterModule.checkForUpdate = async () => {
|
||||||
|
updateCheckMockCalls++;
|
||||||
|
return updateCheckMockCalls === 1
|
||||||
|
? { available: true, remoteVersion: '9.9.8' }
|
||||||
|
: { available: false };
|
||||||
|
};
|
||||||
updaterModule.prepareUpdate = async (onProgress) => {
|
updaterModule.prepareUpdate = async (onProgress) => {
|
||||||
preparedUpdateMockCalls++;
|
preparedUpdateMockCalls++;
|
||||||
if (onProgress) onProgress({ stage: 'prepared', percent: 100 });
|
if (onProgress) onProgress({ stage: 'prepared', percent: 100 });
|
||||||
@@ -44,9 +50,20 @@ updaterModule.launchPreparedUpdate = () => {
|
|||||||
};
|
};
|
||||||
const initialIpcHandlers = new Map();
|
const initialIpcHandlers = new Map();
|
||||||
const registerIpcHandler = ipcMain.handle.bind(ipcMain);
|
const registerIpcHandler = ipcMain.handle.bind(ipcMain);
|
||||||
|
let initialConfigReadDelayed = false;
|
||||||
ipcMain.handle = (channel, listener) => {
|
ipcMain.handle = (channel, listener) => {
|
||||||
if (!initialIpcHandlers.has(channel)) initialIpcHandlers.set(channel, listener);
|
const registeredListener = channel === 'get-config'
|
||||||
return registerIpcHandler(channel, listener);
|
? async (...args) => {
|
||||||
|
const result = await listener(...args);
|
||||||
|
if (!initialConfigReadDelayed) {
|
||||||
|
initialConfigReadDelayed = true;
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 4000));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
: listener;
|
||||||
|
if (!initialIpcHandlers.has(channel)) initialIpcHandlers.set(channel, registeredListener);
|
||||||
|
return registerIpcHandler(channel, registeredListener);
|
||||||
};
|
};
|
||||||
function restoreInitialIpcHandler(channel) {
|
function restoreInitialIpcHandler(channel) {
|
||||||
ipcMain.removeHandler(channel);
|
ipcMain.removeHandler(channel);
|
||||||
@@ -132,6 +149,10 @@ setTimeout(async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const startupUpdateState = await wc.executeJavaScript('(() => { const button = document.getElementById("headerUpdateBtn"); return [_knownUpdateInfo?.remoteVersion, button?.hidden, getComputedStyle(button).display, document.getElementById("updateBanner")?.style.display].join("|"); })()');
|
||||||
|
check('Startup update survives pending renderer initialization', startupUpdateState === '9.9.8|false|flex|flex');
|
||||||
|
await wc.executeJavaScript('_knownUpdateInfo = null; closeUpdateDialog(); _syncHeaderUpdateState();');
|
||||||
|
|
||||||
await wc.executeJavaScript('queueJobs = []; selectedFiles = []; selectedJobIds.clear(); rebuildJobIndex(); setUploadSidebarFilter("all"); updateUploadView(); renderQueueTable(); updateStatusBar();');
|
await wc.executeJavaScript('queueJobs = []; selectedFiles = []; selectedJobIds.clear(); rebuildJobIndex(); setUploadSidebarFilter("all"); updateUploadView(); renderQueueTable(); updateStatusBar();');
|
||||||
console.log('\\n=== Upload View ===');
|
console.log('\\n=== Upload View ===');
|
||||||
|
|
||||||
@@ -150,6 +171,9 @@ setTimeout(async () => {
|
|||||||
const headerUpdateButtonExists = await wc.executeJavaScript('Boolean(document.getElementById("headerUpdateBtn"))');
|
const headerUpdateButtonExists = await wc.executeJavaScript('Boolean(document.getElementById("headerUpdateBtn"))');
|
||||||
check('App header exposes the update action', headerUpdateButtonExists);
|
check('App header exposes the update action', headerUpdateButtonExists);
|
||||||
|
|
||||||
|
const initialHeaderUpdateVisibility = await wc.executeJavaScript('(() => { const button = document.getElementById("headerUpdateBtn"); return [button?.hidden, getComputedStyle(button).display].join("|"); })()');
|
||||||
|
check('Header update action stays hidden until an update is available', initialHeaderUpdateVisibility === 'true|none');
|
||||||
|
|
||||||
const initialUpdateLabel = await wc.executeJavaScript('document.querySelector("#headerUpdateBtn .header-update-label")?.textContent?.trim()');
|
const initialUpdateLabel = await wc.executeJavaScript('document.querySelector("#headerUpdateBtn .header-update-label")?.textContent?.trim()');
|
||||||
check('App header uses the compact update label', initialUpdateLabel === 'Update');
|
check('App header uses the compact update label', initialUpdateLabel === 'Update');
|
||||||
|
|
||||||
@@ -492,14 +516,21 @@ setTimeout(async () => {
|
|||||||
document.getElementById('headerUpdateBtn').click();
|
document.getElementById('headerUpdateBtn').click();
|
||||||
})()\`);
|
})()\`);
|
||||||
await new Promise(resolve => setTimeout(resolve, 100));
|
await new Promise(resolve => setTimeout(resolve, 100));
|
||||||
const coordinatedUpdateBusy = await wc.executeJavaScript('(() => { const manual = document.getElementById("manualUpdateCheckBtn"); const header = document.getElementById("headerUpdateBtn"); return [manual?.disabled, manual?.getAttribute("aria-busy"), manual?.textContent?.trim(), header?.disabled, header?.getAttribute("aria-busy")].join("|"); })()');
|
const coordinatedUpdateBusy = await wc.executeJavaScript('(() => { const manual = document.getElementById("manualUpdateCheckBtn"); const header = document.getElementById("headerUpdateBtn"); return [manual?.disabled, manual?.getAttribute("aria-busy"), manual?.textContent?.trim(), header?.disabled, header?.getAttribute("aria-busy"), header?.hidden].join("|"); })()');
|
||||||
check('All update entry points share one in-flight check', updateCheckCallCount === 1 && coordinatedUpdateBusy === 'true|true|Prüfe…|true|true');
|
check('All update entry points share one in-flight check', updateCheckCallCount === 1 && coordinatedUpdateBusy === 'true|true|Prüfe…|true|true|true');
|
||||||
updateCheckResolvers.splice(0).forEach(resolve => resolve({ available: false, error: 'Simulierter Netzwerkfehler' }));
|
updateCheckResolvers.splice(0).forEach(resolve => resolve({ available: false, error: 'Simulierter Netzwerkfehler' }));
|
||||||
await new Promise(resolve => setTimeout(resolve, 150));
|
await new Promise(resolve => setTimeout(resolve, 150));
|
||||||
const coordinatedUpdateError = await wc.executeJavaScript('(() => { const manual = document.getElementById("manualUpdateCheckBtn"); const header = document.getElementById("headerUpdateBtn"); return [manual?.disabled, header?.disabled, manual?.textContent?.trim(), document.getElementById("copyToast")?.textContent?.trim()].join("|"); })()');
|
const coordinatedUpdateError = await wc.executeJavaScript('(() => { const manual = document.getElementById("manualUpdateCheckBtn"); const header = document.getElementById("headerUpdateBtn"); return [manual?.disabled, header?.disabled, header?.hidden, manual?.textContent?.trim(), document.getElementById("copyToast")?.textContent?.trim()].join("|"); })()');
|
||||||
check('Settings update check uses the shared error contract', coordinatedUpdateError === 'false|false|Nach Updates suchen|Updateprüfung fehlgeschlagen');
|
check('Settings update check uses the shared error contract', coordinatedUpdateError === 'false|false|true|Nach Updates suchen|Updateprüfung fehlgeschlagen');
|
||||||
await wc.executeJavaScript('document.getElementById("copyToast")?.classList.remove("show")');
|
await wc.executeJavaScript('document.getElementById("copyToast")?.classList.remove("show")');
|
||||||
|
|
||||||
|
await wc.executeJavaScript('requestUpdateCheck(); true');
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 100));
|
||||||
|
updateCheckResolvers.splice(0).forEach(resolve => resolve({ available: false }));
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 150));
|
||||||
|
const noUpdateHeaderVisibility = await wc.executeJavaScript('(() => { const button = document.getElementById("headerUpdateBtn"); return [button?.hidden, getComputedStyle(button).display].join("|"); })()');
|
||||||
|
check('Successful no-update result keeps the header action hidden', noUpdateHeaderVisibility === 'true|none');
|
||||||
|
|
||||||
const settingsNavigation = await wc.executeJavaScript('(() => { const buttons = [...document.querySelectorAll(".settings-nav-button")]; return [buttons.length, buttons.map(button => button.textContent.trim()).join("|"), document.querySelector(".settings-nav-button.active")?.dataset.settingsPage, document.getElementById("settingsSearchInput")?.placeholder].join("::"); })()');
|
const settingsNavigation = await wc.executeJavaScript('(() => { const buttons = [...document.querySelectorAll(".settings-nav-button")]; return [buttons.length, buttons.map(button => button.textContent.trim()).join("|"), document.querySelector(".settings-nav-button.active")?.dataset.settingsPage, document.getElementById("settingsSearchInput")?.placeholder].join("::"); })()');
|
||||||
check('Settings use the task-based sidebar navigation', settingsNavigation === '8::Allgemein|Uploads|Automatik|Benachrichtigungen|Logs & Support|Fernsteuerung|Diagnose-Zugriff|Backup & Übertragen::allgemein::Einstellungen durchsuchen');
|
check('Settings use the task-based sidebar navigation', settingsNavigation === '8::Allgemein|Uploads|Automatik|Benachrichtigungen|Logs & Support|Fernsteuerung|Diagnose-Zugriff|Backup & Übertragen::allgemein::Einstellungen durchsuchen');
|
||||||
|
|
||||||
@@ -1043,8 +1074,8 @@ setTimeout(async () => {
|
|||||||
check('Responsive queue keeps the fixed virtual row height', queueProgressVisibility.standard.rowHeight === 28 && queueProgressVisibility.minimum.rowHeight === 28);
|
check('Responsive queue keeps the fixed virtual row height', queueProgressVisibility.standard.rowHeight === 28 && queueProgressVisibility.minimum.rowHeight === 28);
|
||||||
check('Minimum window keeps the settings header compact', compactSettingsHeader <= 58);
|
check('Minimum window keeps the settings header compact', compactSettingsHeader <= 58);
|
||||||
|
|
||||||
const updateOverlayState = await wc.executeJavaScript('document.getElementById("headerUpdateBtn").focus(); showUpdateBanner({ remoteVersion: "9.9.9" }); (() => { const overlay = document.getElementById("updateBanner"); const dialog = overlay?.querySelector(".update-dialog"); return [overlay?.classList.contains("update-overlay"), overlay?.style.display, dialog?.getAttribute("role"), dialog?.getAttribute("aria-modal")].join("|"); })()');
|
const updateOverlayState = await wc.executeJavaScript('_knownUpdateInfo = { available: true, remoteVersion: "9.9.9" }; _syncHeaderUpdateState(); document.getElementById("headerUpdateBtn").focus(); showUpdateBanner({ remoteVersion: "9.9.9" }); (() => { const overlay = document.getElementById("updateBanner"); const dialog = overlay?.querySelector(".update-dialog"); const button = document.getElementById("headerUpdateBtn"); return [overlay?.classList.contains("update-overlay"), overlay?.style.display, dialog?.getAttribute("role"), dialog?.getAttribute("aria-modal"), button?.hidden, getComputedStyle(button).display].join("|"); })()');
|
||||||
check('Available update opens an accessible update dialog', updateOverlayState === 'true|flex|dialog|true');
|
check('Available update opens an accessible update dialog', updateOverlayState === 'true|flex|dialog|true|false|flex');
|
||||||
|
|
||||||
await new Promise(resolve => setTimeout(resolve, 100));
|
await new Promise(resolve => setTimeout(resolve, 100));
|
||||||
const updateModalKeyboard = await wc.executeJavaScript(\`(() => {
|
const updateModalKeyboard = await wc.executeJavaScript(\`(() => {
|
||||||
@@ -1086,20 +1117,22 @@ setTimeout(async () => {
|
|||||||
overlay.dispatchEvent(new MouseEvent('click', { bubbles: true }));
|
overlay.dispatchEvent(new MouseEvent('click', { bubbles: true }));
|
||||||
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true, cancelable: true }));
|
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true, cancelable: true }));
|
||||||
const progress = document.getElementById('updateProgressBar');
|
const progress = document.getElementById('updateProgressBar');
|
||||||
|
const header = document.getElementById('headerUpdateBtn');
|
||||||
return {
|
return {
|
||||||
display: overlay.style.display,
|
display: overlay.style.display,
|
||||||
hidden: overlay.getAttribute('aria-hidden'),
|
hidden: overlay.getAttribute('aria-hidden'),
|
||||||
closeDisabled: document.getElementById('updateCloseBtn').disabled,
|
closeDisabled: document.getElementById('updateCloseBtn').disabled,
|
||||||
dismissDisabled: document.getElementById('dismissUpdateBtn').disabled,
|
dismissDisabled: document.getElementById('dismissUpdateBtn').disabled,
|
||||||
|
headerHidden: header.hidden,
|
||||||
progressLabel: progress.getAttribute('aria-label'),
|
progressLabel: progress.getAttribute('aria-label'),
|
||||||
progressText: progress.getAttribute('aria-valuetext')
|
progressText: progress.getAttribute('aria-valuetext')
|
||||||
};
|
};
|
||||||
})()\`);
|
})()\`);
|
||||||
check('Busy update keeps its progress dialog open', busyUpdateState.display === 'flex' && busyUpdateState.hidden === 'false' && busyUpdateState.closeDisabled === true && busyUpdateState.dismissDisabled === true);
|
check('Busy update keeps its progress dialog open', busyUpdateState.display === 'flex' && busyUpdateState.hidden === 'false' && busyUpdateState.closeDisabled === true && busyUpdateState.dismissDisabled === true && busyUpdateState.headerHidden === false);
|
||||||
check('Update progress exposes an accessible live value', busyUpdateState.progressLabel === 'Update-Fortschritt' && busyUpdateState.progressText === 'Download 50%');
|
check('Update progress exposes an accessible live value', busyUpdateState.progressLabel === 'Update-Fortschritt' && busyUpdateState.progressText === 'Download 50%');
|
||||||
|
|
||||||
const updateErrorRecovery = await wc.executeJavaScript('handleUpdateProgress({ stage: "error", error: "Netzwerkfehler" }); document.getElementById("dismissUpdateBtn").click(); document.getElementById("updateBanner").style.display + "|" + document.getElementById("updateCloseBtn").disabled + "|" + document.getElementById("dismissUpdateBtn").disabled');
|
const updateErrorRecovery = await wc.executeJavaScript('handleUpdateProgress({ stage: "error", error: "Netzwerkfehler" }); document.getElementById("dismissUpdateBtn").click(); document.getElementById("updateBanner").style.display + "|" + document.getElementById("updateCloseBtn").disabled + "|" + document.getElementById("dismissUpdateBtn").disabled + "|" + document.getElementById("headerUpdateBtn").hidden');
|
||||||
check('Update errors restore all close actions', updateErrorRecovery === 'none|false|false');
|
check('Update errors restore all close actions', updateErrorRecovery === 'none|false|false|false');
|
||||||
|
|
||||||
const initialInstallUpdateHandler = initialIpcHandlers.get('app:install-update');
|
const initialInstallUpdateHandler = initialIpcHandlers.get('app:install-update');
|
||||||
const initialUpdateQueueHandler = initialIpcHandlers.get('save-pending-queue');
|
const initialUpdateQueueHandler = initialIpcHandlers.get('save-pending-queue');
|
||||||
@@ -1267,7 +1300,7 @@ try {
|
|||||||
const result = execFileSync(
|
const result = execFileSync(
|
||||||
electronPath,
|
electronPath,
|
||||||
[`--user-data-dir=${userDataPath}`, '--require', injectPath, mainPath],
|
[`--user-data-dir=${userDataPath}`, '--require', injectPath, mainPath],
|
||||||
{ cwd: path.join(__dirname, '..'), timeout: 45000, encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }
|
{ cwd: path.join(__dirname, '..'), timeout: 60000, encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }
|
||||||
);
|
);
|
||||||
console.log(result);
|
console.log(result);
|
||||||
const isolatedConfigPath = path.join(userDataPath, 'electron-config.json');
|
const isolatedConfigPath = path.join(userDataPath, 'electron-config.json');
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ test('a prepared installer launches at most once', () => {
|
|||||||
|
|
||||||
test('release plan keeps product artifacts separate from the transport tag', async () => {
|
test('release plan keeps product artifacts separate from the transport tag', async () => {
|
||||||
const { createReleasePlan, parseReleaseArgs, renderLatestYml } = await import(releasePlanUrl);
|
const { createReleasePlan, parseReleaseArgs, renderLatestYml } = await import(releasePlanUrl);
|
||||||
const plan = createReleasePlan(parseReleaseArgs(['2.0.6', '--transport-tag', 'v3.3.114', 'Interface', 'redesign']));
|
const plan = createReleasePlan(parseReleaseArgs(['2.0.7', '--transport-tag', 'v3.3.115', 'Update', 'visibility']));
|
||||||
const latestYml = renderLatestYml(plan, 'abc123', 456, '2026-08-07T12:00:00.000Z');
|
const latestYml = renderLatestYml(plan, 'abc123', 456, '2026-08-07T12:00:00.000Z');
|
||||||
assert.deepEqual({
|
assert.deepEqual({
|
||||||
version: plan.version,
|
version: plan.version,
|
||||||
@@ -93,17 +93,17 @@ test('release plan keeps product artifacts separate from the transport tag', asy
|
|||||||
expectedArtifacts: plan.expectedArtifacts,
|
expectedArtifacts: plan.expectedArtifacts,
|
||||||
latestYml
|
latestYml
|
||||||
}, {
|
}, {
|
||||||
version: '2.0.6',
|
version: '2.0.7',
|
||||||
transportTag: 'v3.3.114',
|
transportTag: 'v3.3.115',
|
||||||
releaseTitle: 'Multi-Hoster-Upload v2.0.6',
|
releaseTitle: 'Multi-Hoster-Upload v2.0.7',
|
||||||
releaseBody: 'Interface redesign',
|
releaseBody: 'Update visibility',
|
||||||
expectedArtifacts: [
|
expectedArtifacts: [
|
||||||
'Multi-Hoster-Upload Setup 2.0.6.exe',
|
'Multi-Hoster-Upload Setup 2.0.7.exe',
|
||||||
'Multi-Hoster-Upload 2.0.6.exe',
|
'Multi-Hoster-Upload 2.0.7.exe',
|
||||||
'Multi-Hoster-Upload Setup 2.0.6.exe.blockmap',
|
'Multi-Hoster-Upload Setup 2.0.7.exe.blockmap',
|
||||||
'latest.yml'
|
'latest.yml'
|
||||||
],
|
],
|
||||||
latestYml: "version: 2.0.6\nfiles:\n - url: Multi-Hoster-Upload Setup 2.0.6.exe\n sha512: abc123\n size: 456\npath: Multi-Hoster-Upload Setup 2.0.6.exe\nsha512: abc123\nreleaseDate: '2026-08-07T12:00:00.000Z'\n"
|
latestYml: "version: 2.0.7\nfiles:\n - url: Multi-Hoster-Upload Setup 2.0.7.exe\n sha512: abc123\n size: 456\npath: Multi-Hoster-Upload Setup 2.0.7.exe\nsha512: abc123\nreleaseDate: '2026-08-07T12:00:00.000Z'\n"
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user