Skip to content

Commit 023d862

Browse files
authored
update patternizer to use variant structure (#43)
* update clusterGroupName to variant in values-global.yaml * add support for variants folder structure * add singleargocd deprecation warning
1 parent 1743afd commit 023d862

10 files changed

Lines changed: 645 additions & 48 deletions

File tree

‎README.md‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Patternizer
22

3-
![Version: 2.2.0](https://img.shields.io/badge/Version-2.2.0-informational?style=flat-square)
3+
![Version: 2.3.0](https://img.shields.io/badge/Version-2.3.0-informational?style=flat-square)
44
[![Quay Repository](https://img.shields.io/badge/Quay.io-patternizer-blue?logo=quay)](https://quay.io/repository/validatedpatterns/patternizer)
55
[![CI Pipeline](https://github.com/validatedpatterns/patternizer/actions/workflows/build-push.yaml/badge.svg?branch=main)](https://github.com/validatedpatterns/patternizer/actions/workflows/build-push.yaml)
66

@@ -132,6 +132,11 @@ What upgrade does:
132132
- If no `Makefile` exists: copies the default `Makefile`
133133
- If a `Makefile` exists and already contains `include Makefile-common` anywhere: leaves it unchanged
134134
- Otherwise: prepends `include Makefile-common` to the first line so your existing targets are preserved
135+
- Prints a deprecation warning if `values-global.yaml` still uses `main.clusterGroupName`, which the Validated Patterns operator deprecated in favor of `main.variant` in version 0.0.78 (`upgrade` does not modify the file; run `patternizer init` to migrate automatically)
136+
- Prints a deprecation warning if the pattern does not use the [variants folder structure](https://validatedpatterns.io/blog/2026-08-04-variants-folder-structure/) (introduced in operator version 0.0.78) — that is, if `variants/<variant>/values-<variant>.yaml` is missing for the configured variant (`upgrade` does not move any files; run `patternizer init` to migrate automatically)
137+
- Prints a warning if `global.singleArgoCD` is not set in `values-global.yaml`, recommending you set `global.singleArgoCD: true` if possible (see the [single ArgoCD instance](https://validatedpatterns.io/blog/2026-06-04-single-argocd-option/) blog post)
138+
139+
These warnings are written to stderr, grouped after the success message, so they stand out as a call to action.
135140
136141
### Understanding Secrets Management
137142
@@ -148,7 +153,7 @@ For more details on how secrets work in the framework, see the [Secrets Manageme
148153
Running `patternizer init` creates the following:
149154
150155
- `values-global.yaml`: Global pattern configuration.
151-
- `values-<cluster_group>.yaml`: Cluster group-specific values.
156+
- `variants/<variant>/values-<variant>.yaml`: Variant-specific (cluster group) values, using the [variants folder structure](https://validatedpatterns.io/blog/2026-08-04-variants-folder-structure/). A legacy root-level `values-<variant>.yaml` is migrated into this folder automatically.
152157
- `pattern.sh`: A utility script for common pattern operations (`install`, `upgrade`, etc.).
153158
- `Makefile`: A simple Makefile that includes `Makefile-common`.
154159
- `Makefile-common`: The core Makefile with all pattern-related targets.

‎src/cmd/init_test.go‎

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ var _ = Describe("patternizer init", func() {
8080
},
8181
},
8282
Main: types.Main{
83-
ClusterGroupName: "prod",
83+
Variant: "prod",
8484
MultiSourceConfig: types.MultiSourceConfig{
8585
Enabled: true,
8686
ClusterGroupChartVersion: "0.9.*",
@@ -91,7 +91,7 @@ var _ = Describe("patternizer init", func() {
9191
})
9292

9393
It("should create an appropriate clustergroup values file", func() {
94-
clusterGroupValuesFile := filepath.Join(tempDir, "values-prod.yaml")
94+
clusterGroupValuesFile := filepath.Join(tempDir, "variants", "prod", "values-prod.yaml")
9595
expectedClusterGroupValues := types.ValuesClusterGroup{
9696
ClusterGroup: types.ClusterGroup{
9797
Name: "prod",
@@ -129,7 +129,7 @@ var _ = Describe("patternizer init", func() {
129129
},
130130
},
131131
Main: types.Main{
132-
ClusterGroupName: "prod",
132+
Variant: "prod",
133133
MultiSourceConfig: types.MultiSourceConfig{
134134
Enabled: true,
135135
ClusterGroupChartVersion: "0.9.*",
@@ -140,7 +140,7 @@ var _ = Describe("patternizer init", func() {
140140
})
141141

142142
It("should create an appropriate clustergroup values file", func() {
143-
clusterGroupValuesFile := filepath.Join(tempDir, "values-prod.yaml")
143+
clusterGroupValuesFile := filepath.Join(tempDir, "variants", "prod", "values-prod.yaml")
144144
expectedNamespace := filepath.Base(tempDir)
145145
expectedClusterGroupValues := types.ValuesClusterGroup{
146146
ClusterGroup: types.ClusterGroup{
@@ -189,7 +189,7 @@ var _ = Describe("patternizer init", func() {
189189
},
190190
},
191191
Main: types.Main{
192-
ClusterGroupName: "test",
192+
Variant: "test",
193193
MultiSourceConfig: types.MultiSourceConfig{
194194
Enabled: true,
195195
ClusterGroupChartVersion: "0.9.*",
@@ -200,7 +200,7 @@ var _ = Describe("patternizer init", func() {
200200
})
201201

202202
It("should create an appropriate clustergroup values file", func() {
203-
clusterGroupValuesFile := filepath.Join(tempDir, "values-test.yaml")
203+
clusterGroupValuesFile := filepath.Join(tempDir, "variants", "test", "values-test.yaml")
204204
expectedClusterGroupValues := types.ValuesClusterGroup{
205205
ClusterGroup: types.ClusterGroup{
206206
Name: "test",
@@ -238,7 +238,7 @@ var _ = Describe("patternizer init", func() {
238238
},
239239
},
240240
Main: types.Main{
241-
ClusterGroupName: "test",
241+
Variant: "test",
242242
MultiSourceConfig: types.MultiSourceConfig{
243243
Enabled: true,
244244
ClusterGroupChartVersion: "0.9.*",
@@ -249,7 +249,7 @@ var _ = Describe("patternizer init", func() {
249249
})
250250

251251
It("should create an appropriate clustergroup values file", func() {
252-
clusterGroupValuesFile := filepath.Join(tempDir, "values-test.yaml")
252+
clusterGroupValuesFile := filepath.Join(tempDir, "variants", "test", "values-test.yaml")
253253
expectedClusterGroupValues := types.ValuesClusterGroup{
254254
ClusterGroup: types.ClusterGroup{
255255
Name: "test",
@@ -270,6 +270,10 @@ var _ = Describe("patternizer init", func() {
270270
}
271271
verifyClusterGroupValues(clusterGroupValuesFile, &expectedClusterGroupValues)
272272
})
273+
274+
It("should remove the legacy root-level values file after migration", func() {
275+
Expect(filepath.Join(tempDir, "values-test.yaml")).NotTo(BeAnExistingFile())
276+
})
273277
})
274278

275279
for _, alias := range []string{"create", "bootstrap"} {
@@ -308,7 +312,7 @@ var _ = Describe("patternizer init", func() {
308312
},
309313
},
310314
Main: types.Main{
311-
ClusterGroupName: "test",
315+
Variant: "test",
312316
MultiSourceConfig: types.MultiSourceConfig{
313317
Enabled: true,
314318
ClusterGroupChartVersion: "0.9.*",
@@ -348,7 +352,7 @@ var _ = Describe("patternizer init --with-secrets", func() {
348352
},
349353
},
350354
Main: types.Main{
351-
ClusterGroupName: "prod",
355+
Variant: "prod",
352356
MultiSourceConfig: types.MultiSourceConfig{
353357
Enabled: true,
354358
ClusterGroupChartVersion: "0.9.*",
@@ -359,7 +363,7 @@ var _ = Describe("patternizer init --with-secrets", func() {
359363
})
360364

361365
It("should create an appropriate clustergroup values file", func() {
362-
clusterGroupValuesFile := filepath.Join(tempDir, "values-prod.yaml")
366+
clusterGroupValuesFile := filepath.Join(tempDir, "variants", "prod", "values-prod.yaml")
363367
expectedClusterGroupValues := types.ValuesClusterGroup{
364368
ClusterGroup: types.ClusterGroup{
365369
Name: "prod",
@@ -428,7 +432,7 @@ var _ = Describe("patternizer init --with-secrets", func() {
428432
},
429433
},
430434
Main: types.Main{
431-
ClusterGroupName: "prod",
435+
Variant: "prod",
432436
MultiSourceConfig: types.MultiSourceConfig{
433437
Enabled: true,
434438
ClusterGroupChartVersion: "0.9.*",
@@ -439,7 +443,7 @@ var _ = Describe("patternizer init --with-secrets", func() {
439443
})
440444

441445
It("should create an appropriate clustergroup values file", func() {
442-
clusterGroupValuesFile := filepath.Join(tempDir, "values-prod.yaml")
446+
clusterGroupValuesFile := filepath.Join(tempDir, "variants", "prod", "values-prod.yaml")
443447
expectedNamespace := filepath.Base(tempDir)
444448
expectedClusterGroupValues := types.ValuesClusterGroup{
445449
ClusterGroup: types.ClusterGroup{
@@ -518,7 +522,7 @@ var _ = Describe("patternizer init --with-secrets", func() {
518522
},
519523
},
520524
Main: types.Main{
521-
ClusterGroupName: "test",
525+
Variant: "test",
522526
MultiSourceConfig: types.MultiSourceConfig{
523527
Enabled: true,
524528
ClusterGroupChartVersion: "0.9.*",
@@ -529,7 +533,7 @@ var _ = Describe("patternizer init --with-secrets", func() {
529533
})
530534

531535
It("should create an appropriate clustergroup values file", func() {
532-
clusterGroupValuesFile := filepath.Join(tempDir, "values-test.yaml")
536+
clusterGroupValuesFile := filepath.Join(tempDir, "variants", "test", "values-test.yaml")
533537
expectedClusterGroupValues := types.ValuesClusterGroup{
534538
ClusterGroup: types.ClusterGroup{
535539
Name: "test",
@@ -595,7 +599,7 @@ var _ = Describe("patternizer init --with-secrets", func() {
595599
},
596600
},
597601
Main: types.Main{
598-
ClusterGroupName: "prod",
602+
Variant: "prod",
599603
MultiSourceConfig: types.MultiSourceConfig{
600604
Enabled: true,
601605
ClusterGroupChartVersion: "0.9.*",
@@ -606,7 +610,7 @@ var _ = Describe("patternizer init --with-secrets", func() {
606610
})
607611

608612
It("should update the clustergroup values file to include secrets", func() {
609-
clusterGroupValuesFile := filepath.Join(tempDir, "values-prod.yaml")
613+
clusterGroupValuesFile := filepath.Join(tempDir, "variants", "prod", "values-prod.yaml")
610614
expectedNamespace := filepath.Base(tempDir)
611615
expectedClusterGroupValues := types.ValuesClusterGroup{
612616
ClusterGroup: types.ClusterGroup{
@@ -686,7 +690,7 @@ var _ = Describe("patternizer init --with-secrets", func() {
686690
},
687691
},
688692
Main: types.Main{
689-
ClusterGroupName: "test",
693+
Variant: "test",
690694
MultiSourceConfig: types.MultiSourceConfig{
691695
Enabled: true,
692696
ClusterGroupChartVersion: "0.9.*",
@@ -697,7 +701,7 @@ var _ = Describe("patternizer init --with-secrets", func() {
697701
})
698702

699703
It("should create an appropriate clustergroup values file", func() {
700-
clusterGroupValuesFile := filepath.Join(tempDir, "values-test.yaml")
704+
clusterGroupValuesFile := filepath.Join(tempDir, "variants", "test", "values-test.yaml")
701705
expectedClusterGroupValues := types.ValuesClusterGroup{
702706
ClusterGroup: types.ClusterGroup{
703707
Name: "test",
@@ -788,7 +792,7 @@ clusterGroup:
788792
})
789793

790794
It("should migrate list-style namespaces to map-style", func() {
791-
clusterGroupValuesFile := filepath.Join(tempDir, "values-prod.yaml")
795+
clusterGroupValuesFile := filepath.Join(tempDir, "variants", "prod", "values-prod.yaml")
792796
expectedClusterGroupValues := types.ValuesClusterGroup{
793797
ClusterGroup: types.ClusterGroup{
794798
Name: "prod",
@@ -833,7 +837,7 @@ clusterGroup:
833837
})
834838

835839
It("should preserve map-style namespaces", func() {
836-
clusterGroupValuesFile := filepath.Join(tempDir, "values-prod.yaml")
840+
clusterGroupValuesFile := filepath.Join(tempDir, "variants", "prod", "values-prod.yaml")
837841
expectedClusterGroupValues := types.ValuesClusterGroup{
838842
ClusterGroup: types.ClusterGroup{
839843
Name: "prod",

‎src/cmd/upgrade.go‎

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,58 @@ func runUpgrade(replaceMakefile bool) error {
7070
return fmt.Errorf("error installing skills: %w", err)
7171
}
7272

73+
warnings, err := collectUpgradeWarnings(repoRoot)
74+
if err != nil {
75+
return err
76+
}
77+
7378
fmt.Printf("Successfully upgraded pattern repository in %s\n", repoRoot)
79+
80+
emitUpgradeWarnings(warnings)
7481
return nil
7582
}
83+
84+
// collectUpgradeWarnings inspects the pattern's values-global.yaml and returns a list of
85+
// compact deprecation warnings that should be surfaced to the user as a call to action.
86+
func collectUpgradeWarnings(repoRoot string) ([]string, error) {
87+
var warnings []string
88+
89+
deprecated, err := pattern.UsesDeprecatedClusterGroupName(repoRoot)
90+
if err != nil {
91+
return nil, fmt.Errorf("error checking for deprecated fields: %w", err)
92+
}
93+
if deprecated {
94+
warnings = append(warnings, "WARNING: values-global.yaml uses deprecated 'main.clusterGroupName' (operator 0.0.78). Set 'main.variant' instead.")
95+
}
96+
97+
variant, folderMissing, err := pattern.VariantFolderFileMissing(repoRoot)
98+
if err != nil {
99+
return nil, fmt.Errorf("error checking for variants folder structure: %w", err)
100+
}
101+
if folderMissing {
102+
warnings = append(warnings, fmt.Sprintf("WARNING: not using the variants folder structure (variants/%s/values-%s.yaml not found; operator 0.0.78). See https://validatedpatterns.io/blog/2026-08-04-variants-folder-structure/", variant, variant))
103+
}
104+
105+
missingSingleArgoCD, err := pattern.MissingSingleArgoCD(repoRoot)
106+
if err != nil {
107+
return nil, fmt.Errorf("error checking for singleArgoCD: %w", err)
108+
}
109+
if missingSingleArgoCD {
110+
warnings = append(warnings, "WARNING: 'global.singleArgoCD' is not set. Set 'global.singleArgoCD: true' if possible. See https://validatedpatterns.io/blog/2026-06-04-single-argocd-option/")
111+
}
112+
113+
return warnings, nil
114+
}
115+
116+
// emitUpgradeWarnings prints deprecation warnings to stderr as a grouped block, separated
117+
// from the normal stdout logs so they stand out as a call to action.
118+
func emitUpgradeWarnings(warnings []string) {
119+
if len(warnings) == 0 {
120+
return
121+
}
122+
123+
fmt.Fprintln(os.Stderr)
124+
for _, warning := range warnings {
125+
fmt.Fprintln(os.Stderr, warning)
126+
}
127+
}

0 commit comments

Comments
 (0)