Skip to content

Commit 38051ba

Browse files
authored
fix(latest): add make_latest property to the GH release POST request during publish (#1157)
* Add make_latest publish flag and isLatestRelease helper * fix integration tests * Add two new integration tests for publishing releases without assets * Add another integration test for maintenance releases
1 parent be62f5e commit 38051ba

File tree

5 files changed

+246
-1
lines changed

5 files changed

+246
-1
lines changed

lib/is-latest-release.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default function isLatestRelease({ type, main }) {
2+
return type === "release" && main ? "true" : "false";
3+
}

lib/publish.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import globAssets from "./glob-assets.js";
1111
import resolveConfig from "./resolve-config.js";
1212
import { toOctokitOptions } from "./octokit.js";
1313
import isPrerelease from "./is-prerelease.js";
14+
import isLatestRelease from "./is-latest-release.js";
1415

1516
const debug = debugFactory("semantic-release:github");
1617

@@ -52,6 +53,7 @@ export default async function publish(pluginConfig, context, { Octokit }) {
5253
name: template(releaseNameTemplate)(context),
5354
body: template(releaseBodyTemplate)(context),
5455
prerelease: isPrerelease(branch),
56+
make_latest: isLatestRelease(branch),
5557
};
5658

5759
debug("release object: %O", release);

test/integration.test.js

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,189 @@ test("Throw SemanticReleaseError if invalid config", async (t) => {
187187
t.is(errors[8].code, "ENOGHTOKEN");
188188
});
189189

190+
test("Publish a release without assets on a main release branch", async (t) => {
191+
const owner = "test_user";
192+
const repo = "test_repo";
193+
const env = { GITHUB_TOKEN: "github_token" };
194+
const nextRelease = {
195+
gitTag: "v1.0.0",
196+
name: "v1.0.0",
197+
notes: "Test release note body",
198+
};
199+
const options = { repositoryUrl: `https://github.com/${owner}/${repo}.git` };
200+
const releaseUrl = `https://github.com/${owner}/${repo}/releases/${nextRelease.version}`;
201+
const releaseId = 1;
202+
203+
const fetch = fetchMock
204+
.sandbox()
205+
.getOnce(`https://api.github.local/repos/${owner}/${repo}`, {
206+
permissions: {
207+
push: true,
208+
},
209+
clone_url: `https://api.github.local/${owner}/${repo}.git`,
210+
})
211+
.postOnce(
212+
`https://api.github.local/repos/${owner}/${repo}/releases`,
213+
{ html_url: releaseUrl, id: releaseId },
214+
{
215+
body: {
216+
tag_name: nextRelease.gitTag,
217+
name: nextRelease.name,
218+
body: nextRelease.notes,
219+
prerelease: false,
220+
make_latest: "true",
221+
},
222+
},
223+
);
224+
225+
const result = await t.context.m.publish(
226+
{},
227+
{
228+
cwd,
229+
env,
230+
options,
231+
branch: { type: "release", main: true },
232+
nextRelease,
233+
logger: t.context.logger,
234+
},
235+
{
236+
Octokit: TestOctokit.defaults((options) => ({
237+
...options,
238+
request: { ...options.request, fetch },
239+
})),
240+
},
241+
);
242+
243+
t.is(result.url, releaseUrl);
244+
t.is(result.name, "GitHub release");
245+
t.is(result.id, releaseId);
246+
t.deepEqual(t.context.log.args[0], ["Verify GitHub authentication"]);
247+
t.true(t.context.log.calledWith("Published GitHub release: %s", releaseUrl));
248+
t.true(fetch.done());
249+
});
250+
251+
test("Publish a release without assets on a non-main release branch", async (t) => {
252+
const owner = "test_user";
253+
const repo = "test_repo";
254+
const env = { GITHUB_TOKEN: "github_token" };
255+
const nextRelease = {
256+
gitTag: "v1.0.0",
257+
name: "v1.0.0",
258+
notes: "Test release note body",
259+
};
260+
const options = { repositoryUrl: `https://github.com/${owner}/${repo}.git` };
261+
const releaseUrl = `https://github.com/${owner}/${repo}/releases/${nextRelease.version}`;
262+
const releaseId = 1;
263+
264+
const fetch = fetchMock
265+
.sandbox()
266+
.getOnce(`https://api.github.local/repos/${owner}/${repo}`, {
267+
permissions: {
268+
push: true,
269+
},
270+
clone_url: `https://api.github.local/${owner}/${repo}.git`,
271+
})
272+
.postOnce(
273+
`https://api.github.local/repos/${owner}/${repo}/releases`,
274+
{ html_url: releaseUrl, id: releaseId },
275+
{
276+
body: {
277+
tag_name: nextRelease.gitTag,
278+
name: nextRelease.name,
279+
body: nextRelease.notes,
280+
prerelease: true,
281+
make_latest: "false",
282+
},
283+
},
284+
);
285+
286+
const result = await t.context.m.publish(
287+
{},
288+
{
289+
cwd,
290+
env,
291+
options,
292+
branch: { type: "release" },
293+
nextRelease,
294+
logger: t.context.logger,
295+
},
296+
{
297+
Octokit: TestOctokit.defaults((options) => ({
298+
...options,
299+
request: { ...options.request, fetch },
300+
})),
301+
},
302+
);
303+
304+
t.is(result.url, releaseUrl);
305+
t.is(result.name, "GitHub release");
306+
t.is(result.id, releaseId);
307+
t.deepEqual(t.context.log.args[0], ["Verify GitHub authentication"]);
308+
t.true(t.context.log.calledWith("Published GitHub release: %s", releaseUrl));
309+
t.true(fetch.done());
310+
});
311+
312+
test("Publish a release without assets on a maintenance branch", async (t) => {
313+
const owner = "test_user";
314+
const repo = "test_repo";
315+
const env = { GITHUB_TOKEN: "github_token" };
316+
const nextRelease = {
317+
gitTag: "v1.0.0",
318+
name: "v1.0.0",
319+
notes: "Test release note body",
320+
};
321+
const options = { repositoryUrl: `https://github.com/${owner}/${repo}.git` };
322+
const releaseUrl = `https://github.com/${owner}/${repo}/releases/${nextRelease.version}`;
323+
const releaseId = 1;
324+
325+
const fetch = fetchMock
326+
.sandbox()
327+
.getOnce(`https://api.github.local/repos/${owner}/${repo}`, {
328+
permissions: {
329+
push: true,
330+
},
331+
clone_url: `https://api.github.local/${owner}/${repo}.git`,
332+
})
333+
.postOnce(
334+
`https://api.github.local/repos/${owner}/${repo}/releases`,
335+
{ html_url: releaseUrl, id: releaseId },
336+
{
337+
body: {
338+
tag_name: nextRelease.gitTag,
339+
name: nextRelease.name,
340+
body: nextRelease.notes,
341+
prerelease: false,
342+
make_latest: "false",
343+
},
344+
},
345+
);
346+
347+
const result = await t.context.m.publish(
348+
{},
349+
{
350+
cwd,
351+
env,
352+
options,
353+
branch: { type: "maintenance" },
354+
nextRelease,
355+
logger: t.context.logger,
356+
},
357+
{
358+
Octokit: TestOctokit.defaults((options) => ({
359+
...options,
360+
request: { ...options.request, fetch },
361+
})),
362+
},
363+
);
364+
365+
t.is(result.url, releaseUrl);
366+
t.is(result.name, "GitHub release");
367+
t.is(result.id, releaseId);
368+
t.deepEqual(t.context.log.args[0], ["Verify GitHub authentication"]);
369+
t.true(t.context.log.calledWith("Published GitHub release: %s", releaseUrl));
370+
t.true(fetch.done());
371+
});
372+
190373
test("Publish a release with an array of assets", async (t) => {
191374
const owner = "test_user";
192375
const repo = "test_repo";
@@ -227,6 +410,7 @@ test("Publish a release with an array of assets", async (t) => {
227410
body: nextRelease.notes,
228411
draft: true,
229412
prerelease: false,
413+
make_latest: "true",
230414
},
231415
},
232416
)
@@ -322,6 +506,7 @@ test("Publish a release with release information in assets", async (t) => {
322506
body: nextRelease.notes,
323507
draft: true,
324508
prerelease: true,
509+
make_latest: "false",
325510
},
326511
},
327512
)
@@ -718,6 +903,7 @@ test("Verify, release and notify success", async (t) => {
718903
body: nextRelease.notes,
719904
draft: true,
720905
prerelease: false,
906+
make_latest: "true",
721907
},
722908
},
723909
)

test/is-latest-release.test.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import test from "ava";
2+
import isLatestRelease from "../lib/is-latest-release.js";
3+
4+
test("Test for empty object", (t) => {
5+
const branch = {};
6+
t.is(isLatestRelease(branch), "false");
7+
});
8+
9+
test("Test if type release and main is used correctly", (t) => {
10+
const branch = {
11+
type: "release",
12+
main: true,
13+
};
14+
t.is(isLatestRelease(branch), "true");
15+
});
16+
17+
test("Test if type prerelease is used correctly", (t) => {
18+
const branch = {
19+
type: "prerelease",
20+
main: true,
21+
};
22+
t.is(isLatestRelease(branch), "false");
23+
});
24+
25+
test("Test if type main property as boolean is used correctly", (t) => {
26+
const branch = {
27+
type: "release",
28+
main: false,
29+
};
30+
t.is(isLatestRelease(branch), "false");
31+
});
32+
33+
test("Test maintenance branch returns false", (t) => {
34+
const branch = {
35+
type: "maintenance",
36+
main: false,
37+
};
38+
t.is(isLatestRelease(branch), "false");
39+
});

0 commit comments

Comments
 (0)