diff --git a/.changeset/hot-ravens-beg.md b/.changeset/hot-ravens-beg.md new file mode 100644 index 00000000000..37e107d0fca --- /dev/null +++ b/.changeset/hot-ravens-beg.md @@ -0,0 +1,5 @@ +--- +"app-builder-lib": patch +--- + +NSIS: Fix non-utilized for Silent Flag in Uninstaller diff --git a/packages/app-builder-lib/templates/nsis/uninstaller.nsh b/packages/app-builder-lib/templates/nsis/uninstaller.nsh index 4db9a85f2a0..917b3da126b 100644 --- a/packages/app-builder-lib/templates/nsis/uninstaller.nsh +++ b/packages/app-builder-lib/templates/nsis/uninstaller.nsh @@ -8,6 +8,13 @@ Function un.onInit !insertmacro check64BitAndSetRegView + # Parse command line for /S flag and set silent mode + ${GetParameters} $R0 + ${GetOptions} $R0 "/S" $R1 + ${IfNot} ${Errors} + SetSilent silent + ${EndIf} + ${If} ${Silent} call un.checkAppRunning ${else} diff --git a/test/src/updater/blackboxUpdateTest.ts b/test/src/updater/blackboxUpdateTest.ts index 8e2bef4b277..2fae60b4234 100644 --- a/test/src/updater/blackboxUpdateTest.ts +++ b/test/src/updater/blackboxUpdateTest.ts @@ -93,65 +93,8 @@ async function runTest(target: string, arch: Arch = Arch.x64) { const newAppDir = outDirs[1] const dirPath = oldAppDir.dir - let appPath: string - // Setup tests by installing the previous version - if (target === "AppImage") { - appPath = path.join(dirPath, `TestApp.AppImage`) - } else if (target === "deb") { - DebUpdater.installWithCommandRunner( - "dpkg", - path.join(dirPath, `TestApp.deb`), - commandWithArgs => { - execSync(commandWithArgs.join(" "), { stdio: "inherit" }) - }, - console - ) - appPath = path.join("/opt", "TestApp", "TestApp") - } else if (target === "rpm") { - RpmUpdater.installWithCommandRunner( - "zypper", - path.join(dirPath, `TestApp.rpm`), - commandWithArgs => { - execSync(commandWithArgs.join(" "), { stdio: "inherit" }) - }, - console - ) - appPath = path.join("/opt", "TestApp", "TestApp") - } else if (target === "pacman") { - PacmanUpdater.installWithCommandRunner( - path.join(dirPath, `TestApp.pacman`), - commandWithArgs => { - execSync(commandWithArgs.join(" "), { stdio: "inherit" }) - }, - console - ) - // execSync(`sudo pacman -Syyu --noconfirm`, { stdio: "inherit" }) - // execSync(`sudo pacman -U --noconfirm "${path.join(dirPath, `TestApp.pacman`)}"`, { stdio: "inherit" }) - appPath = path.join("/opt", "TestApp", "TestApp") - } else if (process.platform === "win32") { - // access installed app's location - const localProgramsPath = path.join(process.env.LOCALAPPDATA || path.join(homedir(), "AppData", "Local"), "Programs", "TestApp") - // this is to clear dev environment when not running on an ephemeral GH runner. - // Reinstallation will otherwise fail due to "uninstall" message prompt, so we must uninstall first (hence the setTimeout delay) - const uninstaller = path.join(localProgramsPath, "Uninstall TestApp.exe") - if (existsSync(uninstaller)) { - console.log("Uninstalling", uninstaller) - execFileSync(uninstaller, [], { stdio: "inherit" }) - await new Promise(resolve => setTimeout(resolve, 5000)) - } - - const installerPath = path.join(dirPath, "TestApp Setup.exe") - console.log("Installing windows", installerPath) - // Don't use /S for silent install as we lose stdout pipe - execFileSync(installerPath, [], { stdio: "inherit" }) - - appPath = path.join(localProgramsPath, "TestApp.exe") - } else if (process.platform === "darwin") { - appPath = path.join(dirPath, `mac${getArchSuffix(arch)}`, `TestApp.app`, "Contents", "MacOS", "TestApp") - } else { - throw new Error(`Unsupported Update test target: ${target}`) - } + const appPath = await handleInitialInstallPerOS({ target, dirPath, arch }) if (!existsSync(appPath)) { throw new Error(`App not found: ${appPath}`) @@ -176,6 +119,7 @@ async function runTest(target: string, arch: Arch = Arch.x64) { }) // windows needs to release file locks, so a delay seems to be needed await new Promise(resolve => setTimeout(resolve, 1000)) + await handleCleanupPerOS({ target }) await tmpDir.cleanup() } @@ -300,6 +244,87 @@ async function doBuild( } } +async function handleInitialInstallPerOS({ target, dirPath, arch }: { target: string; dirPath: string; arch: Arch }): Promise { + let appPath: string + if (target === "AppImage") { + appPath = path.join(dirPath, `TestApp.AppImage`) + } else if (target === "deb") { + DebUpdater.installWithCommandRunner( + "dpkg", + path.join(dirPath, `TestApp.deb`), + commandWithArgs => { + execSync(commandWithArgs.join(" "), { stdio: "inherit" }) + }, + console + ) + appPath = path.join("/opt", "TestApp", "TestApp") + } else if (target === "rpm") { + RpmUpdater.installWithCommandRunner( + "zypper", + path.join(dirPath, `TestApp.rpm`), + commandWithArgs => { + execSync(commandWithArgs.join(" "), { stdio: "inherit" }) + }, + console + ) + appPath = path.join("/opt", "TestApp", "TestApp") + } else if (target === "pacman") { + PacmanUpdater.installWithCommandRunner( + path.join(dirPath, `TestApp.pacman`), + commandWithArgs => { + execSync(commandWithArgs.join(" "), { stdio: "inherit" }) + }, + console + ) + // execSync(`sudo pacman -Syyu --noconfirm`, { stdio: "inherit" }) + // execSync(`sudo pacman -U --noconfirm "${path.join(dirPath, `TestApp.pacman`)}"`, { stdio: "inherit" }) + appPath = path.join("/opt", "TestApp", "TestApp") + } else if (process.platform === "win32") { + // access installed app's location + const localProgramsPath = path.join(process.env.LOCALAPPDATA || path.join(homedir(), "AppData", "Local"), "Programs", "TestApp") + // this is to clear dev environment when not running on an ephemeral GH runner. + // Reinstallation will otherwise fail due to "uninstall" message prompt, so we must uninstall first (hence the setTimeout delay) + const uninstaller = path.join(localProgramsPath, "Uninstall TestApp.exe") + if (existsSync(uninstaller)) { + console.log("Uninstalling", uninstaller) + execFileSync(uninstaller, ["/S", "/C", "exit"], { stdio: "inherit" }) + await new Promise(resolve => setTimeout(resolve, 5000)) + } + + const installerPath = path.join(dirPath, "TestApp Setup.exe") + console.log("Installing windows", installerPath) + // Don't use /S for silent install as we lose stdout pipe + execFileSync(installerPath, ["/S"], { stdio: "inherit" }) + + appPath = path.join(localProgramsPath, "TestApp.exe") + } else if (process.platform === "darwin") { + appPath = path.join(dirPath, `mac${getArchSuffix(arch)}`, `TestApp.app`, "Contents", "MacOS", "TestApp") + } else { + throw new Error(`Unsupported Update test target: ${target}`) + } + return appPath +} + +async function handleCleanupPerOS({ target }: { target: string }) { + if (target === "deb") { + // TODO: ignore for now, this doesn't block CI, but proper uninstall logic should be implemented + // execSync("dpkg -r testapp", { stdio: "inherit" }); + } else if (target === "rpm") { + execSync(`zypper rm -y testapp`, { stdio: "inherit" }) + } else if (target === "pacman") { + execSync(`pacman -R --noconfirm testapp`, { stdio: "inherit" }) + } else if (process.platform === "win32") { + // access installed app's location + const localProgramsPath = path.join(process.env.LOCALAPPDATA || path.join(homedir(), "AppData", "Local"), "Programs", "TestApp") + const uninstaller = path.join(localProgramsPath, "Uninstall TestApp.exe") + console.log("Uninstalling", uninstaller) + execFileSync(uninstaller, ["/S", "/C", "exit"], { stdio: "inherit" }) + await new Promise(resolve => setTimeout(resolve, 5000)) + } else if (process.platform === "darwin") { + // ignore, nothing to uninstall, it's running/updating out of the local `dist` directory + } +} + async function runTestWithinServer(doTest: (rootDirectory: string, updateConfigPath: string) => Promise) { const tmpDir = new TmpDir("blackbox-update-test") const root = await tmpDir.getTempDir({ prefix: "server-root" })