Skip to content

Commit d03edbf

Browse files
committed
Implement GHCompare commits iterable
1 parent ede3d42 commit d03edbf

23 files changed

Lines changed: 2428 additions & 133 deletions

File tree

src/main/java/org/kohsuke/github/GHCompare.java

Lines changed: 87 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
package org.kohsuke.github;
22

3+
import com.fasterxml.jackson.annotation.JacksonInject;
34
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
45
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
6+
import org.jetbrains.annotations.NotNull;
57

8+
import java.io.IOException;
9+
import java.net.MalformedURLException;
610
import java.net.URL;
11+
import java.util.Collections;
12+
import java.util.Iterator;
13+
14+
import javax.annotation.Nonnull;
715

816
/**
917
* The model user for comparing 2 commits in the GitHub API.
@@ -21,6 +29,9 @@ public class GHCompare {
2129

2230
private GHRepository owner;
2331

32+
@JacksonInject("GHCompare_usePaginatedCommits")
33+
private boolean usePaginatedCommits;
34+
2435
/**
2536
* Gets url.
2637
*
@@ -126,13 +137,35 @@ public Commit getMergeBaseCommit() {
126137
* @return A copy of the array being stored in the class.
127138
*/
128139
public Commit[] getCommits() {
129-
Commit[] newValue = new Commit[commits.length];
130-
System.arraycopy(commits, 0, newValue, 0, commits.length);
131-
return newValue;
140+
try {
141+
return listCommits().withPageSize(100).toArray();
142+
} catch (IOException e) {
143+
throw new GHException(e.getMessage(), e);
144+
}
132145
}
133146

134147
/**
135-
* Gets an array of commits.
148+
* Iterable of commits for this comparison.
149+
*
150+
* @return iterable of commits
151+
*/
152+
public PagedIterable<Commit> listCommits() {
153+
if (usePaginatedCommits) {
154+
return new GHCompareCommitsIterable();
155+
} else {
156+
// if not using paginated commits, adapt the returned commits array
157+
return new PagedIterable<Commit>() {
158+
@NotNull
159+
@Override
160+
public PagedIterator<Commit> _iterator(int pageSize) {
161+
return new PagedIterator<>(Collections.singleton(commits).iterator(), null);
162+
}
163+
};
164+
}
165+
}
166+
167+
/**
168+
* Gets an array of files.
136169
*
137170
* @return A copy of the array being stored in the class.
138171
*/
@@ -283,4 +316,54 @@ public static class User extends GitUser {
283316
public static enum Status {
284317
behind, ahead, identical, diverged
285318
}
319+
320+
/**
321+
* Iterable for commit listing.
322+
*/
323+
class GHCompareCommitsIterable extends PagedIterable<Commit> {
324+
325+
private GHCompare result;
326+
327+
public GHCompareCommitsIterable() {
328+
}
329+
330+
@Nonnull
331+
@Override
332+
public PagedIterator<Commit> _iterator(int pageSize) {
333+
try {
334+
GitHubRequest request = owner.getRoot()
335+
.createRequest()
336+
.injectMappingValue("GHCompare_usePaginatedCommits", usePaginatedCommits)
337+
.withUrlPath(owner.getApiTailUrl(url.substring(url.lastIndexOf("/compare/"))))
338+
.build();
339+
340+
// page_size must be set for GHCompare commit pagination
341+
if (pageSize == 0) {
342+
pageSize = 10;
343+
}
344+
return new PagedIterator<>(
345+
adapt(GitHubPageIterator
346+
.create(owner.getRoot().getClient(), GHCompare.class, request, pageSize)),
347+
item -> item.wrapUp(owner));
348+
} catch (MalformedURLException e) {
349+
throw new GHException("Malformed URL", e);
350+
}
351+
}
352+
353+
protected Iterator<Commit[]> adapt(final Iterator<GHCompare> base) {
354+
return new Iterator<Commit[]>() {
355+
public boolean hasNext() {
356+
return base.hasNext();
357+
}
358+
359+
public Commit[] next() {
360+
GHCompare v = base.next();
361+
if (result == null) {
362+
result = v;
363+
}
364+
return v.commits;
365+
}
366+
};
367+
}
368+
}
286369
}

