Copy `github/findReferences` from v1 to v3 (#410)

The code will be refactored so that references are expressed in terms of
the GitHub node address code; the implementation is copied first so that
the review will be cleaner.

Test plan:
`yarn travis` passes.
This commit is contained in:
Dandelion Mané 2018-06-22 16:16:48 -07:00 committed by GitHub
parent 127200f67c
commit 2dec8868db
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 189 additions and 0 deletions

View File

@ -0,0 +1,58 @@
// @flow
function findAllMatches(re: RegExp, s: string): any[] {
// modified from: https://stackoverflow.com/a/6323598
let m;
const matches = [];
do {
m = re.exec(s);
if (m) {
matches.push(m);
}
} while (m);
return matches;
}
export function findReferences(body: string): string[] {
// Note to maintainer: If it becomes necessary to encode references in a
// richer format, consider implementing the type signature described in
// https://github.com/sourcecred/sourcecred/pull/130#pullrequestreview-113849998
return [
...findNumericReferences(body),
...findGithubUrlReferences(body),
...findUsernameReferences(body),
];
}
function findNumericReferences(body: string): string[] {
return findAllMatches(/(?:\W|^)(#\d+)(?:\W|$)/g, body).map((x) => x[1]);
}
function findUsernameReferences(body: string): string[] {
return findAllMatches(/(?:\W|^)(@[a-zA-Z0-9-]+)(?:\W|$)/g, body).map(
(x) => x[1]
);
}
function findGithubUrlReferences(body: string): string[] {
const githubNamePart = /(?:[a-zA-Z0-9_-]+)/.source;
const urlRegex = new RegExp(
"" +
/(?:\W|^)/.source +
"(" +
/http(?:s)?:\/\/github.com\//.source +
githubNamePart +
"(?:" +
/\//.source +
githubNamePart +
/\/(?:issues|pull)\//.source +
/(?:\d+)/.source +
/(?:#(?:issue|issuecomment|pullrequestreview|discussion_r)-?(?:\d+))?/
.source +
")?" +
")" +
/(?:[^\w/]|$)/.source,
"gm"
);
return findAllMatches(urlRegex, body).map((match) => match[1]);
}

View File

@ -0,0 +1,131 @@
// @flow
import {findReferences} from "./findReferences.js";
describe("findReferences", () => {
it("finds no references when not present", () => {
expect(findReferences("foo bar bod boink")).toHaveLength(0);
expect(findReferences("")).toHaveLength(0);
});
it("finds trivial numeric references", () => {
expect(findReferences("#1, #2, and #3")).toEqual(["#1", "#2", "#3"]);
});
it("finds numeric references in a multiline string", () => {
const example = `
This is a multiline string.
It refers to #1. Oh, and to #2 too.
(#42 might be included too - who knows?)`;
expect(findReferences(example)).toEqual(["#1", "#2", "#42"]);
});
it("does not find bad references", () => {
expect(findReferences("foo#123 #124bar")).toHaveLength(0);
});
it("does not yet find concise cross-repo links", () => {
// The link below is valid, when we add cross-repo support we
// should fix this test case
expect(findReferences("sourcecred/sourcecred#12")).toHaveLength(0);
});
it("finds a trivial url reference", () => {
expect(
findReferences("https://github.com/sourcecred/sourcecred/issues/86")
).toHaveLength(1);
});
it("finds url references", () => {
const example = `
A directly linked issue:
https://github.com/sourcecred/example-github/issues/1
A directly linked issue with fragment:
https://github.com/sourcecred/example-github/issues/1#issue-300934818
A directly linked pull request:
https://github.com/sourcecred/example-github/pull/3
A directly linked pull request with fragment:
https://github.com/sourcecred/example-github/pull/3#issue-171887741
A directly linked issue comment:
https://github.com/sourcecred/example-github/issues/6#issuecomment-373768442
A directly linked pull request review:
https://github.com/sourcecred/example-github/pull/5#pullrequestreview-100313899
A directly linked pull request review comment:
https://github.com/sourcecred/example-github/pull/5#discussion_r171460198
A directly linked pull request comment:
https://github.com/sourcecred/example-github/pull/3#issuecomment-369162222
`;
const expected = [
"https://github.com/sourcecred/example-github/issues/1",
"https://github.com/sourcecred/example-github/issues/1#issue-300934818",
"https://github.com/sourcecred/example-github/pull/3",
"https://github.com/sourcecred/example-github/pull/3#issue-171887741",
"https://github.com/sourcecred/example-github/issues/6#issuecomment-373768442",
"https://github.com/sourcecred/example-github/pull/5#pullrequestreview-100313899",
"https://github.com/sourcecred/example-github/pull/5#discussion_r171460198",
"https://github.com/sourcecred/example-github/pull/3#issuecomment-369162222",
];
expect(findReferences(example)).toEqual(expected);
});
it("doesn't find urls mangled with word characters", () => {
expect(
findReferences("foohttps://github.com/sourcecred/sourcecred/pull/94")
).toHaveLength(0);
expect(
findReferences("https://github.com/sourcecred/sourcecred/pull/94foo")
).toHaveLength(0);
expect(
findReferences("(https://github.com/sourcecred/sourcecred/pull/94)")
).toHaveLength(1);
});
it("allows but excludes leading and trailing punctuation", () => {
const base = "https://github.com/sourcecred/sourcecred/pull/94";
expect(findReferences(`!${base}`)).toEqual([base]);
expect(findReferences(`${base}!`)).toEqual([base]);
expect(findReferences(`!${base}!`)).toEqual([base]);
});
it("finds username references", () => {
expect(findReferences("hello to @wchargin from @decentralion!")).toEqual([
"@wchargin",
"@decentralion",
]);
});
it("finds usernames with hypens and numbers", () => {
expect(findReferences("@paddy-hack and @0x00 are valid usernames")).toEqual(
["@paddy-hack", "@0x00"]
);
});
it("finds username references by exact url", () => {
expect(findReferences("greetings https://github.com/wchargin")).toEqual([
"https://github.com/wchargin",
]);
});
it("finds a mix of reference types", () => {
expect(
findReferences(
"@wchargin commented on #125, eg https://github.com/sourcecred/sourcecred/pull/125#pullrequestreview-113402856"
)
).toEqual([
"#125",
"https://github.com/sourcecred/sourcecred/pull/125#pullrequestreview-113402856",
"@wchargin",
]);
});
});