From 090473e262389674787d5f2955c070702beca75a Mon Sep 17 00:00:00 2001 From: develar Date: Thu, 4 Aug 2016 10:00:15 +0200 Subject: [PATCH] WIP: NSIS Auto-Update #529 --- .idea/electron-builder.iml | 1 + .travis.yml | 2 +- nsis-auto-updater/package.json | 25 ++++ nsis-auto-updater/src/nsis-updater.ts | 62 ++++++++ nsis-auto-updater/tsconfig.json | 29 ++++ package.json | 9 +- src/publish/BintrayPublisher.ts | 102 +++++++++++++ src/publish/gitHubPublisher.ts | 44 ++---- src/publish/gitHubRequest.ts | 33 ++++- src/util/httpRequest.ts | 12 +- .../fixtures/app-executable-deps/package.json | 2 +- test/fixtures/test-app/package.json | 2 +- test/src/ArtifactPublisherTest.ts | 41 +++--- test/src/BuildTest.ts | 2 +- test/src/helpers/runTests.ts | 7 +- test/src/nsisTest.ts | 138 ++++++++++++++++++ test/src/winPackagerTest.ts | 128 ---------------- tsconfig.json | 1 - 18 files changed, 434 insertions(+), 206 deletions(-) create mode 100644 nsis-auto-updater/package.json create mode 100644 nsis-auto-updater/src/nsis-updater.ts create mode 100755 nsis-auto-updater/tsconfig.json create mode 100644 src/publish/BintrayPublisher.ts create mode 100644 test/src/nsisTest.ts diff --git a/.idea/electron-builder.iml b/.idea/electron-builder.iml index 28ad2ff9e97..86576276fb4 100644 --- a/.idea/electron-builder.iml +++ b/.idea/electron-builder.iml @@ -3,6 +3,7 @@ + diff --git a/.travis.yml b/.travis.yml index 8c4d70421f4..695a7c1c2ce 100755 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ matrix: env: TEST_FILES=BuildTest,linuxPackagerTest,globTest NODE_VERSION=6 PUBLISH_TO_NPM=true - os: osx - env: TEST_FILES=macPackagerTest,winPackagerTest NODE_VERSION=6 + env: TEST_FILES=macPackagerTest,winPackagerTest,nsisTest NODE_VERSION=6 - os: osx env: TEST_FILES=macPackagerTest,CodeSignTest NODE_VERSION=4 diff --git a/nsis-auto-updater/package.json b/nsis-auto-updater/package.json new file mode 100644 index 00000000000..9c79cbf2fc5 --- /dev/null +++ b/nsis-auto-updater/package.json @@ -0,0 +1,25 @@ +{ + "name": "nsis-auto-updater", + "version": "0.0.1", + "description": "NSIS Auto Updater", + "main": "out/nsis-auto-updater/src/nsis-updater.js", + "scripts": { + }, + "author": "Vladimir Krivosheev", + "license": "MIT", + "files": [ + "out" + ], + "dependencies": { + "bluebird": "^3.4.1", + "fs-extra-p": "^1.0.6" + }, + "bundledDependencies": [ + "fs-extra-p", + "bluebird" + ], + "devDependencies": { + "@types/electron": "^0.37.14", + "@types/node": "^4.0.30" + } +} diff --git a/nsis-auto-updater/src/nsis-updater.ts b/nsis-auto-updater/src/nsis-updater.ts new file mode 100644 index 00000000000..50eac0db2b4 --- /dev/null +++ b/nsis-auto-updater/src/nsis-updater.ts @@ -0,0 +1,62 @@ +import { EventEmitter } from "events" +import { app } from "electron" +import { spawn } from "child_process" +import * as path from "path" +import { tmpdir } from "os" + +class NsisUpdater extends EventEmitter { + private setupPath = path.join(tmpdir(), 'innobox-upgrade.exe') + + private updateAvailable = false + private quitAndInstallCalled = false + + constructor(public updateUrl?: string) { + super() + } + + getFeedURL(): string | null | undefined { + return this.updateUrl + } + + setFeedURL(value: string) { + this.updateUrl = value + } + + checkForUpdates(): void { + if (this.updateUrl == null) { + this.emitError("Update URL is not set") + return + } + + this.emit("checking-for-update") + } + + quitAndInstall(): void { + if (!this.updateAvailable) { + this.emitError("No update available, can't quit and install") + return + } + + if (this.quitAndInstallCalled) { + return + } + + // prevent calling several times + this.quitAndInstallCalled = true + + spawn(this.setupPath, ["/S"], { + detached: true, + stdio: "ignore", + }).unref() + + app.quit() + } + + // emit both error object and message, this is to keep compatibility with old APIs + private emitError (message: string) { + return this.emit("error", new Error(message), message) + } +} + +const updater = new NsisUpdater() +export= updater \ No newline at end of file diff --git a/nsis-auto-updater/tsconfig.json b/nsis-auto-updater/tsconfig.json new file mode 100755 index 00000000000..a69352c204b --- /dev/null +++ b/nsis-auto-updater/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es6", + "noImplicitAny": true, + "outDir": "out", + "newLine": "LF", + "noResolve": true, + "noEmitOnError": true, + "inlineSources": true, + "sourceMap": true, + "noImplicitReturns": true, + "strictNullChecks": true, + "noEmitHelpers": true, + "noFallthroughCasesInSwitch": true, + "skipLibCheck": true + }, + "files": [ + "../node_modules/fs-extra-p/index.d.ts", + "../node_modules/fs-extra-p/bluebird.d.ts", + "../src/util/httpRequest.ts" + ], + "include": [ + "src/**/*.ts", + "node_modules/@types/**/*.d.ts" + ], + "exclude": [ + ] +} diff --git a/package.json b/package.json index b22e58a6eb0..040aeae22e4 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "compile": "npm run compile-production && npm run compile-test", "compile-production": "ts-babel", "compile-test": "ts-babel test", + "compile-updater": "tsc -p nsis-auto-updater", "lint": "tslint 'src/**/*.ts' 'test/src/**/*.ts'", "pretest": "npm run compile && npm run lint", "test": "node ./test/out/helpers/runTests.js", @@ -58,7 +59,7 @@ "bugs": "https://github.com/electron-userland/electron-builder/issues", "homepage": "https://github.com/electron-userland/electron-builder", "dependencies": { - "7zip-bin": "^1.0.5", + "7zip-bin": "^1.0.6", "ansi-escapes": "^1.4.0", "asar-electron-builder": "^0.13.2", "bluebird": "^3.4.1", @@ -109,7 +110,7 @@ "@types/debug": "0.0.28", "@types/mime": "0.0.28", "@types/progress": "^1.1.27", - "@types/semver": "^4.3.26", + "@types/semver": "^4.3.27", "@types/source-map-support": "^0.2.27", "ava-tf": "^0.15.4", "babel-plugin-array-includes": "^2.0.3", @@ -121,9 +122,9 @@ "json8": "^0.9.2", "pre-git": "^3.10.0", "should": "^10.0.0", - "ts-babel": "^1.0.3", + "ts-babel": "^1.0.4", "tslint": "3.14.0", - "typescript": "^2.1.0-dev.20160801", + "typescript": "^2.1.0-dev.20160802", "whitespace": "^2.0.0" }, "babel": { diff --git a/src/publish/BintrayPublisher.ts b/src/publish/BintrayPublisher.ts new file mode 100644 index 00000000000..b4fbbd5b2b7 --- /dev/null +++ b/src/publish/BintrayPublisher.ts @@ -0,0 +1,102 @@ +import { Publisher, PublishOptions } from "./publisher" +import { Promise as BluebirdPromise } from "bluebird" +import { bintrayRequest, HttpError, doApiRequest, uploadFile } from "./gitHubRequest" +import { log } from "../util/log" +import { debug } from "../util/util" +import { basename } from "path" +import { stat } from "fs-extra-p" + +//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 + + 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._versionPromise = >this.init() + } + + private async init(): Promise { + try { + return await bintrayRequest(`${this.basePath}/versions/${this.version}`, this.auth) + } + 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() + } + else { + log(`Version ${this.version} doesn't exist, artifacts will be not published`) + } + } + + throw e + } + } + + 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 + if (version == null) { + debug(`Version ${this.version} doesn't exist and is not created, artifact ${fileName} is not published`) + return + } + + const fileStat = await stat(file) + let badGatewayCount = 0 + for (let i = 0; i < 3; i++) { + try { + return await doApiRequest({ + hostname: "api.bintray.com", + path: `/content/${this.user}/${this.repo}/${this.packageName}/${version.name}/${fileName}`, + method: "PUT", + headers: { + "User-Agent": "electron-builder", + "Content-Length": fileStat.size, + "X-Bintray-Override": "1", + "X-Bintray-Publish": "1", + } + }, this.auth, uploadFile.bind(this, file, fileStat, fileName)) + } + catch (e) { + if (e instanceof HttpError && e.response.statusCode === 502 && badGatewayCount++ < 3) { + continue + } + + throw e + } + } + } + + //noinspection JSUnusedGlobalSymbols + deleteRelease(): Promise { + if (!this._versionPromise.isFulfilled()) { + return BluebirdPromise.resolve() + } + + 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") + } +} \ No newline at end of file diff --git a/src/publish/gitHubPublisher.ts b/src/publish/gitHubPublisher.ts index ae97f091706..630bc97f0dc 100644 --- a/src/publish/gitHubPublisher.ts +++ b/src/publish/gitHubPublisher.ts @@ -1,15 +1,12 @@ import { isEmptyOrSpaces } from "../util/util" import { log, warn } from "../util/log" +import { debug } from "../util/util" import { basename } from "path" import { parse as parseUrl } from "url" import * as mime from "mime" import { stat } from "fs-extra-p" -import { createReadStream } from "fs" -import { gitHubRequest, HttpError, doGitHubRequest } from "./gitHubRequest" +import { gitHubRequest, HttpError, doApiRequest, uploadFile } from "./gitHubRequest" import { Promise as BluebirdPromise } from "bluebird" -import { ReadStream } from "tty" -import progressStream = require("progress-stream") -import ProgressBar = require("progress") import { PublishPolicy, PublishOptions, Publisher } from "./publisher" //noinspection JSUnusedLocalSymbols @@ -85,11 +82,11 @@ export class GitHubPublisher implements Publisher { } if (createReleaseIfNotExists) { - log(`Release with tag ${this.tag} doesn't exists, creating one`) + log(`Release with tag ${this.tag} doesn't exist, creating one`) return this.createRelease() } else { - log(`Cannot found release with tag ${this.tag}, artifacts will be not published`) + log(`Release with tag ${this.tag} doesn't exist, artifacts will be not published`) return null } } @@ -98,6 +95,7 @@ export class GitHubPublisher implements Publisher { const fileName = artifactName || basename(file) const release = await this.releasePromise if (release == null) { + debug(`Release with tag ${this.tag} doesn't exist and is not created, artifact ${fileName} is not published`) return } @@ -105,38 +103,18 @@ export class GitHubPublisher implements Publisher { const fileStat = await stat(file) let badGatewayCount = 0 uploadAttempt: for (let i = 0; i < 3; i++) { - const progressBar = (process.stdin).isTTY ? new ProgressBar(`Uploading ${fileName} [:bar] :percent :etas`, { - total: fileStat.size, - incomplete: " ", - stream: process.stdout, - width: 20, - }) : null - try { - return await doGitHubRequest({ + return await doApiRequest({ hostname: parsedUrl.hostname, path: parsedUrl.path, method: "POST", headers: { Accept: "application/vnd.github.v3+json", - "User-Agent": "electron-complete-builder", + "User-Agent": "electron-builder", "Content-Type": mime.lookup(fileName), "Content-Length": fileStat.size } - }, this.token, (request, reject) => { - 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) - }) + }, this.token, uploadFile.bind(this, file, fileStat, fileName)) } catch (e) { if (e instanceof HttpError) { @@ -167,7 +145,7 @@ export class GitHubPublisher implements Publisher { private createRelease() { return gitHubRequest(`/repos/${this.owner}/${this.repo}/releases`, this.token, { tag_name: this.tag, - name: this.tag, + name: this.version, draft: this.options.draft == null || this.options.draft, prerelease: this.options.prerelease != null && this.options.prerelease, }) @@ -182,12 +160,12 @@ export class GitHubPublisher implements Publisher { //noinspection JSUnusedGlobalSymbols async deleteRelease(): Promise { if (!this._releasePromise.isFulfilled()) { - return BluebirdPromise.resolve() + return } const release = this._releasePromise.value() if (release == null) { - return BluebirdPromise.resolve() + return } for (let i = 0; i < 3; i++) { diff --git a/src/publish/gitHubRequest.ts b/src/publish/gitHubRequest.ts index 1b194d4d219..d8837eeee42 100644 --- a/src/publish/gitHubRequest.ts +++ b/src/publish/gitHubRequest.ts @@ -3,6 +3,10 @@ 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") @@ -35,10 +39,10 @@ function request(hostname: string, path: string, token: string | null, data: options.headers["Content-Type"] = "application/json" options.headers["Content-Length"] = encodedData.length } - return doGitHubRequest(options, token, it => it.end(encodedData)) + return doApiRequest(options, token, it => it.end(encodedData)) } -export function doGitHubRequest(options: RequestOptions, token: string | null, requestProcessor: (request: ClientRequest, reject: (error: Error) => void) => void): BluebirdPromise { +export function doApiRequest(options: RequestOptions, token: string | null, requestProcessor: (request: ClientRequest, reject: (error: Error) => void) => void): BluebirdPromise { if (token != null) { (options.headers).authorization = token.startsWith("Basic") ? token : `token ${token}` } @@ -68,7 +72,8 @@ Please double check that your GitHub Token is correct. Due to security reasons G response.on("end", () => { try { if (response.statusCode >= 400) { - if (response.headers["content-type"].includes("json")) { + const contentType = response.headers["content-type"] + if (contentType != null && contentType.includes("json")) { reject(new HttpError(response, JSON.parse(data))) } else { @@ -99,4 +104,26 @@ 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/util/httpRequest.ts b/src/util/httpRequest.ts index bd7b148f14e..3bba03de33f 100644 --- a/src/util/httpRequest.ts +++ b/src/util/httpRequest.ts @@ -17,7 +17,7 @@ export interface DownloadOptions { export const download = <(url: string, destination: string, options?: DownloadOptions) => BluebirdPromise>(BluebirdPromise.promisify(_download)) -function _download(url: string, destination: string, options: DownloadOptions | n, callback: (error: Error) => void): void { +function _download(url: string, destination: string, options: DownloadOptions | null | undefined, callback: (error: Error) => void): void { if (callback == null) { callback = options options = null @@ -62,14 +62,14 @@ function doDownload(url: string, destination: string, redirectCount: number, opt return } - const sha1Header = response.headers["X-Checksum-Sha2"] - if (sha1Header != null && options.sha2 != null) { + const sha2Header = response.headers["X-Checksum-Sha2"] + if (sha2Header != null && options.sha2 != null) { // todo why bintray doesn't send this header always - if (sha1Header == null) { + if (sha2Header == null) { throw new Error("checksum is required, but server response doesn't contain X-Checksum-Sha2 header") } - else if (sha1Header !== options.sha2) { - throw new Error(`checksum mismatch: expected ${options.sha2} but got ${sha1Header} (X-Checksum-Sha2 header)`) + else if (sha2Header !== options.sha2) { + throw new Error(`checksum mismatch: expected ${options.sha2} but got ${sha2Header} (X-Checksum-Sha2 header)`) } } diff --git a/test/fixtures/app-executable-deps/package.json b/test/fixtures/app-executable-deps/package.json index 454ea12d9f8..42b3cea5c73 100644 --- a/test/fixtures/app-executable-deps/package.json +++ b/test/fixtures/app-executable-deps/package.json @@ -1,7 +1,7 @@ { "devDependencies": { "electron-builder": "next", - "electron-prebuilt": "^1.3.1" + "electron-prebuilt": "^1.3.2" }, "build": { "app-category-type": "public.app-category.business" diff --git a/test/fixtures/test-app/package.json b/test/fixtures/test-app/package.json index c8be6a4b391..ba7f3ecec59 100755 --- a/test/fixtures/test-app/package.json +++ b/test/fixtures/test-app/package.json @@ -1,7 +1,7 @@ { "private": true, "build": { - "electronVersion": "1.3.1", + "electronVersion": "1.3.2", "appId": "org.electron-builder.testApp", "app-category-type": "your.app.category.type", "iconUrl": "https://raw.githubusercontent.com/szwacz/electron-boilerplate/master/resources/windows/icon.ico", diff --git a/test/src/ArtifactPublisherTest.ts b/test/src/ArtifactPublisherTest.ts index 3e7e1acaa08..d9321135175 100644 --- a/test/src/ArtifactPublisherTest.ts +++ b/test/src/ArtifactPublisherTest.ts @@ -3,6 +3,7 @@ import { GitHubPublisher } from "out/publish/gitHubPublisher" import { HttpError } from "out/publish/gitHubRequest" import { join } from "path" import * as assertThat from "should/as-function" +import { BintrayPublisher } from "out/publish/BintrayPublisher" //noinspection JSUnusedLocalSymbols const __awaiter = require("out/util/awaiter") @@ -12,7 +13,7 @@ function getRandomInt(min: number, max: number) { } function versionNumber() { - return getRandomInt(0, 99) + "." + Date.now() + "." + getRandomInt(0, 9) + return `${getRandomInt(0, 99)}.${getRandomInt(0, 99)}.${getRandomInt(0, 99)}` } const token = new Buffer("Y2Y5NDdhZDJhYzJlMzg1OGNiNzQzYzcwOWZhNGI0OTk2NWQ4ZDg3Yg==", "base64").toString() @@ -48,15 +49,18 @@ function testAndIgnoreApiRate(name: string, testFunction: () => Promise) { }) } -// testAndIgnoreApiRate("Bintray upload", async () => { -// const publisher = new BintrayPublisher("actperepo", "5df2cadec86dff91392e4c419540785813c3db15", versionNumber(), "test") -// try { -// await publisher.upload(iconPath) -// } -// finally { -// // await publisher.deleteRelease() -// } -// }) +test("Bintray upload", async () => { + const version = versionNumber() + const publisher = new BintrayPublisher("actperepo", "5df2cadec86dff91392e4c419540785813c3db15", version, "test") + try { + const artifactName = `icon-${version}.icns` + await publisher.upload(iconPath, artifactName) + await publisher.upload(iconPath, artifactName) + } + finally { + await publisher.deleteRelease() + } +}) testAndIgnoreApiRate("GitHub upload", async () => { const publisher = new GitHubPublisher("actperepo", "ecb2", versionNumber(), { @@ -64,6 +68,8 @@ testAndIgnoreApiRate("GitHub upload", async () => { }) try { await publisher.upload(iconPath) + // test overwrite + await publisher.upload(iconPath) } finally { await publisher.deleteRelease() @@ -122,17 +128,4 @@ testAndIgnoreApiRate("GitHub upload org", async () => { finally { await publisher.deleteRelease() } -}) - -testAndIgnoreApiRate("GitHub overwrite on upload", async () => { - const publisher = new GitHubPublisher("actperepo", "ecb2", versionNumber(), { - githubToken: token - }) - try { - await publisher.upload(iconPath) - await publisher.upload(iconPath) - } - finally { - await publisher.deleteRelease() - } -}) +}) \ No newline at end of file diff --git a/test/src/BuildTest.ts b/test/src/BuildTest.ts index 5f4aff0235c..6192c2c43e9 100755 --- a/test/src/BuildTest.ts +++ b/test/src/BuildTest.ts @@ -148,7 +148,7 @@ test("relative index", () => assertPack("test-app", allPlatforms(false), { }, true) })) -const electronVersion = "1.3.1" +const electronVersion = "1.3.2" test.ifNotWindows("electron version from electron-prebuilt dependency", () => assertPack("test-app-one", { targets: Platform.LINUX.createTarget(DIR_TARGET), diff --git a/test/src/helpers/runTests.ts b/test/src/helpers/runTests.ts index 067a833c472..c796637ab3c 100755 --- a/test/src/helpers/runTests.ts +++ b/test/src/helpers/runTests.ts @@ -3,7 +3,7 @@ import * as path from "path" import { Promise as BluebirdPromise } from "bluebird" import { copy, emptyDir, outputFile, readdir, readFileSync, readJson, unlink } from "fs-extra-p" import { Platform } from "out/metadata" -import { cpus } from "os" +import { cpus, homedir } from "os" // we set NODE_PATH in this file, so, we cannot use 'out/awaiter' path here //noinspection JSUnusedLocalSymbols @@ -20,7 +20,7 @@ const rootDir = path.join(__dirname, "..", "..", "..") const testPackageDir = path.join(require("os").tmpdir(), "electron_builder_published") const testNodeModules = path.join(testPackageDir, "node_modules") -const electronVersion = "1.3.1" +const electronVersion = "1.3.2" async function main() { await BluebirdPromise.all([ @@ -56,7 +56,7 @@ async function deleteOldElectronVersion(): Promise { return } - const cacheDir = path.join(require("os").homedir(), ".electron") + const cacheDir = path.join(homedir(), ".electron") try { const deletePromises: Array> = [] for (let file of (await readdir(cacheDir))) { @@ -148,6 +148,7 @@ function runTests(): BluebirdPromise { } else { args.push(path.join(baseDir, "winPackagerTest.js")) + args.push(path.join(baseDir, "nsisTest.js")) args.push(...baseForLinuxTests) } console.log(`Test files for node ${circleNodeIndex}: ${args.join(", ")}`) diff --git a/test/src/nsisTest.ts b/test/src/nsisTest.ts new file mode 100644 index 00000000000..b8cbab67edb --- /dev/null +++ b/test/src/nsisTest.ts @@ -0,0 +1,138 @@ +import { Platform, Arch } from "out" +import test from "./helpers/avaEx" +import { assertPack, signed, getTestAsset } from "./helpers/packTester" +import { copy } from "fs-extra-p" +import * as path from "path" +import { Promise as BluebirdPromise } from "bluebird" +import { assertThat } from "./helpers/fileAssert" + +//noinspection JSUnusedLocalSymbols +const __awaiter = require("out/util/awaiter") + +test("nsis", () => assertPack("test-app-one", signed({ + targets: Platform.WINDOWS.createTarget(["nsis"]), + }), { + useTempDir: true, + } +)) + +test.ifDevOrLinuxCi("perMachine, no run after finish", () => assertPack("test-app-one", { + targets: Platform.WINDOWS.createTarget(["nsis"], Arch.ia32, Arch.x64), + devMetadata: { + build: { + fileAssociations: [ + { + ext: "foo", + name: "Test Foo", + } + ], + nsis: { + perMachine: true, + runAfterFinish: false, + }, + } + } +})) + +test.ifNotCiOsx("boring", () => assertPack("test-app-one", signed({ + targets: Platform.WINDOWS.createTarget(["nsis"]), + devMetadata: { + build: { + nsis: { + oneClick: false, + } + } + } +}))) +test.ifNotCiOsx("installerHeaderIcon", () => { + let headerIconPath: string | null = null + return assertPack("test-app-one", { + targets: Platform.WINDOWS.createTarget(["nsis"]), + effectiveOptionComputed: options => { + const defines = options[0] + assertThat(defines.HEADER_ICO).isEqualTo(headerIconPath) + return false + } + }, { + tempDirCreated: projectDir => { + headerIconPath = path.join(projectDir, "build", "installerHeaderIcon.ico") + return copy(getTestAsset("headerIcon.ico"), headerIconPath) + } + } + ) +}) + +test.ifNotCiOsx("boring, MUI_HEADER", () => { + let installerHeaderPath: string | null = null + return assertPack("test-app-one", { + targets: Platform.WINDOWS.createTarget(["nsis"]), + devMetadata: { + build: { + nsis: { + oneClick: false, + } + } + }, + effectiveOptionComputed: options => { + const defines = options[0] + assertThat(defines.MUI_HEADERIMAGE).isEqualTo(null) + assertThat(defines.MUI_HEADERIMAGE_BITMAP).isEqualTo(installerHeaderPath) + assertThat(defines.MUI_HEADERIMAGE_RIGHT).isEqualTo(null) + // speedup, do not build - another MUI_HEADER test will test build + return true + } + }, { + tempDirCreated: projectDir => { + installerHeaderPath = path.join(projectDir, "build", "installerHeader.bmp") + return copy(getTestAsset("installerHeader.bmp"), installerHeaderPath) + } + } + ) +}) + +test.ifNotCiOsx("boring, MUI_HEADER as option", () => { + let installerHeaderPath: string | null = null + return assertPack("test-app-one", { + targets: Platform.WINDOWS.createTarget(["nsis"]), + devMetadata: { + build: { + nsis: { + oneClick: false, + installerHeader: "foo.bmp" + } + } + }, + effectiveOptionComputed: options => { + const defines = options[0] + assertThat(defines.MUI_HEADERIMAGE).isEqualTo(null) + assertThat(defines.MUI_HEADERIMAGE_BITMAP).isEqualTo(installerHeaderPath) + assertThat(defines.MUI_HEADERIMAGE_RIGHT).isEqualTo(null) + // test that we can build such installer + return false + } + }, { + tempDirCreated: projectDir => { + installerHeaderPath = path.join(projectDir, "foo.bmp") + return copy(getTestAsset("installerHeader.bmp"), installerHeaderPath) + }, + } + ) +}) + +test.ifDevOrLinuxCi("custom include", () => assertPack("test-app-one", { + targets: Platform.WINDOWS.createTarget(["nsis"]), +}, { + tempDirCreated: projectDir => copy(getTestAsset("installer.nsh"), path.join(projectDir, "build", "installer.nsh")), + packed: projectDir => BluebirdPromise.all([ + assertThat(path.join(projectDir, "build", "customHeader")).isFile(), + assertThat(path.join(projectDir, "build", "customInit")).isFile(), + assertThat(path.join(projectDir, "build", "customInstall")).isFile(), + ]), +})) + +test.ifDevOrLinuxCi("custom script", () => assertPack("test-app-one", { + targets: Platform.WINDOWS.createTarget(["nsis"]), +}, { + tempDirCreated: projectDir => copy(getTestAsset("installer.nsi"), path.join(projectDir, "build", "installer.nsi")), + packed: projectDir => assertThat(path.join(projectDir, "build", "customInstallerScript")).isFile(), +})) \ No newline at end of file diff --git a/test/src/winPackagerTest.ts b/test/src/winPackagerTest.ts index 8c4c6fd4942..fd9ed5d35cf 100755 --- a/test/src/winPackagerTest.ts +++ b/test/src/winPackagerTest.ts @@ -19,134 +19,6 @@ test.ifNotCiOsx("win", () => assertPack("test-app-one", signed({ }) )) -test("nsis", () => assertPack("test-app-one", signed({ - targets: Platform.WINDOWS.createTarget(["nsis"], Arch.ia32, Arch.x64), - }), { - useTempDir: true, - } -)) - -test.ifDevOrLinuxCi("nsis 32 perMachine, no run after finish", () => assertPack("test-app-one", { - targets: Platform.WINDOWS.createTarget(["nsis"], Arch.ia32), - devMetadata: { - build: { - fileAssociations: [ - { - ext: "foo", - name: "Test Foo", - } - ], - nsis: { - perMachine: true, - runAfterFinish: false, - }, - } - } -})) - -test.ifNotCiOsx("nsis boring", () => assertPack("test-app-one", signed({ - targets: Platform.WINDOWS.createTarget(["nsis"]), - devMetadata: { - build: { - nsis: { - oneClick: false, - } - } - } -}))) -test.ifNotCiOsx("nsis, installerHeaderIcon", () => { - let headerIconPath: string | null = null - return assertPack("test-app-one", { - targets: Platform.WINDOWS.createTarget(["nsis"]), - effectiveOptionComputed: options => { - const defines = options[0] - assertThat(defines.HEADER_ICO).isEqualTo(headerIconPath) - return false - } - }, { - tempDirCreated: projectDir => { - headerIconPath = path.join(projectDir, "build", "installerHeaderIcon.ico") - return copy(getTestAsset("headerIcon.ico"), headerIconPath) - } - } - ) -}) - -test.ifNotCiOsx("nsis boring, MUI_HEADER", () => { - let installerHeaderPath: string | null = null - return assertPack("test-app-one", { - targets: Platform.WINDOWS.createTarget(["nsis"]), - devMetadata: { - build: { - nsis: { - oneClick: false, - } - } - }, - effectiveOptionComputed: options => { - const defines = options[0] - assertThat(defines.MUI_HEADERIMAGE).isEqualTo(null) - assertThat(defines.MUI_HEADERIMAGE_BITMAP).isEqualTo(installerHeaderPath) - assertThat(defines.MUI_HEADERIMAGE_RIGHT).isEqualTo(null) - // speedup, do not build - another MUI_HEADER test will test build - return true - } - }, { - tempDirCreated: projectDir => { - installerHeaderPath = path.join(projectDir, "build", "installerHeader.bmp") - return copy(getTestAsset("installerHeader.bmp"), installerHeaderPath) - } - } - ) -}) - -test.ifNotCiOsx("nsis boring, MUI_HEADER as option", () => { - let installerHeaderPath: string | null = null - return assertPack("test-app-one", { - targets: Platform.WINDOWS.createTarget(["nsis"]), - devMetadata: { - build: { - nsis: { - oneClick: false, - installerHeader: "foo.bmp" - } - } - }, - effectiveOptionComputed: options => { - const defines = options[0] - assertThat(defines.MUI_HEADERIMAGE).isEqualTo(null) - assertThat(defines.MUI_HEADERIMAGE_BITMAP).isEqualTo(installerHeaderPath) - assertThat(defines.MUI_HEADERIMAGE_RIGHT).isEqualTo(null) - // test that we can build such installer - return false - } - }, { - tempDirCreated: projectDir => { - installerHeaderPath = path.join(projectDir, "foo.bmp") - return copy(getTestAsset("installerHeader.bmp"), installerHeaderPath) - }, - } - ) -}) - -test.ifDevOrLinuxCi("nsis - custom include", () => assertPack("test-app-one", { - targets: Platform.WINDOWS.createTarget(["nsis"]), -}, { - tempDirCreated: projectDir => copy(getTestAsset("installer.nsh"), path.join(projectDir, "build", "installer.nsh")), - packed: projectDir => BluebirdPromise.all([ - assertThat(path.join(projectDir, "build", "customHeader")).isFile(), - assertThat(path.join(projectDir, "build", "customInit")).isFile(), - assertThat(path.join(projectDir, "build", "customInstall")).isFile(), - ]), -})) - -test.ifDevOrLinuxCi("nsis - custom script", () => assertPack("test-app-one", { - targets: Platform.WINDOWS.createTarget(["nsis"]), -}, { - tempDirCreated: projectDir => copy(getTestAsset("installer.nsi"), path.join(projectDir, "build", "installer.nsi")), - packed: projectDir => assertThat(path.join(projectDir, "build", "customInstallerScript")).isFile(), -})) - // very slow test.skip("delta and msi", () => assertPack("test-app-one", { targets: Platform.WINDOWS.createTarget(null, Arch.ia32), diff --git a/tsconfig.json b/tsconfig.json index a6a0bbd9666..3f27f947589 100755 --- a/tsconfig.json +++ b/tsconfig.json @@ -30,6 +30,5 @@ "node_modules/@types/**/*.d.ts" ], "exclude": [ - "node_modules/@types/node/node-*.d.ts" ] }