Project permissions capabilities

Added show-repo-account-access command
added show-account-access command
Cleaned up documentation for show-account command
reformatted some code to better meet Gerrit's standards
Tweaked error handling, switched to @RequiresCapability
to ensure calling user is an Administrator

Change-Id: I5c1e53ddeebea18f2ee9d04b9d25d964dbb1ee6d
diff --git a/src/main/java/com/google/gerrit/plugins/AdminConsoleCommandModule.java b/src/main/java/com/google/gerrit/plugins/AdminConsoleCommandModule.java
index be523e4..9a781da 100644
--- a/src/main/java/com/google/gerrit/plugins/AdminConsoleCommandModule.java
+++ b/src/main/java/com/google/gerrit/plugins/AdminConsoleCommandModule.java
@@ -21,5 +21,7 @@
   protected void configureCommands() {
     command(ShowAccountCommand.class);
    alias("show-account", ShowAccountCommand.class);
+   alias("show-repo-account-access", ShowRepoAccountAccessCommand.class);
+   alias("show-repo-access", ShowRepoAccessCommand.class);
   }
 }
diff --git a/src/main/java/com/google/gerrit/plugins/ShowAccountCommand.java b/src/main/java/com/google/gerrit/plugins/ShowAccountCommand.java
index 2d35ab5..2c80d51 100644
--- a/src/main/java/com/google/gerrit/plugins/ShowAccountCommand.java
+++ b/src/main/java/com/google/gerrit/plugins/ShowAccountCommand.java
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 package com.google.gerrit.plugins;
+
 import java.io.IOException;
 import java.util.Collections;
 import java.util.Comparator;
@@ -23,12 +24,13 @@
 import org.kohsuke.args4j.Argument;
 import org.kohsuke.args4j.Option;
 
+import com.google.gerrit.common.data.GlobalCapability;
+import com.google.gerrit.extensions.annotations.RequiresCapability;
 import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.reviewdb.client.Account.Id;
 import com.google.gerrit.reviewdb.client.AccountExternalId;
 import com.google.gerrit.reviewdb.client.AccountSshKey;
 import com.google.gerrit.reviewdb.server.ReviewDb;
-import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.account.AccountResolver;
 import com.google.gerrit.server.account.AccountResource;
@@ -36,12 +38,13 @@
 import com.google.gerrit.server.group.GroupJson.GroupInfo;
 import com.google.gerrit.sshd.CommandMetaData;
 import com.google.gerrit.sshd.SshCommand;
-import com.google.gwtorm.server.ResultSet;
+import com.google.gwtorm.server.OrmException;
 import com.google.gwtorm.server.SchemaFactory;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 
