diff --git a/src/main/java/org/kohsuke/github/GHEvent.java b/src/main/java/org/kohsuke/github/GHEvent.java new file mode 100644 index 000000000..8c255988b --- /dev/null +++ b/src/main/java/org/kohsuke/github/GHEvent.java @@ -0,0 +1,28 @@ +package org.kohsuke.github; + +/** + * Hook event type. + * + * See http://developer.github.com/v3/events/types/ + * + * @author Kohsuke Kawaguchi + */ +public enum GHEvent { + COMMIT_COMMENT, + CREATE, + DELETE, + DOWNLOAD, + FOLLOW, + FORK, + FORK_APPLY, + GIST, + GOLLUM, + ISSUE_COMMENT, + ISSUES, + MEMBER, + PUBLIC, + PULL_REQUEST, + PUSH, + TEAM_ADD, + WATCH +} diff --git a/src/main/java/org/kohsuke/github/GHHook.java b/src/main/java/org/kohsuke/github/GHHook.java new file mode 100644 index 000000000..b6b603a49 --- /dev/null +++ b/src/main/java/org/kohsuke/github/GHHook.java @@ -0,0 +1,60 @@ +package org.kohsuke.github; + +import java.io.IOException; +import java.util.Collections; +import java.util.EnumSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +/** + * @author Kohsuke Kawaguchi + */ +public final class GHHook { + /** + * Repository that the hook belongs to. + */ + /*package*/ transient GHRepository repository; + + String created_at, updated_at, name; + List events; + boolean active; + Map config; + int id; + + /*package*/ GHHook wrap(GHRepository owner) { + this.repository = owner; + return this; + } + + public String getName() { + return name; + } + + public EnumSet getEvents() { + EnumSet s = EnumSet.noneOf(GHEvent.class); + for (String e : events) + Enum.valueOf(GHEvent.class,e.toUpperCase(Locale.ENGLISH)); + return s; + } + + public boolean isActive() { + return active; + } + + public Map getConfig() { + return Collections.unmodifiableMap(config); + } + + public int getId() { + return id; + } + + /** + * Deletes this hook. + */ + public void delete() throws IOException { + new Poster(repository.root,ApiVersion.V3) + .to(String.format("/repos/%s/%s/hooks/%d",repository.getOwnerName(),id),null,"DELETE"); + } +} diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java index 2091d1ed3..52b40f8d9 100644 --- a/src/main/java/org/kohsuke/github/GHRepository.java +++ b/src/main/java/org/kohsuke/github/GHRepository.java @@ -33,12 +33,12 @@ import com.gargoylesoftware.htmlunit.html.HtmlPage; import com.infradna.tool.bridge_method_injector.WithBridgeMethods; import java.io.IOException; -import java.lang.annotation.RetentionPolicy; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.net.URL; import java.util.AbstractSet; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Date; @@ -46,6 +46,7 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.Set; import static java.util.Arrays.*; @@ -299,6 +300,53 @@ public class GHRepository { return root.retrieveWithAuth("/pulls/"+owner.login+'/'+name+"/"+state.name().toLowerCase(Locale.ENGLISH),JsonPullRequests.class).wrap(this); } + /** + * Retrieves the currently configured hooks. + */ + public List getHooks() throws IOException { + List list = new ArrayList(Arrays.asList( + root.retrieveWithAuth3(String.format("/repos/%s/%s/hooks",owner.login,name),GHHook[].class))); + for (GHHook h : list) + h.wrap(this); + return list; + } + + public GHHook getHook(int id) throws IOException { + return root.retrieveWithAuth3(String.format("/repos/%s/%s/hooks/%d",owner.login,name,id),GHHook.class).wrap(this); + } + + /** + * + * See https://api.github.com/hooks for possible names and their configuration scheme. + * TODO: produce type-safe binding + * + * @param name + * Type of the hook to be created. + * @param config + * The configuration hash. + * @param events + * Can be null. Types of events to hook into. + */ + public GHHook createHook(String name, Map config, Collection events, boolean active) throws IOException { + List ea = null; + if (events!=null) { + ea = new ArrayList(); + for (GHEvent e : events) + ea.add(e.name().toLowerCase(Locale.ENGLISH)); + } + + return new Poster(root,ApiVersion.V3) + .with("name",name) + .with("active", active) + ._with("config", config) + ._with("events",ea) + .to(String.format("/repos/%s/%s/hooks",owner.login,name),GHHook.class).wrap(this); + } + + public GHHook createWebHook(URL url, Collection events) throws IOException { + return createHook("web",Collections.singletonMap("url",url.toExternalForm()),events,true); + } + // this is no different from getPullRequests(OPEN) // /** // * Retrieves all the pull requests. @@ -315,6 +363,9 @@ public class GHRepository { /** * Returns a set that represents the post-commit hook URLs. * The returned set is live, and changes made to them are reflected to GitHub. + * + * @deprecated + * Use {@link #getHooks()} and {@link #createHook(String, Map, Collection, boolean)} */ public Set getPostCommitHooks() { return postCommitHooks; @@ -326,15 +377,11 @@ public class GHRepository { private final Set postCommitHooks = new AbstractSet() { private List getPostCommitHooks() { try { - verifyMine(); - - HtmlForm f = getForm(); - List r = new ArrayList(); - for (HtmlInput i : f.getInputsByName("urls[]")) { - String v = i.getValueAttribute(); - if (v.length()==0) continue; - r.add(new URL(v)); + for (GHHook h : getHooks()) { + if (h.getName().equals("web")) { + r.add(new URL(h.getConfig().get("url"))); + } } return r; } catch (IOException e) { @@ -355,22 +402,7 @@ public class GHRepository { @Override public boolean add(URL url) { try { - String u = url.toExternalForm(); - - verifyMine(); - - HtmlForm f = getForm(); - - List controls = f.getInputsByName("urls[]"); - for (HtmlInput i : controls) { - String v = i.getValueAttribute(); - if (v.length()==0) continue; - if (v.equals(u)) - return false; // already there - } - - controls.get(controls.size()-1).setValueAttribute(u); - f.submit(null); + createWebHook(url,null); return true; } catch (IOException e) { throw new GHException("Failed to update post-commit hooks",e); @@ -378,37 +410,20 @@ public class GHRepository { } @Override - public boolean remove(Object o) { + public boolean remove(Object url) { try { - String u = ((URL)o).toExternalForm(); - - verifyMine(); - - HtmlForm f = getForm(); - - List controls = f.getInputsByName("urls[]"); - for (HtmlInput i : controls) { - String v = i.getValueAttribute(); - if (v.length()==0) continue; - if (v.equals(u)) { - i.setValueAttribute(""); - f.submit(null); + String _url = ((URL)url).toExternalForm(); + for (GHHook h : getHooks()) { + if (h.getName().equals("web") && h.getConfig().get("url").equals(_url)) { + h.delete(); return true; } } - return false; } catch (IOException e) { throw new GHException("Failed to update post-commit hooks",e); } } - - private HtmlForm getForm() throws IOException { - WebClient wc = root.createWebClient(); - HtmlPage pg = (HtmlPage)wc.getPage(getUrl()+"/admin"); - HtmlForm f = (HtmlForm) pg.getElementById("new_service"); - return f; - } }; /*package*/ GHRepository wrap(GitHub root) { diff --git a/src/main/java/org/kohsuke/github/Poster.java b/src/main/java/org/kohsuke/github/Poster.java index 29b024d5d..0f7516acb 100644 --- a/src/main/java/org/kohsuke/github/Poster.java +++ b/src/main/java/org/kohsuke/github/Poster.java @@ -94,7 +94,7 @@ class Poster { return _with(key, value); } - private Poster _with(String key, Object value) { + public Poster _with(String key, Object value) { if (value!=null) { args.add(new Entry(key,value)); }