status: Default Template for details

This patch introduces a default Go template for emitting the status
details in a format that is a duplicate of the lock file. There are
several tests that validate the default template. The tests can be
extended to validate additional templates as well.
This commit is contained in:
akutz 2018-03-27 19:24:20 -05:00 коммит произвёл akutz
Родитель edbfaa357b
Коммит 280e6d900a
2 изменённых файлов: 185 добавлений и 0 удалений

Просмотреть файл

@ -599,6 +599,35 @@ type rawStatus struct {
PackageCount int
}
// rawDetail is is additional information used for the status when the
// -detail flag is specified
type rawDetail struct {
Projects []rawDetailProject `json:"projects,omitempty"`
Metadata rawDetailMetadata `json:"metadata,omitempty"`
}
type rawDetailVersion struct {
Revision string `json:"revision,omitempty"`
Version string `json:"version,omitempty"`
Branch string `json:"branch,omitempty"`
}
type rawDetailProject struct {
ProjectRoot string `json:"project-root,omitempty"`
Packages []string `json:"packages,omitempty"`
Locked rawDetailVersion `json:"locked,omitempty"`
Latest rawDetailVersion `json:"latest,omitempty"`
Source string `json:"source,omitempty"`
}
type rawDetailMetadata struct {
AnalyzerName string `json:"analyzer-name,omitempty"`
AnalyzerVersion int `json:"analyzer-version,omitempty"`
InputsDigest string `json:"inputs-digest,omitempty"`
SolverName string `json:"solver-name,omitempty"`
SolverVersion int `json:"solver-version,omitempty"`
}
// BasicStatus contains all the information reported about a single dependency
// in the summary/list status output mode.
type BasicStatus struct {
@ -1091,3 +1120,36 @@ type byProject []projectConstraint
func (p byProject) Len() int { return len(p) }
func (p byProject) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func (p byProject) Less(i, j int) bool { return p[i].Project < p[j].Project }
func execStatusTemplate(w io.Writer, format string, data interface{}) error {
tpl, err := template.New("").Funcs(template.FuncMap{
"dec": func(i int) int {
return i - 1
},
}).Parse(format)
if err != nil {
return err
}
return tpl.Execute(w, data)
}
const defaultStatusTemplate = `# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
{{range $p := .Projects}}[[projects]]{{if $p.Locked.Branch}}
branch = "{{$p.Locked.Branch}}"{{end}}
name = "{{$p.ProjectRoot}}"
packages = [{{if eq 0 (len $p.Packages)}}"."]{{else}}{{range $i, $pkg := $p.Packages}}
"{{$pkg}}"{{if lt $i (dec (len $p.Packages))}},{{end}}{{end}}
]{{end}}
revision = "{{$p.Locked.Revision}}"{{if $p.Source}}
source = "{{$p.Source}}"{{end}}{{if $p.Locked.Version}}
version = "{{$p.Locked.Version}}"{{end}}
{{end}}[solve-meta]
analyzer-name = "{{.Metadata.AnalyzerName}}"
analyzer-version = {{.Metadata.AnalyzerVersion}}
inputs-digest = "{{.Metadata.InputsDigest}}"
solver-name = "{{.Metadata.SolverName}}"
solver-version = {{.Metadata.SolverVersion}}
`

Просмотреть файл

@ -6,6 +6,7 @@ package main
import (
"bytes"
"fmt"
"io/ioutil"
"log"
"path/filepath"
@ -555,3 +556,125 @@ func TestValidateFlags(t *testing.T) {
})
}
}
const expectedStatusDetail = `# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
%s[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "900e50172c505781bfed67991919eccea483d78173f8e5c74404a5f6d05858bb"
solver-name = "gps-cdcl"
solver-version = 1
`
var expectedStatusMetadata = rawDetailMetadata{
AnalyzerName: "dep",
AnalyzerVersion: 1,
InputsDigest: "900e50172c505781bfed67991919eccea483d78173f8e5c74404a5f6d05858bb",
SolverName: "gps-cdcl",
SolverVersion: 1,
}
func TestStatusDetailTemplates(t *testing.T) {
testCases := []struct {
name string
tpl string
exp string
data rawDetail
}{
{
name: "Default Template",
tpl: defaultStatusTemplate,
exp: fmt.Sprintf(expectedStatusDetail, `[[projects]]
branch = "master"
name = "github.com/akutz/one"
packages = ["."]
revision = "b78744579491c1ceeaaa3b40205e56b0591b93a3"
[[projects]]
name = "github.com/akutz/two"
packages = [
".",
"helloworld"
]
revision = "12bd96e66386c1960ab0f74ced1362f66f552f7b"
version = "v1.0.0"
[[projects]]
branch = "feature/morning"
name = "github.com/akutz/three"
packages = [
"a",
"b",
"c"
]
revision = "890a5c3458b43e6104ff5da8dfa139d013d77544"
source = "https://github.com/mandy/three"
`),
data: rawDetail{
Projects: []rawDetailProject{
rawDetailProject{
Locked: rawDetailVersion{
Branch: "master",
Revision: "b78744579491c1ceeaaa3b40205e56b0591b93a3",
},
ProjectRoot: "github.com/akutz/one",
},
rawDetailProject{
Locked: rawDetailVersion{
Revision: "12bd96e66386c1960ab0f74ced1362f66f552f7b",
Version: "v1.0.0",
},
ProjectRoot: "github.com/akutz/two",
Packages: []string{
".",
"helloworld",
},
},
rawDetailProject{
Locked: rawDetailVersion{
Branch: "feature/morning",
Revision: "890a5c3458b43e6104ff5da8dfa139d013d77544",
},
ProjectRoot: "github.com/akutz/three",
Packages: []string{
"a",
"b",
"c",
},
Source: "https://github.com/mandy/three",
},
},
Metadata: expectedStatusMetadata,
},
},
{
name: "Default Template No Projects",
tpl: defaultStatusTemplate,
exp: fmt.Sprintf(expectedStatusDetail, ""),
data: rawDetail{
Metadata: expectedStatusMetadata,
},
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
w := &bytes.Buffer{}
if err := execStatusTemplate(w, tc.tpl, tc.data); err != nil {
t.Error(err)
}
act := w.String()
if act != tc.exp {
t.Errorf(
"unexpected error: \n"+
"(GOT):\n=== BEGIN ===\n%v\n=== END ===\n"+
"(WNT):\n=== BEGIN ===\n%v\n=== END ===\n",
act,
tc.exp)
}
})
}
}