gerrit: add ListProjects method

Change-Id: I04209313610b42813fc4f9697a4c5ec7366c627f
Reviewed-on: https://go-review.googlesource.com/38717
Reviewed-by: Kevin Burke <kev@inburke.com>
diff --git a/gerrit/gerrit.go b/gerrit/gerrit.go
index acce544..346f30c 100644
--- a/gerrit/gerrit.go
+++ b/gerrit/gerrit.go
@@ -18,6 +18,7 @@
 	"io/ioutil"
 	"net/http"
 	"net/url"
+	"sort"
 	"strconv"
 	"strings"
 	"time"
@@ -433,6 +434,31 @@
 	Branches    map[string]string `json:"branches"`
 }
 
+// ListProjects returns the server's active projects.
+//
+// The returned slice is sorted by project ID and excludes the "All-Projects" project.
+//
+// See https://gerrit-review.googlesource.com/Documentation/rest-api-projects.html#list-projects
+func (c *Client) ListProjects(ctx context.Context) ([]ProjectInfo, error) {
+	var res map[string]ProjectInfo
+	err := c.do(ctx, &res, "GET", fmt.Sprintf("/projects/"))
+	if err != nil {
+		return nil, err
+	}
+	var ret []ProjectInfo
+	for name, pi := range res {
+		if name == "All-Projects" {
+			continue
+		}
+		if pi.State != "ACTIVE" {
+			continue
+		}
+		ret = append(ret, pi)
+	}
+	sort.Slice(ret, func(i, j int) bool { return ret[i].ID < ret[j].ID })
+	return ret, nil
+}
+
 // CreateProject creates a new project.
 func (c *Client) CreateProject(ctx context.Context, name string, p ...ProjectInput) (ProjectInfo, error) {
 	var pi ProjectInput