Skip to content

Commit 138e8e2

Browse files
committedSep 2, 2016
feat: bintray publisher
Closes #577
1 parent eb827ea commit 138e8e2

12 files changed

+126
-45
lines changed
 

‎docs/NSIS.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# 32 bit + 64 bit
22

3-
If you build both ia32 and xha arch, you in any case get one installer. Appropriate arch will be installed automatically.
3+
If you build both ia32 and x64 arch, you in any case get one installer. Appropriate arch will be installed automatically.
44

55
# Custom NSIS script
66

‎src/builder.ts

+79-34
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,16 @@ import { PublishOptions, Publisher } from "./publish/publisher"
44
import { GitHubPublisher } from "./publish/gitHubPublisher"
55
import { executeFinally } from "./util/promise"
66
import { Promise as BluebirdPromise } from "bluebird"
7-
import { isEmptyOrSpaces, isCi } from "./util/util"
7+
import { isEmptyOrSpaces, isCi, asArray, debug } from "./util/util"
88
import { log, warn } from "./util/log"
99
import { Platform, Arch, archFromString } from "./metadata"
1010
import { getRepositoryInfo } from "./repositoryInfo"
1111
import { DIR_TARGET } from "./targets/targetFactory"
12+
import { BintrayPublisher, BintrayConfiguration } from "./publish/BintrayPublisher"
1213

1314
//noinspection JSUnusedLocalSymbols
1415
const __awaiter = require("./util/awaiter")
1516

16-
export async function createPublisher(packager: Packager, options: PublishOptions, isPublishOptionGuessed: boolean = false): Promise<Publisher | null> {
17-
const info = await getRepositoryInfo(packager.metadata, packager.devMetadata)
18-
if (info == null) {
19-
if (isPublishOptionGuessed) {
20-
return null
21-
}
22-
23-
warn("Cannot detect repository by .git/config")
24-
throw new Error(`Please specify 'repository' in the dev package.json ('${packager.devPackageFile}')`)
25-
}
26-
else {
27-
const version = packager.metadata.version!
28-
log(`Creating Github Publisher — user: ${info.user}, project: ${info.project}, version: ${version}`)
29-
return new GitHubPublisher(info.user, info.project, version, options, isPublishOptionGuessed)
30-
}
31-
}
32-
3317
export interface BuildOptions extends PackagerOptions, PublishOptions {
3418
}
3519

