From 07fd8470d635b985c9c749fa83bdbc2f20b35d42 Mon Sep 17 00:00:00 2001
From: Zachary Gershman <zgershman@pivotal.io>
Date: Wed, 21 Feb 2018 16:26:46 +0000
Subject: [PATCH] godoc/dl: provide JSON feed of releases

Fixes golang/go#23746

GitHub-Last-Rev: a188d86ac3d63756dbf8b46bca29d003f33bfa27
GitHub-Pull-Request: golang/tools#21
Change-Id: I0ca504081b239cd3cd8f7c1aed205807b5279d2b
Reviewed-on: https://go-review.googlesource.com/93080
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
---
 godoc/dl/dl.go | 40 ++++++++++++++++++++++++++--------------
 1 file changed, 26 insertions(+), 14 deletions(-)

diff --git a/godoc/dl/dl.go b/godoc/dl/dl.go
index 977ba983f..e50b0c24c 100644
--- a/godoc/dl/dl.go
+++ b/godoc/dl/dl.go
@@ -48,15 +48,15 @@ func RegisterHandlers(mux *http.ServeMux) {
 }
 
 type File struct {
-	Filename       string
-	OS             string
-	Arch           string
-	Version        string
-	Checksum       string `datastore:",noindex"` // SHA1; deprecated
-	ChecksumSHA256 string `datastore:",noindex"`
-	Size           int64  `datastore:",noindex"`
-	Kind           string // "archive", "installer", "source"
-	Uploaded       time.Time
+	Filename       string    `json:"filename"`
+	OS             string    `json:"os"`
+	Arch           string    `json:"arch"`
+	Version        string    `json:"-"`
+	Checksum       string    `json:"-" datastore:",noindex"` // SHA1; deprecated
+	ChecksumSHA256 string    `json:"sha256" datastore:",noindex"`
+	Size           int64     `json:"size" datastore:",noindex"`
+	Kind           string    `json:"kind"` // "archive", "installer", "source"
+	Uploaded       time.Time `json:"-"`
 }
 
 func (f File) ChecksumType() string {
@@ -137,11 +137,11 @@ func (f File) URL() string {
 }
 
 type Release struct {
-	Version        string
-	Stable         bool
-	Files          []File
-	Visible        bool // show files on page load
-	SplitPortTable bool // whether files should be split by primary/other ports.
+	Version        string `json:"version"`
+	Stable         bool   `json:"stable"`
+	Files          []File `json:"files"`
+	Visible        bool   `json:"-"` // show files on page load
+	SplitPortTable bool   `json:"-"` // whether files should be split by primary/other ports.
 }
 
 type Feature struct {
@@ -221,6 +221,18 @@ func listHandler(w http.ResponseWriter, r *http.Request) {
 			log.Errorf(c, "cache set error: %v", err)
 		}
 	}
+
+	if r.URL.Query().Get("mode") == "json" {
+		w.Header.Set("Content-Type", "application/json")
+
+		e := json.NewEncoder(w).SetIndent("", " ")
+		if err := e.Encode(d.Stable); err != nil {
+			log.Errorf(c, "failed rendering JSON for releases: %v", err)
+		}
+
+		return
+	}
+
 	if err := listTemplate.ExecuteTemplate(w, "root", d); err != nil {
 		log.Errorf(c, "error executing template: %v", err)
 	}