Skip to content

Commit 0295fd0

Browse files
authored
feat: add support for labels (#131)
1 parent 2593569 commit 0295fd0

File tree

9 files changed

+3518
-2
lines changed

9 files changed

+3518
-2
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ octokit
6868
base: "main" /* optional: defaults to default branch */,
6969
update: false /* optional: set to `true` to enable updating existing pull requests */,
7070
forceFork: false /* optional: force creating fork even when user has write rights */,
71+
labels: [
72+
"bug",
73+
] /* optional: applies the given labels when user has permissions. When updating an existing pull request, already present labels will not be deleted. */
7174
changes: [
7275
{
7376
/* optional: if `files` is not passed, an empty commit is created instead */

src/compose-create-pull-request.ts

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export async function composeCreatePullRequest(
1616
createWhenEmpty,
1717
changes: changesOption,
1818
draft = false,
19+
labels = [],
1920
forceFork = false,
2021
update = false,
2122
}: Options
@@ -203,9 +204,10 @@ export async function composeCreatePullRequest(
203204
draft,
204205
};
205206

207+
let res;
206208
if (existingPullRequest) {
207209
// https://docs.github.com/en/rest/pulls/pulls#update-a-pull-request
208-
return await octokit.request(
210+
res = await octokit.request(
209211
"PATCH /repos/{owner}/{repo}/pulls/{pull_number}",
210212
{
211213
pull_number: existingPullRequest.number,
@@ -214,9 +216,44 @@ export async function composeCreatePullRequest(
214216
);
215217
} else {
216218
// https://developer.github.com/v3/pulls/#create-a-pull-request
217-
return await octokit.request(
219+
res = await octokit.request(
218220
"POST /repos/{owner}/{repo}/pulls",
219221
pullRequestOptions
220222
);
221223
}
224+
225+
if (labels.length) {
226+
try {
227+
const labelRes = await octokit.request(
228+
"POST /repos/{owner}/{repo}/issues/{number}/labels",
229+
{
230+
owner,
231+
repo,
232+
number: res.data.number,
233+
labels,
234+
}
235+
);
236+
237+
// istanbul ignore if
238+
if (labelRes.data.length > labels.length) {
239+
octokit.log.warn(
240+
"The pull request already contains more labels than the ones provided. This could be due to the presence of previous labels."
241+
);
242+
}
243+
} catch (error) {
244+
// @ts-ignore
245+
// istanbul ignore if
246+
if (error.status === 403) {
247+
octokit.log.warn(
248+
"You do not have permissions to apply labels to this pull request. However, the pull request has been successfully created without the requested labels."
249+
);
250+
return res;
251+
}
252+
253+
// @ts-ignore
254+
if (error.status !== 403) throw error;
255+
}
256+
}
257+
258+
return res;
222259
}

src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export type Options = {
1111
body: string;
1212
head: string;
1313
changes: Changes | Changes[];
14+
labels?: String[];
1415
base?: string;
1516
createWhenEmpty?: boolean;
1617
draft?: boolean;

test/fixtures/labels-with-error.json

Lines changed: 1089 additions & 0 deletions
Large diffs are not rendered by default.

test/fixtures/labels-without-permissions.json

Lines changed: 1089 additions & 0 deletions
Large diffs are not rendered by default.

test/fixtures/labels.json

Lines changed: 1109 additions & 0 deletions
Large diffs are not rendered by default.

test/labels-with-error.test.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { Octokit as Core } from "@octokit/core";
2+
import { RequestError } from "@octokit/request-error";
3+
4+
import { createPullRequest } from "../src";
5+
const Octokit = Core.plugin(createPullRequest);
6+
7+
test("labels without error", async () => {
8+
const fixtures = require("./fixtures/labels-with-error");
9+
const fixturePr = fixtures[fixtures.length - 2].response;
10+
const octokit = new Octokit();
11+
12+
octokit.hook.wrap("request", (_, options) => {
13+
const currentFixtures = fixtures.shift();
14+
const {
15+
baseUrl,
16+
method,
17+
url,
18+
request,
19+
headers,
20+
mediaType,
21+
draft,
22+
...params
23+
} = options;
24+
25+
expect(
26+
`${currentFixtures.request.method} ${currentFixtures.request.url}`
27+
).toEqual(`${options.method} ${options.url}`);
28+
29+
Object.keys(params).forEach((paramName) => {
30+
expect(currentFixtures.request[paramName]).toStrictEqual(
31+
params[paramName]
32+
);
33+
});
34+
35+
if (currentFixtures.response.status >= 400) {
36+
throw new RequestError("Error", currentFixtures.response.status, {
37+
request: currentFixtures.request,
38+
headers: currentFixtures.response.headers,
39+
});
40+
}
41+
42+
return currentFixtures.response;
43+
});
44+
45+
expect(async () => {
46+
return octokit.createPullRequest({
47+
owner: "gr2m",
48+
repo: "pull-request-test",
49+
title: "One comes, one goes",
50+
body: "because",
51+
labels: ["enhancement", "help wanted"],
52+
head: "with-labels",
53+
changes: {
54+
files: {
55+
"path/to/file1.txt": "Content for file1",
56+
"path/to/file2.txt": "Content for file2",
57+
},
58+
commit: "why",
59+
},
60+
});
61+
}).rejects.toThrow(new Error("Error"));
62+
});
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { Octokit as Core } from "@octokit/core";
2+
import { RequestError } from "@octokit/request-error";
3+
4+
import { createPullRequest } from "../src";
5+
const Octokit = Core.plugin(createPullRequest);
6+
7+
test("labels without permissions", async () => {
8+
const fixtures = require("./fixtures/labels-without-permissions");
9+
const fixturePr = fixtures[fixtures.length - 2].response;
10+
const octokit = new Octokit();
11+
12+
octokit.hook.wrap("request", (_, options) => {
13+
const currentFixtures = fixtures.shift();
14+
const {
15+
baseUrl,
16+
method,
17+
url,
18+
request,
19+
headers,
20+
mediaType,
21+
draft,
22+
...params
23+
} = options;
24+
25+
expect(
26+
`${currentFixtures.request.method} ${currentFixtures.request.url}`
27+
).toEqual(`${options.method} ${options.url}`);
28+
29+
Object.keys(params).forEach((paramName) => {
30+
expect(currentFixtures.request[paramName]).toStrictEqual(
31+
params[paramName]
32+
);
33+
});
34+
35+
if (currentFixtures.response.status >= 400) {
36+
throw new RequestError("Error", currentFixtures.response.status, {
37+
request: currentFixtures.request,
38+
headers: currentFixtures.response.headers,
39+
});
40+
}
41+
42+
return currentFixtures.response;
43+
});
44+
45+
const pr = await octokit.createPullRequest({
46+
owner: "gr2m",
47+
repo: "pull-request-test",
48+
title: "One comes, one goes",
49+
body: "because",
50+
labels: ["enhancement", "help wanted"],
51+
head: "with-labels",
52+
changes: {
53+
files: {
54+
"path/to/file1.txt": "Content for file1",
55+
"path/to/file2.txt": "Content for file2",
56+
},
57+
commit: "why",
58+
},
59+
});
60+
61+
expect(pr).toStrictEqual(fixturePr);
62+
expect(fixtures.length).toEqual(0);
63+
});

test/labels.test.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { Octokit as Core } from "@octokit/core";
2+
import { RequestError } from "@octokit/request-error";
3+
4+
import { createPullRequest } from "../src";
5+
const Octokit = Core.plugin(createPullRequest);
6+
7+
test("labels", async () => {
8+
const fixtures = require("./fixtures/labels");
9+
const fixturePr = fixtures[fixtures.length - 2].response;
10+
const octokit = new Octokit();
11+
12+
octokit.hook.wrap("request", (_, options) => {
13+
const currentFixtures = fixtures.shift();
14+
const {
15+
baseUrl,
16+
method,
17+
url,
18+
request,
19+
headers,
20+
mediaType,
21+
draft,
22+
...params
23+
} = options;
24+
25+
expect(
26+
`${currentFixtures.request.method} ${currentFixtures.request.url}`
27+
).toEqual(`${options.method} ${options.url}`);
28+
29+
Object.keys(params).forEach((paramName) => {
30+
expect(currentFixtures.request[paramName]).toStrictEqual(
31+
params[paramName]
32+
);
33+
});
34+
35+
if (currentFixtures.response.status >= 400) {
36+
throw new RequestError("Error", currentFixtures.response.status, {
37+
request: currentFixtures.request,
38+
headers: currentFixtures.response.headers,
39+
});
40+
}
41+
42+
return currentFixtures.response;
43+
});
44+
45+
const pr = await octokit.createPullRequest({
46+
owner: "gr2m",
47+
repo: "pull-request-test",
48+
title: "One comes, one goes",
49+
body: "because",
50+
labels: ["enhancement", "help wanted"],
51+
head: "with-labels",
52+
changes: {
53+
files: {
54+
"path/to/file1.txt": "Content for file1",
55+
"path/to/file2.txt": "Content for file2",
56+
},
57+
commit: "why",
58+
},
59+
});
60+
61+
expect(pr).toStrictEqual(fixturePr);
62+
expect(fixtures.length).toEqual(0);
63+
});

0 commit comments

Comments
 (0)