@@ -210,6 +194,9 @@ export async function build(rawOptions?: CliOptions): Promise<void> {
210194
if (options.githubToken === undefined && !isEmptyOrSpaces(process.env.GH_TOKEN)) {
211195
options.githubToken = process.env.GH_TOKEN
212196
}
197+
if (options.bintrayToken === undefined && !isEmptyOrSpaces(process.env.BT_TOKEN)) {
198+
options.bintrayToken = process.env.BT_TOKEN
199+
}
213200

214201
if (options.draft === undefined && !isEmptyOrSpaces(process.env.EP_DRAFT)) {
215202
options.draft = process.env.EP_DRAFT.toLowerCase() === "true"
@@ -238,24 +225,16 @@ export async function build(rawOptions?: CliOptions): Promise<void> {
238225
}
239226
}
240227

241-
if (options.publish !== "never" && options.githubToken == null && isCi()) {
242-
log(`CI detected, publish is set to ${options.publish}, but GH_TOKEN is not set, so artifacts will be not published`)
243-
}
244-
245-
const publishTasks: Array<BluebirdPromise<any>> = []
246228
const packager = new Packager(options)
247-
if (options.publish != null && options.publish !== "never") {
248-
let publisher: Promise<Publisher> | null = null
249-
packager.artifactCreated(event => {
250-
if (publisher == null) {
251-
publisher = createPublisher(packager, options, isPublishOptionGuessed)
252-
}
229+
const publishTasks: Array<BluebirdPromise<any>> = []
253230

254-
if (publisher) {
255-
publisher
256-
.then(it => publishTasks.push(<BluebirdPromise<any>>it.upload(event.file, event.artifactName)))
257-
}
258-
})
231+
if (options.publish != null && options.publish !== "never") {
232+
if (options.githubToken != null || options.bintrayToken != null) {
233+
publishManager(packager, publishTasks, options, isPublishOptionGuessed)
234+
}
235+
else if (isCi()) {
236+
log(`CI detected, publish is set to ${options.publish}, but neither GH_TOKEN nor BT_TOKEN is not set, so artifacts will be not published`)
237+
}
259238
}
260239

261240
await executeFinally(packager.build(), errorOccurred => {
@@ -270,3 +249,69 @@ export async function build(rawOptions?: CliOptions): Promise<void> {
270249
}
271250
})
272251
}
252+
253+
function publishManager(packager: Packager, publishTasks: Array<BluebirdPromise<any>>, options: BuildOptions, isPublishOptionGuessed: boolean) {
254+
const nameToPublisher = new Map<string, Promise<Publisher>>()
255+
packager.artifactCreated(event => {
256+
let publishers = event.packager.platformSpecificBuildOptions.publish
257+
// if explicitly set to null - do not publish
258+
if (publishers === null) {
259+
debug(`${event.file} is not published: publish set to null`)
260+
return
261+
}
262+
263+
if (publishers == null) {
264+
publishers = event.packager.info.devMetadata.build.publish
265+
if (publishers === null) {
266+
debug(`${event.file} is not published: publish set to null in the "build"`)
267+
return
268+
}
269+
270+
if (publishers == null && options.githubToken != null) {
271+
publishers = ["github"]
272+
}
273+
// if both tokens are set — still publish to github (because default publisher is github)
274+
if (publishers == null && options.bintrayToken != null) {
275+
publishers = ["bintray"]
276+
}
277+
}
278+
279+
for (let publisherName of asArray(publishers)) {
280+
let publisher = nameToPublisher.get(publisherName)
281+
if (publisher == null) {
282+
publisher = createPublisher(packager, options, publisherName, isPublishOptionGuessed)
283+
nameToPublisher.set(publisherName, publisher)
284+
}
285+
286+
if (publisher != null) {
287+
publisher
288+
.then(it => it == null ? null : publishTasks.push(<BluebirdPromise<any>>it.upload(event.file, event.artifactName)))
289+
}
290+
}
291+
})
292+
}
293+
294+
export async function createPublisher(packager: Packager, options: PublishOptions, publisherName: string, isPublishOptionGuessed: boolean = false): Promise<Publisher | null> {
295+
const info = await getRepositoryInfo(packager.metadata, packager.devMetadata)
296+
if (info == null) {
297+
if (isPublishOptionGuessed) {
298+
return null
299+
}
300+
301+
warn("Cannot detect repository by .git/config")
302+
throw new Error(`Please specify 'repository' in the dev package.json ('${packager.devPackageFile}')`)
303+
}
304+
305+
if (publisherName === "github") {
306+
const version = packager.metadata.version!
307+
log(`Creating Github Publisher — user: ${info.user}, project: ${info.project}, version: ${version}`)
308+
return new GitHubPublisher(info.user, info.project, version, options, isPublishOptionGuessed)
309+
}
310+
if (publisherName === "bintray") {
311+
const version = packager.metadata.version!
312+
const bintrayInfo: BintrayConfiguration = {user: info.user, packageName: info.project, repo: "generic"}
313+
log(`Creating Bintray Publisher — user: ${bintrayInfo.user}, package: ${bintrayInfo.packageName}, repository: ${bintrayInfo.repo}, version: ${version}`)
314+
return new BintrayPublisher(bintrayInfo, version, options)
315+
}
316+
return null
317+
}

‎src/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
export { Packager } from "./packager"
22
export { PackagerOptions, ArtifactCreated, BuildInfo } from "./platformPackager"
33
export { DIR_TARGET, DEFAULT_TARGET } from "./targets/targetFactory"
4-
export { BuildOptions, build, createPublisher, CliOptions, createTargets } from "./builder"
4+
export { BuildOptions, build, CliOptions, createTargets } from "./builder"
55
export { PublishOptions, Publisher } from "./publish/publisher"
66
export { AppMetadata, DevMetadata, Platform, Arch, archFromString, BuildMetadata, MacOptions, WinBuildOptions, LinuxBuildOptions, CompressionLevel } from "./metadata"

‎src/metadata.ts

+4
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,8 @@ export interface BuildMetadata {
213213
readonly "app-bundle-id"?: string | null
214214

215215
readonly dereference?: boolean
216+
217+
readonly publish?: string | Array<string> | null
216218
}
217219

218220
export interface AfterPackContext {
@@ -571,6 +573,8 @@ export interface PlatformSpecificBuildOptions {
571573
readonly icon?: string | null
572574

573575
readonly fileAssociations?: Array<FileAssociation> | FileAssociation
576+
577+
readonly publish?: string | Array<string> | null
574578
}
575579

576580
export class Platform {

‎src/platformPackager.ts

+3
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ export abstract class PlatformPackager<DC extends PlatformSpecificBuildOptions>
153153
file: file,
154154
artifactName: artifactName,
155155
platform: this.platform,
156+
packager: this,
156157
})
157158
}
158159