-@CommandMetaData(name="show-account", descr="Displays user information")
+@RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
+@CommandMetaData(name = "show-account", descr = "Displays user information")
 public final class ShowAccountCommand extends SshCommand {
 
   @Argument(usage = "User information to find: LastName,\\ Firstname,  email@address.com, account id or an user name.  Be sure to double-escape spaces, for example: \"show-account Last,\\\\ First\"")
@@ -56,16 +59,17 @@
   @Option(name = "--show-keys", usage = "show user's public keys?")
   private boolean showKeys = false;
 
-  final CurrentUser currentUser;
   final AccountResolver accountResolver;
   private final SchemaFactory<ReviewDb> schema;
   private final Provider<GetGroups> accountGetGroups;
   private final IdentifiedUser.GenericFactory userFactory;
 
   @Inject
-  ShowAccountCommand(final CurrentUser cu, AccountResolver ar, final Provider<GetGroups> accountGetGroups, final IdentifiedUser.GenericFactory userFactory, SchemaFactory<ReviewDb> schema)
-      throws ConfigInvalidException, IOException {
-    currentUser = cu;
+  ShowAccountCommand(AccountResolver ar,
+      final Provider<GetGroups> accountGetGroups,
+      final IdentifiedUser.GenericFactory userFactory,
+      SchemaFactory<ReviewDb> schema) throws ConfigInvalidException,
+      IOException {
     accountResolver = ar;
     this.accountGetGroups = accountGetGroups;
     this.userFactory = userFactory;
@@ -73,30 +77,29 @@
   }
 
   @Override
-  public void run() throws UnloggedFailure, Failure, Exception {
+  public void run() throws UnloggedFailure, OrmException {
     Account account;
-    if (!currentUser.getCapabilities().canAdministrateServer()) {
-      stdout.println("You must be a Gerrit Administrator to run this command.  Goodbye");
-      return;
-    }
 
     if (name.isEmpty()) {
-      stdout.print("You need to tell me who to find:  LastName,\\ Firstname, email@address.com, account id or an user name.  Be sure to double-escape spaces, for example: \"show-account Last,\\\\ First\"");
-      return;
+      throw new UnloggedFailure(1,
+          "You need to tell me who to find:  LastName,\\\\ Firstname, email@address.com, account id or an user name.  "
+              + "Be sure to double-escape spaces, for example: \"show-account Last,\\\\ First\"");
     }
 
     Set<Id> idList = accountResolver.findAll(name);
     if (idList.isEmpty()) {
-      stdout.println("No accounts found for your query: \"" + name + "\"");
-      stdout.println("Tip: Try double-escaping spaces, for example: \"show-account Last,\\\\ First\"");
-      return;
-    }
-    else {
-      stdout.println("Found " + idList.size() + " result" + (idList.size() > 1 ? "s" : "") + ": for query: \"" + name + "\"");
+      throw new UnloggedFailure(1,
+          "No accounts found for your query: \""
+              + name
+              + "\""
+              + " Tip: Try double-escaping spaces, for example: \"show-account Last,\\\\ First\"");
+    } else {
+      stdout.println("Found " + idList.size() + " result"
+          + (idList.size() > 1 ? "s" : "") + ": for query: \"" + name + "\"");
       stdout.println();
     }
 
-    for (Id id: idList) {
+    for (Id id : idList) {
       account = accountResolver.find(id.toString());
       stdout.println("Full name:         " + account.getFullName());
       stdout.println("Account Id:        " + id.toString());
@@ -109,26 +112,28 @@
 
       stdout.println("");
       stdout.println("External Ids:");
-      stdout.println(String.format("%-50s %s", "Email Address:", "External Id:"));
-      for (AccountExternalId accountExternalId : db.accountExternalIds().byAccount(account.getId())) {
+      stdout.println(String
+          .format("%-50s %s", "Email Address:", "External Id:"));
+      for (AccountExternalId accountExternalId : db.accountExternalIds()
+          .byAccount(account.getId())) {
         stdout.println(String.format("%-50s %s",
-            (accountExternalId.getEmailAddress() == null ? "" : accountExternalId.getEmailAddress()),
-            accountExternalId.getExternalId()));
+            (accountExternalId.getEmailAddress() == null ? ""
+                : accountExternalId.getEmailAddress()), accountExternalId
+                .getExternalId()));
       }
 
       if (showKeys) {
         stdout.println("");
         stdout.println("Public Keys:");
-        List<AccountSshKey> sshKeys = db.accountSshKeys().byAccount(account.getId()).toList();
-        if (sshKeys == null || sshKeys.isEmpty()){
+        List<AccountSshKey> sshKeys =
+            db.accountSshKeys().byAccount(account.getId()).toList();
+        if (sshKeys == null || sshKeys.isEmpty()) {
           stdout.println("None");
-        }
-        else{
+        } else {
           stdout.println(String.format("%-9s %s", "Status:", "Key:"));
-          for (AccountSshKey sshKey : sshKeys ) {
-            stdout.println(String.format("%-9s %s",
-                (sshKey.isValid() ? "Active" : "Inactive"),
-                sshKey.getSshPublicKey()));
+          for (AccountSshKey sshKey : sshKeys) {
+            stdout.println(String.format("%-9s %s", (sshKey.isValid()
+                ? "Active" : "Inactive"), sshKey.getSshPublicKey()));
           }
         }
       }
@@ -137,12 +142,15 @@
 
       if (showGroups) {
         stdout.println();
-        stdout.println("Member of groups" + (filterGroups == null ? "" : " (Filtering on \"" + filterGroups + "\")") + ":");
-        List<GroupInfo> groupInfos = accountGetGroups.get().apply(
-            new AccountResource(userFactory.create(id)));
+        stdout.println("Member of groups"
+            + (filterGroups == null ? "" : " (Filtering on \"" + filterGroups
+                + "\")") + ":");
+        List<GroupInfo> groupInfos =
+            accountGetGroups.get().apply(
+                new AccountResource(userFactory.create(id)));
 
         Collections.sort(groupInfos, new CustomComparator());
-        for (GroupInfo groupInfo: groupInfos) {
+        for (GroupInfo groupInfo : groupInfos) {
           if (null == filterGroups) {
             stdout.println(groupInfo.name);
           }
@@ -158,4 +166,4 @@
       return o1.name.compareTo(o2.name);
     }
   }
-}
\ No newline at end of file
+}
diff --git a/src/main/java/com/google/gerrit/plugins/ShowRepoAccessCommand.java b/src/main/java/com/google/gerrit/plugins/ShowRepoAccessCommand.java
new file mode 100644
index 0000000..cdf325b
--- /dev/null
+++ b/src/main/java/com/google/gerrit/plugins/ShowRepoAccessCommand.java
@@ -0,0 +1,106 @@
+// Copyright (C) 2012 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.plugins;
+
+import java.io.IOException;
+
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.errors.RepositoryNotFoundException;
+import org.kohsuke.args4j.Argument;
+import org.kohsuke.args4j.Option;
+
+import com.google.gerrit.common.data.AccessSection;
+import com.google.gerrit.common.data.GlobalCapability;
+import com.google.gerrit.common.data.Permission;
+import com.google.gerrit.common.data.PermissionRule;
+import com.google.gerrit.extensions.annotations.RequiresCapability;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.server.git.MetaDataUpdate;
+import com.google.gerrit.server.git.ProjectConfig;
+import com.google.gerrit.sshd.CommandMetaData;
+import com.google.gerrit.sshd.SshCommand;
+import com.google.inject.Inject;
+
+@RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
+@CommandMetaData(name = "show-repo-access", descr = "Displays access on a specific repository")
+public final class ShowRepoAccessCommand extends SshCommand {
+
+  @Argument(usage = "project to show access for?")
+  private String projectName = "";
+
+  @Option(name = "-w", usage = "display without line width truncation")
+  private boolean wide;
+
+  @Inject
+  ShowRepoAccessCommand(final MetaDataUpdate.Server metaDataUpdateFactory)
+      throws ConfigInvalidException, IOException {
+    this.metaDataUpdateFactory = metaDataUpdateFactory;
+  }
+
+  private final MetaDataUpdate.Server metaDataUpdateFactory;
+
+  private int columns = 80;
+  private int permissionGroupWidth;
+
+  @Override
+  public void run() throws UnloggedFailure, Failure, IOException,
+      ConfigInvalidException {
+    // space indented Strings to be used as format for String.format() later
+    String sectionNameFormatter = "  %-25s\n";
+    String ruleNameFormatter = "    %-15s\n ";
+    String permissionNameFormatter = "      %5s %9s %s\n";
+
+    if (projectName.isEmpty()) {
+      throw new UnloggedFailure(1, "Please specify a project to show access for");
+    }
+    final Project.NameKey nameKey = new Project.NameKey(projectName);
+
+    permissionGroupWidth = wide ? Integer.MAX_VALUE : columns - 9 - 5 - 9;
+
+    ProjectConfig config;
+    try {
+      MetaDataUpdate md = metaDataUpdateFactory.create(nameKey);
+      config = ProjectConfig.read(md);
+      for (AccessSection accessSection : config.getAccessSections()) {
+
+        stdout.print((String.format(sectionNameFormatter, accessSection
+            .getName().toString())));
+
+        for (Permission permission : accessSection.getPermissions()) {
+
+          for (PermissionRule rule : permission.getRules()) {
+            stdout
+                .print(String.format(ruleNameFormatter, permission.getName()));
+            stdout.print(String.format(permissionNameFormatter,
+                (rule.getMin() != rule.getMax()) ? "" + rule.getMin() + " "
+                    + rule.getMax() : rule.getAction(),
+                (permission.getExclusiveGroup() ? "EXCLUSIVE" : ""),
+                format(rule.getGroup().getName())));
+          }
+        }
+      }
+    } catch (RepositoryNotFoundException e) {
+      throw new UnloggedFailure(1, "Repository not found");
+    }
+  }
+
+  private String format(final String s) {
+    if (s.length() < permissionGroupWidth) {
+      return s;
+    } else {
+      return s.substring(0, permissionGroupWidth);
+    }
+  }
+}
diff --git a/src/main/java/com/google/gerrit/plugins/ShowRepoAccountAccessCommand.java b/src/main/java/com/google/gerrit/plugins/ShowRepoAccountAccessCommand.java
new file mode 100644
index 0000000..cf2caeb
--- /dev/null
+++ b/src/main/java/com/google/gerrit/plugins/ShowRepoAccountAccessCommand.java
@@ -0,0 +1,184 @@
+// Copyright (C) 2012 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.plugins;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.errors.RepositoryNotFoundException;
+import org.kohsuke.args4j.Argument;
+import org.kohsuke.args4j.Option;
+
+import com.google.gerrit.common.data.AccessSection;
+import com.google.gerrit.common.data.GlobalCapability;
+import com.google.gerrit.common.data.Permission;
+import com.google.gerrit.common.data.PermissionRule;
+import com.google.gerrit.extensions.annotations.RequiresCapability;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.Account.Id;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.server.account.AccountResolver;
+import com.google.gerrit.server.account.AccountResource;
+import com.google.gerrit.server.account.GetGroups;
+import com.google.gerrit.server.git.MetaDataUpdate;
+import com.google.gerrit.server.git.ProjectConfig;
+import com.google.gerrit.server.group.GroupJson.GroupInfo;
+import com.google.gerrit.sshd.CommandMetaData;
+import com.google.gerrit.sshd.SshCommand;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+
+@RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
+@CommandMetaData(name = "show-repo-account-access", descr = "Displays user's access on a specific repository")
+public final class ShowRepoAccountAccessCommand extends SshCommand {
+
+  @Argument(usage = "project to show access for?")
+  private String projectName = "";
+
+  @Option(name = "--user", usage = "User information to find: LastName,\\ Firstname,  email@address.com, account id or an user name. "
+      + "Be sure to double-escape spaces, for example: \"show-repo-account-access All-Projects --user Last,\\\\ First\"")
+  private String name = "";
+
+  @Option(name = "-w", usage = "display without line width truncation")
+  private boolean wide;
+
+  @Inject
+  ShowRepoAccountAccessCommand(
+      final MetaDataUpdate.Server metaDataUpdateFactory,
+      final Provider<GetGroups> accountGetGroups,
+      AccountResolver accountResolver,
+      final IdentifiedUser.GenericFactory userFactory)
+      throws ConfigInvalidException, IOException {
+    this.metaDataUpdateFactory = metaDataUpdateFactory;
+    this.accountGetGroups = accountGetGroups;
+    this.accountResolver = accountResolver;
+    this.userFactory = userFactory;
+  }
+
+  private final MetaDataUpdate.Server metaDataUpdateFactory;
+  private final AccountResolver accountResolver;
+  private final Provider<GetGroups> accountGetGroups;
+  private final IdentifiedUser.GenericFactory userFactory;
+  private int columns = 80;
+  private int permissionGroupWidth;
+
+  @Override
+  public void run() throws UnloggedFailure, Failure, Exception {
+    Account account;
+    String sectionNameFormatter = "  %-25s\n";
+    String ruleNameFormatter = "    %-15s\n ";
+    String permissionNameFormatter = "      %5s %9s %s\n";
+
+    Boolean userHasPermissionsInSection = false;
+    Boolean userHasPermissionsInProject = false;
+
+    if (projectName.isEmpty()) {
+      throw new UnloggedFailure(1, "Please specify a project to show access for");
+    }
+
+    if (name.isEmpty()) {
+      throw new UnloggedFailure(1,
+          "You need to tell me who to find:  LastName,\\\\ Firstname, email@address.com, account id or an user name.  "
+              + "Be sure to double-escape spaces, for example: \"show-repo-account-access All-Projects --user Last,\\\\ First\"");
+    }
+
+    Set<Id> idList = accountResolver.findAll(name);
+    if (idList.isEmpty()) {
+      throw new UnloggedFailure(1,
+          "No accounts found for your query: \""
+              + name
+              + "\""
+              + " Tip: Try double-escaping spaces, for example: \"--user Last,\\\\ First\"");
+    }
+
+    final Project.NameKey nameKey = new Project.NameKey(projectName);
+
+    try {
+      MetaDataUpdate md = metaDataUpdateFactory.create(nameKey);
+      ProjectConfig config;
+      config = ProjectConfig.read(md);
+
+      permissionGroupWidth = wide ? Integer.MAX_VALUE : columns - 9 - 5 - 9;
+
+      for (Id id : idList) {
+        userHasPermissionsInProject = false;
+        account = accountResolver.find(id.toString());
+        stdout.println("Full name:         " + account.getFullName());
+        // Need to know what groups the user is in. This is not a great
+        // solution, but it does work.
+        List<GroupInfo> groupInfos =
+            accountGetGroups.get().apply(
+                new AccountResource(userFactory.create(id)));
+        HashSet<String> groupHash = new HashSet<String>();
+
+        for (GroupInfo groupInfo : groupInfos) {
+          groupHash.add(groupInfo.name);
+        }
+
+        for (AccessSection accessSection : config.getAccessSections()) {
+          StringBuilder sb = new StringBuilder();
+          sb.append((String.format(sectionNameFormatter, accessSection
+              .getName().toString())));
+          // This is a solution to prevent displaying a section heading unless
+          // the user has permissions for it
+          // not the best solution, but I haven't been able to find
+          // "Is user a member of this group" based on the information I have
+          // in a more efficient manner yet.
+          userHasPermissionsInSection = false;
+          for (Permission permission : accessSection.getPermissions()) {
+
+            for (PermissionRule rule : permission.getRules()) {
+
+              if (groupHash.contains(rule.getGroup().getName())) {
+                sb.append(String.format(ruleNameFormatter, permission.getName()));
+                sb.append(String.format(permissionNameFormatter,
+                    (rule.getMin() != rule.getMax()) ? "" + rule.getMin() + " "
+                        + rule.getMax() : rule.getAction(),
+                    (permission.getExclusiveGroup() ? "EXCLUSIVE" : ""),
+                    format(rule.getGroup().getName())));
+                userHasPermissionsInSection = true;
+              }
+            }
+          }
+
+          if (userHasPermissionsInSection) {
+            stdout.print(sb.toString());
+
+            userHasPermissionsInProject = true;
+          }
+        }
+
+
+        if (!userHasPermissionsInProject) {
+          stdout.println("  No access found for this user on this repository");
+        }
+      }
+    } catch (RepositoryNotFoundException e) {
+      throw new UnloggedFailure(1, "Repository not found");
+    }
+  }
+
+  private String format(final String s) {
+    if (s.length() < permissionGroupWidth) {
+      return s;
+    } else {
+      return s.substring(0, permissionGroupWidth);
+    }
+  }
+}
diff --git a/src/main/resources/Documentation/about.md b/src/main/resources/Documentation/about.md
index 16200d6..485a6a2 100644
--- a/src/main/resources/Documentation/about.md
+++ b/src/main/resources/Documentation/about.md
@@ -1,2 +1,3 @@
 Plugin to provide administrator-only functionality, intended to simplify common administrator tasks.
 Currently providing user-level information.
+Also providing access control information by project or project/account
\ No newline at end of file
diff --git a/src/main/resources/Documentation/cmd-show-account.md b/src/main/resources/Documentation/cmd-show-account.md
index 096b407..c1455ec 100644
--- a/src/main/resources/Documentation/cmd-show-account.md
+++ b/src/main/resources/Documentation/cmd-show-account.md
@@ -1,13 +1,13 @@
-admin-console show-account
+@PLUGIN@ show-account
 ================
 
 NAME
 ----
-admin-console show-account show user account information
+@PLUGIN@ show-account show user account information
 
 SYNOPSIS
 --------
->     ssh -p <port> <host> admin-console show-account
+>     ssh -p <port> <host> @PLUGIN@ show-account
 >      [user]
 >      [--show-groups]
 >      [--filter-groups] [filter-string]
@@ -53,20 +53,20 @@
 
 Find a user named Foo
 
->     $ ssh -p 29418 review.example.com admin-console show-user Foo
+>     $ ssh -p @SSH_PORT@ review.example.com @PLUGIN@ show-account Foo
 
 Find a user with email foo@bar.com
 
->     $ ssh -p 29418 review.example.com admin-console show-user foo@bar.com
+>     $ ssh -p @SSH_PORT@ review.example.com @PLUGIN@ show-account foo@bar.com
 
 Find a user named Foo Bar
 
->     $ ssh -p 29418 review.example.com admin-console show-user Bar,\\\\ Foo
+>     $ ssh -p @SSH_PORT@ review.example.com @PLUGIN@ show-account Bar,\\ Foo
 
 Find a user named Foo and show all groups the user is a member of
 
->     $ ssh -p 29418 review.example.com admin-console show-user Foo --show-groups
+>     $ ssh -p @SSH_PORT@ review.example.com @PLUGIN@ show-account Foo --show-groups
 
 Find a user named Foo and show all groups containing "baz" that the user is a member of
 
->     $ ssh -p 29418 review.example.com admin-console show-user Foo --show-groups --filter-groups baz
+>     $ ssh -p @SSH_PORT@ review.example.com @PLUGIN@ show-account Foo --show-groups --filter-groups baz
diff --git a/src/main/resources/Documentation/cmd-show-repo-access.md b/src/main/resources/Documentation/cmd-show-repo-access.md
new file mode 100644
index 0000000..558ab8e
--- /dev/null
+++ b/src/main/resources/Documentation/cmd-show-repo-access.md
@@ -0,0 +1,48 @@
+@PLUGIN@ show-repo-access
+================
+
+NAME
+----
+@PLUGIN@ show-repo-access repository access information
+
+SYNOPSIS
+--------
+>     ssh -p <port> <host> @PLUGIN@ show-repo-access
+>      [repository]
+>      [-w]
+
+
+DESCRIPTION
+-----------
+Displays access for a specific repository.  Does not interpret repository inheritance (currently - may change in the future, or be added as an option)
+Note, see [cmd-show-account](cmd-show-account.html) for more information on the user search functionality provided here.
+
+OPTIONS
+-------
+repository
+> Repository to show access for
+
+-w
+> Display without line width truncation
+--help
+
+-h
+> Display usage information.
+
+ACCESS
+------
+Gerrit Administrators only.
+
+SCRIPTING
+---------
+This command is not intended to be used in scripts.
+
+EXAMPLES
+--------
+
+Find Access for All-Projects
+
+>     $ ssh -p @SSH_PORT@ review.example.com @PLUGIN@ show-repo-access All-Projects
+
+Find Access for a repository named "my-project"
+>     $ ssh -p @SSH_PORT@ review.example.com @PLUGIN@ show-repo-access my-project
\ No newline at end of file
diff --git a/src/main/resources/Documentation/cmd-show-repo-account-access.md b/src/main/resources/Documentation/cmd-show-repo-account-access.md
new file mode 100644
index 0000000..e59913b
--- /dev/null
+++ b/src/main/resources/Documentation/cmd-show-repo-account-access.md
@@ -0,0 +1,52 @@
+@PLUGIN@ show-repo-account-access
+================
+
+NAME
+----
+@PLUGIN@ show-repo-account-access show repository access by account
+
+SYNOPSIS
+--------
+>     ssh -p <port> <host> @PLUGIN@ show-repo-account-access
+>      [repository]
+>      [--user] [user]
+>      [-w]
+
+
+DESCRIPTION
+-----------
+Displays access for a specific repository by user.  Does not interpret repository inheritance (currently - may change in the future, or be added as an option)
+
+OPTIONS
+-------
+repository
+> Repository to show access for
+
+--user
+> User to look up: This can be in one of several formats: LastName,\\\\ FirstName,  email\@address.com, account id or an user name. Be sure to double-escape spaces.  Case-sensitive
+
+-w
+> Display without line width truncation
+--help
+
+-h
+> Display usage information.
+
+ACCESS
+------
+Gerrit Administrators only.
+
+SCRIPTING
+---------
+This command is not intended to be used in scripts.
+
+EXAMPLES
+--------
+
+Find Access for All-Projects and a user named Foo
+
+>     $ ssh -p @SSH_PORT@ review.example.com @PLUGIN@ show-repo-account-access All-Projects --user Foo
+
+Find Access for a repository named "my-project" and a user named Foo
+
+>     $ ssh -p @SSH_PORT@ review.example.com @PLUGIN@ show-repo-access my-project --user Foo
\ No newline at end of file