Skip to content

Commit

Permalink
feat: add support for labels (#131)
Browse files Browse the repository at this point in the history
  • Loading branch information
stefanbuck committed Jun 19, 2023
1 parent 2593569 commit 0295fd0
Show file tree
Hide file tree
Showing 9 changed files with 3,518 additions and 2 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ octokit
base: "main" /* optional: defaults to default branch */,
update: false /* optional: set to `true` to enable updating existing pull requests */,
forceFork: false /* optional: force creating fork even when user has write rights */,
labels: [
"bug",
] /* optional: applies the given labels when user has permissions. When updating an existing pull request, already present labels will not be deleted. */
changes: [
{
/* optional: if `files` is not passed, an empty commit is created instead */
Expand Down
41 changes: 39 additions & 2 deletions src/compose-create-pull-request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export async function composeCreatePullRequest(
createWhenEmpty,
changes: changesOption,
draft = false,
labels = [],
forceFork = false,
update = false,
}: Options
Expand Down Expand Up @@ -203,9 +204,10 @@ export async function composeCreatePullRequest(
draft,
};

let res;
if (existingPullRequest) {
// https://docs.github.com/en/rest/pulls/pulls#update-a-pull-request
return await octokit.request(
res = await octokit.request(
"PATCH /repos/{owner}/{repo}/pulls/{pull_number}",
{
pull_number: existingPullRequest.number,
Expand All @@ -214,9 +216,44 @@ export async function composeCreatePullRequest(
);
} else {
// https://developer.github.com/v3/pulls/#create-a-pull-request
return await octokit.request(
res = await octokit.request(
"POST /repos/{owner}/{repo}/pulls",
pullRequestOptions
);
}

if (labels.length) {
try {
const labelRes = await octokit.request(
"POST /repos/{owner}/{repo}/issues/{number}/labels",
{
owner,
repo,
number: res.data.number,
labels,
}
);

// istanbul ignore if
if (labelRes.data.length > labels.length) {
octokit.log.warn(
"The pull request already contains more labels than the ones provided. This could be due to the presence of previous labels."
);
}
} catch (error) {
// @ts-ignore
// istanbul ignore if
if (error.status === 403) {
octokit.log.warn(
"You do not have permissions to apply labels to this pull request. However, the pull request has been successfully created without the requested labels."
);
return res;
}

// @ts-ignore
if (error.status !== 403) throw error;
}
}

return res;
}
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export type Options = {
body: string;
head: string;
changes: Changes | Changes[];
labels?: String[];
base?: string;
createWhenEmpty?: boolean;
draft?: boolean;
Expand Down
1,089 changes: 1,089 additions & 0 deletions test/fixtures/labels-with-error.json

Large diffs are not rendered by default.

1,089 changes: 1,089 additions & 0 deletions test/fixtures/labels-without-permissions.json

Large diffs are not rendered by default.

1,109 changes: 1,109 additions & 0 deletions test/fixtures/labels.json

Large diffs are not rendered by default.

62 changes: 62 additions & 0 deletions test/labels-with-error.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { Octokit as Core } from "@octokit/core";
import { RequestError } from "@octokit/request-error";

import { createPullRequest } from "../src";
const Octokit = Core.plugin(createPullRequest);

test("labels without error", async () => {
const fixtures = require("./fixtures/labels-with-error");
const fixturePr = fixtures[fixtures.length - 2].response;
const octokit = new Octokit();

octokit.hook.wrap("request", (_, options) => {
const currentFixtures = fixtures.shift();
const {
baseUrl,
method,
url,
request,
headers,
mediaType,
draft,
...params
} = options;

expect(
`${currentFixtures.request.method} ${currentFixtures.request.url}`
).toEqual(`${options.method} ${options.url}`);

Object.keys(params).forEach((paramName) => {
expect(currentFixtures.request[paramName]).toStrictEqual(
params[paramName]
);
});

if (currentFixtures.response.status >= 400) {
throw new RequestError("Error", currentFixtures.response.status, {
request: currentFixtures.request,
headers: currentFixtures.response.headers,
});
}

return currentFixtures.response;
});

expect(async () => {
return octokit.createPullRequest({
owner: "gr2m",
repo: "pull-request-test",
title: "One comes, one goes",
body: "because",
labels: ["enhancement", "help wanted"],
head: "with-labels",
changes: {
files: {
"path/to/file1.txt": "Content for file1",
"path/to/file2.txt": "Content for file2",
},
commit: "why",
},
});
}).rejects.toThrow(new Error("Error"));
});
63 changes: 63 additions & 0 deletions test/labels-without-permissions.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { Octokit as Core } from "@octokit/core";
import { RequestError } from "@octokit/request-error";

import { createPullRequest } from "../src";
const Octokit = Core.plugin(createPullRequest);

test("labels without permissions", async () => {
const fixtures = require("./fixtures/labels-without-permissions");
const fixturePr = fixtures[fixtures.length - 2].response;
const octokit = new Octokit();

octokit.hook.wrap("request", (_, options) => {
const currentFixtures = fixtures.shift();
const {
baseUrl,
method,
url,
request,
headers,
mediaType,
draft,
...params
} = options;

expect(
`${currentFixtures.request.method} ${currentFixtures.request.url}`
).toEqual(`${options.method} ${options.url}`);

Object.keys(params).forEach((paramName) => {
expect(currentFixtures.request[paramName]).toStrictEqual(
params[paramName]
);
});

if (currentFixtures.response.status >= 400) {
throw new RequestError("Error", currentFixtures.response.status, {
request: currentFixtures.request,
headers: currentFixtures.response.headers,
});
}

return currentFixtures.response;
});

const pr = await octokit.createPullRequest({
owner: "gr2m",
repo: "pull-request-test",
title: "One comes, one goes",
body: "because",
labels: ["enhancement", "help wanted"],
head: "with-labels",
changes: {
files: {
"path/to/file1.txt": "Content for file1",
"path/to/file2.txt": "Content for file2",
},
commit: "why",
},
});

expect(pr).toStrictEqual(fixturePr);
expect(fixtures.length).toEqual(0);
});
63 changes: 63 additions & 0 deletions test/labels.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { Octokit as Core } from "@octokit/core";
import { RequestError } from "@octokit/request-error";

import { createPullRequest } from "../src";
const Octokit = Core.plugin(createPullRequest);

test("labels", async () => {
const fixtures = require("./fixtures/labels");
const fixturePr = fixtures[fixtures.length - 2].response;
const octokit = new Octokit();

octokit.hook.wrap("request", (_, options) => {
const currentFixtures = fixtures.shift();
const {
baseUrl,
method,
url,
request,
headers,
mediaType,
draft,
...params
} = options;

expect(
`${currentFixtures.request.method} ${currentFixtures.request.url}`
).toEqual(`${options.method} ${options.url}`);

Object.keys(params).forEach((paramName) => {
expect(currentFixtures.request[paramName]).toStrictEqual(
params[paramName]
);
});

if (currentFixtures.response.status >= 400) {
throw new RequestError("Error", currentFixtures.response.status, {
request: currentFixtures.request,
headers: currentFixtures.response.headers,
});
}

return currentFixtures.response;
});

const pr = await octokit.createPullRequest({
owner: "gr2m",
repo: "pull-request-test",
title: "One comes, one goes",
body: "because",
labels: ["enhancement", "help wanted"],
head: "with-labels",
changes: {
files: {
"path/to/file1.txt": "Content for file1",
"path/to/file2.txt": "Content for file2",
},
commit: "why",
},
});

expect(pr).toStrictEqual(fixturePr);
expect(fixtures.length).toEqual(0);
});

0 comments on commit 0295fd0

Please sign in to comment.