forked from semantic-release/github
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpublish.js
More file actions
191 lines (162 loc) · 5.35 KB
/
publish.js
File metadata and controls
191 lines (162 loc) · 5.35 KB
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
import { resolve, basename, extname } from "node:path";
import { stat, readFile } from "node:fs/promises";
import { isPlainObject, template } from "lodash-es";
import mime from "mime";
import debugFactory from "debug";
import { RELEASE_NAME } from "./definitions/constants.js";
import parseGithubUrl from "./parse-github-url.js";
import globAssets from "./glob-assets.js";
import resolveConfig from "./resolve-config.js";
import { toOctokitOptions } from "./octokit.js";
import isPrerelease from "./is-prerelease.js";
import isLatestRelease from "./is-latest-release.js";
const debug = debugFactory("semantic-release:github");
export default async function publish(pluginConfig, context, { Octokit }) {
const {
cwd,
options: { repositoryUrl },
branch,
nextRelease: { gitTag },
logger,
} = context;
const {
githubToken,
githubUrl,
githubApiPathPrefix,
githubApiUrl,
proxy,
assets,
draftRelease,
releaseNameTemplate,
releaseBodyTemplate,
discussionCategoryName,
} = resolveConfig(pluginConfig, context);
const { owner, repo } = parseGithubUrl(repositoryUrl);
const octokit = new Octokit(
toOctokitOptions({
githubToken,
githubUrl,
githubApiPathPrefix,
githubApiUrl,
proxy,
}),
);
const release = {
owner,
repo,
tag_name: gitTag,
target_commitish: branch.name,
name: template(releaseNameTemplate)(context),
body: template(releaseBodyTemplate)(context),
prerelease: isPrerelease(branch),
make_latest: isLatestRelease(branch),
};
debug("release object: %O", release);
const draftReleaseOptions = { ...release, draft: true };
// When there are no assets, we publish a release directly.
if (!assets || assets.length === 0) {
// If draftRelease is true we create a draft release instead.
if (draftRelease) {
const {
data: { html_url: url, id: releaseId },
} = await octokit.request(
"POST /repos/{owner}/{repo}/releases",
draftReleaseOptions,
);
logger.log("Created GitHub draft release: %s", url);
return { url, name: RELEASE_NAME, id: releaseId };
}
// add discussion_category_name if discussionCategoryName is not undefined or false
if (discussionCategoryName) {
release.discussion_category_name = discussionCategoryName;
}
const {
data: { html_url: url, id: releaseId, discussion_url },
} = await octokit.request("POST /repos/{owner}/{repo}/releases", release);
logger.log("Published GitHub release: %s", url);
if (discussionCategoryName) {
logger.log("Created GitHub release discussion: %s", discussion_url);
}
return { url, name: RELEASE_NAME, id: releaseId, discussion_url };
}
// We'll create a draft release, append the assets to it, and then publish it.
// This is so that the assets are available when we get a Github release event.
const {
data: { upload_url: uploadUrl, html_url: draftUrl, id: releaseId },
} = await octokit.request(
"POST /repos/{owner}/{repo}/releases",
draftReleaseOptions,
);
// Append assets to the release
const globbedAssets = await globAssets(context, assets);
debug("globed assets: %o", globbedAssets);
await Promise.all(
globbedAssets.map(async (asset) => {
const filePath = isPlainObject(asset) ? asset.path : asset;
const resolved = resolve(cwd, filePath);
let file;
try {
file = await stat(resolved);
} catch {
logger.error(
"The asset %s cannot be read, and will be ignored.",
filePath,
);
return;
}
if (!file || !file.isFile()) {
logger.error(
"The asset %s is not a file, and will be ignored.",
resolved,
);
return;
}
const fileName = template(asset.name || basename(filePath))(context);
const upload = {
method: "POST",
url: uploadUrl,
data: await readFile(resolved),
name: fileName,
headers: {
"content-type": mime.getType(extname(fileName)) || "text/plain",
"content-length": file.size,
},
};
debug("file path: %o", filePath);
debug("file name: %o", fileName);
if (isPlainObject(asset) && asset.label) {
upload.label = template(asset.label)(context);
}
const {
data: { browser_download_url: downloadUrl },
} = await octokit.request(upload);
logger.log("Published file %s", downloadUrl);
}),
);
// If we want to create a draft we don't need to update the release again
if (draftRelease) {
logger.log("Created GitHub draft release: %s", draftUrl);
return { url: draftUrl, name: RELEASE_NAME, id: releaseId };
}
const patchRelease = {
owner,
repo,
release_id: releaseId,
draft: false,
};
// add discussion_category_name if discussionCategoryName is not undefined or false
if (discussionCategoryName) {
patchRelease.discussion_category_name = discussionCategoryName;
}
const {
data: { html_url: url, discussion_url },
} = await octokit.request(
"PATCH /repos/{owner}/{repo}/releases/{release_id}",
patchRelease,
);
logger.log("Published GitHub release: %s", url);
if (discussionCategoryName) {
logger.log("Created GitHub release discussion: %s", discussion_url);
}
return { url, name: RELEASE_NAME, id: releaseId, discussion_url };
}