func ParseAllValid(notes []repository.Note) []Report {
	var reports []Report
	for _, note := range notes {
		report, err := Parse(note)
		if err == nil && report.Version == FormatVersion {
			reports = append(reports, report)
		}
	}
	return reports
}
ParseAllValid takes collection of git notes and tries to parse a analyses report
from each one. Any notes that are not valid analyses reports get ignored.
package analyses
import (
	"encoding/json"
	"io/ioutil"
	"net/http"
	"sort"
	"strconv"
	"github.com/google/git-appraise/repository"
)
const (
	Ref = "refs/notes/devtools/analyses"
	StatusLooksGoodToMe = "lgtm"
	StatusForYourInformation = "fyi"
	StatusNeedsMoreWork = "nmw"
	FormatVersion = 0
)
type Report struct {
	Timestamp string `json:"timestamp,omitempty"`
	URL       string `json:"url,omitempty"`
	Status    string `json:"status,omitempty"`
	Version int `json:"v,omitempty"`
}
type LocationRange struct {
	StartLine   uint32 `json:"start_line,omitempty"`
	StartColumn uint32 `json:"start_column,omitempty"`
	EndLine     uint32 `json:"end_line,omitempty"`
	EndColumn   uint32 `json:"end_column,omitempty"`
}
type Location struct {
	Path  string         `json:"path,omitempty"`
	Range *LocationRange `json:"range,omitempty"`
}
type Note struct {
	Location    *Location `json:"location,omitempty"`
	Category    string    `json:"category,omitempty"`
	Description string    `json:"description"`
}
type AnalyzeResponse struct {
	Notes []Note `json:"note,omitempty"`
}
type ReportDetails struct {
	AnalyzeResponse []AnalyzeResponse `json:"analyze_response,omitempty"`
}
func (analysesReport Report) GetLintReportResult() ([]AnalyzeResponse, error) {
	if analysesReport.URL == "" {
		return nil, nil
	}
	res, err := http.Get(analysesReport.URL)
	if err != nil {
		return nil, err
	}
	analysesResults, err := ioutil.ReadAll(res.Body)
	res.Body.Close()
	if err != nil {
		return nil, err
	}
	var details ReportDetails
	err = json.Unmarshal([]byte(analysesResults), &details)
	if err != nil {
		return nil, err
	}
	return details.AnalyzeResponse, nil
}
func (analysesReport Report) GetNotes() ([]Note, error) {
	reportResults, err := analysesReport.GetLintReportResult()
	if err != nil {
		return nil, err
	}
	var reportNotes []Note
	for _, reportResult := range reportResults {
		reportNotes = append(reportNotes, reportResult.Notes...)
	}
	return reportNotes, nil
}
func Parse(note repository.Note) (Report, error) {
	bytes := []byte(note)
	var report Report
	err := json.Unmarshal(bytes, &report)
	return report, err
}
func GetLatestAnalysesReport(reports []Report) (*Report, error) {
	timestampReportMap := make(map[int]*Report)
	var timestamps []int
	for _, report := range reports {
		timestamp, err := strconv.Atoi(report.Timestamp)
		if err != nil {
			return nil, err
		}
		timestamps = append(timestamps, timestamp)
		timestampReportMap[timestamp] = &report
	}
	if len(timestamps) == 0 {
		return nil, nil
	}
	sort.Sort(sort.Reverse(sort.IntSlice(timestamps)))
	return timestampReportMap[timestamps[0]], nil
}