Allow to define different hierarchy for public vs. private repos

It is possible now to differentiate different project hierarchies
for GitHub public and private repositories.
Define the two different base projects in your [github] section using
the publicBaseProject and privateBaseProject.

If not specified in gerrit.config [github] section, the default base
project hierarchy is All-Projects.

Change-Id: Iaea7ee232dbfb2388ab8b23a84b5f397fd2aa150
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GitHubConfig.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GitHubConfig.java
index 2081e11..dbf6b6c 100644
--- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GitHubConfig.java
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GitHubConfig.java
@@ -19,10 +19,14 @@
 
 import org.eclipse.jgit.lib.Config;
 
+import com.google.common.base.Objects;
 import com.google.common.collect.Maps;
+import com.google.gerrit.server.config.AllProjectsName;
+import com.google.gerrit.server.config.AllProjectsNameProvider;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.config.SitePaths;
 import com.google.inject.Inject;
+import com.google.inject.Provider;
 import com.google.inject.Singleton;
 import com.googlesource.gerrit.plugins.github.oauth.CompositeConfig;
 import com.googlesource.gerrit.plugins.github.oauth.GitHubOAuthConfig;
@@ -42,6 +46,8 @@
       "repositoryListPageSize";
   private static final String CONF_REPOSITORY_LIST_LIMIT =
       "repositoryListLimit";
+  private static final String CONF_PUBLIC_BASE_PROJECT = "publicBaseProject";
+  private static final String CONF_PRIVATE_BASE_PROJECT = "privateBaseProject";
 
   public final File gitDir;
   public final int jobPoolLimit;
@@ -49,6 +55,9 @@
   public final int pullRequestListLimit;
   public final int repositoryListPageSize;
   public final int repositoryListLimit;
