From 974f7f32ddc325e5d348aa94fddb5883c1a4eb8a Mon Sep 17 00:00:00 2001 From: develar Date: Sun, 1 May 2016 15:16:07 +0200 Subject: [PATCH] feat: iconUrl git-lfs support, os x identity/installerIdentity options Add Programmatic Usage example Closes #332 --- .idea/dictionaries/develar.xml | 2 + README.md | 32 +++++++--- docs/Options.md | 21 ++++++- docs/programmaticUsage.js | 18 ++++++ package.json | 6 +- src/linuxPackager.ts | 2 +- src/metadata.ts | 70 ++++++++++++++++++--- src/osxPackager.ts | 53 +++++++++++----- src/packager.ts | 3 +- src/platformPackager.ts | 20 +++--- src/winPackager.ts | 22 +++---- test/fixtures/test-app-one/package.json | 2 +- test/fixtures/test-app/package.json | 2 +- test/src/BuildTest.ts | 2 +- test/src/helpers/packTester.ts | 1 - test/src/helpers/runTests.ts | 2 +- test/src/osxPackagerTest.ts | 84 +++++++++++++++++++++++-- test/tsconfig.json | 4 +- typings/deep-assign.d.ts | 2 + 19 files changed, 272 insertions(+), 76 deletions(-) create mode 100644 docs/programmaticUsage.js diff --git a/.idea/dictionaries/develar.xml b/.idea/dictionaries/develar.xml index 58363776b9e..97d30e2bae7 100644 --- a/.idea/dictionaries/develar.xml +++ b/.idea/dictionaries/develar.xml @@ -24,8 +24,10 @@ nokeys nomacver nsis + nuget nupkg nuspec + packagejson passin pkcs postinstall diff --git a/README.md b/README.md index 44507116fb0..1e480d125bb 100755 --- a/README.md +++ b/README.md @@ -1,10 +1,6 @@ -# electron-builder [![NPM version][npm-image]][npm-url] +# electron-builder [![npm version](https://img.shields.io/npm/v/electron-builder.svg)](https://npmjs.org/package/electron-builder) Complete solution to build ready for distribution and "auto update" installers of your app for OS X, Windows and Linux. -```sh -npm install electron-builder --save-dev -``` - * [Native application dependencies](http://electron.atom.io/docs/latest/tutorial/using-native-node-modules/) compilation (only if [two-package.json project structure](#two-packagejson-structure) used). * [Auto Update](#auto-update) ready application packaging. * [Code Signing](https://github.com/electron-userland/electron-builder/wiki/Code-Signing) on a CI server or development machine. @@ -50,7 +46,9 @@ See [options](https://github.com/electron-userland/electron-builder/wiki/Options "build": { "app-bundle-id": "your.id", "app-category-type": "your.app.category.type", - "iconUrl": "(windows only)" + "win": { + "iconUrl": "(windows-only) https link to icon" + } } ``` See [options](https://github.com/electron-userland/electron-builder/wiki/Options). This object will be used as a source of [electron-packager](https://www.npmjs.com/package/electron-packager#packageropts-callback) options. You can specify any other options here. @@ -103,8 +101,26 @@ Want more — please file issue. # Programmatic Usage See `node_modules/electron-builder/out/electron-builder.d.ts`. [Typings](https://github.com/Microsoft/TypeScript/wiki/Typings-for-npm-packages) is supported. -[npm-url]: https://npmjs.org/package/electron-builder -[npm-image]: http://img.shields.io/npm/v/electron-builder.svg +```js +"use strict" + +const builder = require("electron-builder") + +// Promise is returned +builder.build({ + platform: [builder.Platform.OSX], + "//": "platform, arch and other properties, see PackagerOptions in the node_modules/electron-builder/out/electron-builder.d.ts", + devMetadata: { + "//": "build and other properties, see https://goo.gl/5jVxoO" + } +}) + .then(() => { + // handle result + }) + .catch((error) => { + // handle error + }) +``` # Further Reading See the [Wiki](https://github.com/electron-userland/electron-builder/wiki) for more documentation. diff --git a/docs/Options.md b/docs/Options.md index a1befa014e1..00379b5d111 100644 --- a/docs/Options.md +++ b/docs/Options.md @@ -53,10 +53,10 @@ Here documented only `electron-builder` specific options: | app-bundle-id | *OS X-only.* The app bundle ID. See [CFBundleIdentifier](https://developer.apple.com/library/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html#//apple_ref/doc/uid/20001431-102070). | app-category-type |

*OS X-only.* The application category type, as shown in the Finder via *View -> Arrange by Application Category* when viewing the Applications directory.

For example, app-category-type=public.app-category.developer-tools will set the application category to *Developer Tools*.

