Skip to content
Open
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
31 changes: 31 additions & 0 deletions src/main/java/org/kohsuke/github/GHIssueSearchBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,15 @@ public GHIssueSearchBuilder isClosed() {
return q("is:closed");
}

/**
* Filters results to only include issues (excludes pull requests).
*
* @return the gh issue search builder
*/
public GHIssueSearchBuilder isIssue() {
return q("is:issue");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method should also ensure that is:pr is removed if present.

}

/**
* Is merged gh issue search builder.
*
Expand All @@ -75,6 +84,15 @@ public GHIssueSearchBuilder isOpen() {
return q("is:open");
}

/**
* Filters results to only include pull requests (excludes issues).
*
* @return the gh issue search builder
*/
public GHIssueSearchBuilder isPullRequest() {
return q("is:pr");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method should also ensure that is:issue is removed if present.

}

/**
* Mentions gh issue search builder.
*
Expand Down Expand Up @@ -121,6 +139,19 @@ public GHIssueSearchBuilder q(String term) {
return this;
}

/**
* Filters results to a specific repository.
*
* @param owner
* the repository owner
* @param name
* the repository name
* @return the gh issue search builder
*/
public GHIssueSearchBuilder repo(String owner, String name) {
return q("repo:" + owner + "/" + name);
}

/**
* Sort gh issue search builder.
*
Expand Down
38 changes: 38 additions & 0 deletions src/test/java/org/kohsuke/github/AppTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -855,6 +855,44 @@ public void testIssueSearch() {
}
}

/**
* Test issue search with isIssue filter to exclude pull requests.
*/
@Test
public void testIssueSearchIssuesOnly() {
PagedSearchIterable<GHIssue> r = gitHub.searchIssues()
.repo("hub4j", "github-api")
.isIssue()
.isOpen()
.sort(GHIssueSearchBuilder.Sort.UPDATED)
.list();
assertThat(r.getTotalCount(), greaterThan(0));
for (GHIssue issue : r) {
Copy link
Member

@bitwiseman bitwiseman Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anyway to shorten the return list? If we can test this without storing several pages of json that we don't really care about.
Maybe isClosed() and sort.CREATED, then read the first few records?

assertThat(issue.getTitle(), notNullValue());
// Verify it's not a PR (pull_request field should be null)
assertThat(issue.getPullRequest(), nullValue());
}
}

/**
* Test issue search with isPullRequest filter to only return pull requests.
*/
@Test
public void testIssueSearchPullRequestsOnly() {
PagedSearchIterable<GHIssue> r = gitHub.searchIssues()
.repo("hub4j", "github-api")
.isPullRequest()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sure that last called wins

Suggested change
.isPullRequest()
.isIssue()
.isPullRequest()

.isOpen()
.sort(GHIssueSearchBuilder.Sort.UPDATED)
.list();
Copy link
Member

@bitwiseman bitwiseman Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anyway to shorten the return list? If we can test this without storing several pages of json that we don't really care about.

Maybe isClosed() and sort.CREATED, then read the first few records?

assertThat(r.getTotalCount(), greaterThan(0));
for (GHIssue issue : r) {
assertThat(issue.getTitle(), notNullValue());
// Verify it's a PR (pull_request field should not be null)
assertThat(issue.getPullRequest(), notNullValue());
}
}

/**
* Test issue with comment.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"login": "Anonycoders",
"id": 40047636,
"node_id": "MDQ6VXNlcjQwMDQ3NjM2",
"avatar_url": "https://avatars.githubusercontent.com/u/40047636?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/Anonycoders",
"html_url": "https://github.com/Anonycoders",
"followers_url": "https://api.github.com/users/Anonycoders/followers",
"following_url": "https://api.github.com/users/Anonycoders/following{/other_user}",
"gists_url": "https://api.github.com/users/Anonycoders/gists{/gist_id}",
"starred_url": "https://api.github.com/users/Anonycoders/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/Anonycoders/subscriptions",
"organizations_url": "https://api.github.com/users/Anonycoders/orgs",
"repos_url": "https://api.github.com/users/Anonycoders/repos",
"events_url": "https://api.github.com/users/Anonycoders/events{/privacy}",
"received_events_url": "https://api.github.com/users/Anonycoders/received_events",
"type": "User",
"user_view_type": "public",
"site_admin": false,
"name": "Sorena Sarabadani",
"company": "@Adevinta",
"blog": "",
"location": "Berlin, Germany",
"email": "sorena.sarabadani@gmail.com",
"hireable": null,
"bio": "Ex-Shopifyer - Adevinta/Kleinanzeigen",
"twitter_username": "sorena_s",
"notification_email": "sorena.sarabadani@gmail.com",
"public_repos": 12,
"public_gists": 0,
"followers": 38,
"following": 4,
"created_at": "2018-06-08T02:07:15Z",
"updated_at": "2026-01-24T22:07:12Z"
}
Loading
Loading