Add sort by "required" and then name (#43)

This commit is contained in:
Stuart Auld
2018-10-09 19:29:09 +11:00
committed by Martin Etmajer
parent 9422d09f73
commit 0b468e30db
18 changed files with 507 additions and 27 deletions

View File

@@ -10,3 +10,4 @@ Martin Etmajer <metmajer@getcloudnative.io>
Matthew Baker <mbaker@cozero.com.au>
Nick Walke <nwalke@smg.com>
Sergiusz Urbaniak <sergiusz.urbaniak@gmail.com>
Stuart Auld <sja@marsupialmusic.net>

View File

@@ -26,7 +26,7 @@ This project is no longer maintained by Segment. Instead, [Martin Etmajer](https
```bash
Usage:
terraform-docs [--no-required] [--no-sort] [--with-aggregate-type-defaults] [json | markdown | md] <path>...
terraform-docs [--no-required] [--no-sort | --sort-inputs-by-required] [--with-aggregate-type-defaults] [json | markdown | md] <path>...
terraform-docs -h | --help
Examples:
@@ -50,6 +50,7 @@ This project is no longer maintained by Segment. Instead, [Martin Etmajer](https
-h, --help show help information
--no-required omit "Required" column when generating markdown
--no-sort omit sorted rendering of inputs and ouputs
--sort-inputs-by-required sort inputs by name and prints required inputs first
--with-aggregate-type-defaults print default values of aggregate types
--version print version

View File

@@ -253,6 +253,182 @@ func TestInputsFromVariablesTf(t *testing.T) {
assert.Equal(t, expected, actual)
}
func TestInputsSortedByName(t *testing.T) {
actual := doc.TestDoc(t, ".").Inputs
doc.SortInputsByName(actual)
expected := []doc.Input{
doc.Input{
Name: "list-1",
Description: "It's list number one.",
Default: &doc.Value{
Type: "list",
Value: []interface{}{
"a",
"b",
"c",
},
},
Type: "list",
},
doc.Input{
Name: "list-2",
Description: "It's list number two.",
Default: nil,
Type: "list",
},
doc.Input{
Name: "list-3",
Description: "",
Default: &doc.Value{
Type: "list",
Value: []interface{}{},
},
Type: "list",
},
doc.Input{
Name: "map-1",
Description: "It's map number one.",
Default: &doc.Value{
Type: "map",
Value: map[string]interface{}{
"a": float64(1),
"b": float64(2),
"c": float64(3),
},
},
Type: "map",
},
doc.Input{
Name: "map-2",
Description: "It's map number two.",
Default: nil,
Type: "map",
},
doc.Input{
Name: "map-3",
Description: "",
Default: &doc.Value{
Type: "map",
Value: map[string]interface{}{},
},
Type: "map",
},
doc.Input{
Name: "string-1",
Description: "It's string number one.",
Default: &doc.Value{
Type: "string",
Value: "bar",
},
Type: "string",
},
doc.Input{
Name: "string-2",
Description: "It's string number two.",
Default: nil,
Type: "string",
},
doc.Input{
Name: "unquoted",
Description: "",
Default: nil,
Type: "string",
},
}
assert.Equal(t, expected, actual)
}
func TestInputsSortedByRequired(t *testing.T) {
actual := doc.TestDoc(t, ".").Inputs
doc.SortInputsByRequired(actual)
expected := []doc.Input{
doc.Input{
Name: "list-2",
Description: "It's list number two.",
Default: nil,
Type: "list",
},
doc.Input{
Name: "map-2",
Description: "It's map number two.",
Default: nil,
Type: "map",
},
doc.Input{
Name: "string-2",
Description: "It's string number two.",
Default: nil,
Type: "string",
},
doc.Input{
Name: "unquoted",
Description: "",
Default: nil,
Type: "string",
},
doc.Input{
Name: "list-1",
Description: "It's list number one.",
Default: &doc.Value{
Type: "list",
Value: []interface{}{
"a",
"b",
"c",
},
},
Type: "list",
},
doc.Input{
Name: "list-3",
Description: "",
Default: &doc.Value{
Type: "list",
Value: []interface{}{},
},
Type: "list",
},
doc.Input{
Name: "map-1",
Description: "It's map number one.",
Default: &doc.Value{
Type: "map",
Value: map[string]interface{}{
"a": float64(1),
"b": float64(2),
"c": float64(3),
},
},
Type: "map",
},
doc.Input{
Name: "map-3",
Description: "",
Default: &doc.Value{
Type: "map",
Value: map[string]interface{}{},
},
Type: "map",
},
doc.Input{
Name: "string-1",
Description: "It's string number one.",
Default: &doc.Value{
Type: "string",
Value: "bar",
},
Type: "string",
},
}
assert.Equal(t, expected, actual)
}
func TestOutputs(t *testing.T) {
actual := doc.TestDoc(t, ".").Outputs

View File

@@ -53,3 +53,32 @@ func (a inputsSortedByName) Less(i, j int) bool {
func SortInputsByName(inputs []Input) {
sort.Sort(inputsSortedByName(inputs))
}
type inputsSortedByRequired []Input
func (a inputsSortedByRequired) Len() int {
return len(a)
}
func (a inputsSortedByRequired) Swap(i, j int) {
a[i], a[j] = a[j], a[i]
}
func (a inputsSortedByRequired) Less(i, j int) bool {
switch {
// i required, j not: i gets priority
case !a[i].HasDefault() && a[j].HasDefault():
return true
// j required, i not: i does not get priority
case a[i].HasDefault() && !a[j].HasDefault():
return false
// Otherwise, sort by name
default:
return a[i].Name < a[j].Name
}
}
// SortInputsByRequired sorts a list of inputs by whether they are required
func SortInputsByRequired(inputs []Input) {
sort.Sort(inputsSortedByRequired(inputs))
}

View File

@@ -16,3 +16,4 @@
* }
* }
*/

View File

@@ -26,7 +26,8 @@ variable "map-1" {
b = 2
c = 3
}
type = "map"
type = "map"
}
variable "list-3" {

View File

@@ -16,13 +16,17 @@ const (
// Print prints a document as json.
func Print(document *doc.Doc, settings settings.Settings) (string, error) {
if document.HasInputs() {
if settings.Has(print.WithSorting) {
doc.SortInputsByName(document.Inputs)
if settings.Has(print.WithSortByName) {
if settings.Has(print.WithSortInputsByRequired) {
doc.SortInputsByRequired(document.Inputs)
} else {
doc.SortInputsByName(document.Inputs)
}
}
}
if document.HasOutputs() {
if settings.Has(print.WithSorting) {
if settings.Has(print.WithSortByName) {
doc.SortOutputsByName(document.Outputs)
}
}

View File

@@ -28,18 +28,38 @@ func TestPrint(t *testing.T) {
assert.Equal(t, expected, actual)
}
func TestPrintWithSorting(t *testing.T) {
func TestPrintWithSortByName(t *testing.T) {
doc := doc.TestDoc(t, "..")
var settings settings.Settings
settings.Add(print.WithSorting)
settings.Add(print.WithSortByName)
actual, err := json.Print(doc, settings)
if err != nil {
t.Fatal(err)
}
expected, err := print.ReadGoldenFile("json-WithSorting")
expected, err := print.ReadGoldenFile("json-WithSortByName")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, expected, actual)
}
func TestPrintWithSortInputsByRequired(t *testing.T) {
doc := doc.TestDoc(t, "..")
var settings settings.Settings
settings.Add(print.WithSortByName)
settings.Add(print.WithSortInputsByRequired)
actual, err := json.Print(doc, settings)
if err != nil {
t.Fatal(err)
}
expected, err := print.ReadGoldenFile("json-WithSortInputsByRequired")
if err != nil {
t.Fatal(err)
}

View File

@@ -0,0 +1,96 @@
{
"Comment": "Usage:\n\nmodule \"foo\" {\n source = \"github.com/foo/bar\"\n\n id = \"1234567890\"\n name = \"baz\"\n\n zones = [\"us-east-1\", \"us-west-1\"]\n\n tags = {\n Name = \"baz\"\n Created-By = \"first.last@email.com\"\n Date-Created = \"20180101\"\n }\n}\n",
"Inputs": [
{
"Name": "list-2",
"Description": "It's list number two.",
"Default": null,
"Type": "list"
},
{
"Name": "map-2",
"Description": "It's map number two.",
"Default": null,
"Type": "map"
},
{
"Name": "string-2",
"Description": "It's string number two.",
"Default": null,
"Type": "string"
},
{
"Name": "unquoted",
"Description": "",
"Default": null,
"Type": "string"
},
{
"Name": "list-1",
"Description": "It's list number one.",
"Default": {
"Type": "list",
"Value": [
"a",
"b",
"c"
]
},
"Type": "list"
},
{
"Name": "list-3",
"Description": "",
"Default": {
"Type": "list",
"Value": []
},
"Type": "list"
},
{
"Name": "map-1",
"Description": "It's map number one.",
"Default": {
"Type": "map",
"Value": {
"a": 1,
"b": 2,
"c": 3
}
},
"Type": "map"
},
{
"Name": "map-3",
"Description": "",
"Default": {
"Type": "map",
"Value": {}
},
"Type": "map"
},
{
"Name": "string-1",
"Description": "It's string number one.",
"Default": {
"Type": "string",
"Value": "bar"
},
"Type": "string"
}
],
"Outputs": [
{
"Name": "output-1",
"Description": "It's output number one."
},
{
"Name": "output-2",
"Description": "It's output number two."
},
{
"Name": "unquoted",
"Description": "It's unquoted output."
}
]
}

View File

@@ -19,15 +19,19 @@ func Print(document *doc.Doc, settings settings.Settings) (string, error) {
}
if document.HasInputs() {
if settings.Has(print.WithSorting) {
doc.SortInputsByName(document.Inputs)
if settings.Has(print.WithSortByName) {
if settings.Has(print.WithSortInputsByRequired) {
doc.SortInputsByRequired(document.Inputs)
} else {
doc.SortInputsByName(document.Inputs)
}
}
printInputs(&buffer, document.Inputs, settings)
}
if document.HasOutputs() {
if settings.Has(print.WithSorting) {
if settings.Has(print.WithSortByName) {
doc.SortOutputsByName(document.Outputs)
}

View File

@@ -65,18 +65,38 @@ func TestPrintWithRequired(t *testing.T) {
assert.Equal(t, expected, actual)
}
func TestPrintWithSorting(t *testing.T) {
func TestPrintWithSortByName(t *testing.T) {
doc := doc.TestDoc(t, "..")
var settings settings.Settings
settings.Add(print.WithSorting)
settings.Add(print.WithSortByName)
actual, err := markdown.Print(doc, settings)
if err != nil {
t.Fatal(err)
}
expected, err := print.ReadGoldenFile("markdown-WithSorting")
expected, err := print.ReadGoldenFile("markdown-WithSortByName")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, expected, actual)
}
func TestPrintWithSortInputsByRequired(t *testing.T) {
doc := doc.TestDoc(t, "..")
var settings settings.Settings
settings.Add(print.WithSortByName)
settings.Add(print.WithSortInputsByRequired)
actual, err := markdown.Print(doc, settings)
if err != nil {
t.Fatal(err)
}
expected, err := print.ReadGoldenFile("markdown-WithSortInputsByRequired")
if err != nil {
t.Fatal(err)
}

View File

@@ -0,0 +1,38 @@
Usage:
module "foo" {
source = "github.com/foo/bar"
id = "1234567890"
name = "baz"
zones = ["us-east-1", "us-west-1"]
tags = {
Name = "baz"
Created-By = "first.last@email.com"
Date-Created = "20180101"
}
}
## Inputs
| Name | Description | Type | Default |
|------|-------------|:----:|:-----:|
| list-2 | It's list number two. | list | - |
| map-2 | It's map number two. | map | - |
| string-2 | It's string number two. | string | - |
| unquoted | - | string | - |
| list-1 | It's list number one. | list | `<list>` |
| list-3 | - | list | `<list>` |
| map-1 | It's map number one. | map | `<map>` |
| map-3 | - | map | `<map>` |
| string-1 | It's string number one. | string | `bar` |
## Outputs
| Name | Description |
|------|-------------|
| output-1 | It's output number one. |
| output-2 | It's output number two. |
| unquoted | It's unquoted output. |

View File

@@ -18,15 +18,19 @@ func Print(document *doc.Doc, settings settings.Settings) (string, error) {
}
if document.HasInputs() {
if settings.Has(print.WithSorting) {
doc.SortInputsByName(document.Inputs)
if settings.Has(print.WithSortByName) {
if settings.Has(print.WithSortInputsByRequired) {
doc.SortInputsByRequired(document.Inputs)
} else {
doc.SortInputsByName(document.Inputs)
}
}
printInputs(&buffer, document.Inputs, settings)
}
if document.HasOutputs() {
if settings.Has(print.WithSorting) {
if settings.Has(print.WithSortByName) {
doc.SortOutputsByName(document.Outputs)
}

View File

@@ -162,11 +162,11 @@ func TestPrettyWithWithAggregateTypeDefaults(t *testing.T) {
assert.Equal(t, expected, actual)
}
func TestPrettyWithSorting(t *testing.T) {
func TestPrettyWithSortByName(t *testing.T) {
doc := doc.TestDoc(t, "..")
var settings settings.Settings
settings.Add(print.WithSorting)
settings.Add(print.WithSortByName)
actual, err := pretty.Print(doc, settings)
if err != nil {
@@ -238,3 +238,81 @@ func TestPrettyWithSorting(t *testing.T) {
assert.Equal(t, expected, actual)
}
func TestPrettyWithSortInputsByRequired(t *testing.T) {
doc := doc.TestDoc(t, "..")
var settings settings.Settings
settings.Add(print.WithSortByName)
settings.Add(print.WithSortInputsByRequired)
actual, err := pretty.Print(doc, settings)
if err != nil {
t.Fatal(err)
}
sgr_color_1 := "\x1b[36m"
sgr_color_2 := "\x1b[90m"
sgr_reset := "\x1b[0m"
expected :=
"\nUsage:\n" +
"\n" +
"module \"foo\" {\n" +
" source = \"github.com/foo/bar\"\n" +
"\n" +
" id = \"1234567890\"\n" +
" name = \"baz\"\n" +
"\n" +
" zones = [\"us-east-1\", \"us-west-1\"]\n" +
"\n" +
" tags = {\n" +
" Name = \"baz\"\n" +
" Created-By = \"first.last@email.com\"\n" +
" Date-Created = \"20180101\"\n" +
" }\n" +
"}\n" +
"\n" +
"\n" +
" " + sgr_color_1 + "var.list-2" + sgr_reset + " (required)\n" +
" " + sgr_color_2 + "It's list number two." + sgr_reset + "\n" +
"\n" +
" " + sgr_color_1 + "var.map-2" + sgr_reset + " (required)\n" +
" " + sgr_color_2 + "It's map number two." + sgr_reset + "\n" +
"\n" +
" " + sgr_color_1 + "var.string-2" + sgr_reset + " (required)\n" +
" " + sgr_color_2 + "It's string number two." + sgr_reset + "\n" +
"\n" +
" " + sgr_color_1 + "var.unquoted" + sgr_reset + " (required)\n" +
" " + sgr_color_2 + "-" + sgr_reset + "\n" +
"\n" +
" " + sgr_color_1 + "var.list-1" + sgr_reset + " (<list>)\n" +
" " + sgr_color_2 + "It's list number one." + sgr_reset + "\n" +
"\n" +
" " + sgr_color_1 + "var.list-3" + sgr_reset + " (<list>)\n" +
" " + sgr_color_2 + "-" + sgr_reset + "\n" +
"\n" +
" " + sgr_color_1 + "var.map-1" + sgr_reset + " (<map>)\n" +
" " + sgr_color_2 + "It's map number one." + sgr_reset + "\n" +
"\n" +
" " + sgr_color_1 + "var.map-3" + sgr_reset + " (<map>)\n" +
" " + sgr_color_2 + "-" + sgr_reset + "\n" +
"\n" +
" " + sgr_color_1 + "var.string-1" + sgr_reset + " (bar)\n" +
" " + sgr_color_2 + "It's string number one." + sgr_reset + "\n" +
"\n" +
"\n" +
"\n" +
" " + sgr_color_1 + "output.output-1" + sgr_reset + "\n" +
" " + sgr_color_2 + "It's output number one." + sgr_reset + "\n" +
"\n" +
" " + sgr_color_1 + "output.output-2" + sgr_reset + "\n" +
" " + sgr_color_2 + "It's output number two." + sgr_reset + "\n" +
"\n" +
" " + sgr_color_1 + "output.unquoted" + sgr_reset + "\n" +
" " + sgr_color_2 + "It's unquoted output." + sgr_reset + "\n" +
"\n" +
"\n"
assert.Equal(t, expected, actual)
}

View File

@@ -15,8 +15,10 @@ const (
WithAggregateTypeDefaults
// WithRequired prints if inputs are required
WithRequired
// WithSorting prints sorted inputs and outputs
WithSorting
// WithSortByName prints sorted inputs and outputs
WithSortByName
// WithSortInputsByRequired sorts inputs by name and prints required inputs first
WithSortInputsByRequired
)
// GetPrintableValue returns a printable representation of a Terraform value.

17
main.go
View File

@@ -17,7 +17,7 @@ var version = "dev"
const usage = `
Usage:
terraform-docs [--no-required] [--no-sort] [--with-aggregate-type-defaults] [json | markdown | md] <path>...
terraform-docs [--no-required] [--no-sort | --sort-inputs-by-required] [--with-aggregate-type-defaults] [json | markdown | md] <path>...
terraform-docs -h | --help
Examples:
@@ -41,10 +41,11 @@ const usage = `
$ terraform-docs md ./my-module ../config.tf
Options:
-h, --help show help information
--no-required omit "Required" column when generating markdown
--no-sort omit sorted rendering of inputs and ouputs
--with-aggregate-type-defaults print default values of aggregate types
-h, --help show help information
--no-required omit "Required" column when generating markdown
--no-sort omit sorted rendering of inputs and ouputs
--sort-inputs-by-required sort inputs by name and prints required inputs first
--with-aggregate-type-defaults print default values of aggregate types
--version print version
`
@@ -68,7 +69,11 @@ func main() {
}
if !args["--no-sort"].(bool) {
printSettings.Add(print.WithSorting)
printSettings.Add(print.WithSortByName)
}
if args["--sort-inputs-by-required"].(bool) {
printSettings.Add(print.WithSortInputsByRequired)
}
if args["--with-aggregate-type-defaults"].(bool) {