diff --git a/nsis-auto-updater/package.json b/nsis-auto-updater/package.json index 9c79cbf2fc5..77449112177 100644 --- a/nsis-auto-updater/package.json +++ b/nsis-auto-updater/package.json @@ -19,7 +19,6 @@ "bluebird" ], "devDependencies": { - "@types/electron": "^0.37.14", - "@types/node": "^4.0.30" + "@types/electron": "^0.37.14" } } diff --git a/nsis-auto-updater/src/nsis-updater.ts b/nsis-auto-updater/src/nsis-updater.ts index 50eac0db2b4..6cf1275aa25 100644 --- a/nsis-auto-updater/src/nsis-updater.ts +++ b/nsis-auto-updater/src/nsis-updater.ts @@ -1,8 +1,55 @@ import { EventEmitter } from "events" -import { app } from "electron" import { spawn } from "child_process" import * as path from "path" import { tmpdir } from "os" +import { Promise as BluebirdPromise } from "bluebird" +import { BintrayClient } from "../../src/publish/bintray" +import { HttpError } from "../../src/publish/restApiRequest" + +//noinspection JSUnusedLocalSymbols +const __awaiter = require("../../src/util/awaiter") + +interface VersionInfo { + version: string +} + +interface Provider { + checkForUpdates(): Promise +} + +//noinspection ReservedWordAsName +interface BintraySourceMetadata { + // e.g. develar + readonly user: string + // e.g. onshape-desktop-shell + readonly package: string + + // e.g. generic or bin, defaults to generic + readonly repository?: string | null +} + +class BintrayProvider { + private client: BintrayClient + + constructor(configuration: BintraySourceMetadata) { + this.client = new BintrayClient(configuration.user, configuration.package, configuration.repository || "generic") + } + + async checkForUpdates(): Promise { + try { + const data = await this.client.getVersion("_latest") + return { + version: data.name, + } + } + catch (e) { + if (e instanceof HttpError && e.response.statusCode === 404) { + throw new Error(`No latest version, please ensure that user, repository and package correctly configured. Or at least one version is published.${e.stack || e.message}`) + } + throw e + } + } +} class NsisUpdater extends EventEmitter { private setupPath = path.join(tmpdir(), 'innobox-upgrade.exe') @@ -10,6 +57,8 @@ class NsisUpdater extends EventEmitter { private updateAvailable = false private quitAndInstallCalled = false + private client: Provider + constructor(public updateUrl?: string) { super() } @@ -18,17 +67,21 @@ class NsisUpdater extends EventEmitter { return this.updateUrl } - setFeedURL(value: string) { - this.updateUrl = value + setFeedURL(value: string | BintraySourceMetadata) { + this.updateUrl = value.toString() + + this.client = new BintrayProvider(value) } - checkForUpdates(): void { + checkForUpdates(): Promise { if (this.updateUrl == null) { - this.emitError("Update URL is not set") - return + const message = "Update URL is not set" + this.emitError(message) + return BluebirdPromise.reject(new Error(message)) } this.emit("checking-for-update") + return this.client.checkForUpdates() } quitAndInstall(): void { @@ -49,7 +102,7 @@ class NsisUpdater extends EventEmitter { stdio: "ignore", }).unref() - app.quit() + require("electron").app.quit() } // emit both error object and message, this is to keep compatibility with old APIs diff --git a/nsis-auto-updater/tsconfig.json b/nsis-auto-updater/tsconfig.json index a69352c204b..b3921089ca2 100755 --- a/nsis-auto-updater/tsconfig.json +++ b/nsis-auto-updater/tsconfig.json @@ -18,7 +18,10 @@ "files": [ "../node_modules/fs-extra-p/index.d.ts", "../node_modules/fs-extra-p/bluebird.d.ts", - "../src/util/httpRequest.ts" + "../src/util/httpRequest.ts", + "../src/publish/restApiRequest.ts", + "../src/publish/bintray.ts", + "../src/util/awaiter.ts" ], "include": [ "src/**/*.ts", diff --git a/package.json b/package.json index 1e4f29797fd..3a468e3e046 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,9 @@ "install-app-deps": "./out/install-app-deps.js" }, "scripts": { - "compile": "npm run compile-production && npm run compile-test", + "postinstall": "cd nsis-auto-updater && npm install", + "postprune": "cd nsis-auto-updater && npm prune", + "compile": "npm run compile-production && npm run compile-test && npm run compile-updater", "compile-production": "ts-babel", "compile-test": "ts-babel test", "compile-updater": "tsc -p nsis-auto-updater", diff --git a/src/publish/BintrayPublisher.ts b/src/publish/BintrayPublisher.ts index b4fbbd5b2b7..80512cbb118 100644 --- a/src/publish/BintrayPublisher.ts +++ b/src/publish/BintrayPublisher.ts @@ -1,41 +1,35 @@ import { Publisher, PublishOptions } from "./publisher" import { Promise as BluebirdPromise } from "bluebird" -import { bintrayRequest, HttpError, doApiRequest, uploadFile } from "./gitHubRequest" +import { HttpError, doApiRequest } from "./restApiRequest" +import { uploadFile } from "./uploader" import { log } from "../util/log" import { debug } from "../util/util" import { basename } from "path" import { stat } from "fs-extra-p" +import { BintrayClient, Version } from "./bintray" //noinspection JSUnusedLocalSymbols const __awaiter = require("../util/awaiter") -//noinspection ReservedWordAsName -interface Version { - readonly name: string - readonly package: string -} - export class BintrayPublisher implements Publisher { private _versionPromise: BluebirdPromise - private readonly auth: string - private basePath: string + private readonly client: BintrayClient constructor(private user: string, apiKey: string, private version: string, private packageName: string, private repo: string = "generic", private options: PublishOptions = {}) { - this.auth = `Basic ${new Buffer(`${user}:${apiKey}`).toString("base64")}` - this.basePath = `/packages/${this.user}/${this.repo}/${this.packageName}` + this.client = new BintrayClient(user, packageName, repo, apiKey) this._versionPromise = >this.init() } private async init(): Promise { try { - return await bintrayRequest(`${this.basePath}/versions/${this.version}`, this.auth) + return await this.client.getVersion(this.version) } catch (e) { if (e instanceof HttpError && e.response.statusCode === 404) { if (this.options.publish !== "onTagOrDraft") { log(`Version ${this.version} doesn't exist, creating one`) - return this.createVersion() + return this.client.createVersion(this.version) } else { log(`Version ${this.version} doesn't exist, artifacts will be not published`) @@ -46,12 +40,6 @@ export class BintrayPublisher implements Publisher { } } - private createVersion() { - return bintrayRequest(`${this.basePath}/versions`, this.auth, { - name: this.version, - }) - } - async upload(file: string, artifactName?: string): Promise { const fileName = artifactName || basename(file) const version = await this._versionPromise @@ -74,7 +62,7 @@ export class BintrayPublisher implements Publisher { "X-Bintray-Override": "1", "X-Bintray-Publish": "1", } - }, this.auth, uploadFile.bind(this, file, fileStat, fileName)) + }, this.client.auth, uploadFile.bind(this, file, fileStat, fileName)) } catch (e) { if (e instanceof HttpError && e.response.statusCode === 502 && badGatewayCount++ < 3) { @@ -93,10 +81,6 @@ export class BintrayPublisher implements Publisher { } const version = this._versionPromise.value() - if (version == null) { - return BluebirdPromise.resolve() - } - - return bintrayRequest(`/packages/${this.user}/${this.repo}/${this.packageName}/versions/${version.name}`, this.auth, null, "DELETE") + return version == null ? BluebirdPromise.resolve() : this.client.deleteVersion(version.name) } } \ No newline at end of file diff --git a/src/publish/bintray.ts b/src/publish/bintray.ts new file mode 100644 index 00000000000..8517d44af17 --- /dev/null +++ b/src/publish/bintray.ts @@ -0,0 +1,31 @@ +import { bintrayRequest } from "./restApiRequest" + +//noinspection ReservedWordAsName +export interface Version { + readonly name: string + readonly package: string +} + +export class BintrayClient { + private readonly basePath: string + readonly auth: string | null + + constructor(private user: string, private packageName: string, private repo: string = "generic", apiKey?: string | null) { + this.auth = apiKey == null ? null : `Basic ${new Buffer(`${user}:${apiKey}`).toString("base64")}` + this.basePath = `/packages/${this.user}/${this.repo}/${this.packageName}` + } + + getVersion(version: string): Promise { + return bintrayRequest(`${this.basePath}/versions/${version}`, this.auth) + } + + createVersion(version: string): Promise { + return bintrayRequest(`${this.basePath}/versions`, this.auth, { + name: version, + }) + } + + deleteVersion(version: string): Promise { + return bintrayRequest(`/packages/${this.user}/${this.repo}/${this.packageName}/versions/${version}`, this.auth, null, "DELETE") + } +} \ No newline at end of file diff --git a/src/publish/gitHubPublisher.ts b/src/publish/gitHubPublisher.ts index 630bc97f0dc..e8f76b07166 100644 --- a/src/publish/gitHubPublisher.ts +++ b/src/publish/gitHubPublisher.ts @@ -5,9 +5,10 @@ import { basename } from "path" import { parse as parseUrl } from "url" import * as mime from "mime" import { stat } from "fs-extra-p" -import { gitHubRequest, HttpError, doApiRequest, uploadFile } from "./gitHubRequest" +import { githubRequest, HttpError, doApiRequest } from "./restApiRequest" import { Promise as BluebirdPromise } from "bluebird" import { PublishPolicy, PublishOptions, Publisher } from "./publisher" +import { uploadFile } from "./uploader" //noinspection JSUnusedLocalSymbols const __awaiter = require("../util/awaiter") @@ -56,7 +57,7 @@ export class GitHubPublisher implements Publisher { private async init(): Promise { const createReleaseIfNotExists = this.policy !== "onTagOrDraft" // we don't use "Get a release by tag name" because "tag name" means existing git tag, but we draft release and don't create git tag - const releases = await gitHubRequest>(`/repos/${this.owner}/${this.repo}/releases`, this.token) + const releases = await githubRequest>(`/repos/${this.owner}/${this.repo}/releases`, this.token) for (let release of releases) { if (release.tag_name === this.tag) { if (release.draft) { @@ -121,10 +122,10 @@ export class GitHubPublisher implements Publisher { if (e.response.statusCode === 422 && e.description != null && e.description.errors != null && e.description.errors[0].code === "already_exists") { // delete old artifact and re-upload log(`Artifact ${fileName} already exists, overwrite one`) - const assets = await gitHubRequest>(`/repos/${this.owner}/${this.repo}/releases/${release.id}/assets`, this.token) + const assets = await githubRequest>(`/repos/${this.owner}/${this.repo}/releases/${release.id}/assets`, this.token) for (let asset of assets) { if (asset!.name === fileName) { - await gitHubRequest(`/repos/${this.owner}/${this.repo}/releases/assets/${asset!.id}`, this.token, null, "DELETE") + await githubRequest(`/repos/${this.owner}/${this.repo}/releases/assets/${asset!.id}`, this.token, null, "DELETE") continue uploadAttempt } } @@ -143,7 +144,7 @@ export class GitHubPublisher implements Publisher { } private createRelease() { - return gitHubRequest(`/repos/${this.owner}/${this.repo}/releases`, this.token, { + return githubRequest(`/repos/${this.owner}/${this.repo}/releases`, this.token, { tag_name: this.tag, name: this.version, draft: this.options.draft == null || this.options.draft, @@ -154,7 +155,7 @@ export class GitHubPublisher implements Publisher { // test only //noinspection JSUnusedGlobalSymbols async getRelease(): Promise { - return gitHubRequest(`/repos/${this.owner}/${this.repo}/releases/${this._releasePromise.value().id}`, this.token) + return githubRequest(`/repos/${this.owner}/${this.repo}/releases/${this._releasePromise.value().id}`, this.token) } //noinspection JSUnusedGlobalSymbols @@ -170,7 +171,7 @@ export class GitHubPublisher implements Publisher { for (let i = 0; i < 3; i++) { try { - return await gitHubRequest(`/repos/${this.owner}/${this.repo}/releases/${release.id}`, this.token, null, "DELETE") + return await githubRequest(`/repos/${this.owner}/${this.repo}/releases/${release.id}`, this.token, null, "DELETE") } catch (e) { if (e instanceof HttpError && (e.response.statusCode === 405 || e.response.statusCode === 502)) { diff --git a/src/publish/gitHubRequest.ts b/src/publish/restApiRequest.ts similarity index 75% rename from src/publish/gitHubRequest.ts rename to src/publish/restApiRequest.ts index d8837eeee42..690ed9618eb 100644 --- a/src/publish/gitHubRequest.ts +++ b/src/publish/restApiRequest.ts @@ -3,20 +3,16 @@ import { RequestOptions } from "https" import { IncomingMessage, ClientRequest } from "http" import { addTimeOutHandler } from "../util/httpRequest" import { Promise as BluebirdPromise } from "bluebird" -import { createReadStream, Stats } from "fs-extra-p" -import progressStream = require("progress-stream") -import ProgressBar = require("progress") -import { ReadStream } from "tty" //noinspection JSUnusedLocalSymbols const __awaiter = require("../util/awaiter") -export function gitHubRequest(path: string, token: string | null, data: { [name: string]: any; } | null = null, method: string = "GET"): BluebirdPromise { +export function githubRequest(path: string, token: string | null, data: { [name: string]: any; } | null = null, method: string = "GET"): BluebirdPromise { return request("api.github.com", path, token, data, method) } -export function bintrayRequest(path: string, token: string | null, data: { [name: string]: any; } | null = null, method: string = "GET"): BluebirdPromise { - return request("api.bintray.com", path, token, data, method) +export function bintrayRequest(path: string, auth: string | null, data: { [name: string]: any; } | null = null, method: string = "GET"): BluebirdPromise { + return request("api.bintray.com", path, auth, data, method) } function request(hostname: string, path: string, token: string | null, data: { [name: string]: any; } | null = null, method: string = "GET"): BluebirdPromise { @@ -104,26 +100,4 @@ export class HttpError extends Error { constructor(public response: IncomingMessage, public description: any = null) { super(response.statusCode + " " + response.statusMessage + (description == null ? "" : ("\n" + JSON.stringify(description, null, " "))) + "\nHeaders: " + JSON.stringify(response.headers, null, " ")) } -} - -export function uploadFile(file: string, fileStat: Stats, fileName: string, request: ClientRequest, reject: (error: Error) => void) { - const progressBar = (process.stdin).isTTY ? new ProgressBar(`Uploading ${fileName} [:bar] :percent :etas`, { - total: fileStat.size, - incomplete: " ", - stream: process.stdout, - width: 20, - }) : null - - const fileInputStream = createReadStream(file) - fileInputStream.on("error", reject) - fileInputStream - .pipe(progressStream({ - length: fileStat.size, - time: 1000 - }, progress => { - if (progressBar != null) { - progressBar.tick(progress.delta) - } - })) - .pipe(request) } \ No newline at end of file diff --git a/src/publish/uploader.ts b/src/publish/uploader.ts new file mode 100644 index 00000000000..13a14751654 --- /dev/null +++ b/src/publish/uploader.ts @@ -0,0 +1,27 @@ +import progressStream = require("progress-stream") +import ProgressBar = require("progress") +import { createReadStream, Stats } from "fs-extra-p" +import { ReadStream } from "tty" +import { ClientRequest } from "http" + +export function uploadFile(file: string, fileStat: Stats, fileName: string, request: ClientRequest, reject: (error: Error) => void) { + const progressBar = (process.stdin).isTTY ? new ProgressBar(`Uploading ${fileName} [:bar] :percent :etas`, { + total: fileStat.size, + incomplete: " ", + stream: process.stdout, + width: 20, + }) : null + + const fileInputStream = createReadStream(file) + fileInputStream.on("error", reject) + fileInputStream + .pipe(progressStream({ + length: fileStat.size, + time: 1000 + }, progress => { + if (progressBar != null) { + progressBar.tick(progress.delta) + } + })) + .pipe(request) +} \ No newline at end of file diff --git a/templates/nsis/boringInstaller.nsh b/templates/nsis/boringInstaller.nsh index 41a655fb12f..a221621ff42 100644 --- a/templates/nsis/boringInstaller.nsh +++ b/templates/nsis/boringInstaller.nsh @@ -18,6 +18,69 @@ FunctionEnd !insertmacro MUI_UNPAGE_INSTFILES !insertmacro MUI_LANGUAGE "English" +!insertmacro MUI_LANGUAGE "German" +!insertmacro MUI_LANGUAGE "French" +!insertmacro MUI_LANGUAGE "Spanish" +!insertmacro MUI_LANGUAGE "SpanishInternational" +!insertmacro MUI_LANGUAGE "SimpChinese" +!insertmacro MUI_LANGUAGE "TradChinese" +!insertmacro MUI_LANGUAGE "Japanese" +#!insertmacro MUI_LANGUAGE "Korean" +!insertmacro MUI_LANGUAGE "Italian" +!insertmacro MUI_LANGUAGE "Dutch" +#!insertmacro MUI_LANGUAGE "Danish" +#!insertmacro MUI_LANGUAGE "Swedish" +#!insertmacro MUI_LANGUAGE "Norwegian" +#!insertmacro MUI_LANGUAGE "NorwegianNynorsk" +#!insertmacro MUI_LANGUAGE "Finnish" +#!insertmacro MUI_LANGUAGE "Greek" +!insertmacro MUI_LANGUAGE "Russian" +#!insertmacro MUI_LANGUAGE "Portuguese" +#!insertmacro MUI_LANGUAGE "PortugueseBR" +#!insertmacro MUI_LANGUAGE "Polish" +#!insertmacro MUI_LANGUAGE "Ukrainian" +!insertmacro MUI_LANGUAGE "Czech" +#!insertmacro MUI_LANGUAGE "Slovak" +#!insertmacro MUI_LANGUAGE "Croatian" +#!insertmacro MUI_LANGUAGE "Bulgarian" +#!insertmacro MUI_LANGUAGE "Hungarian" +#!insertmacro MUI_LANGUAGE "Thai" +#!insertmacro MUI_LANGUAGE "Romanian" +#!insertmacro MUI_LANGUAGE "Latvian" +#!insertmacro MUI_LANGUAGE "Macedonian" +#!insertmacro MUI_LANGUAGE "Estonian" +#!insertmacro MUI_LANGUAGE "Turkish" +#!insertmacro MUI_LANGUAGE "Lithuanian" +#!insertmacro MUI_LANGUAGE "Slovenian" +#!insertmacro MUI_LANGUAGE "Serbian" +#!insertmacro MUI_LANGUAGE "SerbianLatin" +#!insertmacro MUI_LANGUAGE "Arabic" +#!insertmacro MUI_LANGUAGE "Farsi" +#!insertmacro MUI_LANGUAGE "Hebrew" +#!insertmacro MUI_LANGUAGE "Indonesian" +#!insertmacro MUI_LANGUAGE "Mongolian" +#!insertmacro MUI_LANGUAGE "Luxembourgish" +#!insertmacro MUI_LANGUAGE "Albanian" +#!insertmacro MUI_LANGUAGE "Breton" +#!insertmacro MUI_LANGUAGE "Belarusian" +#!insertmacro MUI_LANGUAGE "Icelandic" +#!insertmacro MUI_LANGUAGE "Malay" +#!insertmacro MUI_LANGUAGE "Bosnian" +#!insertmacro MUI_LANGUAGE "Kurdish" +#!insertmacro MUI_LANGUAGE "Irish" +#!insertmacro MUI_LANGUAGE "Uzbek" +#!insertmacro MUI_LANGUAGE "Galician" +#!insertmacro MUI_LANGUAGE "Afrikaans" +#!insertmacro MUI_LANGUAGE "Catalan" +#!insertmacro MUI_LANGUAGE "Esperanto" +#!insertmacro MUI_LANGUAGE "Asturian" +#!insertmacro MUI_LANGUAGE "Basque" +#!insertmacro MUI_LANGUAGE "Pashto" +#!insertmacro MUI_LANGUAGE "ScotsGaelic" +#!insertmacro MUI_LANGUAGE "Georgian" +#!insertmacro MUI_LANGUAGE "Vietnamese" +#!insertmacro MUI_LANGUAGE "Welsh" +#!insertmacro MUI_LANGUAGE "Armenian" Function GuiInit !insertmacro UAC_PageElevation_OnGuiInit diff --git a/templates/nsis/installer.nsi b/templates/nsis/installer.nsi index c4313b7fa25..8ba9571aa28 100644 --- a/templates/nsis/installer.nsi +++ b/templates/nsis/installer.nsi @@ -152,7 +152,11 @@ Section "un.install" # delete the installed files RMDir /r $INSTDIR - RMDir /r "$APPDATA\${PRODUCT_FILENAME}" + ${GetParameters} $R0 + ${GetOptions} $R0 "/KEEP_APP_DATA" $R1 + ${If} ${Errors} + RMDir /r "$APPDATA\${PRODUCT_FILENAME}" + ${EndIf} !insertmacro MULTIUSER_RegistryRemoveInstallInfo diff --git a/templates/nsis/multiUserUi.nsh b/templates/nsis/multiUserUi.nsh index 8516ce2d9b9..76d4138a028 100755 --- a/templates/nsis/multiUserUi.nsh +++ b/templates/nsis/multiUserUi.nsh @@ -52,18 +52,16 @@ Var RadioButtonLabel1 ${GetParameters} $R0 ${GetOptions} $R0 "/allusers" $R1 - IfErrors notallusers - Call ${UNINSTALLER_FUNCPREFIX}MultiUser.InstallMode.AllUsers - Abort - - notallusers: + ${IfNot} ${Errors} + Call ${UNINSTALLER_FUNCPREFIX}MultiUser.InstallMode.AllUsers + Abort + ${EndIf} ${GetOptions} $R0 "/currentuser" $R1 - IfErrors notcurrentuser - Call ${UNINSTALLER_FUNCPREFIX}MultiUser.InstallMode.CurrentUser - Abort - - notcurrentuser: + ${IfNot} ${Errors} + Call ${UNINSTALLER_FUNCPREFIX}MultiUser.InstallMode.CurrentUser + Abort + ${EndIf} # If uninstalling, will check if there is both a per-user and per-machine installation. If there is only one, will skip the form. # If uninstallation was invoked from the "add/remove programs" Windows will automatically requests elevation (depending if uninstall keys are in HKLM or HKCU) @@ -81,9 +79,9 @@ Var RadioButtonLabel1 !endif !if "${UNINSTALLER_PREFIX}" == UN - !insertmacro MUI_HEADER_TEXT "Choose Installation Options" "Who should this application be installed for?" + !insertmacro MUI_HEADER_TEXT "Choose Uninstallation Options" "Which installation should be removed?" !else - !insertmacro MUI_HEADER_TEXT "Choose Uninstallation Options" "Which installation should be removed?" + !insertmacro MUI_HEADER_TEXT "Choose Installation Options" "Who should this application be installed for?" !endif nsDialogs::Create 1018 diff --git a/test/src/ArtifactPublisherTest.ts b/test/src/ArtifactPublisherTest.ts index ea358278039..7bc28591851 100644 --- a/test/src/ArtifactPublisherTest.ts +++ b/test/src/ArtifactPublisherTest.ts @@ -1,6 +1,6 @@ import test from "./helpers/avaEx" import { GitHubPublisher } from "out/publish/gitHubPublisher" -import { HttpError } from "out/publish/gitHubRequest" +import { HttpError } from "out/publish/restApiRequest" import { join } from "path" import { assertThat } from "./helpers/fileAssert" import { BintrayPublisher } from "out/publish/BintrayPublisher" diff --git a/test/src/nsisTest.ts b/test/src/nsisTest.ts index b8cbab67edb..64fc15f9f39 100644 --- a/test/src/nsisTest.ts +++ b/test/src/nsisTest.ts @@ -9,7 +9,7 @@ import { assertThat } from "./helpers/fileAssert" //noinspection JSUnusedLocalSymbols const __awaiter = require("out/util/awaiter") -test("nsis", () => assertPack("test-app-one", signed({ +test("one-click", () => assertPack("test-app-one", signed({ targets: Platform.WINDOWS.createTarget(["nsis"]), }), { useTempDir: true, @@ -44,6 +44,7 @@ test.ifNotCiOsx("boring", () => assertPack("test-app-one", signed({ } } }))) + test.ifNotCiOsx("installerHeaderIcon", () => { let headerIconPath: string | null = null return assertPack("test-app-one", { diff --git a/test/src/nsisUpdaterTest.ts b/test/src/nsisUpdaterTest.ts new file mode 100644 index 00000000000..af09f1e795e --- /dev/null +++ b/test/src/nsisUpdaterTest.ts @@ -0,0 +1,16 @@ +import test from "./helpers/avaEx" + +//noinspection JSUnusedLocalSymbols +const __awaiter = require("out/util/awaiter") + +const updater = require("../../nsis-auto-updater/out/nsis-auto-updater/src/nsis-updater") + +test("Check updates - no latest version", async (t) => { + //noinspection ReservedWordAsName + updater.setFeedURL({ + user: "actperepo", + package: "no-versions", + }) + + t.throws(updater.checkForUpdates(), /No latest version, please ensure that/) +}) \ No newline at end of file