@@ -459,6 +460,8 @@ export function getArchSuffix(arch: Arch): string {
459460
}
460461

461462
export interface ArtifactCreated {
463+
readonly packager: PlatformPackager<any>
464+
462465
readonly file: string
463466
readonly artifactName?: string
464467

‎src/publish/BintrayPublisher.ts

+9-3
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,19 @@ import { BintrayClient, Version } from "./bintray"
1111
//noinspection JSUnusedLocalSymbols
1212
const __awaiter = require("../util/awaiter")
1313

14+
export interface BintrayConfiguration {
15+
readonly user: string
16+
readonly packageName: string
17+
readonly repo?: string
18+
}
19+
1420
export class BintrayPublisher implements Publisher {
1521
private _versionPromise: BluebirdPromise<Version>
1622

1723
private readonly client: BintrayClient
1824

19-
constructor(private user: string, apiKey: string, private version: string, private packageName: string, private repo: string = "generic", private options: PublishOptions = {}) {
20-
this.client = new BintrayClient(user, packageName, repo, apiKey)
25+
constructor(private info: BintrayConfiguration, private version: string, private options: PublishOptions) {
26+
this.client = new BintrayClient(info.user, info.packageName, info.repo || "generic", options.bintrayToken)
2127
this._versionPromise = <BluebirdPromise<Version>>this.init()
2228
}
2329

@@ -54,7 +60,7 @@ export class BintrayPublisher implements Publisher {
5460
try {
5561
return await doApiRequest<any>({
5662
hostname: "api.bintray.com",
57-
path: `/content/${this.user}/${this.repo}/${this.packageName}/${version.name}/${fileName}`,
63+
path: `/content/${this.client.user}/${this.client.repo}/${this.client.packageName}/${version.name}/${fileName}`,
5864
method: "PUT",
5965
headers: {
6066
"User-Agent": "electron-builder",

‎src/publish/bintray.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export class BintrayClient {
1010
private readonly basePath: string
1111
readonly auth: string | null
1212

13-
constructor(private user: string, private packageName: string, private repo: string = "generic", apiKey?: string | null) {
13+
constructor(public user: string, public packageName: string, public repo: string = "generic", apiKey?: string | null) {
1414
this.auth = apiKey == null ? null : `Basic ${new Buffer(`${user}:${apiKey}`).toString("base64")}`
1515
this.basePath = `/packages/${this.user}/${this.repo}/${this.packageName}`
1616
}

‎src/publish/gitHubPublisher.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ export class GitHubPublisher implements Publisher {
5151
}
5252

5353
this.tag = `v${version}`
54-
this._releasePromise = <BluebirdPromise<Release>>this.init()
54+
this._releasePromise = this.token === "__test__" ? BluebirdPromise.resolve(<any>null) : <BluebirdPromise<Release>>this.init()
5555
}
5656

5757
private async init(): Promise<Release | null> {

‎src/publish/publisher.ts

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ export type PublishPolicy = "onTag" | "onTagOrDraft" | "always" | "never"
33
export interface PublishOptions {
44
publish?: PublishPolicy | null
55
githubToken?: string | null
6+
bintrayToken?: string | null
67

78
draft?: boolean
89
prerelease?: boolean

‎src/targets/squirrelPack.ts

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { remove, copy, createWriteStream, unlink, ensureDir } from "fs-extra-p"
44
import { spawn, exec } from "../util/util"
55
import { debug } from "../util/util"
66
import { WinPackager } from "../winPackager"
7+
import { log } from "../util/log"
78

89
const archiverUtil = require("archiver-utils")
910
const archiver = require("archiver")
@@ -23,6 +24,7 @@ export function convertVersion(version: string): string {
2324
}
2425

2526
function syncReleases(outputDirectory: string, options: SquirrelOptions) {
27+
log("Sync releases to build delta package")
2628
const args = prepareArgs(["-u", options.remoteReleases!, "-r", outputDirectory], path.join(options.vendorPath, "SyncReleases.exe"))
2729
if (options.remoteToken) {
2830
args.push("-t", options.remoteToken)

‎src/winPackager.ts

+1-3
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,8 @@ export class WinPackager extends PlatformPackager<WinBuildOptions> {
111111
}
112112

113113
async pack(outDir: string, arch: Arch, targets: Array<Target>, postAsyncTasks: Array<Promise<any>>): Promise<any> {
114-
const packOptions = await this.computePackOptions()
115114
const appOutDir = this.computeAppOutDir(outDir, arch)
116-
await this.doPack(packOptions, outDir, appOutDir, this.platform.nodeName, arch, this.platformSpecificBuildOptions)
117-
await this.sign(path.join(appOutDir, `${this.appInfo.productFilename}.exe`))
115+
await this.doPack(await this.computePackOptions(), outDir, appOutDir, this.platform.nodeName, arch, this.platformSpecificBuildOptions)
118116
this.packageInDistributableFormat(outDir, appOutDir, arch, targets, postAsyncTasks)
119117
}
120118

‎test/src/ArtifactPublisherTest.ts

+23-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { HttpError } from "out/publish/restApiRequest"
44
import { join } from "path"
55
import { assertThat } from "./helpers/fileAssert"
66
import { BintrayPublisher } from "out/publish/BintrayPublisher"
7+
import { createPublisher } from "out/builder"
78

89
//noinspection JSUnusedLocalSymbols
910
const __awaiter = require("out/util/awaiter")
@@ -53,7 +54,7 @@ function testAndIgnoreApiRate(name: string, testFunction: () => Promise<any>) {
5354
test("Bintray upload", async () => {
5455
const version = versionNumber()
5556
//noinspection SpellCheckingInspection
56-
const publisher = new BintrayPublisher("actperepo", "5df2cadec86dff91392e4c419540785813c3db15", version, "test")
57+
const publisher = new BintrayPublisher({user: "actperepo", packageName: "test", repo: "generic"}, version, {bintrayToken: "5df2cadec86dff91392e4c419540785813c3db15"})
5758
try {
5859
const artifactName = `icon-${version}.icns`
5960
await publisher.upload(iconPath, artifactName)
@@ -132,4 +133,25 @@ testAndIgnoreApiRate("GitHub upload org", async () => {
132133
finally {
133134
await publisher.deleteRelease()
134135
}
136+
})
137+
138+
test("create publisher", async () => {
139+
const packager: any = {
140+
metadata: {
141+
version: "2.0.0",
142+
},
143+
devMetadata: {
144+
repository: "develar/test"
145+
},
146+
}
147+
const publisher = await createPublisher(packager, {
148+
githubToken: "__test__",
149+
}, "github")
150+
151+
assertThat(publisher).hasProperties({
152+
"owner": "develar",
153+
"repo": "test",
154+
"token": "__test__",
155+
"version": "2.0.0",
156+
})
135157
})

0 commit comments

Comments
 (0)
Please sign in to comment.