diff --git a/pom.xml b/pom.xml index 805080b06e..05d286b718 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ github-api - 1.72 + 1.73 GitHub API for Java http://github-api.kohsuke.org/ GitHub API for Java @@ -16,7 +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.72 + github-api-1.73 diff --git a/src/main/java/org/kohsuke/github/GHCommit.java b/src/main/java/org/kohsuke/github/GHCommit.java index a350eeb535..91510fc88c 100644 --- a/src/main/java/org/kohsuke/github/GHCommit.java +++ b/src/main/java/org/kohsuke/github/GHCommit.java @@ -102,7 +102,7 @@ public int getLinesDeleted() { } /** - * "modified", "added", or "deleted" + * "modified", "added", or "removed" */ public String getStatus() { return status; @@ -171,14 +171,15 @@ static class User { String login; } - String url,sha; + String url,html_url,sha; List files; Stats stats; List parents; User author,committer; - public ShortInfo getCommitShortInfo() { + public ShortInfo getCommitShortInfo() throws IOException { + populate(); return commit; } @@ -213,6 +214,13 @@ public int getLinesDeleted() throws IOException { return stats.deletions; } + /** + * URL of this commit like "https://github.com/kohsuke/sandbox-ant/commit/8ae38db0ea5837313ab5f39d43a6f73de3bd9000" + */ + public URL getHtmlUrl() { + return GitHub.parseURL(html_url); + } + /** * [0-9a-f]{40} SHA1 checksum. */ diff --git a/src/main/java/org/kohsuke/github/GHCreateRepositoryBuilder.java b/src/main/java/org/kohsuke/github/GHCreateRepositoryBuilder.java new file mode 100644 index 0000000000..492aaf5c81 --- /dev/null +++ b/src/main/java/org/kohsuke/github/GHCreateRepositoryBuilder.java @@ -0,0 +1,114 @@ +package org.kohsuke.github; + +import java.io.IOException; +import java.net.URL; + +/** + * Creates a repository + * + * @author Kohsuke Kawaguchi + */ +public class GHCreateRepositoryBuilder { + private final GitHub root; + protected final Requester builder; + private final String apiUrlTail; + + /*package*/ GHCreateRepositoryBuilder(GitHub root, String apiUrlTail, String name) { + this.root = root; + this.apiUrlTail = apiUrlTail; + this.builder = new Requester(root); + this.builder.with("name",name); + } + + public GHCreateRepositoryBuilder description(String description) { + this.builder.with("description",description); + return this; + } + + public GHCreateRepositoryBuilder homepage(URL homepage) { + return homepage(homepage.toExternalForm()); + } + + public GHCreateRepositoryBuilder homepage(String homepage) { + this.builder.with("homepage",homepage); + return this; + } + + /** + * Creates a private repository + */ + public GHCreateRepositoryBuilder private_(boolean b) { + this.builder.with("private",b); + return this; + } + + /** + * Enables issue tracker + */ + public GHCreateRepositoryBuilder issues(boolean b) { + this.builder.with("has_issues",b); + return this; + } + + /** + * Enables wiki + */ + public GHCreateRepositoryBuilder wiki(boolean b) { + this.builder.with("has_wiki",b); + return this; + } + + /** + * Enables downloads + */ + public GHCreateRepositoryBuilder downloads(boolean b) { + this.builder.with("has_downloads",b); + return this; + } + + /** + * If true, create an initial commit with empty README. + */ + public GHCreateRepositoryBuilder autoInit(boolean b) { + this.builder.with("auto_init",b); + return this; + } + + /** + * Creates a default .gitignore + * + * See https://developer.github.com/v3/repos/#create + */ + public GHCreateRepositoryBuilder gitignoreTemplate(String language) { + this.builder.with("gitignore_template",language); + return this; + } + + /** + * Desired license template to apply + * + * See https://developer.github.com/v3/repos/#create + */ + public GHCreateRepositoryBuilder licenseTemplate(String license) { + this.builder.with("license_template",license); + return this; + } + + /** + * The team that gets granted access to this repository. Only valid for creating a repository in + * an organization. + */ + public GHCreateRepositoryBuilder team(GHTeam team) { + if (team!=null) + this.builder.with("team_id",team.getId()); + return this; + } + + /** + * Creates a repository with all the parameters. + */ + public GHRepository create() throws IOException { + return builder.method("POST").to(apiUrlTail, GHRepository.class).wrap(root); + } + +} diff --git a/src/main/java/org/kohsuke/github/GHEvent.java b/src/main/java/org/kohsuke/github/GHEvent.java index 9e172146ae..e8e79bb456 100644 --- a/src/main/java/org/kohsuke/github/GHEvent.java +++ b/src/main/java/org/kohsuke/github/GHEvent.java @@ -1,5 +1,7 @@ package org.kohsuke.github; +import java.util.Locale; + /** * Hook event type. * @@ -33,5 +35,18 @@ public enum GHEvent { STATUS, TEAM_ADD, WATCH, - PING + PING, + /** + * Special event type that means "every possible event" + */ + ALL; + + + /** + * Returns GitHub's internal representation of this event. + */ + String symbol() { + if (this==ALL) return "*"; + return name().toLowerCase(Locale.ENGLISH); + } } diff --git a/src/main/java/org/kohsuke/github/GHHook.java b/src/main/java/org/kohsuke/github/GHHook.java index 7d63f9d950..73b2eb4364 100644 --- a/src/main/java/org/kohsuke/github/GHHook.java +++ b/src/main/java/org/kohsuke/github/GHHook.java @@ -26,8 +26,10 @@ public String getName() { public EnumSet getEvents() { EnumSet s = EnumSet.noneOf(GHEvent.class); - for (String e : events) - s.add(Enum.valueOf(GHEvent.class,e.toUpperCase(Locale.ENGLISH))); + for (String e : events) { + if (e.equals("*")) s.add(GHEvent.ALL); + else s.add(Enum.valueOf(GHEvent.class, e.toUpperCase(Locale.ENGLISH))); + } return s; } diff --git a/src/main/java/org/kohsuke/github/GHHooks.java b/src/main/java/org/kohsuke/github/GHHooks.java index 4ee939c5a8..6f64587b17 100644 --- a/src/main/java/org/kohsuke/github/GHHooks.java +++ b/src/main/java/org/kohsuke/github/GHHooks.java @@ -39,7 +39,7 @@ public GHHook createHook(String name, Map config, Collection(); for (GHEvent e : events) - ea.add(e.name().toLowerCase(Locale.ENGLISH)); + ea.add(e.symbol()); } GHHook hook = new Requester(root) diff --git a/src/main/java/org/kohsuke/github/GHOrganization.java b/src/main/java/org/kohsuke/github/GHOrganization.java index 83c8a0474a..c4ae92e6db 100644 --- a/src/main/java/org/kohsuke/github/GHOrganization.java +++ b/src/main/java/org/kohsuke/github/GHOrganization.java @@ -7,7 +7,6 @@ import java.util.Collection; import java.util.Collections; import java.util.List; -import java.util.Locale; import java.util.Map; import java.util.TreeMap; @@ -24,6 +23,8 @@ public class GHOrganization extends GHPerson { * * @return * Newly created repository. + * @deprecated + * Use {@link #createRepository(String)} that uses a builder pattern to let you control every aspect. */ public GHRepository createRepository(String name, String description, String homepage, String team, boolean isPublic) throws IOException { GHTeam t = getTeams().get(team); @@ -32,13 +33,25 @@ public GHRepository createRepository(String name, String description, String hom return createRepository(name, description, homepage, t, isPublic); } + /** + * @deprecated + * Use {@link #createRepository(String)} that uses a builder pattern to let you control every aspect. + */ public GHRepository createRepository(String name, String description, String homepage, GHTeam team, boolean isPublic) throws IOException { if (team==null) throw new IllegalArgumentException("Invalid team"); - // such API doesn't exist, so fall back to HTML scraping - return new Requester(root) - .with("name", name).with("description", description).with("homepage", homepage) - .with("public", isPublic).with("team_id",team.getId()).to("/orgs/"+login+"/repos", GHRepository.class).wrap(root); + return createRepository(name).description(description).homepage(homepage).private_(!isPublic).team(team).create(); + } + + /** + * Starts a builder that creates a new repository. + * + *

