diff --git a/.idea/dictionaries/develar.xml b/.idea/dictionaries/develar.xml
index 83574acb2ac..caa8feae166 100644
--- a/.idea/dictionaries/develar.xml
+++ b/.idea/dictionaries/develar.xml
@@ -29,6 +29,7 @@
passin
pkcs
postinstall
+ productbuild
promisify
repos
rimraf
diff --git a/.idea/runConfigurations/CodeSignTest.xml b/.idea/runConfigurations/CodeSignTest.xml
new file mode 100644
index 00000000000..f1065afd29f
--- /dev/null
+++ b/.idea/runConfigurations/CodeSignTest.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index 14543e7c188..754411cea37 100755
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@ 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](#code-signing) on a CI server or development machine.
+* [Code Signing](https://github.com/electron-userland/electron-builder/wiki/Code-Signing) on a CI server or development machine.
* [Build version management](#build-version-management).
* [Publishing artifacts to GitHub Releases](https://github.com/electron-userland/electron-builder/wiki/Publishing-Artifacts).
@@ -86,25 +86,6 @@ Please note — packaged into an asar archive [by default](https://github.com/el
You need to deploy somewhere releases/downloads server.
Consider to use [Nuts](https://github.com/GitbookIO/nuts) (GitHub as a backend to store assets) or [Electron Release Server](https://github.com/ArekSredzki/electron-release-server).
-# Code Signing
-OS X and Windows code singing is supported.
-On a development machine set environment variable `CSC_NAME` to your identity (recommended). Or pass `--sign` parameter.
-```
-export CSC_NAME="Developer ID Application: Your Name (code)"
-```
-
-## Travis, AppVeyor and other CI servers
-To sign app on build server:
-
-1. [Export](https://developer.apple.com/library/ios/documentation/IDEs/Conceptual/AppDistributionGuide/MaintainingCertificates/MaintainingCertificates.html#//apple_ref/doc/uid/TP40012582-CH31-SW7) certificate.
- [Strong password](http://security.stackexchange.com/a/54773) must be used. Consider to not use special characters (for bash) because “*values are not escaped when your builds are executed*”.
-2. Upload `*.p12` file (e.g. on [Google Drive](http://www.syncwithtech.org/p/direct-download-link-generator.html)).
-3. Set ([Travis](https://docs.travis-ci.com/user/environment-variables/#Encrypted-Variables) or [AppVeyor](https://ci.appveyor.com/tools/encrypt)) `CSC_LINK` and `CSC_KEY_PASSWORD` environment variables:
-```
-travis encrypt "CSC_LINK='https://drive.google.com/uc?export=download&id=***'" --add
-travis encrypt 'CSC_KEY_PASSWORD=beAwareAboutBashEscaping!!!' --add
-```
-
# Build Version Management
`CFBundleVersion` (OS X) and `FileVersion` (Windows) will be set automatically to `version`.`build_number` on CI server (Travis, AppVeyor and CircleCI supported).
diff --git a/docs/Code Signing.md b/docs/Code Signing.md
new file mode 100644
index 00000000000..e63339534a4
--- /dev/null
+++ b/docs/Code Signing.md
@@ -0,0 +1,28 @@
+OS X and Windows code singing is supported.
+
+On a development machine set environment variable `CSC_NAME` (and `CSC_INSTALLER_NAME` if you build for Mac App Store) to your identity.
+
+| Env name | Description
+| -------------- | -----------
+| `CSC_LINK` | The HTTPS link to certificate (`*.p12` file).
+| `CSC_KEY_PASSWORD` | The password to decrypt the certificate given in `CSC_LINK`.
+| `CSC_INSTALLER_LINK` | *osx-only* The HTTPS link to certificate to sign Mac App Store build (`*.p12` file).
+| `CSC_INSTALLER_KEY_PASSWORD` | *osx-only* The password to decrypt the certificate given in `CSC_INSTALLER_LINK`.
+| `CSC_NAME` | *osx-only* Name of certificate (to retrieve from login.keychain). Useful on a development machine (not on CI).
+| `CSC_INSTALLER_NAME` | *osx-only* Name of installer certificate (to retrieve from login.keychain). Useful on a development machine (not on CI).
+
+```
+export CSC_NAME="Developer ID Application: Your Name (code)"
+```
+
+## Travis, AppVeyor and other CI servers
+To sign app on build server you need to set `CSC_LINK`, `CSC_KEY_PASSWORD` (and `CSC_INSTALLER_LINK`, `CSC_INSTALLER_KEY_PASSWORD` if you build for Mac App Store):
+
+1. [Export](https://developer.apple.com/library/ios/documentation/IDEs/Conceptual/AppDistributionGuide/MaintainingCertificates/MaintainingCertificates.html#//apple_ref/doc/uid/TP40012582-CH31-SW7) certificate.
+ [Strong password](http://security.stackexchange.com/a/54773) must be used. Consider to not use special characters (for bash) because “*values are not escaped when your builds are executed*”.
+2. Upload `*.p12` file (e.g. on [Google Drive](http://www.syncwithtech.org/p/direct-download-link-generator.html)).
+3. Set ([Travis](https://docs.travis-ci.com/user/environment-variables/#Encrypted-Variables) or [AppVeyor](https://ci.appveyor.com/tools/encrypt)) `CSC_LINK` and `CSC_KEY_PASSWORD` environment variables:
+```
+travis encrypt "CSC_LINK='https://drive.google.com/uc?export=download&id=***'" --add
+travis encrypt 'CSC_KEY_PASSWORD=beAwareAboutBashEscaping!!!' --add
+```
\ No newline at end of file
diff --git a/docs/Options.md b/docs/Options.md
index 3d0d9381b73..a4b11949bb5 100644
--- a/docs/Options.md
+++ b/docs/Options.md
@@ -53,7 +53,7 @@ Here documented only `electron-builder` specific options:
| app-bundle-id | *OS X-only.* The bundle identifier to use in the application's plist.
| 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.
- 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/${user}/${project}/master/build/icon.ico
by default.
+| 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.
- 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.
| 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).
@@ -70,7 +70,7 @@ 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`).
-| target | Target package type: list of `default`, `dmg`, `zip`.
+| target | Target package type: list of `default`, `dmg`, `zip`, `mas`.
### `.build.win`
diff --git a/package.json b/package.json
index 7efd17e2eb8..6898d9aa0cc 100644
--- a/package.json
+++ b/package.json
@@ -58,7 +58,8 @@
"chalk": "^1.1.3",
"command-line-args": "^2.1.6",
"deep-assign": "^2.0.0",
- "electron-packager": "^7.0.1",
+ "electron-osx-sign-tf": "^0.4.0-beta.0",
+ "electron-packager-tf": "^7.0.2-beta.0",
"electron-winstaller-fixed": "~2.3.0-beta.4",
"fs-extra-p": "^0.3.0",
"globby": "^4.0.0",
diff --git a/src/codeSign.ts b/src/codeSign.ts
index f639e32ea4a..b3baf54e4cb 100644
--- a/src/codeSign.ts
+++ b/src/codeSign.ts
@@ -11,8 +11,10 @@ import { randomBytes } from "crypto"
const __awaiter = require("./awaiter")
export interface CodeSigningInfo {
- cscName: string
- cscKeychainName?: string
+ name: string
+ keychainName?: string
+
+ installerName?: string
}
function randomString(): string {
@@ -23,29 +25,30 @@ export function generateKeychainName(): string {
return "csc-" + randomString() + ".keychain"
}
-export function createKeychain(keychainName: string, cscLink: string, cscKeyPassword: string, csaLink?: string): Promise {
- const authorityCerts = [csaLink || "https://developer.apple.com/certificationauthority/AppleWWDRCA.cer"]
+export function createKeychain(keychainName: string, cscLink: string, cscKeyPassword: string, cscILink?: string, cscIKeyPassword?: string, csaLink?: string): Promise {
+ const certLinks = [csaLink || "https://developer.apple.com/certificationauthority/AppleWWDRCA.cer"]
if (csaLink == null) {
- authorityCerts.push("https://startssl.com/certs/sca.code2.crt", "https://startssl.com/certs/sca.code3.crt")
+ certLinks.push("https://startssl.com/certs/sca.code2.crt", "https://startssl.com/certs/sca.code3.crt")
}
- const authorityCertPaths = authorityCerts.map(() => path.join(tmpdir(), randomString() + ".cer"))
- const developerCertPath = path.join(tmpdir(), randomString() + ".p12")
+ certLinks.push(cscLink)
+ if (cscILink != null) {
+ certLinks.push(cscILink)
+ }
+ const certPaths = certLinks.map(it => path.join(tmpdir(), randomString() + (it.endsWith(".cer") ? ".cer" : ".p12")))
const keychainPassword = randomString()
return executeFinally(BluebirdPromise.all([
- BluebirdPromise.map(authorityCertPaths, (p, i) => download(authorityCerts[i], p)),
- download(cscLink, developerCertPath),
+ BluebirdPromise.map(certPaths, (p, i) => download(certLinks[i], p)),
BluebirdPromise.mapSeries([
["create-keychain", "-p", keychainPassword, keychainName],
["unlock-keychain", "-p", keychainPassword, keychainName],
["set-keychain-settings", "-t", "3600", "-u", keychainName]
], it => exec("security", it))
])
- .then(() => importCerts(keychainName, authorityCertPaths, developerCertPath, cscKeyPassword)),
+ .then(() => importCerts(keychainName, certPaths, [cscKeyPassword, cscIKeyPassword].filter(it => it != null))),
errorOccurred => {
- const tasks = authorityCertPaths.map(it => deleteFile(it, true))
- tasks.push(deleteFile(developerCertPath, true))
+ const tasks = certPaths.map(it => deleteFile(it, true))
if (errorOccurred) {
tasks.push(deleteKeychain(keychainName))
}
@@ -53,15 +56,25 @@ export function createKeychain(keychainName: string, cscLink: string, cscKeyPass
})
}
-async function importCerts(keychainName: string, authorityCertPaths: Array, developerCertPath: string, cscKeyPassword: string): Promise {
- for (let p of authorityCertPaths) {
- await exec("security", ["import", p, "-k", keychainName, "-T", "/usr/bin/codesign"])
+async function importCerts(keychainName: string, paths: Array, keyPasswords: Array): Promise {
+ for (let f of paths.slice(0, -keyPasswords.length)) {
+ await exec("security", ["import", f, "-k", keychainName, "-T", "/usr/bin/codesign"])
+ }
+
+ const namePromises: Array> = []
+ for (let i = paths.length - keyPasswords.length, j = 0; i < paths.length; i++, j++) {
+ const password = keyPasswords[j]
+ const certPath = paths[i]
+ await exec("security", ["import", certPath, "-k", keychainName, "-T", "/usr/bin/codesign", "-T", "/usr/bin/productbuild", "-P", password])
+
+ namePromises.push(extractCommonName(password, certPath))
}
- await exec("security", ["import", developerCertPath, "-k", keychainName, "-T", "/usr/bin/codesign", "-P", cscKeyPassword])
- let cscName = await extractCommonName(cscKeyPassword, developerCertPath)
+
+ const names = await BluebirdPromise.all(namePromises)
return {
- cscName: cscName,
- cscKeychainName: keychainName
+ name: names[0],
+ installerName: names.length > 1 ? names[1] : null,
+ keychainName: keychainName,
}
}
@@ -79,9 +92,9 @@ function extractCommonName(password: string, certPath: string): BluebirdPromise<
}
export function sign(path: string, options: CodeSigningInfo): BluebirdPromise {
- const args = ["--deep", "--force", "--sign", options.cscName, path]
- if (options.cscKeychainName != null) {
- args.push("--keychain", options.cscKeychainName)
+ const args = ["--deep", "--force", "--sign", options.name, path]
+ if (options.keychainName != null) {
+ args.push("--keychain", options.keychainName)
}
return exec("codesign", args)
}
diff --git a/src/macPackager.ts b/src/macPackager.ts
index 4325f9b6b03..d5f191594cd 100644
--- a/src/macPackager.ts
+++ b/src/macPackager.ts
@@ -3,9 +3,10 @@ import { Platform, OsXBuildOptions } from "./metadata"
import * as path from "path"
import { Promise as BluebirdPromise } from "bluebird"
import { log, spawn, statOrNull } from "./util"
-import { createKeychain, deleteKeychain, CodeSigningInfo, generateKeychainName, sign } from "./codeSign"
+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"
//noinspection JSUnusedLocalSymbols
const __awaiter = require("./awaiter")
@@ -21,7 +22,7 @@ export default class OsXPackager extends PlatformPackager {
if (this.options.cscLink != null && this.options.cscKeyPassword != null) {
const keychainName = generateKeychainName()
cleanupTasks.push(() => deleteKeychain(keychainName))
- this.codeSigningInfo = createKeychain(keychainName, this.options.cscLink, this.options.cscKeyPassword, this.options.csaLink)
+ this.codeSigningInfo = createKeychain(keychainName, this.options.cscLink, this.options.cscKeyPassword, this.options.cscInstallerLink, this.options.cscInstallerKeyPassword, this.options.csaLink)
}
else {
this.codeSigningInfo = BluebirdPromise.resolve(null)
@@ -32,7 +33,7 @@ export default class OsXPackager extends PlatformPackager {
target = Array.isArray(target) ? target : [target]
target = target.map(it => it.toLowerCase().trim())
for (let t of target) {
- if (t !== "default" && t !== "dmg" && t !== "zip") {
+ if (t !== "default" && t !== "dmg" && t !== "zip" && t !== "mas") {
throw new Error("Unknown target: " + t)
}
}
@@ -44,23 +45,63 @@ export default class OsXPackager extends PlatformPackager {
return Platform.OSX
}
- async pack(outDir: string, appOutDir: string, arch: string): Promise {
- await super.pack(outDir, appOutDir, arch)
- await this.signMac(path.join(appOutDir, this.appName + ".app"), await this.codeSigningInfo)
+ protected computeAppOutDir(outDir: string, arch: string): string {
+ return this.target.includes("mas") ? path.join(outDir, `${this.appName}-mas-${arch}`) : super.computeAppOutDir(outDir, arch)
}
- private signMac(distPath: string, codeSigningInfo: CodeSigningInfo): Promise {
+ async doPack(outDir: string, appOutDir: string, arch: string): Promise {
+ await super.doPack(outDir, appOutDir, arch)
+ await this.sign(appOutDir, await this.codeSigningInfo)
+ }
+
+ protected beforePack(options: any): void {
+ if (this.target.includes("mas")) {
+ options.platform = "mas"
+ }
+ // disable warning
+ options["osx-sign"] = false
+ }
+
+ private async sign(appOutDir: string, codeSigningInfo: CodeSigningInfo): Promise {
if (codeSigningInfo == null) {
- codeSigningInfo = {cscName: this.options.sign || process.env.CSC_NAME}
+ codeSigningInfo = {
+ name: this.options.sign || process.env.CSC_NAME,
+ installerName: this.options.sign || process.env.CSC_INSTALLER_NAME,
+ }
}
- if (codeSigningInfo.cscName == null) {
+ if (codeSigningInfo.name == null) {
log("App is not signed: CSC_LINK or CSC_NAME are not specified")
- return BluebirdPromise.resolve()
+ return
}
- else {
- log("Signing app")
- return sign(distPath, codeSigningInfo)
+
+ log("Signing app")
+
+ const isMas = this.target.includes("mas")
+ const baseSignOptions: BaseSignOptions = {
+ app: path.join(appOutDir, this.appName + ".app"),
+ platform: isMas ? "mas" : "darwin"
+ }
+ if (codeSigningInfo.keychainName != null) {
+ baseSignOptions.keychain = codeSigningInfo.keychainName
+ }
+
+ await BluebirdPromise.promisify(sign)(Object.assign({
+ identity: codeSigningInfo.name,
+ }, (this.devMetadata.build)["osx-sign"], baseSignOptions))
+
+ if (isMas) {
+ 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({
+ pkg: pkg,
+ identity: installerIdentity,
+ }, baseSignOptions))
+ this.dispatchArtifactCreated(pkg, `${this.metadata.name}-${this.metadata.version}.pkg`)
}
}
diff --git a/src/metadata.ts b/src/metadata.ts
index b81e2fd8da9..5f90454249a 100755
--- a/src/metadata.ts
+++ b/src/metadata.ts
@@ -158,7 +158,7 @@ export interface OsXBuildOptions extends PlatformSpecificBuildOptions {
readonly background?: string
/*
- Target package type: list of `default`, `dmg`, `zip`.
+ Target package type: list of `default`, `dmg`, `zip`, `mas`.
*/
readonly target?: Array
}
diff --git a/src/packager.ts b/src/packager.ts
index 9942ee7a44e..700033ce398 100644
--- a/src/packager.ts
+++ b/src/packager.ts
@@ -35,9 +35,6 @@ export class Packager implements BuildInfo {
//noinspection JSUnusedGlobalSymbols
constructor(public options: PackagerOptions, public repositoryInfo: InfoRetriever = null) {
this.projectDir = options.projectDir == null ? process.cwd() : path.resolve(options.projectDir)
- if (this.appDir === this.projectDir) {
- this.isTwoPackageJsonProjectLayoutUsed = false
- }
}
artifactCreated(handler: (event: ArtifactCreated) => void): Packager {
@@ -55,6 +52,9 @@ export class Packager implements BuildInfo {
this.devMetadata = deepAssign(await readPackageJson(devPackageFile), this.options.devMetadata)
this.appDir = await computeDefaultAppDirectory(this.projectDir, use(this.devMetadata.directories, it => it.app) || this.options.appDir)
+
+ this.isTwoPackageJsonProjectLayoutUsed = this.appDir !== this.projectDir
+
const appPackageFile = this.projectDir === this.appDir ? devPackageFile : path.join(this.appDir, "package.json")
this.metadata = appPackageFile === devPackageFile ? this.devMetadata : await readPackageJson(appPackageFile)
this.checkMetadata(appPackageFile, devPackageFile, platforms)
@@ -74,8 +74,7 @@ export class Packager implements BuildInfo {
for (let arch of normalizeArchs(platform, this.options.arch)) {
await this.installAppDependencies(platform, arch)
// electron-packager uses productName in the directory name
- const appOutDir = path.join(outDir, `${helper.appName}-${platform.nodeName}-${arch}`)
- await helper.pack(outDir, appOutDir, arch)
+ const appOutDir = await helper.pack(outDir, arch)
if (this.options.dist) {
distTasks.push(helper.packageInDistributableFormat(outDir, appOutDir, arch))
}
diff --git a/src/platformPackager.ts b/src/platformPackager.ts
index 24eba5b9f48..5dfebfa0143 100644
--- a/src/platformPackager.ts
+++ b/src/platformPackager.ts
@@ -3,7 +3,7 @@ import { AppMetadata, DevMetadata, Platform, PlatformSpecificBuildOptions, getPr
import EventEmitter = NodeJS.EventEmitter
import { Promise as BluebirdPromise } from "bluebird"
import * as path from "path"
-import packager = require("electron-packager")
+import packager = require("electron-packager-tf")
import globby = require("globby")
import { copy } from "fs-extra-p"
import { statOrNull, use } from "./util"
@@ -34,6 +34,9 @@ export interface PackagerOptions {
csaLink?: string
cscKeyPassword?: string
+ cscInstallerLink?: string
+ cscInstallerKeyPassword?: string
+
platformPackagerFactory?: (packager: Packager, platform: Platform, cleanupTasks: Array<() => Promise>) => PlatformPackager
/**
@@ -90,6 +93,10 @@ export abstract class PlatformPackager
return use(this.devMetadata.directories, it => it.buildResources) || "build"
}
+ protected computeAppOutDir(outDir: string, arch: string): string {
+ return path.join(outDir, `${this.appName}-${this.platform.nodeName}-${arch}`)
+ }
+
protected dispatchArtifactCreated(file: string, artifactName?: string) {
this.info.eventEmitter.emit("artifactCreated", {
file: file,
@@ -98,12 +105,18 @@ export abstract class PlatformPackager
})
}
- async pack(outDir: string, appOutDir: string, arch: string): Promise {
+ async pack(outDir: string, arch: string): Promise {
+ const appOutDir = this.computeAppOutDir(outDir, arch)
await this.doPack(outDir, appOutDir, arch)
await this.copyExtraResources(appOutDir, arch)
+ return appOutDir
+ }
+
+ protected beforePack(options: any): void {
+ // to override
}
- protected async doPack(outDir: string, appOutDir: string, arch: string) {
+ protected async doPack(outDir: string, appOutDir: string, arch: string): Promise {
const version = this.metadata.version
let buildVersion = version
const buildNumber = this.computeBuildNumber()
@@ -140,6 +153,7 @@ export abstract class PlatformPackager
// this option only for windows-installer
delete options.iconUrl
+ this.beforePack(options)
await pack(options)
const outStat = await statOrNull(appOutDir)
diff --git a/src/winPackager.ts b/src/winPackager.ts
index 2d9a150c8dc..597bf14ad50 100644
--- a/src/winPackager.ts
+++ b/src/winPackager.ts
@@ -52,14 +52,15 @@ export class WinPackager extends PlatformPackager {
return iconPath
}
- async pack(outDir: string, appOutDir: string, arch: string): Promise {
+ async pack(outDir: string, arch: string): Promise {
// we must check icon before pack because electron-packager uses icon and it leads to cryptic error message "spawn wine ENOENT"
await this.iconPath
if (!this.options.dist) {
- return await super.pack(outDir, appOutDir, arch)
+ return await super.pack(outDir, arch)
}
+ const appOutDir = this.computeAppOutDir(outDir, arch)
const installerOut = computeDistOut(outDir, arch)
log("Removing %s", installerOut)
await BluebirdPromise.all([
@@ -78,6 +79,8 @@ export class WinPackager extends PlatformPackager {
})
})
}
+
+ return appOutDir
}
protected async doPack(outDir: string, appOutDir: string, arch: string) {
diff --git a/test/README.md b/test/README.md
index e288ed823cd..4c951d545d0 100755
--- a/test/README.md
+++ b/test/README.md
@@ -2,4 +2,7 @@ In addition to [required system packages](./multi-platform-build.md), on OS X `d
# Inspect output if test uses temporary directory
Set environment variable `TEST_APP_TMP_DIR` (e.g. `/tmp/electron-builder-test`).
-Specified directory will be used instead of random temporary directory and *cleared* on each run.
\ No newline at end of file
+Specified directory will be used instead of random temporary directory and *cleared* on each run.
+
+# Test Code Signing Ceritificates
+If test installer certificate is expired: http://security.stackexchange.com/questions/17909/how-to-create-an-apple-installer-package-signing-certificate
\ No newline at end of file
diff --git a/test/fixtures/test-app-one/package.json b/test/fixtures/test-app-one/package.json
index 13d4461e79d..1bf44396fa9 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.6"
+ "electron-prebuilt": "^0.37.7"
},
"build": {
"app-bundle-id": "your.id",
diff --git a/test/fixtures/test-app/package.json b/test/fixtures/test-app/package.json
index 3d33310dde1..a114c1d836c 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.6"
+ "electron-prebuilt": "^0.37.7"
},
"build": {
"app-bundle-id": "your.id",
diff --git a/test/src/BuildTest.ts b/test/src/BuildTest.ts
index 651078647d6..84153cf946d 100755
--- a/test/src/BuildTest.ts
+++ b/test/src/BuildTest.ts
@@ -52,7 +52,7 @@ test("version from electron-prebuilt dependency", () => assertPack("test-app-one
tempDirCreated: projectDir => {
return BluebirdPromise.all([
outputJson(path.join(projectDir, "node_modules", "electron-prebuilt", "package.json"), {
- version: "0.37.6"
+ version: "0.37.7"
}),
modifyPackageJson(projectDir, data => {
data.devDependencies = {}
diff --git a/test/src/CodeSignTest.ts b/test/src/CodeSignTest.ts
index 619fe64c18c..bae8e7c62af 100644
--- a/test/src/CodeSignTest.ts
+++ b/test/src/CodeSignTest.ts
@@ -1,17 +1,31 @@
import { createKeychain, deleteKeychain, generateKeychainName } from "out/codeSign"
import * as assertThat from "should/as-function"
import test from "./helpers/avaEx"
-import { CSC_NAME, CSC_LINK, CSC_KEY_PASSWORD } from "./helpers/codeSignData"
+import {
+ CSC_NAME, CSC_LINK,
+ CSC_KEY_PASSWORD,
+ CSC_INSTALLER_KEY_PASSWORD,
+ CSC_INSTALLER_LINK
+} from "./helpers/codeSignData"
import { executeFinally, all } from "out/promise"
//noinspection JSUnusedLocalSymbols
const __awaiter = require("out/awaiter")
-test.ifOsx("create keychain", async (t) => {
+test.ifOsx("create keychain", async () => {
const keychainName = generateKeychainName()
await executeFinally(createKeychain(keychainName, CSC_LINK, CSC_KEY_PASSWORD)
.then(result => {
- assertThat(result.cscKeychainName).not.empty()
- assertThat(result.cscName).equal(CSC_NAME)
+ assertThat(result.keychainName).not.empty()
+ assertThat(result.name).equal(CSC_NAME)
+ }), () => all([deleteKeychain(keychainName)]))
+})
+
+test.ifOsx("create keychain with installers", async () => {
+ const keychainName = generateKeychainName()
+ await executeFinally(createKeychain(keychainName, CSC_LINK, CSC_KEY_PASSWORD, CSC_INSTALLER_LINK, CSC_INSTALLER_KEY_PASSWORD)
+ .then(result => {
+ assertThat(result.keychainName).not.empty()
+ assertThat(result.name).equal(CSC_NAME)
}), () => all([deleteKeychain(keychainName)]))
})
\ No newline at end of file
diff --git a/test/src/helpers/codeSignData.ts b/test/src/helpers/codeSignData.ts
index f41aed0c1bd..c655353961e 100644
--- a/test/src/helpers/codeSignData.ts
+++ b/test/src/helpers/codeSignData.ts
@@ -1,3 +1,7 @@
export const CSC_LINK = "https://www.dropbox.com/s/86zaffzbao198xe/test.p12?dl=1"
export const CSC_KEY_PASSWORD = "password"
+
+export const CSC_INSTALLER_LINK = "https://www.dropbox.com/s/2drwf5owgoqxkr3/test-installer.p12?dl=1"
+export const CSC_INSTALLER_KEY_PASSWORD = "password"
+
export const CSC_NAME = "Test Test"
\ No newline at end of file
diff --git a/test/src/helpers/packTester.ts b/test/src/helpers/packTester.ts
index cab98045812..cf7a058fabb 100755
--- a/test/src/helpers/packTester.ts
+++ b/test/src/helpers/packTester.ts
@@ -2,7 +2,7 @@ import { copy, emptyDir, remove, writeJson, readJson, readFile } from "fs-extra-
import * as assertThat from "should/as-function"
import * as path from "path"
import { parse as parsePlist } from "plist"
-import { CSC_LINK, CSC_KEY_PASSWORD } from "./codeSignData"
+import { CSC_LINK, CSC_KEY_PASSWORD, CSC_INSTALLER_LINK, CSC_INSTALLER_KEY_PASSWORD } from "./codeSignData"
import { expectedLinuxContents, expectedWinContents } from "./expectedContents"
import { Packager, PackagerOptions, Platform, getProductName, ArtifactCreated } from "out"
import { exec } from "out/util"
@@ -62,6 +62,8 @@ export async function assertPack(fixtureName: string, packagerOptions: PackagerO
projectDir: projectDir,
cscLink: CSC_LINK,
cscKeyPassword: CSC_KEY_PASSWORD,
+ cscInstallerLink: CSC_INSTALLER_LINK,
+ cscInstallerKeyPassword: CSC_INSTALLER_KEY_PASSWORD,
dist: true,
}, packagerOptions), checkOptions)
diff --git a/test/src/helpers/runTests.ts b/test/src/helpers/runTests.ts
index 66ee98ce451..e4da7448a25 100755
--- a/test/src/helpers/runTests.ts
+++ b/test/src/helpers/runTests.ts
@@ -2,6 +2,7 @@ import { spawn } from "child_process"
import * as path from "path"
import { Promise as BluebirdPromise } from "bluebird"
import * as fs from "fs-extra-p"
+import { Platform } from "out/metadata";
// we set NODE_PATH in this file, so, we cannot use 'out/awaiter' path here
//noinspection JSUnusedLocalSymbols
@@ -14,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.6"
+const electronVersion = "0.37.7"
BluebirdPromise.all([
deleteOldElectronVersion(),
@@ -65,12 +66,18 @@ function deleteOldElectronVersion(): Promise {
function downloadAllRequiredElectronVersions(): Promise {
const downloadPromises: Array> = []
- for (let platform of packager.normalizePlatforms(["all"])) {
- for (let arch of packager.normalizeArchs(platform)) {
+
+ const platforms = packager.normalizePlatforms(["all"]).map((it: Platform) => it.nodeName)
+ if (process.platform === "darwin") {
+ platforms.push("mas")
+ }
+
+ for (let platform of platforms) {
+ for (let arch of (platform === "mas" || platform === "darwin" ? ["x64"] : ["ia32", "x64"])) {
downloadPromises.push(downloadElectron({
version: electronVersion,
arch: arch,
- platform: platform.nodeName,
+ platform: platform,
}))
}
}
diff --git a/test/src/osxPackagerTest.ts b/test/src/osxPackagerTest.ts
index b9428f1e7eb..ae2a57b1cb9 100644
--- a/test/src/osxPackagerTest.ts
+++ b/test/src/osxPackagerTest.ts
@@ -11,12 +11,12 @@ import * as assertThat from "should/as-function"
//noinspection JSUnusedLocalSymbols
const __awaiter = require("out/awaiter")
-test.ifOsx("two-package.json", () => assertPack("test-app", {
+test.ifOsx("two-package", () => assertPack("test-app", {
platform: [Platform.OSX],
arch: "all",
}))
-test.ifOsx("one-package.json", () => assertPack("test-app-one", platform(Platform.OSX)))
+test.ifOsx("one-package", () => assertPack("test-app-one", platform(Platform.OSX)))
function createTargetTest(target: string, expectedContents: Array) {
return () => assertPack("test-app-one", {
@@ -38,6 +38,8 @@ test.ifOsx("only dmg", createTargetTest("dmg", ["TestApp-1.1.0.dmg"]))
test.ifOsx("only zip", createTargetTest("zip", ["TestApp-1.1.0-mac.zip"]))
test.ifOsx("invalid target", (t: any) => t.throws(createTargetTest("ttt", [])(), "Unknown target: ttt"))
+test.ifOsx("mas", createTargetTest("mas", ["TestApp-1.1.0.pkg"]))
+
// test.ifOsx("no background", (t: any) => assertPack("test-app-one", platform(Platform.OSX), {
// tempDirCreated: projectDir => deleteFile(path.join(projectDir, "build", "background.png"))
// }))
@@ -73,8 +75,9 @@ class CheckingOsXPackager extends OsXPackager {
super(info, cleanupTasks)
}
- async pack(outDir: string, appOutDir: string, arch: string): Promise {
+ async pack(outDir: string, arch: string): Promise {
// skip pack
+ return this.computeAppOutDir(outDir, arch)
}
async packageInDistributableFormat(outDir: string, appOutDir: string, arch: string): Promise {
diff --git a/test/src/winPackagerTest.ts b/test/src/winPackagerTest.ts
index a568cdc7c02..b264777bbbb 100755
--- a/test/src/winPackagerTest.ts
+++ b/test/src/winPackagerTest.ts
@@ -78,8 +78,9 @@ class CheckingWinPackager extends WinPackager {
super(info, cleanupTasks)
}
- async pack(outDir: string, appOutDir: string, arch: string): Promise {
+ async pack(outDir: string, arch: string): Promise {
// skip pack
+ return this.computeAppOutDir(outDir, arch)
}
async packageInDistributableFormat(outDir: string, appOutDir: string, arch: string): Promise {
diff --git a/tsconfig.json b/tsconfig.json
index a0444327be6..8a3da7e9bdb 100755
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -28,7 +28,8 @@
"node_modules/typescript/lib/lib.es7.d.ts",
"node_modules/fs-extra-p/index.d.ts",
"node_modules/7zip-bin/index.d.ts",
- "node_modules/fs-extra-p/bluebird.d.ts"
+ "node_modules/fs-extra-p/bluebird.d.ts",
+ "node_modules/electron-osx-sign-tf/index.d.ts"
],
"files": [
"typings/appdmg.d.ts",
@@ -51,6 +52,7 @@
"node_modules/fs-extra-p/index.d.ts",
"node_modules/7zip-bin/index.d.ts",
"node_modules/fs-extra-p/bluebird.d.ts",
+ "node_modules/electron-osx-sign-tf/index.d.ts",
"src/awaiter.ts",
"src/build-cli.ts",
"src/builder.ts",
diff --git a/typings/electron-packager.d.ts b/typings/electron-packager.d.ts
index a25e89fc8a7..b6a167332b9 100644
--- a/typings/electron-packager.d.ts
+++ b/typings/electron-packager.d.ts
@@ -105,7 +105,7 @@ declare namespace ElectronPackager {
}
}
-declare module "electron-packager" {
+declare module "electron-packager-tf" {
const packager: ElectronPackager.Packager;
export = packager;
}