diff --git a/.changeset/mighty-otters-sin.md b/.changeset/mighty-otters-sin.md new file mode 100644 index 00000000000..40c7d66bacb --- /dev/null +++ b/.changeset/mighty-otters-sin.md @@ -0,0 +1,5 @@ +--- +"app-builder-lib": patch +--- + +Fix issue where, upon publishing a new release, electron-builder would attempt to create the same release for each artifact in parallel, resulting in conflict errors. diff --git a/packages/app-builder-lib/src/publish/KeygenPublisher.ts b/packages/app-builder-lib/src/publish/KeygenPublisher.ts index 5aa47b229cb..3b07220cf14 100644 --- a/packages/app-builder-lib/src/publish/KeygenPublisher.ts +++ b/packages/app-builder-lib/src/publish/KeygenPublisher.ts @@ -181,13 +181,25 @@ export class KeygenPublisher extends HttpPublisher { private async getOrCreateRelease(): Promise<{ data?: KeygenRelease; errors?: KeygenError[] }> { try { + // First, we'll attempt to fetch the release. return await this.getRelease() } catch (e) { - if (e.statusCode === 404) { - return this.createRelease() + if (e.statusCode !== 404) { + throw e } - throw e + try { + // Next, if the release doesn't exist, we'll attempt to create it. + return await this.createRelease() + } catch (e) { + if (e.statusCode !== 409 && e.statusCode !== 422) { + throw e + } + + // Lastly, when a conflict occurs (in the case of parallel uploads), + // we'll try to fetch it one last time. + return this.getRelease() + } } } diff --git a/test/src/ArtifactPublisherTest.ts b/test/src/ArtifactPublisherTest.ts index 1e609048ff4..50dd94f58b4 100644 --- a/test/src/ArtifactPublisherTest.ts +++ b/test/src/ArtifactPublisherTest.ts @@ -32,6 +32,7 @@ function versionNumber() { //noinspection SpellCheckingInspection const token = Buffer.from("Y2Y5NDdhZDJhYzJlMzg1OGNiNzQzYzcwOWZhNGI0OTk2NWQ4ZDg3Yg==", "base64").toString() const iconPath = path.join(__dirname, "..", "fixtures", "test-app", "build", "icon.icns") +const icoPath = path.join(__dirname, "..", "fixtures", "test-app", "build", "icon.ico") const publishContext: PublishContext = { cancellationToken: new CancellationToken(), @@ -138,7 +139,12 @@ test.ifEnv(process.env.KEYGEN_TOKEN)("Keygen upload", async () => { } as KeygenOptions, versionNumber() ) - const releaseId = await publisher.upload({ file: iconPath, arch: Arch.x64 }) + const [releaseId] = await Promise.all([ + publisher.upload({ file: iconPath, arch: Arch.x64 }), + // test parallel artifact uploads for the same release + publisher.upload({ file: icoPath, arch: Arch.x64 }), + ]) + await publisher.deleteRelease(releaseId) })