+  public final String privateBaseProject;
+  public final String publicBaseProject;
+  public final String allProjectsName;
 
   public static class NextPage {
     public final String uri;
@@ -62,7 +71,7 @@
 
 
   @Inject
-  public GitHubConfig(CompositeConfig config, final SitePaths site)
+  public GitHubConfig(CompositeConfig config, final SitePaths site, AllProjectsNameProvider allProjectsNameProvider)
       throws MalformedURLException {
     super(config);
     String[] wizardFlows =
@@ -90,6 +99,12 @@
     if (gitDir == null) {
       throw new IllegalStateException("gerrit.basePath must be configured");
     }
+
+    privateBaseProject =
+        config.getString(CONF_SECTION, null, CONF_PRIVATE_BASE_PROJECT);
+    publicBaseProject =
+        config.getString(CONF_SECTION, null, CONF_PUBLIC_BASE_PROJECT);
+    allProjectsName = allProjectsNameProvider.get().toString();
   }
 
   private String getSeparator(boolean redirect) {
@@ -109,4 +124,9 @@
   public NextPage getNextPage(String sourcePage) {
     return wizardFromTo.get(sourcePage);
   }
+
+  public String getBaseProject(boolean isPrivateProject) {
+    return Objects.firstNonNull(isPrivateProject ? privateBaseProject
+        : publicBaseProject, allProjectsName);
+  }
 }
diff --git a/github-plugin/src/main/java/com/googlesrouce/gerrit/plugins/github/git/CreateProjectStep.java b/github-plugin/src/main/java/com/googlesrouce/gerrit/plugins/github/git/CreateProjectStep.java
index f68ab55..67ca592 100644
--- a/github-plugin/src/main/java/com/googlesrouce/gerrit/plugins/github/git/CreateProjectStep.java
+++ b/github-plugin/src/main/java/com/googlesrouce/gerrit/plugins/github/git/CreateProjectStep.java
@@ -34,6 +34,7 @@
 import com.google.gerrit.server.project.ProjectCache;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
+import com.googlesource.gerrit.plugins.github.GitHubConfig;
 import com.googlesource.gerrit.plugins.github.GitHubURL;
 
 public class CreateProjectStep extends ImportStep {
@@ -50,8 +51,9 @@
   private String description;
   private GroupBackend groupBackend;
   private String username;
-  private ProjectConfig config;
+  private ProjectConfig projectConfig;
   private ProjectCache projectCache;
+  private GitHubConfig config;
 
   public interface Factory {
     CreateProjectStep create(@Assisted("organisation") String organisation,
@@ -66,6 +68,7 @@
       GroupBackend groupBackend,
       ProjectCache projectCache,
       GitHubRepository.Factory ghRepoFactory,
+      GitHubConfig gitHubConfig,
       @Assisted("organisation") String organisation,
       @Assisted("name") String repository,
       @Assisted("description") String description,
@@ -80,6 +83,7 @@
     this.groupBackend = groupBackend;
     this.projectCache = projectCache;
     this.username = username;
+    this.config = gitHubConfig;
   }
   
   private void setProjectPermissions() {
@@ -115,7 +119,7 @@
   }
   
   private void addPermissions(String refSpec, String... permissions) {
-    AccessSection accessSection = config.getAccessSection(refSpec, true);
+    AccessSection accessSection = projectConfig.getAccessSection(refSpec, true);
     for (String permission : permissions) {
       String[] permParts = permission.split("=");
       String action = permParts[0];
@@ -131,14 +135,14 @@
   }
 
   private void addPermission(String refSpec, String action, PermissionRule rule) {
-    config.getAccessSection(refSpec, true).getPermission(action, true)
+    projectConfig.getAccessSection(refSpec, true).getPermission(action, true)
         .add(rule);
   }
   
   private GroupReference getMyGroup() {
     GroupDescription.Basic g =
         groupBackend.get(AccountGroup.UUID.parse("user:" + username));
-    return config.resolve(GroupReference.forGroup(g));
+    return projectConfig.resolve(GroupReference.forGroup(g));
   }
 
   private NameKey getProjectNameKey() {
@@ -150,14 +154,14 @@
     MetaDataUpdate md = null;
     try {
       md = metaDataUpdateFactory.create(getProjectNameKey());
-      config = ProjectConfig.read(md);
+      projectConfig = ProjectConfig.read(md);
       progress.beginTask("Configure Gerrit project", 2);
       setProjectSettings();
       progress.update(1);
       setProjectPermissions();
       progress.update(1);
       md.setMessage("Imported from " + getSourceUri());
-      config.commit(md);
+      projectConfig.commit(md);
       projectCache.onCreateProject(getProjectNameKey());
     } finally {
       if(md != null) { 
@@ -168,7 +172,8 @@
   }
   
   private void setProjectSettings() {
-    Project project = config.getProject();
+    Project project = projectConfig.getProject();
+    project.setParentName(config.getBaseProject(getRepository().isPrivate()));
     project.setDescription(description);
     project.setSubmitType(SubmitType.MERGE_IF_NECESSARY);
     project.setUseContributorAgreements(InheritableBoolean.INHERIT);
diff --git a/github-plugin/src/main/java/com/googlesrouce/gerrit/plugins/github/git/GitHubRepository.java b/github-plugin/src/main/java/com/googlesrouce/gerrit/plugins/github/git/GitHubRepository.java
index f272630..dbf80f0 100644
--- a/github-plugin/src/main/java/com/googlesrouce/gerrit/plugins/github/git/GitHubRepository.java
+++ b/github-plugin/src/main/java/com/googlesrouce/gerrit/plugins/github/git/GitHubRepository.java
@@ -13,13 +13,23 @@
 // limitations under the License.
 package com.googlesrouce.gerrit.plugins.github.git;
 
+import java.io.IOException;
+import java.net.URL;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.kohsuke.github.*;
+
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 import com.googlesource.gerrit.plugins.github.GitHubURL;
 import com.googlesource.gerrit.plugins.github.oauth.GitHubLogin;
 import com.googlesource.gerrit.plugins.github.oauth.ScopedProvider;
 
-public class GitHubRepository {
+public class GitHubRepository extends GHRepository {
   public interface Factory {
     GitHubRepository create(@Assisted("organisation") String organisation,
         @Assisted("repository") String repository);
@@ -30,6 +40,7 @@
   private final String repository;
   private final GitHubLogin ghLogin;
   private final String cloneUrl;
+  private GHRepository ghRepository;
 
   public String getCloneUrl() {
     return cloneUrl.replace("://", "://" + ghLogin.getMyself().getLogin() + ":"
@@ -44,15 +55,355 @@
     return repository;
   }
 
-
   @Inject
   public GitHubRepository(ScopedProvider<GitHubLogin> ghLoginProvider,
       @GitHubURL String gitHubUrl,
       @Assisted("organisation") String organisation,
-      @Assisted("repository") String repository) {
+      @Assisted("repository") String repository) throws IOException {
     this.cloneUrl = gitHubUrl + "/" + organisation + "/" + repository + ".git";
     this.organisation = organisation;
     this.repository = repository;
     this.ghLogin = ghLoginProvider.get();
+    this.ghRepository =
+        ghLogin.hub.getRepository(organisation + "/" + repository);
+  }
+
+  public String getDescription() {
+    return ghRepository.getDescription();
+  }
+
+  public String getHomepage() {
+    return ghRepository.getHomepage();
+  }
+
+  public String getUrl() {
+    return ghRepository.getUrl();
+  }
+
+  public String getGitTransportUrl() {
+    return ghRepository.getGitTransportUrl();
+  }
+
+  public String gitHttpTransportUrl() {
+    return ghRepository.gitHttpTransportUrl();
+  }
+
+  public String getName() {
+    return ghRepository.getName();
+  }
+
+  public boolean hasPullAccess() {
+    return ghRepository.hasPullAccess();
+  }
+
+  public boolean hasPushAccess() {
+    return ghRepository.hasPushAccess();
+  }
+
+  public boolean hasAdminAccess() {
+    return ghRepository.hasAdminAccess();
+  }
+
+  public String getLanguage() {
+    return ghRepository.getLanguage();
+  }
+
+  public GHUser getOwner() throws IOException {
+    return ghRepository.getOwner();
+  }
+
+  public GHIssue getIssue(int id) throws IOException {
+    return ghRepository.getIssue(id);
+  }
+
+  public GHIssueBuilder createIssue(String title) {
+    return ghRepository.createIssue(title);
+  }
+
+  public List<GHIssue> getIssues(GHIssueState state) throws IOException {
+    return ghRepository.getIssues(state);
+  }
+
+  public PagedIterable<GHIssue> listIssues(GHIssueState state) {
+    return ghRepository.listIssues(state);
+  }
+
+  public GHReleaseBuilder createRelease(String tag) {
+    return ghRepository.createRelease(tag);
+  }
+
+  public List<GHRelease> getReleases() throws IOException {
+    return ghRepository.getReleases();
+  }
+
+  public boolean hasIssues() {
+    return ghRepository.hasIssues();
+  }
+
+  public boolean hasWiki() {
+    return ghRepository.hasWiki();
+  }
+
+  public boolean isFork() {
+    return ghRepository.isFork();
+  }
+
+  public int getForks() {
+    return ghRepository.getForks();
+  }
+
+  public boolean isPrivate() {
+    return ghRepository.isPrivate();
+  }
+
+  public boolean hasDownloads() {
+    return ghRepository.hasDownloads();
+  }
+
+  public int getWatchers() {
+    return ghRepository.getWatchers();
+  }
+
+  public int getOpenIssueCount() {
+    return ghRepository.getOpenIssueCount();
+  }
+
+  public Date getPushedAt() {
+    return ghRepository.getPushedAt();
+  }
+
+  public Date getCreatedAt() {
+    return ghRepository.getCreatedAt();
+  }
+
+  public String getMasterBranch() {
+    return ghRepository.getMasterBranch();
+  }
+
+  public int getSize() {
+    return ghRepository.getSize();
+  }
+
+  public GHPersonSet<GHUser> getCollaborators() throws IOException {
+    return ghRepository.getCollaborators();
+  }
+
+  public Set<String> getCollaboratorNames() throws IOException {
+    return ghRepository.getCollaboratorNames();
+  }
+
+  public Set<GHTeam> getTeams() throws IOException {
+    return ghRepository.getTeams();
+  }
+
+  public void addCollaborators(GHUser... users) throws IOException {
+    ghRepository.addCollaborators(users);
+  }
+
+  public void addCollaborators(Collection<GHUser> users) throws IOException {
+    ghRepository.addCollaborators(users);
+  }
+
+  public void removeCollaborators(GHUser... users) throws IOException {
+    ghRepository.removeCollaborators(users);
+  }
+
+  public void removeCollaborators(Collection<GHUser> users) throws IOException {
+    ghRepository.removeCollaborators(users);
+  }
+
+  public void setEmailServiceHook(String address) throws IOException {
+    ghRepository.setEmailServiceHook(address);
+  }
+
+  public void enableIssueTracker(boolean v) throws IOException {
+    ghRepository.enableIssueTracker(v);
+  }
+
+  public void enableWiki(boolean v) throws IOException {
+    ghRepository.enableWiki(v);
+  }
+
+  public void enableDownloads(boolean v) throws IOException {
+    ghRepository.enableDownloads(v);
+  }
+
+  public void renameTo(String name) throws IOException {
+    ghRepository.renameTo(name);
+  }
+
+  public void setDescription(String value) throws IOException {
+    ghRepository.setDescription(value);
+  }
+
+  public void setHomepage(String value) throws IOException {
+    ghRepository.setHomepage(value);
+  }
+
+  public void delete() throws IOException {
+    ghRepository.delete();
+  }
+
+  public GHRepository fork() throws IOException {
+    return ghRepository.fork();
+  }
+
+  public GHRepository forkTo(GHOrganization org) throws IOException {
+    return ghRepository.forkTo(org);
+  }
+
+  public GHPullRequest getPullRequest(int i) throws IOException {
+    return ghRepository.getPullRequest(i);
+  }
+
+  public List<GHPullRequest> getPullRequests(GHIssueState state)
+      throws IOException {
+    return ghRepository.getPullRequests(state);
+  }
+
+  public PagedIterable<GHPullRequest> listPullRequests(GHIssueState state) {
+    return ghRepository.listPullRequests(state);
+  }
+
+  public List<GHHook> getHooks() throws IOException {
+    return ghRepository.getHooks();
+  }
+
+  public GHHook getHook(int id) throws IOException {
+    return ghRepository.getHook(id);
+  }
+
+  public GHCompare getCompare(String id1, String id2) throws IOException {
+    return ghRepository.getCompare(id1, id2);
+  }
+
+  public GHCompare getCompare(GHCommit id1, GHCommit id2) throws IOException {
+    return ghRepository.getCompare(id1, id2);
+  }
+
+  public GHCompare getCompare(GHBranch id1, GHBranch id2) throws IOException {
+    return ghRepository.getCompare(id1, id2);
+  }
+
+  public GHRef[] getRefs() throws IOException {
+    return ghRepository.getRefs();
+  }
+
+  public GHRef[] getRefs(String refType) throws IOException {
+    return ghRepository.getRefs(refType);
+  }
+
+  public GHCommit getCommit(String sha1) throws IOException {
+    return ghRepository.getCommit(sha1);
+  }
+
+  public PagedIterable<GHCommit> listCommits() {
+    return ghRepository.listCommits();
+  }
+
+  public PagedIterable<GHCommitComment> listCommitComments() {
+    return ghRepository.listCommitComments();
+  }
+
+  public PagedIterable<GHCommitStatus> listCommitStatuses(String sha1)
+      throws IOException {
+    return ghRepository.listCommitStatuses(sha1);
+  }
+
+  public GHCommitStatus getLastCommitStatus(String sha1) throws IOException {
+    return ghRepository.getLastCommitStatus(sha1);
+  }
+
+  public GHCommitStatus createCommitStatus(String sha1, GHCommitState state,
+      String targetUrl, String description) throws IOException {
+    return ghRepository.createCommitStatus(sha1, state, targetUrl, description);
+  }
+
+  public PagedIterable<GHEventInfo> listEvents() throws IOException {
+    return ghRepository.listEvents();
+  }
+
+  public GHHook createHook(String name, Map<String, String> config,
+      Collection<GHEvent> events, boolean active) throws IOException {
+    return ghRepository.createHook(name, config, events, active);
+  }
+
+  public GHHook createWebHook(URL url, Collection<GHEvent> events)
+      throws IOException {
+    return ghRepository.createWebHook(url, events);
+  }
+
+  public GHHook createWebHook(URL url) throws IOException {
+    return ghRepository.createWebHook(url);
+  }
+
+  @SuppressWarnings("deprecation")
+  public Set<URL> getPostCommitHooks() {
+    return ghRepository.getPostCommitHooks();
+  }
+
+  public Map<String, GHBranch> getBranches() throws IOException {
+    return ghRepository.getBranches();
+  }
+
+  @SuppressWarnings("deprecation")
+  public Map<Integer, GHMilestone> getMilestones() throws IOException {
+    return ghRepository.getMilestones();
+  }
+
+  public PagedIterable<GHMilestone> listMilestones(GHIssueState state) {
+    return ghRepository.listMilestones(state);
+  }
+
+  public GHMilestone getMilestone(int number) throws IOException {
+    return ghRepository.getMilestone(number);
+  }
+
+  public GHContent getFileContent(String path) throws IOException {
+    return ghRepository.getFileContent(path);
+  }
+
+  public GHContent getFileContent(String path, String ref) throws IOException {
+    return ghRepository.getFileContent(path, ref);
+  }
+
+  public List<GHContent> getDirectoryContent(String path) throws IOException {
+    return ghRepository.getDirectoryContent(path);
+  }
+
+  public List<GHContent> getDirectoryContent(String path, String ref)
+      throws IOException {
+    return ghRepository.getDirectoryContent(path, ref);
+  }
+
+  public GHContent getReadme() throws Exception {
+    return ghRepository.getReadme();
+  }
+
+  public GHContentUpdateResponse createContent(String content,
+      String commitMessage, String path) throws IOException {
+    return ghRepository.createContent(content, commitMessage, path);
+  }
+
+  public GHContentUpdateResponse createContent(String content,
+      String commitMessage, String path, String branch) throws IOException {
+    return ghRepository.createContent(content, commitMessage, path, branch);
+  }
+
+  public GHMilestone createMilestone(String title, String description)
+      throws IOException {
+    return ghRepository.createMilestone(title, description);
+  }
+
+  public String toString() {
+    return ghRepository.toString();
+  }
+
+  public int hashCode() {
+    return ghRepository.hashCode();
+  }
+
+  public boolean equals(Object obj) {
+    return ghRepository.equals(obj);
   }
 }
diff --git a/github-plugin/src/main/java/com/googlesrouce/gerrit/plugins/github/git/ImportStep.java b/github-plugin/src/main/java/com/googlesrouce/gerrit/plugins/github/git/ImportStep.java
index 7efe78d..572dfc1 100644
--- a/github-plugin/src/main/java/com/googlesrouce/gerrit/plugins/github/git/ImportStep.java
+++ b/github-plugin/src/main/java/com/googlesrouce/gerrit/plugins/github/git/ImportStep.java
@@ -34,10 +34,14 @@
     return gitHubRepository.getOrganisation();
   }
 
-  public String getRepository() {
+  public String getRepositoryName() {
     return gitHubRepository.getRepository();
   }
 
+  public GitHubRepository getRepository() {
+    return gitHubRepository;
+  }
+
   public abstract void doImport(ProgressMonitor progress) throws Exception;
 
   public abstract boolean rollback();
diff --git a/github-plugin/src/main/java/com/googlesrouce/gerrit/plugins/github/git/ReplicateProjectStep.java b/github-plugin/src/main/java/com/googlesrouce/gerrit/plugins/github/git/ReplicateProjectStep.java
index 83fbb51..fe93d67 100644
--- a/github-plugin/src/main/java/com/googlesrouce/gerrit/plugins/github/git/ReplicateProjectStep.java
+++ b/github-plugin/src/main/java/com/googlesrouce/gerrit/plugins/github/git/ReplicateProjectStep.java
@@ -56,7 +56,7 @@
   public void doImport(ProgressMonitor progress) throws Exception {
     progress.beginTask("Setting up Gerrit replication", 2);
 
-    String repositoryName = getOrganisation() + "/" + getRepository();
+    String repositoryName = getOrganisation() + "/" + getRepositoryName();
     progress.update(1);
     replicationConfig.addSecureCredentials(getOrganisation(), authUsername,
         authToken);