From e8d8562b9eebd12d0129163d73460e0cf3af2905 Mon Sep 17 00:00:00 2001 From: SAY-5 Date: Tue, 21 Apr 2026 17:06:51 -0700 Subject: [PATCH] cmd/flux: search for kind within the YAML document instead of line+1 detectFileUpgrades hard-coded the kind: lookup at apiVersion line+1, so manifests with any other field (metadata:, comments, annotations) or reversed field order silently returned "no migration needed" even when apiVersion was deprecated (#5839). Search within the current YAML document boundaries: scan backwards to the previous '---' separator or start-of-file, then forwards to the next '---' separator. First kind: line wins. The order is backwards-then-forwards so that for a conventional apiVersion/kind ordering we only scan the single line + the document boundary; the forward fallback covers the reversed-order case. Adds a regression fixture with three documents covering: - apiVersion first, kind after metadata: - kind first, apiVersion after metadata: - kind first, apiVersion last Fixes #5839 Signed-off-by: SAY-5 --- cmd/flux/migrate.go | 35 ++++++++++++++----- cmd/flux/migrate_test.go | 11 ++++++ .../file-system/non-adjacent-kind.yaml | 14 ++++++++ .../file-system/non-adjacent-kind.yaml.golden | 14 ++++++++ .../non-adjacent-kind.yaml.output.golden | 6 ++++ 5 files changed, 71 insertions(+), 9 deletions(-) create mode 100644 cmd/flux/testdata/migrate/file-system/non-adjacent-kind.yaml create mode 100644 cmd/flux/testdata/migrate/file-system/non-adjacent-kind.yaml.golden create mode 100644 cmd/flux/testdata/migrate/file-system/non-adjacent-kind.yaml.output.golden diff --git a/cmd/flux/migrate.go b/cmd/flux/migrate.go index 01449f14..11c6c3e1 100644 --- a/cmd/flux/migrate.go +++ b/cmd/flux/migrate.go @@ -624,18 +624,35 @@ func (f *FileSystemMigrator) detectFileUpgrades(file string) ([]APIUpgrade, erro continue } - // Parse kind. - if line+1 >= len(lines) { - continue - } - kindLine := lines[line+1] + // Parse kind. YAML allows fields to be ordered arbitrarily, so the + // kind: line may appear before or after apiVersion: within the same + // document. Search within the current document boundaries (delimited + // by "---" separators) rather than hard-coding line+1. const kindPrefix = "kind: " - idx = strings.Index(kindLine, kindPrefix) - if idx == -1 { + kind := "" + for j := line - 1; j >= 0; j-- { + if strings.HasPrefix(strings.TrimSpace(lines[j]), "---") { + break + } + if k := strings.Index(lines[j], kindPrefix); k != -1 { + kind = strings.Split(strings.TrimSpace(lines[j][k+len(kindPrefix):]), " ")[0] + break + } + } + if kind == "" { + for j := line + 1; j < len(lines); j++ { + if strings.HasPrefix(strings.TrimSpace(lines[j]), "---") { + break + } + if k := strings.Index(lines[j], kindPrefix); k != -1 { + kind = strings.Split(strings.TrimSpace(lines[j][k+len(kindPrefix):]), " ")[0] + break + } + } + } + if kind == "" { continue } - kindValuePrefix := strings.TrimSpace(kindLine[idx+len(kindPrefix):]) - kind := strings.Split(kindValuePrefix, " ")[0] // Build GroupKind. gk := schema.GroupKind{ diff --git a/cmd/flux/migrate_test.go b/cmd/flux/migrate_test.go index 0820fb82..bd16649e 100644 --- a/cmd/flux/migrate_test.go +++ b/cmd/flux/migrate_test.go @@ -71,6 +71,17 @@ func TestFileSystemMigrator(t *testing.T) { }, }, }, + { + name: "migrate single file with non-adjacent apiVersion and kind", + path: "testdata/migrate/file-system/non-adjacent-kind.yaml", + outputGolden: "testdata/migrate/file-system/non-adjacent-kind.yaml.output.golden", + writtenFiles: []writtenFile{ + { + file: "testdata/migrate/file-system/non-adjacent-kind.yaml", + goldenFile: "testdata/migrate/file-system/non-adjacent-kind.yaml.golden", + }, + }, + }, { name: "migrate files in directory", path: "testdata/migrate/file-system/dir", diff --git a/cmd/flux/testdata/migrate/file-system/non-adjacent-kind.yaml b/cmd/flux/testdata/migrate/file-system/non-adjacent-kind.yaml new file mode 100644 index 00000000..79aef13a --- /dev/null +++ b/cmd/flux/testdata/migrate/file-system/non-adjacent-kind.yaml @@ -0,0 +1,14 @@ +apiVersion: image.toolkit.fluxcd.io/v1beta1 +metadata: + name: podinfo +kind: ImageRepository +--- +metadata: + name: alpine +kind: ImagePolicy +apiVersion: image.toolkit.fluxcd.io/v1beta2 +--- +kind: ImageUpdateAutomation +metadata: + name: flux-system +apiVersion: image.toolkit.fluxcd.io/v1beta1 diff --git a/cmd/flux/testdata/migrate/file-system/non-adjacent-kind.yaml.golden b/cmd/flux/testdata/migrate/file-system/non-adjacent-kind.yaml.golden new file mode 100644 index 00000000..9e4ea650 --- /dev/null +++ b/cmd/flux/testdata/migrate/file-system/non-adjacent-kind.yaml.golden @@ -0,0 +1,14 @@ +apiVersion: image.toolkit.fluxcd.io/v1 +metadata: + name: podinfo +kind: ImageRepository +--- +metadata: + name: alpine +kind: ImagePolicy +apiVersion: image.toolkit.fluxcd.io/v1 +--- +kind: ImageUpdateAutomation +metadata: + name: flux-system +apiVersion: image.toolkit.fluxcd.io/v1 diff --git a/cmd/flux/testdata/migrate/file-system/non-adjacent-kind.yaml.output.golden b/cmd/flux/testdata/migrate/file-system/non-adjacent-kind.yaml.output.golden new file mode 100644 index 00000000..da1f34f2 --- /dev/null +++ b/cmd/flux/testdata/migrate/file-system/non-adjacent-kind.yaml.output.golden @@ -0,0 +1,6 @@ +► starting migration of custom resources +✚ testdata/migrate/file-system/non-adjacent-kind.yaml:1: ImageRepository v1beta1 -> v1 +✚ testdata/migrate/file-system/non-adjacent-kind.yaml:9: ImagePolicy v1beta2 -> v1 +✚ testdata/migrate/file-system/non-adjacent-kind.yaml:14: ImageUpdateAutomation v1beta1 -> v1 +✔ file testdata/migrate/file-system/non-adjacent-kind.yaml migrated successfully +✔ custom resources migrated successfully