Skip to content

Commit

Permalink
Add possibility to generate subsectioned Values Tables
Browse files Browse the repository at this point in the history
This adds `@section` comments, which will be parsed into
semantic section info for valueRows. This allows to generate
sectioned Values Tables by adding the templates
`chart.valuesSectionedSection` and `chart.valuesSectionedSectionHTML`
and thereby keeping compatability with default Values Tables
  • Loading branch information
Haepaxlog committed Sep 5, 2023
1 parent 913cc49 commit 94cc6af
Show file tree
Hide file tree
Showing 5 changed files with 177 additions and 4 deletions.
79 changes: 76 additions & 3 deletions pkg/document/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type valueRow struct {
Default string
AutoDescription string
Description string
Section string
Column int
LineNumber int
Dependency string
Expand All @@ -30,17 +31,52 @@ type chartTemplateData struct {
helm.ChartDocumentationInfo
HelmDocsVersion string
Values []valueRow
Sections []section
Files files
}

func sortValueRows(valueRows []valueRow) {
type section struct {
SectionName string
SectionItems []valueRow
}

func sortValueRows(valueRows []valueRow) ([]valueRow, []section) {
sortOrder := viper.GetString("sort-values-order")

if sortOrder != FileSortOrder && sortOrder != AlphaNumSortOrder {
log.Warnf("Invalid sort order provided %s, defaulting to %s", sortOrder, AlphaNumSortOrder)
sortOrder = AlphaNumSortOrder
}

var valueRowsSectionSorted []section
valueRowsSectionSorted = append(valueRowsSectionSorted, section{
SectionName: "General",
SectionItems: []valueRow{},
})

for _, row := range valueRows {
if row.Section == "" {
valueRowsSectionSorted[0].SectionItems = append(valueRowsSectionSorted[0].SectionItems, row)
continue
}

containsSection := false
for i, section := range valueRowsSectionSorted {
if section.SectionName == row.Section {
containsSection = true
valueRowsSectionSorted[i].SectionItems = append(valueRowsSectionSorted[i].SectionItems, row)
break
}
}

if !containsSection {
valueRowsSectionSorted = append(valueRowsSectionSorted, section{
SectionName: row.Section,
SectionItems: []valueRow{row},
})
}
}

sort.Slice(valueRows, func(i, j int) bool {
// Globals sort above non-globals.
if valueRows[i].IsGlobal != valueRows[j].IsGlobal {
Expand Down Expand Up @@ -73,6 +109,42 @@ func sortValueRows(valueRows []valueRow) {
panic("cannot get here")
}
})

for _, section := range valueRowsSectionSorted {
sort.Slice(section.SectionItems, func(i, j int) bool {
// Globals sort above non-globals.
if section.SectionItems[i].IsGlobal != section.SectionItems[j].IsGlobal {
return section.SectionItems[i].IsGlobal
}

// Group by dependency for non-globals.
if !section.SectionItems[i].IsGlobal && !section.SectionItems[j].IsGlobal {
// Values for the main chart sort above values for dependencies.
if (section.SectionItems[i].Dependency == "") != (section.SectionItems[j].Dependency == "") {
return section.SectionItems[i].Dependency == ""
}

// Group dependency values together.
if section.SectionItems[i].Dependency != section.SectionItems[j].Dependency {
return section.SectionItems[i].Dependency < section.SectionItems[j].Dependency
}
}

// Sort the remaining values within the same section.SectionItems using the configured sort order.
switch sortOrder {
case FileSortOrder:
if section.SectionItems[i].LineNumber == section.SectionItems[j].LineNumber {
return section.SectionItems[i].Column < section.SectionItems[j].Column
}
return section.SectionItems[i].LineNumber < section.SectionItems[j].LineNumber
case AlphaNumSortOrder:
return section.SectionItems[i].Key < section.SectionItems[j].Key
default:
panic("cannot get here")
}
})
}
return valueRows, valueRowsSectionSorted
}

func getUnsortedValueRows(document *yaml.Node, descriptions map[string]helm.ChartValueDescription) ([]valueRow, error) {
Expand Down Expand Up @@ -134,7 +206,7 @@ func getChartTemplateData(info helm.ChartDocumentationInfo, helmDocsVersion stri
}
}

sortValueRows(valuesTableRows)
valueRowsSorted, valueRowsSectionSorted := sortValueRows(valuesTableRows)

files, err := getFiles(info.ChartDirectory)
if err != nil {
Expand All @@ -144,7 +216,8 @@ func getChartTemplateData(info helm.ChartDocumentationInfo, helmDocsVersion stri
return chartTemplateData{
ChartDocumentationInfo: info,
HelmDocsVersion: helmDocsVersion,
Values: valuesTableRows,
Values: valueRowsSorted,
Sections: valueRowsSectionSorted,
Files: files,
}, nil
}
Expand Down
79 changes: 79 additions & 0 deletions pkg/document/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,84 @@ func getValuesTableTemplates() string {
return valuesSectionBuilder.String()
}

func getValuesTableSectionedTemplates() string {
valuesSectionBuilder := strings.Builder{}
valuesSectionBuilder.WriteString(`{{ define "chart.valuesSectionedHeader" }}## Values{{ end }}`)

valuesSectionBuilder.WriteString(`{{ define "chart.valuesSectionedTable" }}`)
valuesSectionBuilder.WriteString("{{ range .Sections }}")
valuesSectionBuilder.WriteString("\n")
valuesSectionBuilder.WriteString("\n### {{ .SectionName }}\n")
valuesSectionBuilder.WriteString("| Key | Type | Default | Description |\n")
valuesSectionBuilder.WriteString("|-----|------|---------|-------------|\n")
valuesSectionBuilder.WriteString(" {{- range .SectionItems }}")
valuesSectionBuilder.WriteString("\n| {{ .Key }} | {{ .Type }} | {{ if .Default }}{{ .Default }}{{ else }}{{ .AutoDefault }}{{ end }} | {{ if .Description }}{{ .Description }}{{ else }}{{ .AutoDescription }}{{ end }} |")
valuesSectionBuilder.WriteString(" {{- end }}")
valuesSectionBuilder.WriteString("{{ end }}")
valuesSectionBuilder.WriteString("{{ end }}")

valuesSectionBuilder.WriteString(`{{ define "chart.valuesSectionedSection" }}`)
valuesSectionBuilder.WriteString("{{ if .Values }}")
valuesSectionBuilder.WriteString(`{{ template "chart.valuesSectionedHeader" . }}`)
valuesSectionBuilder.WriteString("\n\n")
valuesSectionBuilder.WriteString(`{{ template "chart.valuesSectionedTable" . }}`)
valuesSectionBuilder.WriteString("{{ end }}")
valuesSectionBuilder.WriteString("{{ end }}")

// For HTML tables
valuesSectionBuilder.WriteString(`
{{ define "chart.valueDefaultColumnRender" }}
{{- $defaultValue := (default .Default .AutoDefault) -}}
{{- $notationType := .NotationType }}
{{- if (and (hasPrefix "` + "`" + `" $defaultValue) (hasSuffix "` + "`" + `" $defaultValue) ) -}}
{{- $defaultValue = (toPrettyJson (fromJson (trimAll "` + "`" + `" (default .Default .AutoDefault) ) ) ) -}}
{{- $notationType = "json" }}
{{- end -}}
<pre lang="{{ $notationType }}">
{{- if (eq $notationType "tpl" ) }}
{{ .Key }}: |
{{- $defaultValue | nindent 2 }}
{{- else }}
{{ $defaultValue }}
{{- end }}
</pre>
{{ end }}
{{ define "chart.valuesSectionedTableHtml" }}
{{- range .Sections }}
<h3>{{- .SectionName }}</h3>
<table>
<thead>
<th>Key</th>
<th>Type</th>
<th>Default</th>
<th>Description</th>
</thead>
<tbody>
{{- range .SectionItems }}
<tr>
<td>{{ .Key }}</td>
<td>{{ .Type }}</td>
<td>{{ template "chart.valueDefaultColumnRender" . }}</td>
<td>{{ if .Description }}{{ .Description }}{{ else }}{{ .AutoDescription }}{{ end }}</td>
</tr>
{{- end }}
</tbody>
</table>
{{- end }}
{{ end }}
{{ define "chart.valuesSectionedSectionHtml" }}
{{ if .Sections }}
{{ template "chart.valuesSectionedHeader" . }}
{{ template "chart.valuesSectionedTableHtml" . }}
{{ end }}
{{ end }}
`)

return valuesSectionBuilder.String()
}

func getHelmDocsVersionTemplates() string {
versionSectionBuilder := strings.Builder{}
versionSectionBuilder.WriteString(`{{ define "helm-docs.version" }}{{ if .HelmDocsVersion }}{{ .HelmDocsVersion }}{{ end }}{{ end }}`)
Expand Down Expand Up @@ -350,6 +428,7 @@ func getDocumentationTemplates(chartDirectory string, chartSearchRoot string, te
getSourceLinkTemplates(),
getRequirementsTableTemplates(),
getValuesTableTemplates(),
getValuesTableSectionedTemplates(),
getHomepageTemplate(),
getMaintainersTemplate(),
getHelmDocsVersionTemplates(),
Expand Down
12 changes: 12 additions & 0 deletions pkg/document/values.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,13 +93,19 @@ func parseNilValueType(key string, description helm.ChartValueDescription, autoD
description.Default = "`nil`"
}

section := description.Section
if section == "" && autoDescription.Section != "" {
section = autoDescription.Section
}

return valueRow{
Key: key,
Type: t,
AutoDefault: autoDescription.Default,
Default: description.Default,
AutoDescription: autoDescription.Description,
Description: description.Description,
Section: section,
Column: column,
LineNumber: lineNumber,
}
Expand Down Expand Up @@ -179,6 +185,11 @@ func createValueRow(
defaultValue = fmt.Sprintf("%s", value)
}

section := description.Section
if section == "" && autoDescription.Section != "" {
section = autoDescription.Section
}

return valueRow{
Key: key,
Type: defaultType,
Expand All @@ -187,6 +198,7 @@ func createValueRow(
Default: defaultValue,
AutoDescription: autoDescription.Description,
Description: description.Description,
Section: section,
Column: column,
LineNumber: lineNumber,
}, nil
Expand Down
5 changes: 4 additions & 1 deletion pkg/helm/chart_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ var commentContinuationRegex = regexp.MustCompile("^\\s*#(\\s?)(.*)$")
var defaultValueRegex = regexp.MustCompile("^\\s*# @default -- (.*)$")
var valueTypeRegex = regexp.MustCompile("^\\((.*?)\\)\\s*(.*)$")
var valueNotationTypeRegex = regexp.MustCompile("^\\s*#\\s+@notationType\\s+--\\s+(.*)$")
var sectionRegex = regexp.MustCompile("^\\s*# @section -- (.*)$")

type ChartMetaMaintainer struct {
Email string
Expand Down Expand Up @@ -57,6 +58,7 @@ type ChartRequirements struct {
type ChartValueDescription struct {
Description string
Default string
Section string
ValueType string
NotationType string
}
Expand Down Expand Up @@ -268,9 +270,10 @@ func parseChartValuesFileComments(chartDirectory string, values *yaml.Node, lint
// If we've already found a values comment, on the next line try and parse a custom default value. If we find one
// that completes parsing for this key, add it to the list and reset to searching for a new key
defaultCommentMatch := defaultValueRegex.FindStringSubmatch(currentLine)
sectionCommentMatch := sectionRegex.FindStringSubmatch(currentLine)
commentContinuationMatch := commentContinuationRegex.FindStringSubmatch(currentLine)

if len(defaultCommentMatch) > 1 || len(commentContinuationMatch) > 1 {
if len(defaultCommentMatch) > 1 || len(sectionCommentMatch) > 1 || len(commentContinuationMatch) > 1 {
commentLines = append(commentLines, currentLine)
continue
}
Expand Down
6 changes: 6 additions & 0 deletions pkg/helm/comment.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ func ParseComment(commentLines []string) (string, ChartValueDescription) {
rawFlagMatch := rawDescriptionRegex.FindStringSubmatch(line)
defaultCommentMatch := defaultValueRegex.FindStringSubmatch(line)
notationTypeCommentMatch := valueNotationTypeRegex.FindStringSubmatch(line)
sectionCommentMatch := sectionRegex.FindStringSubmatch(line)

if !isRaw && len(rawFlagMatch) == 1 {
isRaw = true
Expand All @@ -66,6 +67,11 @@ func ParseComment(commentLines []string) (string, ChartValueDescription) {
continue
}

if len(sectionCommentMatch) > 1 {
c.Section = sectionCommentMatch[1]
continue
}

commentContinuationMatch := commentContinuationRegex.FindStringSubmatch(line)

if isRaw {
Expand Down

0 comments on commit 94cc6af

Please sign in to comment.