src/main/java/org/kohsuke/github/GHRepository.java

Lines changed: 16 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ public class GHRepository extends GHObject {
125125
private GHRepository source, parent;
126126

127127
private Boolean isTemplate;
128+
private boolean compareUsePaginatedCommits;
128129

129130
static GHRepository read(GitHub root, String owner, String name) throws IOException {
130131
return root.createRequest().withUrlPath("/repos/" + owner + '/' + name).fetch(GHRepository.class).wrap(root);
@@ -1642,6 +1643,13 @@ public GHHook getHook(int id) throws IOException {
16421643
return GHHooks.repoContext(this, owner).getHook(id);
16431644
}
16441645

1646+
/**
1647+
*
1648+
*/
1649+
public void setCompareUsePaginatedCommits(boolean value) {
1650+
compareUsePaginatedCommits = value;
1651+
}
1652+
16451653
/**
16461654
* Gets a comparison between 2 points in the repository. This would be similar to calling
16471655
* <code>git log id1...id2</code> against a local repository.
@@ -1656,9 +1664,14 @@ public GHHook getHook(int id) throws IOException {
16561664
* on failure communicating with GitHub
16571665
*/
16581666
public GHCompare getCompare(String id1, String id2) throws IOException {
1659-
GHCompare compare = root.createRequest()
1660-
.withUrlPath(getApiTailUrl(String.format("compare/%s...%s", id1, id2)))
1661-
.fetch(GHCompare.class);
1667+
final Requester requester = root.createRequest()
1668+
.withUrlPath(getApiTailUrl(String.format("compare/%s...%s", id1, id2)));
1669+
1670+
if (compareUsePaginatedCommits) {
1671+
requester.with("per_page", 1).with("page", 1);
1672+
}
1673+
requester.injectMappingValue("GHCompare_usePaginatedCommits", compareUsePaginatedCommits);
1674+
GHCompare compare = requester.fetch(GHCompare.class);
16621675
return compare.wrap(this);
16631676
}
16641677

@@ -1705,33 +1718,6 @@ public GHCompare getCompare(GHBranch id1, GHBranch id2) throws IOException {
17051718
}
17061719

17071720
return getCompare(id1.getName(), id2.getName());
1708-
1709-
}
1710-
1711-
/**
1712-
* Gets a comparison between 2 points in the repository. This would be similar to calling
1713-
* <code>git log id1...id2</code> against a local repository.
1714-
*
1715-
* @param id1
1716-
* an identifier for the first point to compare from, this can be a sha1 ID (for a commit, tag etc) or a
1717-
* direct tag name
1718-
* @param id2
1719-
* an identifier for the second point to compare to. Can be the same as the first point.
1720-
* @param perPage
1721-
* Results per page (max 100) Default: 30
1722-
* @param page
1723-
* Page number of the results to fetch. Default: 1
1724-
* @return the comparison output
1725-
* @throws IOException
1726-
* on failure communicating with GitHub
1727-
*/
1728-
public GHCompare getCompare(String id1, String id2, int perPage, int page) throws IOException {
1729-
GHCompare compare = root.createRequest()
1730-
.with("per_page", perPage)
1731-
.with("page", page)
1732-
.withUrlPath(getApiTailUrl(String.format("compare/%s...%s", id1, id2)))
1733-
.fetch(GHCompare.class);
1734-
return compare.wrap(this);
17351721
}
17361722

17371723
/**

src/test/java/org/kohsuke/github/GHRepositoryTest.java

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -869,11 +869,30 @@ public void getLastCommitStatus() throws Exception {
869869

870870
@Test
871871
public void getCommitsBetween() throws Exception {
872-
GHCompare compare = getRepository().getCompare("e46a9f3f2ac55db96de3c5c4706f2813b3a96465",
873-
"8051615eff597f4e49f4f47625e6fc2b49f26bfc",
874-
10,
875-
1);
876-
assertThat(compare.getTotalCommits(), is(9));
872+
GHRepository repository = getRepository();
873+
int startingCount = mockGitHub.getRequestCount();
874+
compareCommitsBetween(repository);
875+
assertThat(mockGitHub.getRequestCount(), equalTo(startingCount + 1));
876+
}
877877

878+
@Test
879+
public void getCommitsBetweenPaginated() throws Exception {
880+
GHRepository repository = getRepository();
881+
int startingCount = mockGitHub.getRequestCount();
882+
repository.setCompareUsePaginatedCommits(true);
883+
compareCommitsBetween(repository);
884+
assertThat(mockGitHub.getRequestCount(), equalTo(startingCount + 3));
885+
}
886+
887+
private void compareCommitsBetween(GHRepository repository) throws IOException {
888+
GHCompare compare = repository.getCompare("e46a9f3f2ac55db96de3c5c4706f2813b3a96465",
889+
"8051615eff597f4e49f4f47625e6fc2b49f26bfc");
890+
int actualCount = 0;
891+
for (GHCompare.Commit item : compare.listCommits().withPageSize(5)) {
892+
assertThat(item, notNullValue());
893+
actualCount++;
894+
}
895+
assertThat(compare.getTotalCommits(), is(9));
896+
assertThat(actualCount, is(9));
878897
}
879898
}

src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/getCommitsBetween/__files/orgs_hub4j-test-org-2.json

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,24 @@
2727
"html_url": "https://github.com/hub4j-test-org",
2828
"created_at": "2014-05-10T19:39:11Z",
2929
"updated_at": "2020-06-04T05:56:10Z",
30-
"type": "Organization"
30+
"type": "Organization",
31+
"total_private_repos": 2,
32+
"owned_private_repos": 2,
33+
"private_gists": 0,
34+
"disk_usage": 11979,
35+
"collaborators": 0,
36+
"billing_email": "kk@kohsuke.org",
37+
"default_repository_permission": "none",
38+
"members_can_create_repositories": false,
39+
"two_factor_requirement_enabled": false,
40+
"members_can_create_pages": true,
41+
"members_can_create_public_pages": true,
42+
"members_can_create_private_pages": true,
43+
"plan": {
44+
"name": "free",
45+
"space": 976562499,
46+
"private_repos": 10000,
47+
"filled_seats": 26,
48+
"seats": 3
49+
}
3150
}

src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/getCommitsBetween/__files/repos_hub4j-test-org_github-api-3.json

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,18 @@
9898
"watchers": 0,
9999
"default_branch": "main",
100100
"permissions": {
101-
"admin": false,
102-
"push": false,
101+
"admin": true,
102+
"maintain": true,
103+
"push": true,
104+
"triage": true,
103105
"pull": true
104106
},
105107
"temp_clone_token": "",
108+
"allow_squash_merge": true,
109+
"allow_merge_commit": true,
110+
"allow_rebase_merge": true,
111+
"allow_auto_merge": false,
112+
"delete_branch_on_merge": false,
106113
"organization": {
107114
"login": "hub4j-test-org",
108115
"id": 7544739,
@@ -190,37 +197,37 @@
190197
"releases_url": "https://api.github.com/repos/hub4j/github-api/releases{/id}",
191198
"deployments_url": "https://api.github.com/repos/hub4j/github-api/deployments",
192199
"created_at": "2010-04-19T04:13:03Z",
193-
"updated_at": "2021-08-08T22:08:33Z",
194-
"pushed_at": "2021-08-08T22:13:20Z",
200+
"updated_at": "2021-09-06T01:04:31Z",
201+
"pushed_at": "2021-09-06T01:11:49Z",
195202
"git_url": "git://github.com/hub4j/github-api.git",
196203
"ssh_url": "git@github.com:hub4j/github-api.git",
197204
"clone_url": "https://github.com/hub4j/github-api.git",
198205
"svn_url": "https://github.com/hub4j/github-api",
199206
"homepage": "https://github-api.kohsuke.org/",
200-
"size": 35143,
201-
"stargazers_count": 792,
202-
"watchers_count": 792,
207+
"size": 35774,
208+
"stargazers_count": 803,
209+
"watchers_count": 803,
203210
"language": "Java",
204211
"has_issues": true,
205212
"has_projects": true,
206213
"has_downloads": true,
207214
"has_wiki": true,
208215
"has_pages": true,
209-
"forks_count": 556,
216+
"forks_count": 559,
210217
"mirror_url": null,
211218
"archived": false,
212219
"disabled": false,
213-
"open_issues_count": 85,
220+
"open_issues_count": 83,
214221
"license": {
215222
"key": "mit",
216223
"name": "MIT License",
217224
"spdx_id": "MIT",
218225
"url": "https://api.github.com/licenses/mit",
219226
"node_id": "MDc6TGljZW5zZTEz"
220227
},
221-
"forks": 556,
222-
"open_issues": 85,
223-
"watchers": 792,
228+
"forks": 559,
229+
"open_issues": 83,
230+
"watchers": 803,
224231
"default_branch": "main"
225232
},
226233
"source": {
@@ -290,39 +297,39 @@
290297
"releases_url": "https://api.github.com/repos/hub4j/github-api/releases{/id}",
291298
"deployments_url": "https://api.github.com/repos/hub4j/github-api/deployments",
292299
"created_at": "2010-04-19T04:13:03Z",
293-
"updated_at": "2021-08-08T22:08:33Z",
294-
"pushed_at": "2021-08-08T22:13:20Z",
300+
"updated_at": "2021-09-06T01:04:31Z",
301+
"pushed_at": "2021-09-06T01:11:49Z",
295302
"git_url": "git://github.com/hub4j/github-api.git",
296303
"ssh_url": "git@github.com:hub4j/github-api.git",
297304
"clone_url": "https://github.com/hub4j/github-api.git",
298305
"svn_url": "https://github.com/hub4j/github-api",
299306
"homepage": "https://github-api.kohsuke.org/",
300-
"size": 35143,
301-
"stargazers_count": 792,
302-
"watchers_count": 792,
307+
"size": 35774,
308+
"stargazers_count": 803,
309+
"watchers_count": 803,
303310
"language": "Java",
304311
"has_issues": true,
305312
"has_projects": true,
306313
"has_downloads": true,
307314
"has_wiki": true,
308315
"has_pages": true,
309-
"forks_count": 556,
316+
"forks_count": 559,
310317
"mirror_url": null,
311318
"archived": false,
312319
"disabled": false,
313-
"open_issues_count": 85,
320+
"open_issues_count": 83,
314321
"license": {
315322
"key": "mit",
316323
"name": "MIT License",
317324
"spdx_id": "MIT",
318325
"url": "https://api.github.com/licenses/mit",
319326
"node_id": "MDc6TGljZW5zZTEz"
320327
},
321-
"forks": 556,
322-
"open_issues": 85,
323-
"watchers": 792,
328+
"forks": 559,
329+
"open_issues": 83,
330+
"watchers": 803,
324331
"default_branch": "main"
325332
},
326-
"network_count": 556,
333+
"network_count": 559,
327334
"subscribers_count": 1
328335
}

src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/getCommitsBetween/__files/repos_hub4j-test-org_github-api_compare-4.json renamed to src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/getCommitsBetween/__files/repos_hub4j-test-org_github-api_compare_e46a9f3f2ac55db96de3c5c4706f2813b3a964658051615eff597f4e49f4f47625e6fc2b49f26bfc-4.json

File renamed without changes.

0 commit comments

Comments
 (0)