Valid values are listed in [Apple’s documentation](https://developer.apple.com/library/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/LaunchServicesKeys.html#//apple_ref/doc/uid/TP40009250-SW8).

| asar |

Whether to package the application’s source code into an archive, using [Electron’s archive format](https://github.com/electron/asar). Defaults to true. Reasons why you may want to disable this feature are described in [an application packaging tutorial in Electron’s documentation](http://electron.atom.io/docs/latest/tutorial/application-packaging/#limitations-on-node-api/).

-| iconUrl |

*windows-only.* A URL to an ICO file to use as the application icon (displayed in Control Panel > Programs and Features). Defaults to the Electron icon.

Please note — [local icon file url is not accepted](https://github.com/atom/grunt-electron-installer/issues/73), must be https/http.

| productName | See [AppMetadata.productName](#AppMetadata-productName). | extraResources |

A [glob expression](https://www.npmjs.com/package/glob#glob-primer), when specified, copy the file or directory with matching names directly into the app’s directory (Contents/Resources for OS X).

You can use ${os} (expanded to osx, linux or win according to current platform) and ${arch} in the pattern.

If directory matched, all contents are copied. So, you can just specify foo to copy <project_dir>/foo directory.

May be specified in the platform options (i.e. in the build.osx).

| osx | See [.build.osx](#OsXBuildOptions). +| mas | See [.build.mas](#MasBuildOptions). | win | See [.build.win](#LinuxBuildOptions). | linux | See [.build.linux](#LinuxBuildOptions). | compression | The compression level, one of `store`, `normal`, `maximum` (default: `normal`). If you want to rapidly test build, `store` can reduce build time significantly. @@ -70,7 +70,21 @@ See all [appdmg options](https://www.npmjs.com/package/appdmg#json-specification | --- | --- | icon | The path to icon, which will be shown when mounted (default: `build/icon.icns`). | background | The path to background (default: `build/background.png`). The resolution of this file determines the resolution of the installer window. -| target | Target package type: list of `default`, `dmg`, `zip`, `mas`, `7z`. +| target | Target package type: list of `default`, `dmg`, `zip`, `mas`, `7z`. Defaults to `default` (dmg and zip for Squirrel.Mac). +| identity |

The name of certificate to use when signing. Consider using environment variables [CSC_LINK or CSC_NAME](https://github.com/electron-userland/electron-builder/wiki/Code-Signing). MAS installer identity is specified in the [.build.mas](#MasBuildOptions-identity).

+| entitlements |

The path to entitlements file for signing the app. build/osx.entitlements will be used if exists (it is a recommended way to set). MAS entitlements is specified in the [.build.mas](#MasBuildOptions-entitlements).

+| entitlementsInherit |

The path to child entitlements which inherit the security settings for signing frameworks and bundles of a distribution. build/osx.inherit.entitlements will be used if exists (it is a recommended way to set). Otherwise [default](https://github.com/electron-userland/electron-osx-sign/blob/master/default.darwin.inherit.entitlements).

This option only applies when signing with entitlements provided.

+ + +### `.build.mas` + +MAS (Mac Application Store) specific options (in addition to `build.osx`). + +| Name | Description +| --- | --- +| identity | The name of certificate to use when signing. Consider using environment variables [CSC_INSTALLER_LINK or CSC_INSTALLER_NAME](https://github.com/electron-userland/electron-builder/wiki/Code-Signing). +| entitlements |

The path to entitlements file for signing the app. build/mas.entitlements will be used if exists (it is a recommended way to set). Otherwise [default](https://github.com/electron-userland/electron-osx-sign/blob/master/default.mas.entitlements).

+| entitlementsInherit |

The path to child entitlements which inherit the security settings for signing frameworks and bundles of a distribution. build/mas.inherit.entitlements will be used if exists (it is a recommended way to set). Otherwise [default](https://github.com/electron-userland/electron-osx-sign/blob/master/default.mas.inherit.entitlements).

### `.build.win` @@ -79,7 +93,8 @@ See all [windows-installer options](https://github.com/electron/windows-installe | Name | Description | --- | --- -| loadingGif |

The path to a .gif file to display during install. build/install-spinner.gif will be used if exists (otherwise [default](https://github.com/electron/windows-installer/blob/master/resources/install-spinner.gif)).

+| iconUrl |

*windows-only.* A URL to an ICO file to use as the application icon (displayed in Control Panel > Programs and Features). Defaults to the Electron icon.

Please note — [local icon file url is not accepted](https://github.com/atom/grunt-electron-installer/issues/73), must be https/http.

+| loadingGif |

The path to a .gif file to display during install. build/install-spinner.gif will be used if exists (it is a recommended way to set) (otherwise [default](https://github.com/electron/windows-installer/blob/master/resources/install-spinner.gif)).

| noMsi | Whether to create an MSI installer. Defaults to `true` (MSI is not created). diff --git a/docs/programmaticUsage.js b/docs/programmaticUsage.js new file mode 100644 index 00000000000..7927e99328d --- /dev/null +++ b/docs/programmaticUsage.js @@ -0,0 +1,18 @@ +"use strict" + +const builder = require("electron-builder") + +// Promise is returned +builder.build({ + platform: [builder.Platform.OSX], + "//": "platform, arch and other properties, see PackagerOptions in the node_modules/electron-builder/out/electron-builder.d.ts", + devMetadata: { + "//": "build and other properties, see https://goo.gl/5jVxoO" + } +}) + .then(() => { + // handle result + }) + .catch((error) => { + // handle error + }) \ No newline at end of file diff --git a/package.json b/package.json index be0ea4bef41..392e7496cf3 100644 --- a/package.json +++ b/package.json @@ -60,9 +60,9 @@ "command-line-args": "^2.1.6", "debug": "^2.2.0", "deep-assign": "^2.0.0", - "electron-osx-sign-tf": "^0.4.0-beta.0", + "electron-osx-sign-tf": "~0.5.0-beta.0", "electron-packager-tf": "^7.0.2-beta.0", - "electron-winstaller-fixed": "~2.4.0-beta.0", + "electron-winstaller-fixed": "~2.4.0-beta.1", "fs-extra-p": "^0.4.0", "globby": "^4.0.0", "hosted-git-info": "^2.1.4", @@ -91,7 +91,7 @@ "babel-plugin-transform-es2015-parameters": "^6.7.0", "babel-plugin-transform-es2015-spread": "^6.6.5", "decompress-zip": "^0.3.0", - "electron-download": "^2.1.1", + "electron-download": "^2.1.2", "json-parse-helpfulerror": "^1.0.3", "path-sort": "^0.1.0", "plist": "^1.2.0", diff --git a/src/linuxPackager.ts b/src/linuxPackager.ts index 79779a61a63..48584d12f2c 100755 --- a/src/linuxPackager.ts +++ b/src/linuxPackager.ts @@ -44,7 +44,7 @@ export class LinuxPackager extends PlatformPackager { const tempDir = await tempDirPromise const promises: Array>> = [] - if (this.customBuildOptions == null || this.customBuildOptions.desktop == null) { + if (this.customBuildOptions.desktop == null) { promises.push(this.computeDesktopIconPath(tempDir)) } diff --git a/src/metadata.ts b/src/metadata.ts index 2eff159fdd7..e37c80afa39 100755 --- a/src/metadata.ts +++ b/src/metadata.ts @@ -94,14 +94,7 @@ export interface BuildMetadata { */ readonly asar?: boolean - /* - *windows-only.* A URL to an ICO file to use as the application icon (displayed in Control Panel > Programs and Features). Defaults to the Electron icon. - - Please note — [local icon file url is not accepted](https://github.com/atom/grunt-electron-installer/issues/73), must be https/http. - - * If you don't plan to build windows installer, you can omit it. - * If your project repository is public on GitHub, it will be `https://raw.githubusercontent.com/${u}/${p}/master/build/icon.ico` by default. - */ + // deprecated readonly iconUrl?: string /* @@ -125,6 +118,11 @@ export interface BuildMetadata { */ readonly osx?: OsXBuildOptions + /* + See [.build.mas](#MasBuildOptions). + */ + readonly mas?: MasBuildOptions + /** See [.build.win](#LinuxBuildOptions). */ @@ -160,9 +158,53 @@ export interface OsXBuildOptions extends PlatformSpecificBuildOptions { readonly background?: string /* - Target package type: list of `default`, `dmg`, `zip`, `mas`, `7z`. + Target package type: list of `default`, `dmg`, `zip`, `mas`, `7z`. Defaults to `default` (dmg and zip for Squirrel.Mac). */ readonly target?: Array + + /* + The name of certificate to use when signing. Consider using environment variables [CSC_LINK or CSC_NAME](https://github.com/electron-userland/electron-builder/wiki/Code-Signing). + MAS installer identity is specified in the [.build.mas](#MasBuildOptions-identity). + */ + readonly identity?: string + + /* + The path to entitlements file for signing the app. `build/osx.entitlements` will be used if exists (it is a recommended way to set). + MAS entitlements is specified in the [.build.mas](#MasBuildOptions-entitlements). + */ + readonly entitlements?: string + + /* + The path to child entitlements which inherit the security settings for signing frameworks and bundles of a distribution. `build/osx.inherit.entitlements` will be used if exists (it is a recommended way to set). + Otherwise [default](https://github.com/electron-userland/electron-osx-sign/blob/master/default.darwin.inherit.entitlements). + + This option only applies when signing with `entitlements` provided. + */ + readonly entitlementsInherit?: string +} + +/* + ### `.build.mas` + + MAS (Mac Application Store) specific options (in addition to `build.osx`). + */ +export interface MasBuildOptions extends OsXBuildOptions { + /* + The name of certificate to use when signing. Consider using environment variables [CSC_INSTALLER_LINK or CSC_INSTALLER_NAME](https://github.com/electron-userland/electron-builder/wiki/Code-Signing). + */ + readonly identity?: string + + /* + The path to entitlements file for signing the app. `build/mas.entitlements` will be used if exists (it is a recommended way to set). + Otherwise [default](https://github.com/electron-userland/electron-osx-sign/blob/master/default.mas.entitlements). + */ + readonly entitlements?: string + + /* + The path to child entitlements which inherit the security settings for signing frameworks and bundles of a distribution. `build/mas.inherit.entitlements` will be used if exists (it is a recommended way to set). + Otherwise [default](https://github.com/electron-userland/electron-osx-sign/blob/master/default.mas.inherit.entitlements). + */ + readonly entitlementsInherit?: string } /* @@ -174,10 +216,18 @@ export interface WinBuildOptions extends PlatformSpecificBuildOptions { readonly certificateFile?: string readonly certificatePassword?: string + /* + *windows-only.* A URL to an ICO file to use as the application icon (displayed in Control Panel > Programs and Features). Defaults to the Electron icon. + + Please note — [local icon file url is not accepted](https://github.com/atom/grunt-electron-installer/issues/73), must be https/http. + + * If you don't plan to build windows installer, you can omit it. + * If your project repository is public on GitHub, it will be `https://github.com/${u}/${p}/blob/master/build/icon.ico?raw=true` by default. + */ readonly iconUrl?: string /* - The path to a .gif file to display during install. `build/install-spinner.gif` will be used if exists + The path to a .gif file to display during install. `build/install-spinner.gif` will be used if exists (it is a recommended way to set) (otherwise [default](https://github.com/electron/windows-installer/blob/master/resources/install-spinner.gif)). */ readonly loadingGif?: string diff --git a/src/osxPackager.ts b/src/osxPackager.ts index 3f070e8f84c..fbb0cc15f5f 100644 --- a/src/osxPackager.ts +++ b/src/osxPackager.ts @@ -1,12 +1,12 @@ import { PlatformPackager, BuildInfo, normalizeTargets } from "./platformPackager" -import { Platform, OsXBuildOptions } from "./metadata" +import { Platform, OsXBuildOptions, MasBuildOptions } from "./metadata" import * as path from "path" import { Promise as BluebirdPromise } from "bluebird" import { log, debug, spawn, statOrNull } from "./util" import { createKeychain, deleteKeychain, CodeSigningInfo, generateKeychainName } from "./codeSign" import { path7za } from "7zip-bin" import deepAssign = require("deep-assign") -import { sign, flat, BaseSignOptions } from "electron-osx-sign-tf" +import { sign, flat, BaseSignOptions, SignOptions, FlatOptions } from "electron-osx-sign-tf" //noinspection JSUnusedLocalSymbols const __awaiter = require("./awaiter") @@ -28,7 +28,7 @@ export default class OsXPackager extends PlatformPackager { this.codeSigningInfo = BluebirdPromise.resolve(null) } - const targets = normalizeTargets(this.customBuildOptions == null ? null : this.customBuildOptions.target) + const targets = normalizeTargets(this.customBuildOptions.target) if (targets != null) { for (let target of targets) { if (target !== "default" && target !== "dmg" && target !== "zip" && target !== "mas" && target !== "7z") { @@ -48,16 +48,17 @@ export default class OsXPackager extends PlatformPackager { let nonMasPromise: Promise = null if (this.targets.length > 1 || this.targets[0] !== "mas") { const appOutDir = this.computeAppOutDir(outDir, arch) - nonMasPromise = this.doPack(packOptions, outDir, appOutDir, arch) - .then(() => this.sign(appOutDir, false)) + nonMasPromise = this.doPack(packOptions, outDir, appOutDir, arch, this.customBuildOptions) + .then(() => this.sign(appOutDir, null)) .then(() => postAsyncTasks.push(this.packageInDistributableFormat(outDir, appOutDir, arch))) } if (this.targets.includes("mas")) { // osx-sign - disable warning const appOutDir = path.join(outDir, `${this.appName}-mas-${arch}`) - await this.doPack(Object.assign({}, packOptions, {platform: "mas", "osx-sign": false}), outDir, appOutDir, arch) - await this.sign(appOutDir, true) + const masBuildOptions = deepAssign({}, this.customBuildOptions, (this.devMetadata.build)["mas"]) + await this.doPack(Object.assign({}, packOptions, {platform: "mas", "osx-sign": false}), outDir, appOutDir, arch, masBuildOptions) + await this.sign(appOutDir, masBuildOptions) } if (nonMasPromise != null) { @@ -65,12 +66,12 @@ export default class OsXPackager extends PlatformPackager { } } - private async sign(appOutDir: string, isMas: boolean): Promise { + private async sign(appOutDir: string, masOptions: MasBuildOptions): Promise { let codeSigningInfo = await this.codeSigningInfo if (codeSigningInfo == null) { codeSigningInfo = { - name: this.options.sign || process.env.CSC_NAME, - installerName: this.options.sign || process.env.CSC_INSTALLER_NAME, + name: this.options.sign || process.env.CSC_NAME || this.customBuildOptions.identity, + installerName: this.options.sign || process.env.CSC_INSTALLER_NAME || (masOptions == null ? null : masOptions.identity), } } @@ -79,28 +80,38 @@ export default class OsXPackager extends PlatformPackager { return } - log("Signing app") + log(`Signing app (${codeSigningInfo.name})`) const baseSignOptions: BaseSignOptions = { app: path.join(appOutDir, this.appName + ".app"), - platform: isMas ? "mas" : "darwin" + platform: masOptions == null ? "darwin" : "mas" } if (codeSigningInfo.keychainName != null) { baseSignOptions.keychain = codeSigningInfo.keychainName } - await BluebirdPromise.promisify(sign)(Object.assign({ + const signOptions = Object.assign({ identity: codeSigningInfo.name, - }, (this.devMetadata.build)["osx-sign"], baseSignOptions)) + }, (this.devMetadata.build)["osx-sign"], baseSignOptions) - if (isMas) { + const customSignOptions = masOptions || this.customBuildOptions + if (customSignOptions.entitlements != null) { + signOptions.entitlements = customSignOptions.entitlements + } + if (customSignOptions.entitlementsInherit != null) { + signOptions["entitlements-inherit"] = customSignOptions.entitlementsInherit + } + + await this.doSign(signOptions) + + if (masOptions != null) { const installerIdentity = codeSigningInfo.installerName if (installerIdentity == null) { throw new Error("Signing is required for mas builds but CSC_INSTALLER_LINK or CSC_INSTALLER_NAME are not specified") } const pkg = path.join(appOutDir, `${this.appName}-${this.metadata.version}.pkg`) - await BluebirdPromise.promisify(flat)(Object.assign({ + await this.doFlat(Object.assign({ pkg: pkg, identity: installerIdentity, }, baseSignOptions)) @@ -108,6 +119,14 @@ export default class OsXPackager extends PlatformPackager { } } + protected async doSign(opts: SignOptions): Promise { + return BluebirdPromise.promisify(sign)(opts) + } + + protected async doFlat(opts: FlatOptions): Promise { + return BluebirdPromise.promisify(flat)(opts) + } + protected async computeEffectiveDistOptions(appOutDir: string): Promise { const specification: appdmg.Specification = deepAssign({ title: this.appName, @@ -123,7 +142,7 @@ export default class OsXPackager extends PlatformPackager { ] }, this.customBuildOptions) - if (this.customBuildOptions == null || !("background" in this.customBuildOptions)) { + if (!("background" in this.customBuildOptions)) { const background = path.join(this.buildResourcesDir, "background.png") const info = await statOrNull(background) if (info != null && info.isFile()) { diff --git a/src/packager.ts b/src/packager.ts index b0aa6fee4de..184227a1774 100644 --- a/src/packager.ts +++ b/src/packager.ts @@ -175,7 +175,8 @@ export function normalizeArchs(platform: Platform, arch?: string) { } } -export function normalizePlatforms(platforms: Array): Array { +export function normalizePlatforms(rawPlatforms: Array | string | Platform): Array { + const platforms = rawPlatforms == null || Array.isArray(rawPlatforms) ? (>rawPlatforms) : [rawPlatforms] if (platforms == null || platforms.length === 0) { return [Platform.fromString(process.platform)] } diff --git a/src/platformPackager.ts b/src/platformPackager.ts index 32108047c0f..2082984e8e7 100644 --- a/src/platformPackager.ts +++ b/src/platformPackager.ts @@ -72,7 +72,7 @@ export abstract class PlatformPackager readonly metadata: AppMetadata readonly devMetadata: DevMetadata - customBuildOptions: DC + readonly customBuildOptions: DC readonly appName: string @@ -85,9 +85,7 @@ export abstract class PlatformPackager this.devMetadata = info.devMetadata this.buildResourcesDir = path.resolve(this.projectDir, this.relativeBuildResourcesDirname) - - this.customBuildOptions = (info.devMetadata.build)[this.platform.buildConfigurationKey] - + this.customBuildOptions = (info.devMetadata.build)[this.platform.buildConfigurationKey] || Object.create(null) this.appName = getProductName(this.metadata, this.devMetadata) } @@ -109,12 +107,12 @@ export abstract class PlatformPackager pack(outDir: string, arch: string, postAsyncTasks: Array>): Promise { const appOutDir = this.computeAppOutDir(outDir, arch) - return this.doPack(this.computePackOptions(outDir, arch), outDir, appOutDir, arch, postAsyncTasks) + return this.doPack(this.computePackOptions(outDir, arch), outDir, appOutDir, arch, this.customBuildOptions, postAsyncTasks) } - protected async doPack(options: ElectronPackagerOptions, outDir: string, appOutDir: string, arch: string, postAsyncTasks: Array> = null) { + protected async doPack(options: ElectronPackagerOptions, outDir: string, appOutDir: string, arch: string, customBuildOptions: DC, postAsyncTasks: Array> = null) { await this.packApp(options, appOutDir) - await this.copyExtraResources(appOutDir, arch) + await this.copyExtraResources(appOutDir, arch, customBuildOptions) if (postAsyncTasks != null && this.options.dist) { postAsyncTasks.push(this.packageInDistributableFormat(outDir, appOutDir, arch)) } @@ -162,11 +160,11 @@ export abstract class PlatformPackager await this.sanityCheckPackage(appOutDir, options.asar) } - protected getExtraResources(arch: string): Promise> { + private getExtraResources(arch: string, customBuildOptions: DC): Promise> { const buildMetadata: any = this.devMetadata.build let extraResources: Array = buildMetadata == null ? null : buildMetadata.extraResources - const platformSpecificExtraResources = this.customBuildOptions == null ? null : this.customBuildOptions.extraResources + const platformSpecificExtraResources = customBuildOptions.extraResources if (platformSpecificExtraResources != null) { extraResources = extraResources == null ? platformSpecificExtraResources : extraResources.concat(platformSpecificExtraResources) } @@ -181,12 +179,12 @@ export abstract class PlatformPackager return globby(expandedPatterns, {cwd: this.projectDir}) } - protected async copyExtraResources(appOutDir: string, arch: string): Promise> { + protected async copyExtraResources(appOutDir: string, arch: string, customBuildOptions: DC): Promise> { let resourcesDir = appOutDir if (this.platform === Platform.OSX) { resourcesDir = this.getOSXResourcesDir(appOutDir) } - return await BluebirdPromise.map(await this.getExtraResources(arch), it => copy(path.join(this.projectDir, it), path.join(resourcesDir, it))) + return await BluebirdPromise.map(await this.getExtraResources(arch, customBuildOptions), it => copy(path.join(this.projectDir, it), path.join(resourcesDir, it))) } protected abstract packageInDistributableFormat(outDir: string, appOutDir: string, arch: string): Promise diff --git a/src/winPackager.ts b/src/winPackager.ts index aa7736d4c05..4ad8518c330 100644 --- a/src/winPackager.ts +++ b/src/winPackager.ts @@ -3,7 +3,7 @@ import { Promise as BluebirdPromise } from "bluebird" import { PlatformPackager, BuildInfo } from "./platformPackager" import { Platform, WinBuildOptions } from "./metadata" import * as path from "path" -import { log, statOrNull, use } from "./util" +import { log, statOrNull } from "./util" import { readFile, deleteFile, stat, rename, copy, emptyDir, writeFile, open, close, read } from "fs-extra-p" import { sign } from "signcode-tf" @@ -35,7 +35,7 @@ export class WinPackager extends PlatformPackager { this.iconPath = this.getValidIconPath() - if (this.options.dist && (this.customBuildOptions == null || this.customBuildOptions.loadingGif == null)) { + if (this.options.dist && this.customBuildOptions.loadingGif == null) { const installSpinnerPath = path.join(this.buildResourcesDir, "install-spinner.gif") this.loadingGifStat = statOrNull(installSpinnerPath) .then(it => it != null && !it.isDirectory() ? installSpinnerPath : null) @@ -68,7 +68,7 @@ export class WinPackager extends PlatformPackager { emptyDir(installerOut) ]) - const extraResources = await this.copyExtraResources(appOutDir, arch) + const extraResources = await this.copyExtraResources(appOutDir, arch, this.customBuildOptions) if (extraResources.length > 0) { this.extraNuGetFileSources = BluebirdPromise.map(extraResources, file => { return stat(file) @@ -104,23 +104,21 @@ export class WinPackager extends PlatformPackager { } protected async computeEffectiveDistOptions(appOutDir: string, installerOutDir: string): Promise { - let iconUrl = this.devMetadata.build.iconUrl - if (!iconUrl) { - use(this.customBuildOptions, it => iconUrl = it.iconUrl) - - if (!iconUrl && this.info.repositoryInfo != null) { + let iconUrl = this.customBuildOptions.iconUrl || this.devMetadata.build.iconUrl + if (iconUrl == null) { + if (this.info.repositoryInfo != null) { const info = await this.info.repositoryInfo.getInfo(this) if (info != null) { - iconUrl = `https://raw.githubusercontent.com/${info.user}/${info.project}/master/${this.relativeBuildResourcesDirname}/icon.ico` + iconUrl = `https://github.com/${info.user}/${info.project}/blob/master/${this.relativeBuildResourcesDirname}/icon.ico?raw=true` } } - if (!iconUrl) { - throw new Error("iconUrl is not specified, please see https://github.com/electron-userland/electron-builder#in-short") + if (iconUrl == null) { + throw new Error("iconUrl is not specified, please see https://github.com/electron-userland/electron-builder/wiki/Options#WinBuildOptions-iconUrl") } } - use(this.customBuildOptions, checkConflictingOptions) + checkConflictingOptions(this.customBuildOptions) const projectUrl = await this.computePackageUrl() const options: any = Object.assign({ diff --git a/test/fixtures/test-app-one/package.json b/test/fixtures/test-app-one/package.json index 1bf44396fa9..1bd432e4ac9 100755 --- a/test/fixtures/test-app-one/package.json +++ b/test/fixtures/test-app-one/package.json @@ -10,7 +10,7 @@ "author": "Foo Bar ", "license": "MIT", "devDependencies": { - "electron-prebuilt": "^0.37.7" + "electron-prebuilt": "^0.37.8" }, "build": { "app-bundle-id": "your.id", diff --git a/test/fixtures/test-app/package.json b/test/fixtures/test-app/package.json index a114c1d836c..2cfe0c21252 100755 --- a/test/fixtures/test-app/package.json +++ b/test/fixtures/test-app/package.json @@ -4,7 +4,7 @@ "start": "electron ." }, "devDependencies": { - "electron-prebuilt": "^0.37.7" + "electron-prebuilt": "^0.37.8" }, "build": { "app-bundle-id": "your.id", diff --git a/test/src/BuildTest.ts b/test/src/BuildTest.ts index 516cce282d0..3fa70194cf5 100755 --- a/test/src/BuildTest.ts +++ b/test/src/BuildTest.ts @@ -90,7 +90,7 @@ test("version from electron-prebuilt dependency", () => assertPack("test-app-one }, { tempDirCreated: projectDir => BluebirdPromise.all([ outputJson(path.join(projectDir, "node_modules", "electron-prebuilt", "package.json"), { - version: "0.37.7" + version: "0.37.8" }), modifyPackageJson(projectDir, data => { data.devDependencies = {} diff --git a/test/src/helpers/packTester.ts b/test/src/helpers/packTester.ts index 3692e7fbe66..bfc1b5b327a 100755 --- a/test/src/helpers/packTester.ts +++ b/test/src/helpers/packTester.ts @@ -24,7 +24,6 @@ if (process.env.TRAVIS !== "true") { export const outDirName = "dist" interface AssertPackOptions { - readonly useTempDir?: boolean readonly tempDirCreated?: (projectDir: string) => Promise readonly packed?: (projectDir: string) => Promise readonly expectedContents?: Array diff --git a/test/src/helpers/runTests.ts b/test/src/helpers/runTests.ts index e4da7448a25..b0bdb87a371 100755 --- a/test/src/helpers/runTests.ts +++ b/test/src/helpers/runTests.ts @@ -15,7 +15,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 = "0.37.7" +const electronVersion = "0.37.8" BluebirdPromise.all([ deleteOldElectronVersion(), diff --git a/test/src/osxPackagerTest.ts b/test/src/osxPackagerTest.ts index cd6f696e3ec..8392c0b5e32 100644 --- a/test/src/osxPackagerTest.ts +++ b/test/src/osxPackagerTest.ts @@ -7,6 +7,9 @@ import * as path from "path" import { BuildInfo } from "out/platformPackager" import { Promise as BluebirdPromise } from "bluebird" import * as assertThat from "should/as-function" +import ElectronPackagerOptions = ElectronPackager.ElectronPackagerOptions +import { OsXBuildOptions } from "out/metadata" +import { SignOptions, FlatOptions } from "electron-osx-sign-tf" //noinspection JSUnusedLocalSymbols const __awaiter = require("out/awaiter") @@ -19,7 +22,7 @@ test.ifOsx("two-package", () => assertPack("test-app", { test.ifOsx("one-package", () => assertPack("test-app-one", platform(Platform.OSX))) function createTargetTest(target: Array, expectedContents: Array) { - return () => assertPack("test-app-one", { + const options = { platform: [Platform.OSX], devMetadata: { build: { @@ -28,8 +31,8 @@ function createTargetTest(target: Array, expectedContents: Array } } } - }, { - useTempDir: true, + } + return () => assertPack("test-app-one", options, { expectedContents: expectedContents }) } @@ -41,6 +44,69 @@ test.ifOsx("invalid target", (t: any) => t.throws(createTargetTest(["ttt"], [])( test.ifOsx("mas", createTargetTest(["mas"], ["TestApp-1.1.0.pkg"])) test.ifOsx("mas and 7z", createTargetTest(["mas", "7z"], ["TestApp-1.1.0-osx.7z", "TestApp-1.1.0.pkg"])) +test.ifOsx("custom mas", () => { + let platformPackager: CheckingOsXPackager = null + return assertPack("test-app-one", { + platform: [Platform.OSX], + platformPackagerFactory: (packager, platform, cleanupTasks) => platformPackager = new CheckingOsXPackager(packager, cleanupTasks), + cscLink: null, + cscInstallerLink: null, + devMetadata: { + build: { + osx: { + identity: "osx", + target: ["mas"] + }, + mas: { + identity: "MAS", + entitlements: "mas-entitlements file path", + entitlementsInherit: "mas-entitlementsInherit file path", + } + } + } + }, { + packed: () => { + assertThat(platformPackager.effectiveSignOptions).has.properties({ + identity: "osx", + entitlements: "mas-entitlements file path", + "entitlements-inherit": "mas-entitlementsInherit file path", + }) + assertThat(platformPackager.effectiveFlatOptions).has.properties({ + identity: "MAS", + }) + return BluebirdPromise.resolve(null) + } + }) +}) + +test.ifOsx("identity in package.json", () => { + let platformPackager: CheckingOsXPackager = null + return assertPack("test-app-one", { + platform: [Platform.OSX], + platformPackagerFactory: (packager, platform, cleanupTasks) => platformPackager = new CheckingOsXPackager(packager, cleanupTasks), + cscLink: null, + cscInstallerLink: null, + devMetadata: { + build: { + osx: { + identity: "osx", + entitlements: "osx-entitlements file path", + entitlementsInherit: "osx-entitlementsInherit file path", + } + } + } + }, { + packed: () => { + assertThat(platformPackager.effectiveSignOptions).has.properties({ + identity: "osx", + entitlements: "osx-entitlements file path", + "entitlements-inherit": "osx-entitlementsInherit file path", + }) + return BluebirdPromise.resolve(null) + } + }) +}) + // test.ifOsx("no background", (t: any) => assertPack("test-app-one", platform(Platform.OSX), { // tempDirCreated: projectDir => deleteFile(path.join(projectDir, "build", "background.png")) // })) @@ -71,16 +137,26 @@ test.ifOsx("custom background", () => { class CheckingOsXPackager extends OsXPackager { effectiveDistOptions: any + effectiveSignOptions: SignOptions + effectiveFlatOptions: FlatOptions constructor(info: BuildInfo, cleanupTasks: Array<() => Promise>) { super(info, cleanupTasks) } - async pack(outDir: string, arch: string): Promise { + async doPack(options: ElectronPackagerOptions, outDir: string, appOutDir: string, arch: string, customBuildOptions: OsXBuildOptions, postAsyncTasks: Array> = null) { // skip pack this.effectiveDistOptions = await this.computeEffectiveDistOptions(this.computeAppOutDir(outDir, arch)) } + async doSign(opts: SignOptions): Promise { + this.effectiveSignOptions = opts + } + + async doFlat(opts: FlatOptions): Promise { + this.effectiveFlatOptions = opts + } + async packageInDistributableFormat(outDir: string, appOutDir: string, arch: string): Promise { // skip } diff --git a/test/tsconfig.json b/test/tsconfig.json index e1e9718af3e..b1da0dd092a 100755 --- a/test/tsconfig.json +++ b/test/tsconfig.json @@ -24,7 +24,8 @@ "src/**/*.ts", "../node_modules/fs-extra-p/index.d.ts", "../node_modules/fs-extra-p/bluebird.d.ts", - "out/electron-builder.d.ts" + "out/electron-builder.d.ts", + "../node_modules/electron-osx-sign-tf/index.d.ts" ], "files": [ "../typings/appdmg.d.ts", @@ -55,6 +56,7 @@ "../node_modules/fs-extra-p/index.d.ts", "../node_modules/fs-extra-p/bluebird.d.ts", "out/electron-builder.d.ts", + "../node_modules/electron-osx-sign-tf/index.d.ts", "src/ArtifactPublisherTest.ts", "src/BuildTest.ts", "src/CodeSignTest.ts", diff --git a/typings/deep-assign.d.ts b/typings/deep-assign.d.ts index 8325c9bff04..2dcd705c21e 100644 --- a/typings/deep-assign.d.ts +++ b/typings/deep-assign.d.ts @@ -1,5 +1,7 @@ declare module "deep-assign" { function deepAssign(target: T, source: U): T & U + function deepAssign(target: T, source: U, source2: U): T & U + export = deepAssign } \ No newline at end of file