diff --git a/github/pom.xml b/github/pom.xml index d52b92f5d..7348901ee 100644 --- a/github/pom.xml +++ b/github/pom.xml @@ -79,6 +79,21 @@ spring-boot-starter-test test + + org.junit.platform + junit-platform-launcher + test + + + org.junit.jupiter + junit-jupiter-engine + test + + + org.junit.jupiter + junit-jupiter-params + test + \ No newline at end of file diff --git a/github/src/main/java/io/fundrequest/platform/github/parser/GithubResult.java b/github/src/main/java/io/fundrequest/platform/github/parser/GithubResult.java index c41d35eec..c40ee94c2 100644 --- a/github/src/main/java/io/fundrequest/platform/github/parser/GithubResult.java +++ b/github/src/main/java/io/fundrequest/platform/github/parser/GithubResult.java @@ -15,7 +15,8 @@ public class GithubResult { private String number; private String title; private String state; - @JsonProperty("body_html") private String body; + @JsonProperty("body_html") + private String bodyHtml; private GithubUser user; } diff --git a/github/src/main/java/io/fundrequest/platform/github/scraper/GithubScraper.java b/github/src/main/java/io/fundrequest/platform/github/scraper/GithubScraper.java index cd3a2f411..5f20cb402 100644 --- a/github/src/main/java/io/fundrequest/platform/github/scraper/GithubScraper.java +++ b/github/src/main/java/io/fundrequest/platform/github/scraper/GithubScraper.java @@ -1,6 +1,7 @@ package io.fundrequest.platform.github.scraper; import io.fundrequest.common.infrastructure.JsoupSpringWrapper; +import io.fundrequest.platform.github.scraper.model.GithubId; import io.fundrequest.platform.github.scraper.model.GithubIssue; import org.jsoup.nodes.Document; import org.springframework.stereotype.Component; @@ -29,7 +30,7 @@ public GithubIssue fetchGithubIssue(final String owner, final String repo, final } return GithubIssue.builder() .number(number) - .solver(solverResolver.resolve(document, owner, repo)) + .solver(solverResolver.resolve(document, GithubId.builder().owner(owner).repo(repo).number(number).build()).orElse(null)) .status(statusResolver.resolve(document)) .build(); } diff --git a/github/src/main/java/io/fundrequest/platform/github/scraper/GithubSolverResolver.java b/github/src/main/java/io/fundrequest/platform/github/scraper/GithubSolverResolver.java index 0ddbed2d6..6d216701e 100644 --- a/github/src/main/java/io/fundrequest/platform/github/scraper/GithubSolverResolver.java +++ b/github/src/main/java/io/fundrequest/platform/github/scraper/GithubSolverResolver.java @@ -2,54 +2,75 @@ import io.fundrequest.platform.github.GithubGateway; import io.fundrequest.platform.github.parser.GithubResult; +import io.fundrequest.platform.github.scraper.model.GithubId; import org.apache.commons.lang.StringUtils; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; import org.springframework.stereotype.Component; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.regex.Pattern; + @Component public class GithubSolverResolver { + private static final List CLOSING_KEYWORDS = Arrays.asList("close", "closes", "closed", "fix", "fixes", "fixed", "resolve", "resolves", "resolved"); + private final GithubGateway githubGateway; public GithubSolverResolver(final GithubGateway githubGateway) { this.githubGateway = githubGateway; } - public String resolve(final Document document, final String owner, final String repo) { + public Optional resolve(final Document document, final GithubId issueGithubId) { return document.select(".discussion-item") .stream() .filter(this::isPullRequest) .filter(this::isMerged) - .map(this::resolvePullRequestNumber) - .map(pullRequestNumber -> fetchAuthorFromPullRequest(pullRequestNumber, owner, repo)) + .map(this::resolvePullRequestGithubId) + .map(pullRequestGithubId -> fetchAuthorFromPullRequest(pullRequestGithubId, issueGithubId)) + .filter(Optional::isPresent) + .map(Optional::get) .filter(StringUtils::isNotEmpty) - .findFirst() - .orElse(null); + .findFirst(); } - private String resolvePullRequestNumber(final Element discussionItem) { - final String pullRequestNumber; + private GithubId resolvePullRequestGithubId(final Element discussionItem) { if (isPullRequestInSingleDiscussionItem(discussionItem)) { - pullRequestNumber = getPullRequestNumberFromSingleDiscussionItem(discussionItem); + return getPullRequestGithubIdFromSingleDiscussionItem(discussionItem); } else { - pullRequestNumber = getPullRequestNumberFromInlineDiscussionItem(discussionItem); + return getPullRequestGithubIdFromInlineDiscussionItem(discussionItem); } - return pullRequestNumber.replace("#", ""); } - private String getPullRequestNumberFromSingleDiscussionItem(final Element discussionItem) { - return discussionItem.select(".discussion-item [id^=ref-pullrequest-] ~ .discussion-item-ref-title span.issue-num").text(); + private GithubId getPullRequestGithubIdFromSingleDiscussionItem(final Element discussionItem) { + return GithubId.fromString(discussionItem.select(".discussion-item [id^=ref-pullrequest-] ~ .discussion-item-ref-title a").attr("href")) + .orElseThrow(() -> new RuntimeException("No pullrequest identifier is found")); + } + + private GithubId getPullRequestGithubIdFromInlineDiscussionItem(final Element discussionItem) { + return GithubId.fromString(discussionItem.select(".discussion-item [id^=ref-pullrequest-] a").attr("href")) + .orElseThrow(() -> new RuntimeException("No pullrequest identifier is found")); } - private String getPullRequestNumberFromInlineDiscussionItem(final Element discussionItem) { - return discussionItem.select(".discussion-item [id^=ref-pullrequest-] span.issue-num").text(); + private Optional fetchAuthorFromPullRequest(final GithubId pullRequestGithubId, final GithubId issueGithubId) { + final GithubResult pullRequest = githubGateway.getPullrequest(pullRequestGithubId.getOwner(), pullRequestGithubId.getRepo(), pullRequestGithubId.getNumber()); + if (pullRequest != null && pullRequestFixesIssue(pullRequest, issueGithubId)) { + return Optional.of(pullRequest.getUser().getLogin()); + } + return Optional.empty(); } - private String fetchAuthorFromPullRequest(final String pullRequestNumber, final String owner, final String repo) { - final GithubResult pullRequest = githubGateway.getPullrequest(owner, repo, pullRequestNumber); - return pullRequest.getUser().getLogin(); + private boolean pullRequestFixesIssue(final GithubResult pullRequest, final GithubId issueGithubId) { + final String pullRequestBody = pullRequest.getBody(); + + return pullRequestBody != null && CLOSING_KEYWORDS.stream() + .anyMatch(keyword -> Pattern.compile("\\b" + keyword.toLowerCase() + "\\b:?\\s*#" + issueGithubId.getNumber()) + .matcher(pullRequestBody.toLowerCase()) + .find()); } private boolean isPullRequestInSingleDiscussionItem(final Element discussionItem) { diff --git a/github/src/main/java/io/fundrequest/platform/github/scraper/model/GithubId.java b/github/src/main/java/io/fundrequest/platform/github/scraper/model/GithubId.java new file mode 100644 index 000000000..0c6c920ef --- /dev/null +++ b/github/src/main/java/io/fundrequest/platform/github/scraper/model/GithubId.java @@ -0,0 +1,32 @@ +package io.fundrequest.platform.github.scraper.model; + +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; + +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +@Getter +@Builder +@EqualsAndHashCode +public class GithubId { + + private final String owner; + private final String repo; + private final String number; + + public static Optional fromString(final String githubIdAsString) { + final Pattern pattern = Pattern.compile("^.*?/?(?.+)/(?.+)/.+/(?\\d+)$"); + final Matcher matcher = pattern.matcher(githubIdAsString); + if (matcher.matches()) { + return Optional.of(GithubId.builder() + .owner(matcher.group("owner")) + .repo(matcher.group("repo")) + .number(matcher.group("number")) + .build()); + } + return Optional.empty(); + } +} diff --git a/github/src/test/java/io/fundrequest/platform/github/scraper/DocumentMockBuilder.java b/github/src/test/java/io/fundrequest/platform/github/scraper/DocumentMockBuilder.java index ac6777594..0ab515560 100644 --- a/github/src/test/java/io/fundrequest/platform/github/scraper/DocumentMockBuilder.java +++ b/github/src/test/java/io/fundrequest/platform/github/scraper/DocumentMockBuilder.java @@ -1,5 +1,6 @@ package io.fundrequest.platform.github.scraper; +import io.fundrequest.platform.github.scraper.model.GithubId; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; @@ -7,6 +8,7 @@ import java.util.ArrayList; import java.util.List; +import static org.mockito.Mockito.RETURNS_DEEP_STUBS; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -41,7 +43,7 @@ public static class DiscussionItemBuilder { private final Element element; private DiscussionItemBuilder() { - this.element = mock(Element.class); + this.element = mock(Element.class, RETURNS_DEEP_STUBS); } public static DiscussionItemBuilder builder() { @@ -69,19 +71,17 @@ public DiscussionItemBuilder withAuthor(final String author) { return this; } - public DiscussionItemBuilder withIssueNum(final int issueNum, final boolean isInlinePullRequest) { + public DiscussionItemBuilder withPullrequestReference(final GithubId githubId, final boolean isInlinePullRequest) { final Elements pullRequestElements = mock(Elements.class); - final Elements pullRequestIssueNumElements = mock(Elements.class); when(pullRequestElements.isEmpty()).thenReturn(!isInlinePullRequest); when(element.select(".discussion-item .discussion-item-rollup-ref [id^=ref-pullrequest-]")).thenReturn(pullRequestElements); + final String githubIssueId = String.format("/%s/%s/pulls/%s", githubId.getOwner(), githubId.getRepo(), githubId.getNumber()); if (isInlinePullRequest) { - when(pullRequestIssueNumElements.text()).thenReturn("#" + String.valueOf(issueNum)); - when(element.select(".discussion-item [id^=ref-pullrequest-] span.issue-num")).thenReturn(pullRequestIssueNumElements); + when(element.select(".discussion-item [id^=ref-pullrequest-] a").attr("href")).thenReturn(githubIssueId); } else { - when(pullRequestIssueNumElements.text()).thenReturn("#" + String.valueOf(issueNum)); - when(element.select(".discussion-item [id^=ref-pullrequest-] ~ .discussion-item-ref-title span.issue-num")).thenReturn(pullRequestIssueNumElements); + when(element.select(".discussion-item [id^=ref-pullrequest-] ~ .discussion-item-ref-title a").attr("href")).thenReturn(githubIssueId); } return this; } diff --git a/github/src/test/java/io/fundrequest/platform/github/scraper/GithubScraperIntegrationTest.java b/github/src/test/java/io/fundrequest/platform/github/scraper/GithubScraperIntegrationTest.java index 5765c8b47..ad8d1aee6 100644 --- a/github/src/test/java/io/fundrequest/platform/github/scraper/GithubScraperIntegrationTest.java +++ b/github/src/test/java/io/fundrequest/platform/github/scraper/GithubScraperIntegrationTest.java @@ -54,8 +54,7 @@ public void fetch_parsesCorrectSolver_whenReferencerInIssueIsNotOwnerPullRequest assertThat(githubIssue.getNumber()).isEqualTo("48"); assertThat(githubIssue.getSolver()).isEqualTo("pauliax"); - //TODO Uncomment when issue https://github.com/FundRequest/contracts/issues/48 is closed. - // assertThat(githubIssue.getStatus()).isEqualTo("Closed"); + assertThat(githubIssue.getStatus()).isEqualTo("Closed"); } @Test @@ -70,4 +69,43 @@ public void fetch_whenNoSolver() { assertThat(githubIssue.getSolver()).isNull(); assertThat(githubIssue.getStatus()).isEqualTo("Closed"); } + + @Test + public void fetch_issueRandomlyReferencedInPullRequestFromSameRepo() { + final String owner = "aragon"; + final String repo = "aragonOS"; + final String number = "280"; + + final GithubIssue githubIssue = scraper.fetchGithubIssue(owner, repo, number); + + assertThat(githubIssue.getNumber()).isEqualTo("280"); + assertThat(githubIssue.getSolver()).isNull(); + assertThat(githubIssue.getStatus()).isEqualTo("Open"); + } + + @Test + public void fetch_issueRandomlyReferencedInPullRequestFromOtherRepo() { + final String owner = "trufflesuite"; + final String repo = "truffle"; + final String number = "501"; + + final GithubIssue githubIssue = scraper.fetchGithubIssue(owner, repo, number); + + assertThat(githubIssue.getNumber()).isEqualTo("501"); + assertThat(githubIssue.getSolver()).isNull(); + assertThat(githubIssue.getStatus()).isEqualTo("Open"); + } + + @Test + public void fetch_() { + final String owner = "FundRequest"; + final String repo = "contracts"; + final String number = "50"; + + final GithubIssue githubIssue = scraper.fetchGithubIssue(owner, repo, number); + + assertThat(githubIssue.getNumber()).isEqualTo("50"); + assertThat(githubIssue.getSolver()).isEqualTo("thomasvds"); + assertThat(githubIssue.getStatus()).isEqualTo("Closed"); + } } diff --git a/github/src/test/java/io/fundrequest/platform/github/scraper/GithubScraperTest.java b/github/src/test/java/io/fundrequest/platform/github/scraper/GithubScraperTest.java index ce63c688d..bbe89d15f 100644 --- a/github/src/test/java/io/fundrequest/platform/github/scraper/GithubScraperTest.java +++ b/github/src/test/java/io/fundrequest/platform/github/scraper/GithubScraperTest.java @@ -2,12 +2,14 @@ import io.fundrequest.common.infrastructure.JsoupSpringWrapper; +import io.fundrequest.platform.github.scraper.model.GithubId; import io.fundrequest.platform.github.scraper.model.GithubIssue; import org.jsoup.nodes.Document; import org.junit.Before; import org.junit.Test; import java.io.IOException; +import java.util.Optional; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.RETURNS_DEEP_STUBS; @@ -39,7 +41,7 @@ public void fetchGithubIssue() throws IOException { final Document document = mock(Document.class); when(jsoup.connect("https://github.com/" + owner + "/" + repo + "/issues/" + number).get()).thenReturn(document); - when(solverParser.resolve(document, owner, repo)).thenReturn(expectedSolver); + when(solverParser.resolve(document, GithubId.builder().owner(owner).repo(repo).number(number).build())).thenReturn(Optional.of(expectedSolver)); when(statusParser.resolve(document)).thenReturn(expectedStatus); final GithubIssue returnedIssue = scraper.fetchGithubIssue(owner, repo, number); diff --git a/github/src/test/java/io/fundrequest/platform/github/scraper/GithubSolverResolverTest.java b/github/src/test/java/io/fundrequest/platform/github/scraper/GithubSolverResolverTest.java index 7688caac6..c595d7322 100644 --- a/github/src/test/java/io/fundrequest/platform/github/scraper/GithubSolverResolverTest.java +++ b/github/src/test/java/io/fundrequest/platform/github/scraper/GithubSolverResolverTest.java @@ -3,31 +3,36 @@ import io.fundrequest.platform.github.GithubGateway; import io.fundrequest.platform.github.parser.GithubResult; import io.fundrequest.platform.github.parser.GithubUser; +import io.fundrequest.platform.github.scraper.model.GithubId; import org.jsoup.nodes.Document; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import java.util.Optional; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -public class GithubSolverResolverTest { +class GithubSolverResolverTest { private GithubSolverResolver parser; private GithubGateway githubGateway; - @Before - public void setUp() { + @BeforeEach + void setUp() { githubGateway = mock(GithubGateway.class); parser = new GithubSolverResolver(githubGateway); } @Test - public void parse() { - final String owner = "tfjgk"; - final String repo = "hfcjgv"; + void parse() { final String solver = "dfgh"; - final int pullrequestNumber = 765; + final GithubUser solverUser = GithubUser.builder().login(solver).build(); + final GithubId issueGithubId = GithubId.builder().owner("tfjgk").repo("hfcjgv").number("435").build(); + final GithubId pullrequestGithubId = GithubId.builder().owner("gb").repo("awerg").number("765").build(); final Document doc = DocumentMockBuilder.documentBuilder() .addDiscussionItem(DocumentMockBuilder.discussionItemBuilder() .isPullRequest(false) @@ -36,31 +41,36 @@ public void parse() { .isPullRequest(true) .isMerged(false) .withAuthor("hgfcjgv") - .withIssueNum(53, false) + .withPullrequestReference(GithubId.builder().owner("xnbf").repo("afds").number("53").build(), false) .build()) .addDiscussionItem(DocumentMockBuilder.discussionItemBuilder() .isPullRequest(true) .isMerged(true) .withAuthor("gdhfh") - .withIssueNum(pullrequestNumber, false) + .withPullrequestReference(pullrequestGithubId, false) .build()) .build(); - when(githubGateway.getPullrequest(owner, repo, String.valueOf(pullrequestNumber))).thenReturn(GithubResult.builder() - .user(GithubUser.builder().login(solver).build()) - .build()); + when(githubGateway.getPullrequest("xnbf", "afds", "53")).thenReturn(GithubResult.builder() + .user(GithubUser.builder().login("hgfcjgv").build()) + .body("fixes #" + issueGithubId.getNumber()) + .build()); + when(githubGateway.getPullrequest(pullrequestGithubId.getOwner(), pullrequestGithubId.getRepo(), pullrequestGithubId.getNumber())).thenReturn(GithubResult.builder() + .user(solverUser) + .body("Fixes #" + issueGithubId.getNumber()) + .build()); - final String returnedSolver = parser.resolve(doc, owner, repo); + final Optional result = parser.resolve(doc, issueGithubId); - assertThat(returnedSolver).isEqualTo(solver); + assertThat(result).contains(solver); } @Test - public void parse_pullRequestMerged_noSolverOnPage() { - final String owner = "tfjgk"; - final String repo = "hfcjgv"; + void parse_pullRequestMerged_noSolverOnPage() { final String solver = "dfgh"; - final int pullrequestNumber = 765; + final GithubUser solverUser = GithubUser.builder().login(solver).build(); + final GithubId issueGithubId = GithubId.builder().owner("tfjgk").repo("hfcjgv").number("435").build(); + final GithubId pullrequestGithubId = GithubId.builder().owner("gb").repo("awerg").number("765").build(); final Document doc = DocumentMockBuilder.documentBuilder() .addDiscussionItem(DocumentMockBuilder.discussionItemBuilder() .isPullRequest(false) @@ -69,39 +79,41 @@ public void parse_pullRequestMerged_noSolverOnPage() { .isPullRequest(true) .isMerged(false) .withAuthor("hgfcjgv") - .withIssueNum(53, false) + .withPullrequestReference(GithubId.builder().owner("xnbf").repo("afds").number("53").build(), false) .build()) .addDiscussionItem(DocumentMockBuilder.discussionItemBuilder() .isPullRequest(true) .isMerged(true) .withAuthor("") - .withIssueNum(pullrequestNumber, true) + .withPullrequestReference(pullrequestGithubId, false) .build()) .build(); - when(githubGateway.getPullrequest(owner, repo, String.valueOf(pullrequestNumber))).thenReturn(GithubResult.builder() - .user(GithubUser.builder().login(solver).build()) - .build()); - - final String returnedSolver = parser.resolve(doc, owner, repo); + when(githubGateway.getPullrequest("xnbf", "afds", "53")).thenReturn(GithubResult.builder() + .user(GithubUser.builder().login("hgfcjgv").build()) + .body("fixes #" + issueGithubId.getNumber()) + .build()); + when(githubGateway.getPullrequest(pullrequestGithubId.getOwner(), pullrequestGithubId.getRepo(), pullrequestGithubId.getNumber())).thenReturn(GithubResult.builder() + .user(solverUser) + .body("fixes #" + issueGithubId.getNumber()) + .build()); + final Optional result = parser.resolve(doc, issueGithubId); - assertThat(returnedSolver).isEqualTo(solver); + assertThat(result).contains(solver); } @Test - public void parse_noDiscussionItems() { - final String owner = "tfjgk"; - final String repo = "hfcjgv"; + void parse_noDiscussionItems() { + final GithubId issueGithubId = GithubId.builder().owner("tfjgk").repo("hfcjgv").number("35").build(); final Document doc = DocumentMockBuilder.documentBuilder().build(); - final String returnedSolver = parser.resolve(doc, owner, repo); + final Optional result = parser.resolve(doc, issueGithubId); - assertThat(returnedSolver).isNull(); + assertThat(result).isEmpty(); } @Test - public void parse_noPullRequest() { - final String owner = "tfjgk"; - final String repo = "hfcjgv"; + void parse_noPullRequest() { + final GithubId issueGithubId = GithubId.builder().owner("tfjgk").repo("hfcjgv").number("35").build(); final Document doc = DocumentMockBuilder.documentBuilder() .addDiscussionItem(DocumentMockBuilder.discussionItemBuilder() .isPullRequest(false) @@ -111,34 +123,33 @@ public void parse_noPullRequest() { .build()) .build(); - final String returnedSolver = parser.resolve(doc, owner, repo); + final Optional result = parser.resolve(doc, issueGithubId); - assertThat(returnedSolver).isNull();; + assertThat(result).isEmpty(); } @Test - public void parse_noMergedPullRequest() { - final String owner = "tfjgk"; - final String repo = "hfcjgv"; + void parse_noMergedPullRequest() { + final GithubId issueGithubId = GithubId.builder().owner("tfjgk").repo("hfcjgv").number("35").build(); + final GithubId pullrequestGithubId = GithubId.builder().owner("gb").repo("awerg").number("765").build(); final Document doc = DocumentMockBuilder.documentBuilder() .addDiscussionItem(DocumentMockBuilder.discussionItemBuilder() .isPullRequest(true) - .withIssueNum(53, false) + .withPullrequestReference(pullrequestGithubId, false) .isMerged(false) .withAuthor("hgfcjgv") .build()) .build(); - final String returnedSolver = parser.resolve(doc, owner, repo); + final Optional result = parser.resolve(doc, issueGithubId); - assertThat(returnedSolver).isNull(); + assertThat(result).isEmpty(); } @Test - public void parse_noSolver() { - final String owner = "tfjgk"; - final String repo = "hfcjgv"; - final int pullrequestNumber = 43; + void parse_noSolver() { + final GithubId issueGithubId = GithubId.builder().owner("tfjgk").repo("hfcjgv").number("35").build(); + final GithubId pullrequestGithubId = GithubId.builder().owner("gb").repo("awerg").number("765").build(); final Document doc = DocumentMockBuilder.documentBuilder() .addDiscussionItem(DocumentMockBuilder.discussionItemBuilder() .isPullRequest(false) @@ -146,22 +157,142 @@ public void parse_noSolver() { .addDiscussionItem(DocumentMockBuilder.discussionItemBuilder() .isPullRequest(true) .isMerged(false) - .withIssueNum(31, false) + .withPullrequestReference(GithubId.builder().owner("xnbf").repo("afds").number("53").build(), false) .withAuthor("ljhkgfdy") .build()) .addDiscussionItem(DocumentMockBuilder.discussionItemBuilder() .isPullRequest(true) .isMerged(true) .withAuthor("") - .withIssueNum(pullrequestNumber, true) + .withPullrequestReference(pullrequestGithubId, true) + .build()) + .build(); + when(githubGateway.getPullrequest(pullrequestGithubId.getOwner(), pullrequestGithubId.getRepo(), pullrequestGithubId.getNumber())).thenReturn(GithubResult.builder() + .user(GithubUser.builder().login("").build()) + .body("fixes #" + issueGithubId.getNumber()) + .build()); + + final Optional result = parser.resolve(doc, issueGithubId); + + assertThat(result).isEmpty(); + } + + @ParameterizedTest + @ValueSource(strings = {"close ", "closes ", "closed ", "fix ", "fixes ", "fixed ", "resolve ", "resolves ", "resolved ", "close: ", "closes: ", "closed: ", "fix: ", "fixes: ", "fixed: ", "resolve: ", + "resolves: ", "resolved: ", "close:", "closes:", "closed:", "fix:", "fixes:", "fixed:", "resolve:", + "resolves:", "resolved:", "Close ", "Closes ", "Closed ", "Fix ", "Fixes ", "Fixed ", "Resolve ", "Resolves ", "Resolved", "close: ", "closes: "}) + void parse_withClosingKeywords(final String keyword) { + final String solver = "dfgh"; + final GithubUser solverUser = GithubUser.builder().login(solver).build(); + final GithubId issueGithubId = GithubId.builder().owner("tfjgk").repo("hfcjgv").number("435").build(); + final GithubId pullrequestGithubId = GithubId.builder().owner("gb").repo("awerg").number("765").build(); + final Document doc = DocumentMockBuilder.documentBuilder() + .addDiscussionItem(DocumentMockBuilder.discussionItemBuilder() + .isPullRequest(false) + .build()) + .addDiscussionItem(DocumentMockBuilder.discussionItemBuilder() + .isPullRequest(true) + .isMerged(false) + .withAuthor("hgfcjgv") + .withPullrequestReference(GithubId.builder().owner("xnbf").repo("afds").number("53").build(), false) + .build()) + .addDiscussionItem(DocumentMockBuilder.discussionItemBuilder() + .isPullRequest(true) + .isMerged(true) + .withAuthor("gdhfh") + .withPullrequestReference(pullrequestGithubId, false) .build()) .build(); - when(githubGateway.getPullrequest(owner, repo, String.valueOf(pullrequestNumber))).thenReturn(GithubResult.builder() - .user(GithubUser.builder().login("").build()) - .build()); - final String returnedSolver = parser.resolve(doc, owner, repo); + when(githubGateway.getPullrequest("xnbf", "afds", "53")).thenReturn(GithubResult.builder() + .user(GithubUser.builder().login("hgfcjgv").build()) + .body("fixes #" + issueGithubId.getNumber()) + .build()); + when(githubGateway.getPullrequest(pullrequestGithubId.getOwner(), pullrequestGithubId.getRepo(), pullrequestGithubId.getNumber())).thenReturn(GithubResult.builder() + .user(solverUser) + .body(String.format("%s#%s", + keyword, + issueGithubId.getNumber())) + .build()); + + final Optional result = parser.resolve(doc, issueGithubId); + + assertThat(result).contains(solver); + } + + @Test + void parse_noClosingKeyword() { + final String solver = "dfgh"; + final GithubUser solverUser = GithubUser.builder().login(solver).build(); + final GithubId issueGithubId = GithubId.builder().owner("tfjgk").repo("hfcjgv").number("435").build(); + final GithubId pullrequestGithubId = GithubId.builder().owner("gb").repo("awerg").number("765").build(); + final Document doc = DocumentMockBuilder.documentBuilder() + .addDiscussionItem(DocumentMockBuilder.discussionItemBuilder() + .isPullRequest(false) + .build()) + .addDiscussionItem(DocumentMockBuilder.discussionItemBuilder() + .isPullRequest(true) + .isMerged(false) + .withAuthor("hgfcjgv") + .withPullrequestReference(GithubId.builder().owner("xnbf").repo("afds").number("53").build(), false) + .build()) + .addDiscussionItem(DocumentMockBuilder.discussionItemBuilder() + .isPullRequest(true) + .isMerged(true) + .withAuthor("gdhfh") + .withPullrequestReference(pullrequestGithubId, false) + .build()) + .build(); + + when(githubGateway.getPullrequest("xnbf", "afds", "53")).thenReturn(GithubResult.builder() + .user(GithubUser.builder().login("hgfcjgv").build()) + .body("fixes #" + issueGithubId.getNumber()) + .build()); + when(githubGateway.getPullrequest(pullrequestGithubId.getOwner(), pullrequestGithubId.getRepo(), pullrequestGithubId.getNumber())).thenReturn(GithubResult.builder() + .user(solverUser) + .body("") + .build()); + + final Optional result = parser.resolve(doc, issueGithubId); + + assertThat(result).isEmpty(); + } + + @Test + void parse_noClosingKeywordReferenceToIssue() { + final String solver = "dfgh"; + final GithubUser solverUser = GithubUser.builder().login(solver).build(); + final GithubId issueGithubId = GithubId.builder().owner("tfjgk").repo("hfcjgv").number("435").build(); + final GithubId pullrequestGithubId = GithubId.builder().owner("gb").repo("awerg").number("765").build(); + final Document doc = DocumentMockBuilder.documentBuilder() + .addDiscussionItem(DocumentMockBuilder.discussionItemBuilder() + .isPullRequest(false) + .build()) + .addDiscussionItem(DocumentMockBuilder.discussionItemBuilder() + .isPullRequest(true) + .isMerged(false) + .withAuthor("hgfcjgv") + .withPullrequestReference(GithubId.builder().owner("xnbf").repo("afds").number("53").build(), false) + .build()) + .addDiscussionItem(DocumentMockBuilder.discussionItemBuilder() + .isPullRequest(true) + .isMerged(true) + .withAuthor("gdhfh") + .withPullrequestReference(pullrequestGithubId, false) + .build()) + .build(); + + when(githubGateway.getPullrequest("xnbf", "afds", "53")).thenReturn(GithubResult.builder() + .user(GithubUser.builder().login("hgfcjgv").build()) + .body("fixes #" + issueGithubId.getNumber()) + .build()); + when(githubGateway.getPullrequest(pullrequestGithubId.getOwner(), pullrequestGithubId.getRepo(), pullrequestGithubId.getNumber())).thenReturn(GithubResult.builder() + .user(solverUser) + .body("#" + issueGithubId.getNumber()) + .build()); + + final Optional result = parser.resolve(doc, issueGithubId); - assertThat(returnedSolver).isNull(); + assertThat(result).isEmpty(); } } diff --git a/github/src/test/java/io/fundrequest/platform/github/scraper/model/GithubIdTest.java b/github/src/test/java/io/fundrequest/platform/github/scraper/model/GithubIdTest.java new file mode 100644 index 000000000..c53d307a9 --- /dev/null +++ b/github/src/test/java/io/fundrequest/platform/github/scraper/model/GithubIdTest.java @@ -0,0 +1,67 @@ +package io.fundrequest.platform.github.scraper.model; + + +import org.junit.Test; + +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + +public class GithubIdTest { + + @Test + public void fromString_issue() { + + final Optional resultOptional = GithubId.fromString("/FundRequest/area51/issues/38"); + + assertThat(resultOptional).isPresent(); + final GithubId result = resultOptional.get(); + assertThat(result.getOwner()).isEqualTo("FundRequest"); + assertThat(result.getRepo()).isEqualTo("area51"); + assertThat(result.getNumber()).isEqualTo("38"); + } + + @Test + public void fromString_issueFullURL() { + + final Optional resultOptional = GithubId.fromString("https://github.com/trufflesuite/truffle/issues/501"); + + assertThat(resultOptional).isPresent(); + final GithubId result = resultOptional.get(); + assertThat(result.getOwner()).isEqualTo("trufflesuite"); + assertThat(result.getRepo()).isEqualTo("truffle"); + assertThat(result.getNumber()).isEqualTo("501"); + } + + @Test + public void fromString_pullrequest() { + + final Optional resultOptional = GithubId.fromString("/smartcontractkit/chainlink/pull/276"); + + assertThat(resultOptional).isPresent(); + final GithubId result = resultOptional.get(); + assertThat(result.getOwner()).isEqualTo("smartcontractkit"); + assertThat(result.getRepo()).isEqualTo("chainlink"); + assertThat(result.getNumber()).isEqualTo("276"); + } + + @Test + public void fromString_pullrequestFullURL() { + + final Optional resultOptional = GithubId.fromString("https://github.com/aragon/aragonOS/pull/204"); + + assertThat(resultOptional).isPresent(); + final GithubId result = resultOptional.get(); + assertThat(result.getOwner()).isEqualTo("aragon"); + assertThat(result.getRepo()).isEqualTo("aragonOS"); + assertThat(result.getNumber()).isEqualTo("204"); + } + + @Test + public void noMatchEmtpy() { + + final Optional resultOptional = GithubId.fromString("/hfgdjfgk"); + + assertThat(resultOptional).isEmpty(); + } +}