+ * You use the returned builder to set various properties, then call {@link GHCreateRepositoryBuilder#create()} + * to finally createa repository. + */ + public GHCreateRepositoryBuilder createRepository(String name) throws IOException { + return new GHCreateRepositoryBuilder(root,"/orgs/"+login+"/repos",name); } /** @@ -185,7 +198,7 @@ public GHTeam createTeam(String name, Permission p, Collection rep } public GHTeam createTeam(String name, Permission p, GHRepository... repositories) throws IOException { - return createTeam(name,p, Arrays.asList(repositories)); + return createTeam(name, p, Arrays.asList(repositories)); } /** diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java index b024814625..fbd64709a6 100644 --- a/src/main/java/org/kohsuke/github/GHRepository.java +++ b/src/main/java/org/kohsuke/github/GHRepository.java @@ -475,7 +475,7 @@ private void modifyCollaborators(Collection users, String method) throws public void setEmailServiceHook(String address) throws IOException { Map config = new HashMap(); config.put("address", address); - new Requester(root).method("POST").with("name", "email").with("config", config).with("active", "true") + new Requester(root).method("POST").with("name", "email").with("config", config).with("active", true) .to(getApiTailUrl("hooks")); } diff --git a/src/main/java/org/kohsuke/github/GitHub.java b/src/main/java/org/kohsuke/github/GitHub.java index b6ddd6e965..77d178800c 100644 --- a/src/main/java/org/kohsuke/github/GitHub.java +++ b/src/main/java/org/kohsuke/github/GitHub.java @@ -410,17 +410,28 @@ public T parseEventPayload(Reader r, Class type) t /** * Creates a new repository. * - * To create a repository in an organization, see - * {@link GHOrganization#createRepository(String, String, String, GHTeam, boolean)} - * * @return * Newly created repository. + * @deprecated + * Use {@link #createRepository(String)} that uses a builder pattern to let you control every aspect. */ public GHRepository createRepository(String name, String description, String homepage, boolean isPublic) throws IOException { - Requester requester = new Requester(this) - .with("name", name).with("description", description).with("homepage", homepage) - .with("public", isPublic ? 1 : 0); - return requester.method("POST").to("/user/repos", GHRepository.class).wrap(this); + return createRepository(name).description(description).homepage(homepage).private_(!isPublic).create(); + } + + /** + * Starts a builder that creates a new repository. + * + *

+ * You use the returned builder to set various properties, then call {@link GHCreateRepositoryBuilder#create()} + * to finally createa repository. + * + *

+ * To create a repository in an organization, see + * {@link GHOrganization#createRepository(String, String, String, GHTeam, boolean)} + */ + public GHCreateRepositoryBuilder createRepository(String name) { + return new GHCreateRepositoryBuilder(this,"/user/repos",name); } /** diff --git a/src/test/java/org/kohsuke/github/AppTest.java b/src/test/java/org/kohsuke/github/AppTest.java index 5d5e0a5fef..c8d523cd81 100755 --- a/src/test/java/org/kohsuke/github/AppTest.java +++ b/src/test/java/org/kohsuke/github/AppTest.java @@ -38,6 +38,21 @@ public void testRepoCRUD() throws Exception { getUser().getRepository(targetName).delete(); } + @Test + public void testRepositoryWithAutoInitializationCRUD() throws IOException { + String name = "github-api-test-autoinit"; + deleteRepository(name); + GHRepository r = gitHub.createRepository(name) + .description("a test repository for auto init") + .homepage("http://github-api.kohsuke.org/") + .autoInit(true).create(); + r.enableIssueTracker(false); + r.enableDownloads(false); + r.enableWiki(false); + assertNotNull(r.getReadme()); + getUser().getRepository(name).delete(); + } + private void deleteRepository(final String name) throws IOException { GHRepository repository = getUser().getRepository(name); if(repository != null) { @@ -326,6 +341,8 @@ public void testCommit() throws Exception { System.out.println(commit); assertEquals(1, commit.getParents().size()); assertEquals(1,commit.getFiles().size()); + assertEquals("https://github.com/jenkinsci/jenkins/commit/08c1c9970af4d609ae754fbe803e06186e3206f7", + commit.getHtmlUrl().toString()); File f = commit.getFiles().get(0); assertEquals(48,f.getLinesChanged()); @@ -774,7 +791,7 @@ public void markDown() throws Exception { assertTrue(actual.contains("href=\"https://github.com/kohsuke\"")); assertTrue(actual.contains("href=\"https://github.com/kohsuke/github-api/pull/1\"")); assertTrue(actual.contains("class=\"user-mention\"")); - assertTrue(actual.contains("class=\"issue-link\"")); + assertTrue(actual.contains("class=\"issue-link ")); assertTrue(actual.contains("to fix issue")); } diff --git a/src/test/java/org/kohsuke/github/GHOrganizationTest.java b/src/test/java/org/kohsuke/github/GHOrganizationTest.java new file mode 100644 index 0000000000..a1c5d3b921 --- /dev/null +++ b/src/test/java/org/kohsuke/github/GHOrganizationTest.java @@ -0,0 +1,43 @@ +package org.kohsuke.github; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Test; + +import java.io.IOException; + +public class GHOrganizationTest extends AbstractGitHubApiTestBase { + + public static final String GITHUB_API_TEST = "github-api-test"; + private GHOrganization org; + + @Override + public void setUp() throws Exception { + super.setUp(); + org = gitHub.getOrganization("github-api-test-org"); + } + + @Test + public void testCreateRepository() throws IOException { + GHRepository repository = org.createRepository(GITHUB_API_TEST, + "a test repository used to test kohsuke's github-api", "http://github-api.kohsuke.org/", "Core Developers", true); + Assert.assertNotNull(repository); + } + + @Test + public void testCreateRepositoryWithAutoInitialization() throws IOException { + GHRepository repository = org.createRepository(GITHUB_API_TEST) + .description("a test repository used to test kohsuke's github-api") + .homepage("http://github-api.kohsuke.org/") + .team(org.getTeamByName("Core Developers")) + .autoInit(true).create(); + Assert.assertNotNull(repository); + Assert.assertNotNull(repository.getReadme()); + } + + @After + public void cleanUp() throws Exception { + GHRepository repository = org.getRepository(GITHUB_API_TEST); + repository.delete(); + } +}