Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion src/main/java/org/kohsuke/github/GHRepository.java
Original file line number Diff line number Diff line change
Expand Up @@ -727,7 +727,20 @@ public boolean isPrivate() {
* Visibility of a repository.
*/
public enum Visibility {
PUBLIC, INTERNAL, PRIVATE, UNKNOWN;
PUBLIC,
INTERNAL,
PRIVATE,

/**
* Placeholder for unexpected data values.
*
* This avoids throwing exceptions during data binding or reading when the list of allowed values returned from
* GitHub is expanded.
*
* Do not pass this value to any methods. If this value is returned during a request, check the log output and
* report an issue for the missing value.
*/
UNKNOWN;

public static Visibility from(String value) {
return EnumUtils.getNullableEnumOrDefault(Visibility.class, value, Visibility.UNKNOWN);
Expand Down
92 changes: 92 additions & 0 deletions src/main/java/org/kohsuke/github/GHRepositorySearchBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,62 @@ public GHRepositorySearchBuilder forks(String v) {
return q("forks:" + v);
}

/**
* Searching in forks
*
* The default search mode is {@link Fork#PARENT_ONLY}. In that mode, forks are not included in search results.
*
* <p>
* Passing {@link Fork#PARENT_AND_FORKS} or {@link Fork#FORKS_ONLY} will show results from forks, but only if they
* have more stars than the parent repository.
*
* <p>
* IMPORTANT: Regardless of this setting, no search results will ever be returned for forks with equal or fewer
* stars than the parent repository. Forks with less stars than the parent repository are not included in the index
* for code searching.
*
* @param fork
* search mode for forks
*
* @return the gh repository search builder
*
* @see <a href=
* "https://docs.github.com/en/github/searching-for-information-on-github/searching-on-github/searching-in-forks">Searching
* in forks</a>
*
*/
public GHRepositorySearchBuilder fork(Fork fork) {
if (Fork.PARENT_ONLY.equals(fork)) {
this.terms.removeIf(term -> term.contains("fork:"));
return this;
}

return q("fork:" + fork);
}

/**
* Search by repository visibility
*
* @param visibility
* repository visibility
*
* @return the gh repository search builder
* @throws GHException
* if {@link GHRepository.Visibility#UNKNOWN} is passed. UNKNOWN is a placeholder for unexpected values
* encountered when reading data.
* @see <a href=
* "https://docs.github.com/en/github/searching-for-information-on-github/searching-on-github/searching-for-repositories#search-by-repository-visibility">Search
* by repository visibility</a>
*/
public GHRepositorySearchBuilder visibility(GHRepository.Visibility visibility) {
if (visibility == GHRepository.Visibility.UNKNOWN) {
throw new GHException(
"UNKNOWN is a placeholder for unexpected values encountered when reading data. It cannot be passed as a search parameter.");
}

return q("is:" + visibility);
}

/**
* Created gh repository search builder.
*
Expand Down Expand Up @@ -160,6 +216,42 @@ public enum Sort {
STARS, FORKS, UPDATED
}

/**
* The enum for Fork search mode
*/
public enum Fork {

/**
* Search in the parent repository and in forks with more stars than the parent repository.
*
* Forks with the same or fewer stars than the parent repository are still ignored.
*/
PARENT_AND_FORKS("true"),

/**
* Search only in forks with more stars than the parent repository.
*
* The parent repository is ignored. If no forks have more stars than the parent, no results will be returned.
*/
FORKS_ONLY("only"),

/**
* (Default) Search only the parent repository.
*
* Forks are ignored.
*/
PARENT_ONLY("");

private String filterMode;
Fork(String mode) {
this.filterMode = mode;
}

public String toString() {
return filterMode;
}
}

private static class RepositorySearchResult extends SearchResult<GHRepository> {
private GHRepository[] items;

Expand Down
61 changes: 61 additions & 0 deletions src/test/java/org/kohsuke/github/GHRepositoryTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import static org.hamcrest.Matchers.*;
import static org.hamcrest.core.IsInstanceOf.instanceOf;
import static org.junit.Assert.assertThrows;
import static org.kohsuke.github.GHVerification.Reason.*;

/**
Expand Down Expand Up @@ -417,6 +418,66 @@ public void listCommitCommentsNoComments() throws IOException {
assertThat("Commit has no comments", commitComments.isEmpty());
}

@Test
public void searchAllPublicAndForkedRepos() throws IOException {
PagedSearchIterable<GHRepository> list = gitHub.searchRepositories()
.user("t0m4uk1991")
.visibility(GHRepository.Visibility.PUBLIC)
.fork(GHRepositorySearchBuilder.Fork.PARENT_AND_FORKS)
.list();
List<GHRepository> u = list.toList();
assertThat(u.size(), is(14));
assertThat(u.stream().filter(item -> item.getName().equals("github-api")).count(), is(1L));
assertThat(u.stream().filter(item -> item.getName().equals("Complete-Python-3-Bootcamp")).count(), is(1L));
}

@Test
public void searchForPublicForkedOnlyRepos() throws IOException {
PagedSearchIterable<GHRepository> list = gitHub.searchRepositories()
.user("t0m4uk1991")
.visibility(GHRepository.Visibility.PUBLIC)
.fork(GHRepositorySearchBuilder.Fork.FORKS_ONLY)
.list();
List<GHRepository> u = list.toList();
assertThat(u.size(), is(2));
assertThat(u.get(0).getName(), is("github-api"));
assertThat(u.get(1).getName(), is("Complete-Python-3-Bootcamp"));
}

@Test
public void ghRepositorySearchBuilderIgnoresUnknownVisibility() {
GHRepositorySearchBuilder ghRepositorySearchBuilder;

GHException exception = assertThrows(GHException.class,
() -> new GHRepositorySearchBuilder(gitHub).visibility(Visibility.UNKNOWN));
assertThat(exception.getMessage(),
startsWith("UNKNOWN is a placeholder for unexpected values encountered when reading data."));

ghRepositorySearchBuilder = new GHRepositorySearchBuilder(gitHub).visibility(Visibility.PUBLIC);
assertThat(ghRepositorySearchBuilder.terms.stream().filter(item -> item.contains("is:")).count(), is(1L));

ghRepositorySearchBuilder = new GHRepositorySearchBuilder(gitHub).visibility(Visibility.PRIVATE);
assertThat(ghRepositorySearchBuilder.terms.stream().filter(item -> item.contains("is:")).count(), is(1L));

ghRepositorySearchBuilder = new GHRepositorySearchBuilder(gitHub).visibility(Visibility.INTERNAL);
assertThat(ghRepositorySearchBuilder.terms.stream().filter(item -> item.contains("is:")).count(), is(1L));
}

@Test
public void ghRepositorySearchBuilderForkDefaultResetForksSearchTerms() {
GHRepositorySearchBuilder ghRepositorySearchBuilder = new GHRepositorySearchBuilder(gitHub);
ghRepositorySearchBuilder = ghRepositorySearchBuilder.fork(GHRepositorySearchBuilder.Fork.PARENT_AND_FORKS);
assertThat(ghRepositorySearchBuilder.terms.stream().filter(item -> item.contains("fork:true")).count(), is(1L));
assertThat(ghRepositorySearchBuilder.terms.stream().filter(item -> item.contains("fork:")).count(), is(1L));

ghRepositorySearchBuilder = ghRepositorySearchBuilder.fork(GHRepositorySearchBuilder.Fork.FORKS_ONLY);
assertThat(ghRepositorySearchBuilder.terms.stream().filter(item -> item.contains("fork:only")).count(), is(1L));
assertThat(ghRepositorySearchBuilder.terms.stream().filter(item -> item.contains("fork:")).count(), is(2L));

ghRepositorySearchBuilder = ghRepositorySearchBuilder.fork(GHRepositorySearchBuilder.Fork.PARENT_ONLY);
assertThat(ghRepositorySearchBuilder.terms.stream().filter(item -> item.contains("fork:")).count(), is(0L));
}

@Test
public void listCommitCommentsSomeComments() throws IOException {
List<GHCommitComment> commitComments = getRepository()
Expand Down
Loading