generated from actions/typescript-action
-
Notifications
You must be signed in to change notification settings - Fork 161
/
create-release.ts
130 lines (118 loc) · 3.7 KB
/
create-release.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
import fs from 'node:fs';
import * as core from '@actions/core';
import { getOctokit, context } from '@actions/github';
import type { GitHub } from '@actions/github/lib/utils';
interface Release {
id: number;
uploadUrl: string;
htmlUrl: string;
}
interface GitHubRelease {
id: number;
upload_url: string;
html_url: string;
tag_name: string;
}
function allReleases(
github: InstanceType<typeof GitHub>,
owner: string,
repo: string,
): AsyncIterableIterator<{ data: GitHubRelease[] }> {
const params = { per_page: 100, owner, repo };
return github.paginate.iterator(
github.rest.repos.listReleases.endpoint.merge(params),
);
}
/// Try to get release by tag. If there's none, releaseName is required to create one.
export async function getOrCreateRelease(
owner: string,
repo: string,
tagName: string,
releaseName?: string,
body?: string,
commitish?: string,
draft = true,
prerelease = true,
): Promise<Release> {
if (process.env.GITHUB_TOKEN === undefined) {
throw new Error('GITHUB_TOKEN is required');
}
// Get authenticated GitHub client (Ocktokit): https://github.com/actions/toolkit/tree/master/packages/github#usage
const github = getOctokit(process.env.GITHUB_TOKEN);
const bodyPath = core.getInput('body_path', { required: false });
let bodyFileContent: string | null = null;
if (bodyPath !== '' && !!bodyPath) {
try {
bodyFileContent = fs.readFileSync(bodyPath, { encoding: 'utf8' });
} catch (error) {
// @ts-expect-error Catching errors in typescript is a headache
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
core.setFailed(error.message);
}
}
let release: GitHubRelease | null = null;
try {
// you can't get a an existing draft by tag
// so we must find one in the list of all releases
if (draft) {
console.log(`Looking for a draft release with tag ${tagName}...`);
for await (const response of allReleases(github, owner, repo)) {
const releaseWithTag = response.data.find(
(release) => release.tag_name === tagName,
);
if (releaseWithTag) {
release = releaseWithTag;
console.log(
`Found draft release with tag ${tagName} on the release list.`,
);
break;
}
}
if (!release) {
throw new Error('release not found');
}
} else {
const foundRelease = await github.rest.repos.getReleaseByTag({
owner,
repo,
tag: tagName,
});
release = foundRelease.data;
console.log(`Found release with tag ${tagName}.`);
}
} catch (error) {
// @ts-expect-error Catching errors in typescript is a headache
if (error.status === 404 || error.message === 'release not found') {
console.log(`Couldn't find release with tag ${tagName}. Creating one.`);
if (!releaseName) {
console.error('"releaseName" not set but required to create release.');
} else {
const createdRelease = await github.rest.repos.createRelease({
owner,
repo,
tag_name: tagName,
name: releaseName,
body: bodyFileContent || body,
draft,
prerelease,
target_commitish: commitish || context.sha,
});
release = createdRelease.data;
}
} else {
console.log(
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
`⚠️ Unexpected error fetching GitHub release for tag ${tagName}: ${error}`,
);
throw error;
}
}
if (!release) {
throw new Error('Release not found or created.');
}
return {
id: release.id,
uploadUrl: release.upload_url,
htmlUrl: release.html_url,
};
}