From 1283006b53c9e6334798220f722aa2527c28e0f3 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Wed, 27 Nov 2013 11:57:40 -0800 Subject: [PATCH 01/16] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 48d7ce7b8e..7ead3a2a7f 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ github-api - 1.47 + 1.48-SNAPSHOT GitHub API for Java http://github-api.kohsuke.org/ GitHub API for Java From 925d26e54c80c951203519e3b546d4fb591ab2ff Mon Sep 17 00:00:00 2001 From: Alexandre COLLIGNON Date: Wed, 18 Sep 2013 11:29:04 +0200 Subject: [PATCH 02/16] Add GitHub Contents API read methods --- .../java/org/kohsuke/github/GHContent.java | 72 +++++++++++++++++++ .../java/org/kohsuke/github/GHRepository.java | 16 ++++- .../github/GHContentIntegrationTest.java | 42 +++++++++++ 3 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/kohsuke/github/GHContent.java create mode 100644 src/test/java/org/kohsuke/github/GHContentIntegrationTest.java diff --git a/src/main/java/org/kohsuke/github/GHContent.java b/src/main/java/org/kohsuke/github/GHContent.java new file mode 100644 index 0000000000..ba31f49741 --- /dev/null +++ b/src/main/java/org/kohsuke/github/GHContent.java @@ -0,0 +1,72 @@ +package org.kohsuke.github; + +/** + * A Content of a repository. + * + * @author Alexandre COLLIGNON + */ +public final class GHContent { + private GHRepository owner; + + private String type; + private String encoding; + private long size; + private String name; + private String path; + private String content; + private String url; // this is the API url + private String git_url; // this is the Blob url + private String html_url; // this is the UI + + public GHRepository getOwner() { + return owner; + } + + public String getType() { + return type; + } + + public String getEncoding() { + return encoding; + } + + public long getSize() { + return size; + } + + public String getName() { + return name; + } + + public String getPath() { + return path; + } + + public String getContent() { + return new String(javax.xml.bind.DatatypeConverter.parseBase64Binary(getEncodedContent())); + } + + public String getEncodedContent() { + return content; + } + + public String getUrl() { + return url; + } + + public String getGitUrl() { + return git_url; + } + + public String getHtmlUrl() { + return html_url; + } + + public boolean isFile() { + return "file".equals(type); + } + + public boolean isDirectory() { + return "dir".equals(type); + } +} diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java index f1a3100a46..f4cd9fd163 100644 --- a/src/main/java/org/kohsuke/github/GHRepository.java +++ b/src/main/java/org/kohsuke/github/GHRepository.java @@ -733,7 +733,21 @@ public GHMilestone getMilestone(int number) throws IOException { } return m; } - + + public GHContent getFileContent(String path) throws IOException { + return root.retrieve().to(String.format("/repos/%s/%s/contents/%s", owner.login, name, path), GHContent.class); + } + + public List getDirectoryContent(String path) throws IOException { + GHContent[] files = root.retrieve().to(String.format("/repos/%s/%s/contents/%s", owner.login, name, path), GHContent[].class); + + return Arrays.asList(files); + } + + public GHContent getReadme() throws Exception { + return getFileContent("readme"); + } + public GHMilestone createMilestone(String title, String description) throws IOException { return new Requester(root) .with("title", title).with("description", description).method("POST").to(getApiTailUrl("milestones"), GHMilestone.class).wrap(this); diff --git a/src/test/java/org/kohsuke/github/GHContentIntegrationTest.java b/src/test/java/org/kohsuke/github/GHContentIntegrationTest.java new file mode 100644 index 0000000000..bb2e71b8ad --- /dev/null +++ b/src/test/java/org/kohsuke/github/GHContentIntegrationTest.java @@ -0,0 +1,42 @@ +package org.kohsuke.github; + +import junit.framework.TestCase; + +import java.util.List; + +/** + * Unit test for {@link GHContent}. + */ +public class GHContentIntegrationTest extends TestCase { + + private GitHub gitHub; + private GHRepository repo; + + @Override + public void setUp() throws Exception { + super.setUp(); + // we just read at the moment + gitHub = GitHub.connectAnonymously(); + repo = gitHub.getUser("acollign").getRepository("github-api-test"); + } + + public void testGetFileContent() throws Exception { + GHContent content = repo.getFileContent("ghcontent-ro/a-file-with-content"); + + assertTrue(content.isFile()); + assertEquals("thanks for reading me\n", content.getContent()); + } + + public void testGetEmptyFileContent() throws Exception { + GHContent content = repo.getFileContent("ghcontent-ro/an-empty-file"); + + assertTrue(content.isFile()); + assertEquals("", content.getContent()); + } + + public void testGetDirectoryContent() throws Exception { + List entries = repo.getDirectoryContent("ghcontent-ro/a-dir-with-3-entries"); + + assertTrue(entries.size() == 3); + } +} From 3b49370c063c5df209a238afdf5a2298b861ebe7 Mon Sep 17 00:00:00 2001 From: Matt Farmer Date: Wed, 27 Nov 2013 23:28:40 -0500 Subject: [PATCH 03/16] Add the ability to retrieve the sha of the content. --- src/main/java/org/kohsuke/github/GHContent.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/org/kohsuke/github/GHContent.java b/src/main/java/org/kohsuke/github/GHContent.java index ba31f49741..92078d8406 100644 --- a/src/main/java/org/kohsuke/github/GHContent.java +++ b/src/main/java/org/kohsuke/github/GHContent.java @@ -11,6 +11,7 @@ public final class GHContent { private String type; private String encoding; private long size; + private String sha; private String name; private String path; private String content; @@ -34,6 +35,10 @@ public long getSize() { return size; } + public String getSha() { + return sha; + } + public String getName() { return name; } From 4ffd46b3913f4d85a6f1c51946d688e6c5c7ad4a Mon Sep 17 00:00:00 2001 From: Matt Farmer Date: Thu, 28 Nov 2013 00:03:43 -0500 Subject: [PATCH 04/16] Implement the ability to update existing content. --- .../java/org/kohsuke/github/GHContent.java | 27 ++++++++++++++++++- .../java/org/kohsuke/github/GHRepository.java | 2 +- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHContent.java b/src/main/java/org/kohsuke/github/GHContent.java index 92078d8406..993393b483 100644 --- a/src/main/java/org/kohsuke/github/GHContent.java +++ b/src/main/java/org/kohsuke/github/GHContent.java @@ -1,5 +1,9 @@ package org.kohsuke.github; +import java.io.IOException; + +import javax.xml.bind.DatatypeConverter; + /** * A Content of a repository. * @@ -48,7 +52,7 @@ public String getPath() { } public String getContent() { - return new String(javax.xml.bind.DatatypeConverter.parseBase64Binary(getEncodedContent())); + return new String(DatatypeConverter.parseBase64Binary(getEncodedContent())); } public String getEncodedContent() { @@ -74,4 +78,25 @@ public boolean isFile() { public boolean isDirectory() { return "dir".equals(type); } + + public void update(String newContent, String commitMessage) throws IOException { + new Requester(owner.root) + .with("path", path) + .with("message", commitMessage) + .with("sha", sha) + .with("content", DatatypeConverter.printBase64Binary(newContent.getBytes())) + .method("PUT") + .to(getApiRoute()); + + this.content = newContent; + } + + private String getApiRoute() { + return "/repos/" + owner.getOwnerName() + "/" + owner.getName() + "/contents/" + path; + } + + GHContent wrap(GHRepository owner) { + this.owner = owner; + return this; + } } diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java index f4cd9fd163..e657ac15fe 100644 --- a/src/main/java/org/kohsuke/github/GHRepository.java +++ b/src/main/java/org/kohsuke/github/GHRepository.java @@ -735,7 +735,7 @@ public GHMilestone getMilestone(int number) throws IOException { } public GHContent getFileContent(String path) throws IOException { - return root.retrieve().to(String.format("/repos/%s/%s/contents/%s", owner.login, name, path), GHContent.class); + return root.retrieve().to(String.format("/repos/%s/%s/contents/%s", owner.login, name, path), GHContent.class).wrap(this); } public List getDirectoryContent(String path) throws IOException { From 387d4e5bc976f97d3d6c2cbedaa5dba513a9fd70 Mon Sep 17 00:00:00 2001 From: Matt Farmer Date: Thu, 28 Nov 2013 00:12:30 -0500 Subject: [PATCH 05/16] Return the new GHContentUpdateResponse from content changes. --- .../java/org/kohsuke/github/GHContent.java | 10 +++++++--- .../github/GHContentUpdateResponse.java | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+), 3 deletions(-) create mode 100644 src/main/java/org/kohsuke/github/GHContentUpdateResponse.java diff --git a/src/main/java/org/kohsuke/github/GHContent.java b/src/main/java/org/kohsuke/github/GHContent.java index 993393b483..8584c805d0 100644 --- a/src/main/java/org/kohsuke/github/GHContent.java +++ b/src/main/java/org/kohsuke/github/GHContent.java @@ -79,16 +79,20 @@ public boolean isDirectory() { return "dir".equals(type); } - public void update(String newContent, String commitMessage) throws IOException { - new Requester(owner.root) + public GHContentUpdateResponse update(String newContent, String commitMessage) throws IOException { + GHContentUpdateResponse response = new Requester(owner.root) .with("path", path) .with("message", commitMessage) .with("sha", sha) .with("content", DatatypeConverter.printBase64Binary(newContent.getBytes())) .method("PUT") - .to(getApiRoute()); + .to(getApiRoute(), GHContentUpdateResponse.class); + + response.getContent().wrap(owner); + response.getCommit().wrapUp(owner); this.content = newContent; + return response; } private String getApiRoute() { diff --git a/src/main/java/org/kohsuke/github/GHContentUpdateResponse.java b/src/main/java/org/kohsuke/github/GHContentUpdateResponse.java new file mode 100644 index 0000000000..faa0545ad6 --- /dev/null +++ b/src/main/java/org/kohsuke/github/GHContentUpdateResponse.java @@ -0,0 +1,18 @@ +package org.kohsuke.github; + +/** + * The response that is returned when updating + * repository content. +**/ +public final class GHContentUpdateResponse { + private GHContent content; + private GHCommit commit; + + public GHContent getContent() { + return content; + } + + public GHCommit getCommit() { + return commit; + } +} From fc260d4a37c4a80e2d1267f342c31caec0a8d7fc Mon Sep 17 00:00:00 2001 From: Matt Farmer Date: Thu, 28 Nov 2013 00:21:25 -0500 Subject: [PATCH 06/16] Implement the ability to create content via content api. --- .../java/org/kohsuke/github/GHRepository.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java index e657ac15fe..04f4044bc0 100644 --- a/src/main/java/org/kohsuke/github/GHRepository.java +++ b/src/main/java/org/kohsuke/github/GHRepository.java @@ -42,6 +42,7 @@ import java.util.Map; import java.util.Set; import java.util.TreeMap; +import javax.xml.bind.DatatypeConverter; import static java.util.Arrays.*; @@ -748,6 +749,20 @@ public GHContent getReadme() throws Exception { return getFileContent("readme"); } + public GHContentUpdateResponse createContent(String content, String commitMessage, String path) throws IOException { + GHContentUpdateResponse response = new Requester(root) + .with("path", path) + .with("message", commitMessage) + .with("content", DatatypeConverter.printBase64Binary(content.getBytes())) + .method("PUT") + .to(getApiTailUrl("contents/" + path), GHContentUpdateResponse.class); + + response.getContent().wrap(this); + response.getCommit().wrapUp(this); + + return response; + } + public GHMilestone createMilestone(String title, String description) throws IOException { return new Requester(root) .with("title", title).with("description", description).method("POST").to(getApiTailUrl("milestones"), GHMilestone.class).wrap(this); From 54037e6e10de9ef925f503856bf82b679b385c7c Mon Sep 17 00:00:00 2001 From: Matt Farmer Date: Thu, 28 Nov 2013 00:29:49 -0500 Subject: [PATCH 07/16] Add the ability to specify a branch name with GHContent updates. --- src/main/java/org/kohsuke/github/GHContent.java | 15 ++++++++++++--- .../java/org/kohsuke/github/GHRepository.java | 15 ++++++++++++--- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHContent.java b/src/main/java/org/kohsuke/github/GHContent.java index 8584c805d0..d1ea30d97b 100644 --- a/src/main/java/org/kohsuke/github/GHContent.java +++ b/src/main/java/org/kohsuke/github/GHContent.java @@ -80,13 +80,22 @@ public boolean isDirectory() { } public GHContentUpdateResponse update(String newContent, String commitMessage) throws IOException { - GHContentUpdateResponse response = new Requester(owner.root) + return update(newContent, commitMessage, null); + } + + public GHContentUpdateResponse update(String newContent, String commitMessage, String branch) throws IOException { + Requester requester = new Requester(owner.root) .with("path", path) .with("message", commitMessage) .with("sha", sha) .with("content", DatatypeConverter.printBase64Binary(newContent.getBytes())) - .method("PUT") - .to(getApiRoute(), GHContentUpdateResponse.class); + .method("PUT"); + + if (branch != null) { + requester.with("branch", branch); + } + + GHContentUpdateResponse response = requester.to(getApiRoute(), GHContentUpdateResponse.class); response.getContent().wrap(owner); response.getCommit().wrapUp(owner); diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java index 04f4044bc0..3ee92b7daf 100644 --- a/src/main/java/org/kohsuke/github/GHRepository.java +++ b/src/main/java/org/kohsuke/github/GHRepository.java @@ -750,12 +750,21 @@ public GHContent getReadme() throws Exception { } public GHContentUpdateResponse createContent(String content, String commitMessage, String path) throws IOException { - GHContentUpdateResponse response = new Requester(root) + return createContent(content, commitMessage, path, null); + } + + public GHContentUpdateResponse createContent(String content, String commitMessage, String path, String branch) throws IOException { + Requester requester = new Requester(root) .with("path", path) .with("message", commitMessage) .with("content", DatatypeConverter.printBase64Binary(content.getBytes())) - .method("PUT") - .to(getApiTailUrl("contents/" + path), GHContentUpdateResponse.class); + .method("PUT"); + + if (branch != null) { + requester.with("branch", branch); + } + + GHContentUpdateResponse response = requester.to(getApiTailUrl("contents/" + path), GHContentUpdateResponse.class); response.getContent().wrap(this); response.getCommit().wrapUp(this); From b0c30759c8d518a04dfafd414e7938b786a37bde Mon Sep 17 00:00:00 2001 From: Matt Farmer Date: Thu, 28 Nov 2013 00:33:07 -0500 Subject: [PATCH 08/16] Properly wrap content on directory listing retrieval. --- src/main/java/org/kohsuke/github/GHContent.java | 7 +++++++ src/main/java/org/kohsuke/github/GHRepository.java | 2 ++ 2 files changed, 9 insertions(+) diff --git a/src/main/java/org/kohsuke/github/GHContent.java b/src/main/java/org/kohsuke/github/GHContent.java index d1ea30d97b..d4926c2399 100644 --- a/src/main/java/org/kohsuke/github/GHContent.java +++ b/src/main/java/org/kohsuke/github/GHContent.java @@ -112,4 +112,11 @@ GHContent wrap(GHRepository owner) { this.owner = owner; return this; } + + public static GHContent[] wrap(GHContent[] contents, GHRepository repository) { + for (GHContent unwrappedContent : contents) { + unwrappedContent.wrap(repository); + } + return contents; + } } diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java index 3ee92b7daf..4cc02f3f14 100644 --- a/src/main/java/org/kohsuke/github/GHRepository.java +++ b/src/main/java/org/kohsuke/github/GHRepository.java @@ -742,6 +742,8 @@ public GHContent getFileContent(String path) throws IOException { public List getDirectoryContent(String path) throws IOException { GHContent[] files = root.retrieve().to(String.format("/repos/%s/%s/contents/%s", owner.login, name, path), GHContent[].class); + GHContent.wrap(files, this); + return Arrays.asList(files); } From f8d14d2e56576bdb8699b45099e9bd0fc32182e6 Mon Sep 17 00:00:00 2001 From: Matt Farmer Date: Thu, 28 Nov 2013 00:37:40 -0500 Subject: [PATCH 09/16] Implement the ability to delete content. --- .../java/org/kohsuke/github/GHContent.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/main/java/org/kohsuke/github/GHContent.java b/src/main/java/org/kohsuke/github/GHContent.java index d4926c2399..22fb1ec164 100644 --- a/src/main/java/org/kohsuke/github/GHContent.java +++ b/src/main/java/org/kohsuke/github/GHContent.java @@ -104,6 +104,27 @@ public GHContentUpdateResponse update(String newContent, String commitMessage, S return response; } + public GHContentUpdateResponse delete(String message) throws IOException { + return delete(message, null); + } + + public GHContentUpdateResponse delete(String commitMessage, String branch) throws IOException { + Requester requester = new Requester(owner.root) + .with("path", path) + .with("message", commitMessage) + .with("sha", sha) + .method("DELETE"); + + if (branch != null) { + requester.with("branch", branch); + } + + GHContentUpdateResponse response = requester.to(getApiRoute(), GHContentUpdateResponse.class); + + response.getCommit().wrapUp(owner); + return response; + } + private String getApiRoute() { return "/repos/" + owner.getOwnerName() + "/" + owner.getName() + "/contents/" + path; } From a56357f0c175bd60ab6cea56cd8dc0f12adc2bcb Mon Sep 17 00:00:00 2001 From: Matt Farmer Date: Thu, 28 Nov 2013 09:44:27 -0500 Subject: [PATCH 10/16] Implement the ability to retrieve conent if not populated. The create and update API calls don't send back the content you just sent, so that field is null. If this GHContent was instantiated from one of those calls, we want to make sure we can retrieve the content (and updated sha, etc) on the fly. --- .../java/org/kohsuke/github/GHContent.java | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHContent.java b/src/main/java/org/kohsuke/github/GHContent.java index 22fb1ec164..c8e6b5d3b4 100644 --- a/src/main/java/org/kohsuke/github/GHContent.java +++ b/src/main/java/org/kohsuke/github/GHContent.java @@ -51,11 +51,37 @@ public String getPath() { return path; } - public String getContent() { + /** + * Retrieve the decoded content that is stored at this location. + * + * Due to the nature of GitHub's API, you're not guaranteed that + * the content will already be populated, so this may trigger + * network activity, and can throw an IOException. + **/ + public String getContent() throws IOException { return new String(DatatypeConverter.parseBase64Binary(getEncodedContent())); } - public String getEncodedContent() { + /** + * Retrieve the raw content that is stored at this location. + * + * Due to the nature of GitHub's API, you're not guaranteed that + * the content will already be populated, so this may trigger + * network activity, and can throw an IOException. + **/ + public String getEncodedContent() throws IOException { + if (content != null) + return content; + + GHContent retrievedContent = owner.getFileContent(path); + + this.size = retrievedContent.size; + this.sha = retrievedContent.sha; + this.content = retrievedContent.content; + this.url = retrievedContent.url; + this.git_url = retrievedContent.git_url; + this.html_url = retrievedContent.html_url; + return content; } From 9f3c5b93e33a9d5d1881d24ce59b54ace4d236cd Mon Sep 17 00:00:00 2001 From: Matt Farmer Date: Thu, 28 Nov 2013 09:45:21 -0500 Subject: [PATCH 11/16] Store encoded content in class level variable on update. --- src/main/java/org/kohsuke/github/GHContent.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHContent.java b/src/main/java/org/kohsuke/github/GHContent.java index c8e6b5d3b4..adc1285ed9 100644 --- a/src/main/java/org/kohsuke/github/GHContent.java +++ b/src/main/java/org/kohsuke/github/GHContent.java @@ -110,11 +110,13 @@ public GHContentUpdateResponse update(String newContent, String commitMessage) t } public GHContentUpdateResponse update(String newContent, String commitMessage, String branch) throws IOException { + String encodedContent = DatatypeConverter.printBase64Binary(newContent.getBytes()); + Requester requester = new Requester(owner.root) .with("path", path) .with("message", commitMessage) .with("sha", sha) - .with("content", DatatypeConverter.printBase64Binary(newContent.getBytes())) + .with("content", encodedContent) .method("PUT"); if (branch != null) { @@ -126,7 +128,7 @@ public GHContentUpdateResponse update(String newContent, String commitMessage, S response.getContent().wrap(owner); response.getCommit().wrapUp(owner); - this.content = newContent; + this.content = encodedContent; return response; } From f3207855cad72e91f2a8ed553afdc02aa1934d54 Mon Sep 17 00:00:00 2001 From: Matt Farmer Date: Thu, 28 Nov 2013 09:45:54 -0500 Subject: [PATCH 12/16] Implement a CRUD integration test for the content api. --- .../github/GHContentIntegrationTest.java | 33 ++++++++++++++++--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/src/test/java/org/kohsuke/github/GHContentIntegrationTest.java b/src/test/java/org/kohsuke/github/GHContentIntegrationTest.java index bb2e71b8ad..d375f85403 100644 --- a/src/test/java/org/kohsuke/github/GHContentIntegrationTest.java +++ b/src/test/java/org/kohsuke/github/GHContentIntegrationTest.java @@ -3,21 +3,24 @@ import junit.framework.TestCase; import java.util.List; +import java.util.UUID; /** - * Unit test for {@link GHContent}. + * Integration test for {@link GHContent}. */ public class GHContentIntegrationTest extends TestCase { private GitHub gitHub; private GHRepository repo; + private String createdFilename; @Override public void setUp() throws Exception { super.setUp(); - // we just read at the moment - gitHub = GitHub.connectAnonymously(); - repo = gitHub.getUser("acollign").getRepository("github-api-test"); + + gitHub = GitHub.connect(); + repo = gitHub.getRepository("acollign/github-api-test").fork(); + createdFilename = UUID.randomUUID().toString(); } public void testGetFileContent() throws Exception { @@ -39,4 +42,26 @@ public void testGetDirectoryContent() throws Exception { assertTrue(entries.size() == 3); } + + public void testCRUDContent() throws Exception { + GHContentUpdateResponse created = repo.createContent("this is an awesome file I created\n", "Creating a file for integration tests.", createdFilename); + GHContent createdContent = created.getContent(); + + assertNotNull(created.getCommit()); + assertNotNull(created.getContent()); + assertNotNull(createdContent.getContent()); + assertEquals("this is an awesome file I created\n", createdContent.getContent()); + + GHContentUpdateResponse updatedContentResponse = createdContent.update("this is some new content\n", "Updated file for integration tests."); + GHContent updatedContent = updatedContentResponse.getContent(); + + assertNotNull(updatedContentResponse.getCommit()); + assertNotNull(updatedContentResponse.getContent()); + assertEquals("this is some new content\n", updatedContent.getContent()); + + GHContentUpdateResponse deleteResponse = updatedContent.delete("Enough of this foolishness!"); + + assertNotNull(deleteResponse.getCommit()); + assertNull(deleteResponse.getContent()); + } } From 811b96bcbe9675b1e9e0aeefb92ee70860a4b91c Mon Sep 17 00:00:00 2001 From: Matt Farmer Date: Thu, 28 Nov 2013 10:02:37 -0500 Subject: [PATCH 13/16] Implement the ability to retrieve content from a particular ref. --- .../java/org/kohsuke/github/GHRepository.java | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java index 4cc02f3f14..c1146f8e4b 100644 --- a/src/main/java/org/kohsuke/github/GHRepository.java +++ b/src/main/java/org/kohsuke/github/GHRepository.java @@ -736,11 +736,31 @@ public GHMilestone getMilestone(int number) throws IOException { } public GHContent getFileContent(String path) throws IOException { - return root.retrieve().to(String.format("/repos/%s/%s/contents/%s", owner.login, name, path), GHContent.class).wrap(this); + return getFileContent(path, null); + } + + public GHContent getFileContent(String path, String ref) throws IOException { + Requester requester = root.retrieve(); + String target = String.format("/repos/%s/%s/contents/%s", owner.login, name, path); + + if (ref != null) + target = target + "?ref=" + ref; + + return requester.to(target, GHContent.class).wrap(this); } public List getDirectoryContent(String path) throws IOException { - GHContent[] files = root.retrieve().to(String.format("/repos/%s/%s/contents/%s", owner.login, name, path), GHContent[].class); + return getDirectoryContent(path, null); + } + + public List getDirectoryContent(String path, String ref) throws IOException { + Requester requester = root.retrieve(); + String target = String.format("/repos/%s/%s/contents/%s", owner.login, name, path); + + if (ref != null) + target = target + "?ref=" + ref; + + GHContent[] files = requester.to(target, GHContent[].class); GHContent.wrap(files, this); From 4b5241443517690f237205f16ebb56ac15b17916 Mon Sep 17 00:00:00 2001 From: Luca Milanesio Date: Wed, 11 Dec 2013 00:30:27 +0000 Subject: [PATCH 14/16] Fetching of user's verified keys through standard OAuth scope. Allow the fetching of a user's verified key list without requiring to have an OAuth user scope (which implies user's profile READ/WRITE permissions). This would relax the requirements of GitHub OAuth scope when fetching public information such as their SSH public keys. --- src/main/java/org/kohsuke/github/GHKey.java | 6 +++--- src/main/java/org/kohsuke/github/GHMyself.java | 18 ++++++++++++++++++ .../java/org/kohsuke/github/GHVerifiedKey.java | 13 +++++++++++++ 3 files changed, 34 insertions(+), 3 deletions(-) create mode 100644 src/main/java/org/kohsuke/github/GHVerifiedKey.java diff --git a/src/main/java/org/kohsuke/github/GHKey.java b/src/main/java/org/kohsuke/github/GHKey.java index e9692453d4..91632cf175 100644 --- a/src/main/java/org/kohsuke/github/GHKey.java +++ b/src/main/java/org/kohsuke/github/GHKey.java @@ -10,9 +10,9 @@ public class GHKey { /*package almost final*/ GitHub root; - private String url, key, title; - private boolean verified; - private int id; + protected String url, key, title; + protected boolean verified; + protected int id; public int getId() { return id; diff --git a/src/main/java/org/kohsuke/github/GHMyself.java b/src/main/java/org/kohsuke/github/GHMyself.java index 7a612007ac..70e732ac9e 100644 --- a/src/main/java/org/kohsuke/github/GHMyself.java +++ b/src/main/java/org/kohsuke/github/GHMyself.java @@ -34,6 +34,9 @@ public List getEmails() throws IOException { /** * Returns the read-only list of all the pulic keys of the current user. * + * NOTE: When using OAuth authenticaiton, the READ/WRITE User scope is + * required by the GitHub APIs, otherwise you will get a 404 NOT FOUND. + * * @return * Always non-null. */ @@ -41,6 +44,21 @@ public List getPublicKeys() throws IOException { return Collections.unmodifiableList(Arrays.asList(root.retrieve().to("/user/keys", GHKey[].class))); } + /** + * Returns the read-only list of all the pulic verified keys of the current user. + * + * Differently from the getPublicKeys() method, the retrieval of the user's + * verified public keys does not require any READ/WRITE OAuth Scope to the + * user's profile. + * + * @return + * Always non-null. + */ + public List getPublicVerifiedKeys() throws IOException { + return Collections.unmodifiableList(Arrays.asList(root.retrieve().to( + "/users/" + getLogin() + "/keys", GHVerifiedKey[].class))); + } + /** * Gets the organization that this user belongs to. */ diff --git a/src/main/java/org/kohsuke/github/GHVerifiedKey.java b/src/main/java/org/kohsuke/github/GHVerifiedKey.java new file mode 100644 index 0000000000..d81597d748 --- /dev/null +++ b/src/main/java/org/kohsuke/github/GHVerifiedKey.java @@ -0,0 +1,13 @@ +package org.kohsuke.github; + +public class GHVerifiedKey extends GHKey { + + public GHVerifiedKey() { + this.verified = true; + } + + @Override + public String getTitle() { + return (title == null ? "key-" + id : title); + } +} From 7d1f636cddd5653a7fa000b18ecf60978504b87c Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Wed, 1 Jan 2014 21:12:17 -0800 Subject: [PATCH 15/16] Recover from earlier test failures --- src/test/java/org/kohsuke/AppTest.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/java/org/kohsuke/AppTest.java b/src/test/java/org/kohsuke/AppTest.java index 64908e7a87..0b8177657c 100644 --- a/src/test/java/org/kohsuke/AppTest.java +++ b/src/test/java/org/kohsuke/AppTest.java @@ -46,6 +46,9 @@ public void setUp() throws Exception { } public void testRepoCRUD() throws Exception { + GHRepository existing = gitHub.getMyself().getRepository("github-api-test"); + if (existing!=null) + existing.delete(); GHRepository r = gitHub.createRepository("github-api-test", "a test repository", "http://github-api.kohsuke.org/", true); r.enableIssueTracker(false); r.enableDownloads(false); From 55e218ac3740670d90e31ab081011c8646028bc2 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Mon, 6 Jan 2014 08:51:56 -0800 Subject: [PATCH 16/16] [maven-release-plugin] prepare release github-api-1.48 --- pom.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7ead3a2a7f..3ab470b664 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ github-api - 1.48-SNAPSHOT + 1.48 GitHub API for Java http://github-api.kohsuke.org/ GitHub API for Java @@ -16,6 +16,7 @@ scm:git:git@github.com/kohsuke/${project.artifactId}.git scm:git:ssh://git@github.com/kohsuke/${project.artifactId}.git http://${project.artifactId}.kohsuke.org/ + github-api-1.48