Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 1 addition & 6 deletions internal/workload/v1/kinds/workload.go
Original file line number Diff line number Diff line change
Expand Up @@ -365,12 +365,7 @@ func (ws *WorkloadSpec) processMarkerResults(markerResults []*inspect.YAMLResult
continue
}

// set the comments based on the description field of a field marker
comments := []string{}

if marker.GetDescription() != "" {
comments = append(comments, strings.Split(marker.GetDescription(), "\n")...)
}
comments := marker.GetComments("+kubebuilder:")

// set the sample value based on if a default was specified in the marker or not
if marker.GetDefault() != nil {
Expand Down
4 changes: 4 additions & 0 deletions internal/workload/v1/markers/collection_field_marker.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,3 +137,7 @@ func (cfm *CollectionFieldMarker) SetDescription(description string) {
func (cfm *CollectionFieldMarker) SetForCollection(forCollection bool) {
cfm.forCollection = forCollection
}

func (cfm *CollectionFieldMarker) GetComments(exceptions ...string) []string {
return commentsFromMarker(cfm.GetDescription(), exceptions...)
}
4 changes: 4 additions & 0 deletions internal/workload/v1/markers/field_marker.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,3 +162,7 @@ func (fm *FieldMarker) SetDescription(description string) {
func (fm *FieldMarker) SetForCollection(forCollection bool) {
fm.forCollection = forCollection
}

func (fm *FieldMarker) GetComments(exceptions ...string) []string {
return commentsFromMarker(fm.GetDescription(), exceptions...)
}
164 changes: 164 additions & 0 deletions internal/workload/v1/markers/markers.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ type FieldMarkerProcessor interface {
GetReplaceText() string
GetSpecPrefix() string
GetSourceCodeVariable() string
GetComments(exceptions ...string) []string

IsCollectionFieldMarker() bool
IsFieldMarker() bool
Expand Down Expand Up @@ -219,6 +220,169 @@ func validField(field string, validFields []string) bool {
return false
}

const commentWrapWidth = 80

// commentsFromMarker builds the formatted comment slice for a field marker.
// It splits the description into word-wrapped blocks (at commentWrapWidth) and
// prepends a blank line so the description is visually separated from any
// preceding marker annotations (e.g. the "(Default: X)" that setDefault writes
// into api.Markers). Any block line that begins with an exception prefix is
// emitted verbatim without word-wrapping.
//
// Note: the default annotation itself is intentionally NOT included here — it
// is already written to api.Markers by setDefault/setCommentsAndDefault.
func commentsFromMarker(description string, exceptions ...string) []string {
description = strings.Trim(description, "\n")
if description == "" {
return nil
}

// Leading blank line separates the description from marker annotations
// (e.g. +kubebuilder:default=X or (Default: X)) that precede it.
comments := []string{""}

for i, block := range buildDescriptionBlocks(strings.Split(description, "\n")) {
blockLines := wrapCommentBlock(block, exceptions)
if len(blockLines) == 0 {
continue
}

if i > 0 {
comments = append(comments, "")
}

comments = append(comments, blockLines...)
}

return normalizeCommentLines(comments)
}

// buildDescriptionBlocks splits trimmed non-blank lines into paragraph blocks,
// separated by blank (or whitespace-only) lines.
func buildDescriptionBlocks(rawLines []string) [][]string {
var blocks [][]string

var current []string

for _, line := range rawLines {
if trimmed := strings.TrimSpace(line); trimmed == "" {
if len(current) > 0 {
blocks = append(blocks, current)
current = nil
}
} else {
current = append(current, trimmed)
}
}

if len(current) > 0 {
blocks = append(blocks, current)
}

return blocks
}

// normalizeCommentLines collapses consecutive blank entries into one and removes
// any trailing blank entry. Returns nil when nothing remains.
func normalizeCommentLines(comments []string) []string {
normalized := comments[:0:0]

for i, c := range comments {
if c == "" && i > 0 && comments[i-1] == "" {
continue
}

normalized = append(normalized, c)
}

for len(normalized) > 0 && normalized[len(normalized)-1] == "" {
normalized = normalized[:len(normalized)-1]
}

if len(normalized) == 0 {
return nil
}

return normalized
}

// wrapCommentBlock emits the lines of a description block as wrapped comment strings.
// Lines beginning with an exception prefix are passed through verbatim on their
// own line; all other lines are joined and word-wrapped at commentWrapWidth.
func wrapCommentBlock(lines, exceptions []string) []string {
var result []string

var pending []string

flush := func() {
if len(pending) == 0 {
return
}

result = append(result, wrapCommentLine(strings.Join(pending, " "))...)
pending = nil
}

for _, line := range lines {
if isCommentLineException(line, exceptions) {
flush()
result = append(result, line)
} else {
pending = append(pending, line)
}
}

flush()

return result
}

var wordRe = regexp.MustCompile(`\S+`)

// wrapCommentLine wraps text at commentWrapWidth characters, breaking only at word
// boundaries. Whitespace runs between words (e.g. double-spaces after a
// sentence-ending period) are preserved in the output.
func wrapCommentLine(text string) []string {
if text == "" {
return nil
}
locs := wordRe.FindAllStringIndex(text, -1)

if len(locs) == 0 {
return nil
}

var lines []string

lineStart := locs[0][0]
lineEnd := locs[0][1]

for _, loc := range locs[1:] {
wordEnd := loc[1]
if wordEnd-lineStart > commentWrapWidth {
lines = append(lines, text[lineStart:lineEnd])
lineStart = loc[0]
}

lineEnd = wordEnd
}

lines = append(lines, text[lineStart:lineEnd])

return lines
}
Comment thread
scottlee01818 marked this conversation as resolved.

// isCommentLineException returns true when line begins with any of the exception prefixes.
func isCommentLineException(line string, exceptions []string) bool {
for _, exc := range exceptions {
if strings.HasPrefix(line, exc) {
return true
}
}

return false
}

// getSourceCodeFieldVariable gets a full variable name for a marker as it is intended to be
// passed into the generate package to generate the source code. This includes particular
// tags that are needed by the generator to properly identify when a variable starts and ends.
Expand Down
Loading
Loading