Skip to content

Commit 7da8983

Browse files
authored
feat: mark release as draft until all artifacts are uploaded (#692)
Previously, the releases were created and then artifacts (if any) were added to them. This broke when GitHub released "immutable" releases, which disallow changes after the release is published. Make it so that releases are always marked as "draft" when being worked on by the action, and unmarked as draft (if desired) once the action is completed. Fixes #653
1 parent 8797328 commit 7da8983

File tree

4 files changed

+67
-8
lines changed

4 files changed

+67
-8
lines changed

__tests__/github.test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ describe('github', () => {
4949
getReleaseByTag: () => Promise.reject('Not implemented'),
5050
createRelease: () => Promise.reject('Not implemented'),
5151
updateRelease: () => Promise.reject('Not implemented'),
52+
finalizeRelease: () => Promise.reject('Not implemented'),
5253
allReleases: async function* () {
5354
yield { data: [mockRelease] };
5455
},
@@ -254,11 +255,12 @@ describe('github', () => {
254255
name: 'test',
255256
body: 'test',
256257
target_commitish: 'main',
257-
draft: false,
258+
draft: true,
258259
prerelease: false,
259260
assets: [],
260261
},
261262
}),
263+
finalizeRelease: async () => {},
262264
allReleases: async function* () {
263265
yield {
264266
data: [

dist/index.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/github.ts

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ export interface Releaser {
5858
make_latest: 'true' | 'false' | 'legacy' | undefined;
5959
}): Promise<{ data: Release }>;
6060

61+
finalizeRelease(params: {
62+
owner: string;
63+
repo: string;
64+
release_id: number;
65+
}): Promise<{ data: Release }>;
66+
6167
allReleases(params: { owner: string; repo: string }): AsyncIterableIterator<{ data: Release[] }>;
6268
}
6369

@@ -160,6 +166,15 @@ export class GitHubReleaser implements Releaser {
160166
return this.github.rest.repos.updateRelease(params);
161167
}
162168

169+
async finalizeRelease(params: { owner: string; repo: string; release_id: number }) {
170+
return await this.github.rest.repos.updateRelease({
171+
owner: params.owner,
172+
repo: params.repo,
173+
release_id: params.release_id,
174+
draft: false,
175+
});
176+
}
177+
163178
allReleases(params: { owner: string; repo: string }): AsyncIterableIterator<{ data: Release[] }> {
164179
const updatedParams = { per_page: 100, ...params };
165180
return this.github.paginate.iterator(
@@ -303,7 +318,6 @@ export const release = async (
303318
body = workflowBody || existingReleaseBody;
304319
}
305320

306-
const draft = config.input_draft !== undefined ? config.input_draft : existingRelease.draft;
307321
const prerelease =
308322
config.input_prerelease !== undefined ? config.input_prerelease : existingRelease.prerelease;
309323

@@ -317,7 +331,7 @@ export const release = async (
317331
target_commitish,
318332
name,
319333
body,
320-
draft,
334+
draft: existingRelease.draft,
321335
prerelease,
322336
discussion_category_name,
323337
generate_release_notes,
@@ -345,6 +359,45 @@ export const release = async (
345359
}
346360
};
347361

362+
/**
363+
* Finalizes a release by unmarking it as "draft" (if relevant)
364+
* after all artifacts have been uploaded.
365+
*
366+
* @param config - Release configuration as specified by user
367+
* @param releaser - The GitHub API wrapper for release operations
368+
* @param release - The existing release to be finalized
369+
* @param maxRetries - The maximum number of attempts to finalize the release
370+
*/
371+
export const finalizeRelease = async (
372+
config: Config,
373+
releaser: Releaser,
374+
release: Release,
375+
maxRetries: number = 3,
376+
): Promise<Release> => {
377+
if (config.input_draft === true) {
378+
return release;
379+
}
380+
381+
if (maxRetries <= 0) {
382+
console.log(`❌ Too many retries. Aborting...`);
383+
throw new Error('Too many retries.');
384+
}
385+
386+
const [owner, repo] = config.github_repository.split('/');
387+
try {
388+
const { data } = await releaser.finalizeRelease({
389+
owner,
390+
repo,
391+
release_id: release.id,
392+
});
393+
394+
return data;
395+
} catch {
396+
console.log(`retrying... (${maxRetries - 1} retries remaining)`);
397+
return finalizeRelease(config, releaser, release, maxRetries - 1);
398+
}
399+
};
400+
348401
/**
349402
* Finds a release by tag name from all a repository's releases.
350403
*
@@ -385,7 +438,6 @@ async function createRelease(
385438
const tag_name = tag;
386439
const name = config.input_name || tag;
387440
const body = releaseBody(config);
388-
const draft = config.input_draft;
389441
const prerelease = config.input_prerelease;
390442
const target_commitish = config.input_target_commitish;
391443
const make_latest = config.input_make_latest;
@@ -401,7 +453,7 @@ async function createRelease(
401453
tag_name,
402454
name,
403455
body,
404-
draft,
456+
draft: true,
405457
prerelease,
406458
target_commitish,
407459
discussion_category_name,

src/main.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { setFailed, setOutput } from '@actions/core';
22
import { getOctokit } from '@actions/github';
3-
import { GitHubReleaser, release, upload } from './github';
3+
import { GitHubReleaser, release, finalizeRelease, upload } from './github';
44
import { isTag, parseConfig, paths, unmatchedPatterns, uploadUrl } from './util';
55

66
import { env } from 'process';
@@ -48,7 +48,8 @@ async function run() {
4848
},
4949
});
5050
//);
51-
const rel = await release(config, new GitHubReleaser(gh));
51+
const releaser = new GitHubReleaser(gh);
52+
let rel = await release(config, releaser);
5253
if (config.input_files && config.input_files.length > 0) {
5354
const files = paths(config.input_files, config.input_working_directory);
5455
if (files.length == 0) {
@@ -81,6 +82,10 @@ async function run() {
8182
const assets = results.filter(Boolean);
8283
setOutput('assets', assets);
8384
}
85+
86+
console.log('Finalizing release...');
87+
rel = await finalizeRelease(config, releaser, rel);
88+
8489
console.log(`🎉 Release ready at ${rel.html_url}`);
8590
setOutput('url', rel.html_url);
8691
setOutput('id', rel.id.toString());

0 commit comments

Comments
 (0)