Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package helm-schema for openSUSE:Factory checked in at 2026-02-09 15:35:10 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/helm-schema (Old) and /work/SRC/openSUSE:Factory/.helm-schema.new.1670 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "helm-schema" Mon Feb 9 15:35:10 2026 rev:4 rq:1331951 version:0.21.1 Changes: -------- --- /work/SRC/openSUSE:Factory/helm-schema/helm-schema.changes 2026-01-30 18:26:59.345395645 +0100 +++ /work/SRC/openSUSE:Factory/.helm-schema.new.1670/helm-schema.changes 2026-02-09 15:35:44.369637691 +0100 @@ -1,0 +2,14 @@ +Mon Feb 09 06:45:19 UTC 2026 - Johannes Kastl <[email protected]> + +- Update to version 0.21.1: + no code changes +- Update to version 0.21.0: + * feat: Add annotate functionality +- Update to version 0.20.3: + * fix(uncomment): preserve indentation and flush buffer on + uncommented lines + * chore(deps): update alpine:3.23 docker digest to 2510918 + * chore(deps): update azure/setup-helm digest to 1a275c3 + * chore(deps): update docker/login-action digest to c94ce9f + +------------------------------------------------------------------- Old: ---- helm-schema-0.20.2.obscpio New: ---- helm-schema-0.21.1.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ helm-schema.spec ++++++ --- /var/tmp/diff_new_pack.iL16sZ/_old 2026-02-09 15:35:44.957662360 +0100 +++ /var/tmp/diff_new_pack.iL16sZ/_new 2026-02-09 15:35:44.957662360 +0100 @@ -17,7 +17,7 @@ Name: helm-schema -Version: 0.20.2 +Version: 0.21.1 Release: 0 Summary: Generate jsonschemas from helm charts License: MIT ++++++ _service ++++++ --- /var/tmp/diff_new_pack.iL16sZ/_old 2026-02-09 15:35:45.005664373 +0100 +++ /var/tmp/diff_new_pack.iL16sZ/_new 2026-02-09 15:35:45.009664541 +0100 @@ -3,7 +3,7 @@ <param name="url">https://github.com/dadav/helm-schema</param> <param name="scm">git</param> <param name="exclude">.git</param> - <param name="revision">0.20.2</param> + <param name="revision">0.21.1</param> <param name="versionformat">@PARENT_TAG@</param> <param name="changesgenerate">enable</param> </service> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.iL16sZ/_old 2026-02-09 15:35:45.033665551 +0100 +++ /var/tmp/diff_new_pack.iL16sZ/_new 2026-02-09 15:35:45.037665719 +0100 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/dadav/helm-schema</param> - <param name="changesrevision">7711600f4ada6f2a71ccb81668e2637789315c7b</param></service></servicedata> + <param name="changesrevision">c0ca4c5c600f237539b2a1e5fbfcac7bb963bbbc</param></service></servicedata> (No newline at EOF) ++++++ helm-schema-0.20.2.obscpio -> helm-schema-0.21.1.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/helm-schema-0.20.2/CLAUDE.md new/helm-schema-0.21.1/CLAUDE.md --- old/helm-schema-0.20.2/CLAUDE.md 2026-01-29 21:32:50.000000000 +0100 +++ new/helm-schema-0.21.1/CLAUDE.md 2026-02-09 06:52:57.000000000 +0100 @@ -61,6 +61,8 @@ 6. **Output** (`cmd/helm-schema/main.go`): Writes `values.schema.json` files to each chart directory. +7. **Annotation Mode** (`pkg/schema/annotate.go`): With `--annotate` / `-A` flag, writes inferred `@schema` type annotation blocks into `values.yaml` files for keys that don't already have them. This is a separate execution mode that modifies values files instead of generating JSON schema. Keys that already have `@schema` blocks are skipped. + ### Key Components #### Schema Parsing (`pkg/schema/schema.go`) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/helm-schema-0.20.2/Dockerfile new/helm-schema-0.21.1/Dockerfile --- old/helm-schema-0.20.2/Dockerfile 2026-01-29 21:32:50.000000000 +0100 +++ new/helm-schema-0.21.1/Dockerfile 2026-02-09 06:52:57.000000000 +0100 @@ -1,4 +1,4 @@ -FROM alpine:3.23@sha256:865b95f46d98cf867a156fe4a135ad3fe50d2056aa3f25ed31662dff6da4eb62 +FROM alpine:3.23@sha256:25109184c71bdad752c8312a8623239686a9a2071e8825f20acb8f2198c3f659 ARG TARGETPLATFORM RUN adduser -k /dev/null -u 10001 -D helm-schema \ && chgrp 0 /home/helm-schema \ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/helm-schema-0.20.2/cmd/helm-schema/cli.go new/helm-schema-0.21.1/cmd/helm-schema/cli.go --- old/helm-schema-0.20.2/cmd/helm-schema/cli.go 2026-01-29 21:32:50.000000000 +0100 +++ new/helm-schema-0.21.1/cmd/helm-schema/cli.go 2026-02-09 06:52:57.000000000 +0100 @@ -79,6 +79,8 @@ BoolP("skip-dependencies-schema-validation", "m", false, "skip schema validation for dependencies by setting additionalProperties to true and removing from required") cmd.PersistentFlags(). BoolP("allow-circular-dependencies", "w", false, "allow circular dependencies between charts (will log a warning instead of failing)") + cmd.PersistentFlags(). + BoolP("annotate", "A", false, "write inferred @schema annotations into values.yaml files for unannotated keys") viper.AutomaticEnv() viper.SetEnvPrefix("HELM_SCHEMA") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/helm-schema-0.20.2/cmd/helm-schema/main.go new/helm-schema-0.21.1/cmd/helm-schema/main.go --- old/helm-schema-0.20.2/cmd/helm-schema/main.go 2026-01-29 21:32:50.000000000 +0100 +++ new/helm-schema-0.21.1/cmd/helm-schema/main.go 2026-02-09 06:52:57.000000000 +0100 @@ -55,6 +55,7 @@ dontAddGlobal := viper.GetBool("dont-add-global") skipDepsSchemaValidation := viper.GetBool("skip-dependencies-schema-validation") allowCircularDeps := viper.GetBool("allow-circular-dependencies") + annotate := viper.GetBool("annotate") for _, dep := range dependenciesFilter { dependenciesFilterMap[dep] = true } @@ -99,6 +100,7 @@ helmDocsCompatibilityMode, dontRemoveHelmDocsPrefix, dontAddGlobal, + annotate, valueFileNames, skipConfig, outFile, @@ -145,6 +147,28 @@ } } + // In annotate mode, just report errors and return (no schema generation) + if annotate { + foundErrors := false + for _, result := range results { + if len(result.Errors) > 0 { + foundErrors = true + if result.Chart != nil { + log.Errorf("Found %d errors while annotating chart %s (%s)", len(result.Errors), result.Chart.Name, result.ChartPath) + } else { + log.Errorf("Found %d errors while annotating chart %s", len(result.Errors), result.ChartPath) + } + for _, err := range result.Errors { + log.Error(err) + } + } + } + if foundErrors { + return errors.New("some errors were found") + } + return nil + } + if !noDeps { results, err = schema.TopoSort(results, allowCircularDeps) if err != nil { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/helm-schema-0.20.2/cmd/helm-schema/version.go new/helm-schema-0.21.1/cmd/helm-schema/version.go --- old/helm-schema-0.20.2/cmd/helm-schema/version.go 2026-01-29 21:32:50.000000000 +0100 +++ new/helm-schema-0.21.1/cmd/helm-schema/version.go 2026-02-09 06:52:57.000000000 +0100 @@ -1,3 +1,3 @@ package main -var version string = "0.20.2" +var version string = "0.21.1" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/helm-schema-0.20.2/pkg/schema/annotate.go new/helm-schema-0.21.1/pkg/schema/annotate.go --- old/helm-schema-0.20.2/pkg/schema/annotate.go 1970-01-01 01:00:00.000000000 +0100 +++ new/helm-schema-0.21.1/pkg/schema/annotate.go 2026-02-09 06:52:57.000000000 +0100 @@ -0,0 +1,194 @@ +package schema + +import ( + "fmt" + "os" + "sort" + "strings" + + log "github.com/sirupsen/logrus" + "gopkg.in/yaml.v3" +) + +// HasSchemaAnnotation checks if a HeadComment already contains a # @schema block. +// It matches exact "# @schema" lines but not "# @schema.root" lines. +func HasSchemaAnnotation(comment string) bool { + for _, line := range strings.Split(comment, "\n") { + trimmed := strings.TrimSpace(line) + if trimmed == "# @schema" { + return true + } + } + return false +} + +// typeAnnotationFromTag maps a YAML tag to the annotation type string. +// Uses the same mapping as typeFromTag. +func typeAnnotationFromTag(tag string) string { + switch tag { + case nullTag: + return `"null"` + case boolTag: + return "boolean" + case strTag: + return "string" + case intTag: + return "integer" + case floatTag: + return "number" + case timestampTag: + return "string" + case arrayTag: + return "array" + case mapTag: + return "object" + default: + return "" + } +} + +// InsertionPoint represents where to insert an annotation block in the file. +type InsertionPoint struct { + Line int // 1-based line number of the key node + Indent string // indentation string (spaces) derived from keyNode.Column + TypeStr string // type annotation value +} + +// collectInsertionPoints walks the yaml.Node tree and collects InsertionPoints +// for keys that don't already have @schema annotations. +func collectInsertionPoints(node *yaml.Node) []InsertionPoint { + var points []InsertionPoint + collectInsertionPointsRecursive(node, &points) + return points +} + +func collectInsertionPointsRecursive(node *yaml.Node, points *[]InsertionPoint) { + if node == nil { + return + } + + switch node.Kind { + case yaml.DocumentNode: + for _, child := range node.Content { + collectInsertionPointsRecursive(child, points) + } + case yaml.MappingNode: + for i := 0; i < len(node.Content)-1; i += 2 { + keyNode := node.Content[i] + valueNode := node.Content[i+1] + + if !HasSchemaAnnotation(keyNode.HeadComment) { + typeStr := typeAnnotationFromTag(valueNode.Tag) + if typeStr != "" { + indent := strings.Repeat(" ", keyNode.Column-1) + *points = append(*points, InsertionPoint{ + Line: keyNode.Line, + Indent: indent, + TypeStr: typeStr, + }) + } + } + + // Recurse into mapping values for nested keys + if valueNode.Kind == yaml.MappingNode { + collectInsertionPointsRecursive(valueNode, points) + } + + // Handle alias nodes that point to mappings + if valueNode.Kind == yaml.AliasNode && valueNode.Alias != nil && valueNode.Alias.Kind == yaml.MappingNode { + collectInsertionPointsRecursive(valueNode.Alias, points) + } + } + } +} + +// AnnotateContent parses YAML content, collects insertion points for keys +// that lack @schema annotations, and inserts type annotation blocks. +// Returns the modified content. +func AnnotateContent(content []byte) ([]byte, error) { + var doc yaml.Node + if err := yaml.Unmarshal(content, &doc); err != nil { + return nil, fmt.Errorf("failed to parse YAML: %w", err) + } + + points := collectInsertionPoints(&doc) + if len(points) == 0 { + return content, nil + } + + lines := strings.Split(string(content), "\n") + + // Sort by line number descending so insertions don't shift earlier line numbers + sort.Slice(points, func(i, j int) bool { + return points[i].Line > points[j].Line + }) + + for _, pt := range points { + // pt.Line is 1-based; convert to 0-based index + targetIdx := pt.Line - 1 + if targetIdx < 0 || targetIdx >= len(lines) { + continue + } + + // Walk backwards past any existing HeadComment lines (lines starting with #) + // to insert the annotation above existing comments + insertIdx := targetIdx + for insertIdx > 0 { + candidate := strings.TrimSpace(lines[insertIdx-1]) + if strings.HasPrefix(candidate, "#") { + insertIdx-- + } else { + break + } + } + + // Build the 3 annotation lines + annotationLines := []string{ + pt.Indent + "# @schema", + pt.Indent + "# type: " + pt.TypeStr, + pt.Indent + "# @schema", + } + + // Insert at insertIdx + newLines := make([]string, 0, len(lines)+3) + newLines = append(newLines, lines[:insertIdx]...) + newLines = append(newLines, annotationLines...) + newLines = append(newLines, lines[insertIdx:]...) + lines = newLines + } + + return []byte(strings.Join(lines, "\n")), nil +} + +// AnnotateValuesFile reads a values.yaml file, annotates unannotated keys +// with @schema type blocks, and writes the result back (or prints to stdout if dryRun). +func AnnotateValuesFile(valuesPath string, dryRun bool) error { + fileInfo, err := os.Stat(valuesPath) + if err != nil { + return fmt.Errorf("failed to stat %s: %w", valuesPath, err) + } + perm := fileInfo.Mode().Perm() + + content, err := os.ReadFile(valuesPath) + if err != nil { + return fmt.Errorf("failed to read %s: %w", valuesPath, err) + } + + annotated, err := AnnotateContent(content) + if err != nil { + return fmt.Errorf("failed to annotate %s: %w", valuesPath, err) + } + + if dryRun { + log.Infof("Annotated values for %s", valuesPath) + fmt.Print(string(annotated)) + return nil + } + + if err := os.WriteFile(valuesPath, annotated, perm); err != nil { + return fmt.Errorf("failed to write %s: %w", valuesPath, err) + } + + log.Infof("Annotated %s", valuesPath) + return nil +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/helm-schema-0.20.2/pkg/schema/annotate_test.go new/helm-schema-0.21.1/pkg/schema/annotate_test.go --- old/helm-schema-0.20.2/pkg/schema/annotate_test.go 1970-01-01 01:00:00.000000000 +0100 +++ new/helm-schema-0.21.1/pkg/schema/annotate_test.go 2026-02-09 06:52:57.000000000 +0100 @@ -0,0 +1,248 @@ +package schema + +import ( + "strings" + "testing" + + "gopkg.in/yaml.v3" +) + +func TestHasSchemaAnnotation(t *testing.T) { + tests := []struct { + name string + comment string + want bool + }{ + { + name: "empty comment", + comment: "", + want: false, + }, + { + name: "no schema annotation", + comment: "# This is a normal comment", + want: false, + }, + { + name: "has schema annotation", + comment: "# @schema\n# type: string\n# @schema", + want: true, + }, + { + name: "has schema.root only", + comment: "# @schema.root\n# title: foo\n# @schema.root", + want: false, + }, + { + name: "has both schema and schema.root", + comment: "# @schema.root\n# title: foo\n# @schema.root\n# @schema\n# type: string\n# @schema", + want: true, + }, + { + name: "schema prefix but not exact", + comment: "# @schema.something", + want: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := HasSchemaAnnotation(tt.comment) + if got != tt.want { + t.Errorf("HasSchemaAnnotation(%q) = %v, want %v", tt.comment, got, tt.want) + } + }) + } +} + +func TestTypeAnnotationFromTag(t *testing.T) { + tests := []struct { + tag string + want string + }{ + {"!!null", `"null"`}, + {"!!bool", "boolean"}, + {"!!str", "string"}, + {"!!int", "integer"}, + {"!!float", "number"}, + {"!!timestamp", "string"}, + {"!!seq", "array"}, + {"!!map", "object"}, + {"!!unknown", ""}, + } + + for _, tt := range tests { + t.Run(tt.tag, func(t *testing.T) { + got := typeAnnotationFromTag(tt.tag) + if got != tt.want { + t.Errorf("typeAnnotationFromTag(%q) = %q, want %q", tt.tag, got, tt.want) + } + }) + } +} + +func TestCollectInsertionPoints(t *testing.T) { + tests := []struct { + name string + yaml string + wantCount int + wantTypes []string + }{ + { + name: "simple flat yaml", + yaml: "name: hello\nport: 80\nenabled: true\n", + wantCount: 3, + wantTypes: []string{"string", "integer", "boolean"}, + }, + { + name: "nested objects", + yaml: "service:\n type: ClusterIP\n port: 80\n", + wantCount: 3, + wantTypes: []string{"object", "string", "integer"}, + }, + { + name: "already annotated key", + yaml: "# @schema\n# type: string\n# @schema\nname: hello\nport: 80\n", + wantCount: 1, + wantTypes: []string{"integer"}, + }, + { + name: "null value", + yaml: "key:\n", + wantCount: 1, + wantTypes: []string{`"null"`}, + }, + { + name: "array value", + yaml: "items: []\n", + wantCount: 1, + wantTypes: []string{"array"}, + }, + { + name: "empty map value", + yaml: "config: {}\n", + wantCount: 1, + wantTypes: []string{"object"}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var doc yaml.Node + if err := yaml.Unmarshal([]byte(tt.yaml), &doc); err != nil { + t.Fatalf("failed to parse YAML: %v", err) + } + points := collectInsertionPoints(&doc) + if len(points) != tt.wantCount { + t.Errorf("got %d insertion points, want %d", len(points), tt.wantCount) + for _, p := range points { + t.Logf(" line=%d type=%s", p.Line, p.TypeStr) + } + } + for i, wantType := range tt.wantTypes { + if i >= len(points) { + break + } + if points[i].TypeStr != wantType { + t.Errorf("point[%d].TypeStr = %q, want %q", i, points[i].TypeStr, wantType) + } + } + }) + } +} + +func TestAnnotateContent(t *testing.T) { + tests := []struct { + name string + input string + want string + wantErr bool + }{ + { + name: "simple unannotated file", + input: "port: 80\n", + want: "# @schema\n# type: integer\n# @schema\nport: 80\n", + }, + { + name: "multiple keys", + input: "name: hello\nport: 80\n", + want: "# @schema\n# type: string\n# @schema\nname: hello\n# @schema\n# type: integer\n# @schema\nport: 80\n", + }, + { + name: "already fully annotated", + input: "# @schema\n# type: integer\n# @schema\nport: 80\n", + want: "# @schema\n# type: integer\n# @schema\nport: 80\n", + }, + { + name: "partially annotated", + input: "# @schema\n# type: string\n# @schema\nname: hello\nport: 80\n", + want: "# @schema\n# type: string\n# @schema\nname: hello\n# @schema\n# type: integer\n# @schema\nport: 80\n", + }, + { + name: "nested objects with indentation", + input: "service:\n type: ClusterIP\n port: 80\n", + want: "# @schema\n# type: object\n# @schema\nservice:\n # @schema\n # type: string\n # @schema\n type: ClusterIP\n # @schema\n # type: integer\n # @schema\n port: 80\n", + }, + { + name: "key with existing comment - annotation goes above comment", + input: "# This is the port\nport: 80\n", + want: "# @schema\n# type: integer\n# @schema\n# This is the port\nport: 80\n", + }, + { + name: "empty file", + input: "", + want: "", + }, + { + name: "document separator preserved", + input: "---\nport: 80\n", + want: "---\n# @schema\n# type: integer\n# @schema\nport: 80\n", + }, + { + name: "boolean value", + input: "enabled: true\n", + want: "# @schema\n# type: boolean\n# @schema\nenabled: true\n", + }, + { + name: "null value", + input: "key:\n", + want: "# @schema\n# type: \"null\"\n# @schema\nkey:\n", + }, + { + name: "array value", + input: "items: []\n", + want: "# @schema\n# type: array\n# @schema\nitems: []\n", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := AnnotateContent([]byte(tt.input)) + if (err != nil) != tt.wantErr { + t.Fatalf("AnnotateContent() error = %v, wantErr %v", err, tt.wantErr) + } + if string(got) != tt.want { + t.Errorf("AnnotateContent() mismatch\ngot:\n%s\nwant:\n%s", string(got), tt.want) + // Show diff line by line + gotLines := strings.Split(string(got), "\n") + wantLines := strings.Split(tt.want, "\n") + maxLen := len(gotLines) + if len(wantLines) > maxLen { + maxLen = len(wantLines) + } + for i := 0; i < maxLen; i++ { + var g, w string + if i < len(gotLines) { + g = gotLines[i] + } + if i < len(wantLines) { + w = wantLines[i] + } + if g != w { + t.Errorf(" line %d: got=%q want=%q", i, g, w) + } + } + } + }) + } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/helm-schema-0.20.2/pkg/schema/worker.go new/helm-schema-0.21.1/pkg/schema/worker.go --- old/helm-schema-0.20.2/pkg/schema/worker.go 2026-01-29 21:32:50.000000000 +0100 +++ new/helm-schema-0.21.1/pkg/schema/worker.go 2026-02-09 06:52:57.000000000 +0100 @@ -21,7 +21,7 @@ } func Worker( - dryRun, uncomment, addSchemaReference, keepFullComment, helmDocsCompatibilityMode, dontRemoveHelmDocsPrefix, dontAddGlobal bool, + dryRun, uncomment, addSchemaReference, keepFullComment, helmDocsCompatibilityMode, dontRemoveHelmDocsPrefix, dontAddGlobal, annotate bool, valueFileNames []string, skipAutoGenerationConfig *SkipAutoGenerationConfig, outFile string, @@ -86,6 +86,15 @@ results <- result continue } + + // Annotate mode: write @schema annotations into values.yaml and skip schema generation + if annotate { + if err := AnnotateValuesFile(valuesPath, dryRun); err != nil { + result.Errors = append(result.Errors, err) + } + results <- result + continue + } // Check if we need to add a schema reference if addSchemaReference { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/helm-schema-0.20.2/pkg/schema/worker_test.go new/helm-schema-0.21.1/pkg/schema/worker_test.go --- old/helm-schema-0.20.2/pkg/schema/worker_test.go 2026-01-29 21:32:50.000000000 +0100 +++ new/helm-schema-0.21.1/pkg/schema/worker_test.go 2026-02-09 06:52:57.000000000 +0100 @@ -130,6 +130,7 @@ tt.helmDocsCompatibilityMode, tt.dontRemoveHelmDocsPrefix, tt.dontAddGlobal, + false, // annotate tt.valueFileNames, tt.skipAutoGenerationConfig, tt.outFile, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/helm-schema-0.20.2/pkg/util/file.go new/helm-schema-0.21.1/pkg/util/file.go --- old/helm-schema-0.20.2/pkg/util/file.go 2026-01-29 21:32:50.000000000 +0100 +++ new/helm-schema-0.21.1/pkg/util/file.go 2026-02-09 06:52:57.000000000 +0100 @@ -68,12 +68,14 @@ scanner := bufio.NewScanner(reader) commentMatcher := regexp.MustCompile(`^\s*#\s*`) - commentYamlMapMatcher := regexp.MustCompile(`^(\s*#\s*)[^:]+:.*$`) + // Capture indentation and comment marker separately + // Group 1: indentation (spaces/tabs before #) + // Group 2: comment marker (# and following space) + commentYamlMapMatcher := regexp.MustCompile(`^(\s*)(#\s*)([^:]+:.*)$`) schemaMatcher := regexp.MustCompile(`^\s*#\s@schema\s*`) var line string var inCode, inSchema bool - var codeIndention int var unknownYaml interface{} for scanner.Scan() { @@ -105,10 +107,14 @@ continue } + var indentation string + var commentMarkerLen int + // Havent found a potential yaml block yet if !inCode { if matches := commentYamlMapMatcher.FindStringSubmatch(line); matches != nil { - codeIndention = len(matches[1]) + indentation = matches[1] // Just the leading whitespace + commentMarkerLen = len(matches[2]) // Just "# " (typically 2 chars) inCode = true } } @@ -117,7 +123,7 @@ if inCode { if commentMatcher.Match([]byte(line)) { // Strip the commet away - strippedLine := line[codeIndention:] + strippedLine := indentation + line[len(indentation)+commentMarkerLen:] // add it to the already parsed valid yaml appendAndNLStr(&buff, strippedLine) // check if the new block is still valid yaml @@ -133,6 +139,14 @@ continue } + // FIX: Line is NOT a comment - we've exited the commented block + // Flush the buffer to result and reset state + if len(buff) > 0 { + appendAndNL(&result, &buff) + buff = make([]byte, 0) + } + inCode = false + // If the line is not a comment it must be yaml appendAndNLStr(&buff, line) continue diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/helm-schema-0.20.2/plugin.yaml new/helm-schema-0.21.1/plugin.yaml --- old/helm-schema-0.20.2/plugin.yaml 2026-01-29 21:32:50.000000000 +0100 +++ new/helm-schema-0.21.1/plugin.yaml 2026-02-09 06:52:57.000000000 +0100 @@ -1,6 +1,6 @@ --- name: "schema" -version: "0.20.2" +version: "0.21.1" usage: "generate jsonschemas for your helm charts" description: "generate jsonschemas for your helm charts" command: "$HELM_PLUGIN_DIR/bin/helm-schema" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/helm-schema-0.20.2/tests/run.sh new/helm-schema-0.21.1/tests/run.sh --- old/helm-schema-0.20.2/tests/run.sh 2026-01-29 21:32:50.000000000 +0100 +++ new/helm-schema-0.21.1/tests/run.sh 2026-02-09 06:52:57.000000000 +0100 @@ -6,6 +6,11 @@ cp ../examples/values.schema.json test_repo_example_expected.schema.json for test_file in test_*.yaml; do + # Skip annotate test files from normal schema generation tests + case "$test_file" in + test_annotate_*) continue ;; + esac + expected_file="${test_file%.yaml}_expected.schema.json" generated_file="${test_file%.yaml}_generated.schema.json" if ! ./helm-schema -f "$test_file" -o "$generated_file"; then @@ -22,4 +27,14 @@ fi done +# Annotate test +echo "Testing annotate mode" +annotate_output=$(./helm-schema --annotate -d -f test_annotate_input.yaml 2>/dev/null) +if diff -y --suppress-common-lines <(echo "$annotate_output") test_annotate_expected.yaml; then + echo "✅: annotate mode" +else + echo "❌: annotate mode" + rc=1 +fi + exit "$rc" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/helm-schema-0.20.2/tests/test_annotate_expected.yaml new/helm-schema-0.21.1/tests/test_annotate_expected.yaml --- old/helm-schema-0.20.2/tests/test_annotate_expected.yaml 1970-01-01 01:00:00.000000000 +0100 +++ new/helm-schema-0.21.1/tests/test_annotate_expected.yaml 2026-02-09 06:52:57.000000000 +0100 @@ -0,0 +1,64 @@ +# @schema +# type: integer +# @schema +replicaCount: 1 + +# @schema +# type: object +# @schema +image: + # @schema + # type: string + # @schema + repository: nginx + # @schema + # type: string + # @schema + pullPolicy: IfNotPresent + # @schema + # type: string + # @schema + # Overrides the image tag whose default is the chart appVersion. + tag: "" + +# @schema +# type: array +# @schema +imagePullSecrets: [] +# @schema +# type: string +# @schema +nameOverride: "" + +# @schema +# type: boolean +# @schema +alreadyAnnotated: true + +# @schema +# type: object +# @schema +service: + # @schema + # type: string + # @schema + type: ClusterIP + # @schema + # type: integer + # @schema + port: 80 + +# @schema +# type: boolean +# @schema +enabled: false + +# @schema +# type: object +# @schema +config: {} + +# @schema +# type: "null" +# @schema +key: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/helm-schema-0.20.2/tests/test_annotate_input.yaml new/helm-schema-0.21.1/tests/test_annotate_input.yaml --- old/helm-schema-0.20.2/tests/test_annotate_input.yaml 1970-01-01 01:00:00.000000000 +0100 +++ new/helm-schema-0.21.1/tests/test_annotate_input.yaml 2026-02-09 06:52:57.000000000 +0100 @@ -0,0 +1,25 @@ +replicaCount: 1 + +image: + repository: nginx + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the chart appVersion. + tag: "" + +imagePullSecrets: [] +nameOverride: "" + +# @schema +# type: boolean +# @schema +alreadyAnnotated: true + +service: + type: ClusterIP + port: 80 + +enabled: false + +config: {} + +key: ++++++ helm-schema.obsinfo ++++++ --- /var/tmp/diff_new_pack.iL16sZ/_old 2026-02-09 15:35:45.209672958 +0100 +++ /var/tmp/diff_new_pack.iL16sZ/_new 2026-02-09 15:35:45.217673294 +0100 @@ -1,5 +1,5 @@ name: helm-schema -version: 0.20.2 -mtime: 1769718770 -commit: 7711600f4ada6f2a71ccb81668e2637789315c7b +version: 0.21.1 +mtime: 1770616377 +commit: c0ca4c5c600f237539b2a1e5fbfcac7bb963bbbc ++++++ vendor.tar.gz ++++++
