helm-env-delta 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +1128 -0
  3. package/bin/index.js +2 -0
  4. package/dist/ZodError.d.ts +8 -0
  5. package/dist/ZodError.js +33 -0
  6. package/dist/arrayDiffer.d.ts +8 -0
  7. package/dist/arrayDiffer.js +47 -0
  8. package/dist/commandLine.d.ts +9 -0
  9. package/dist/commandLine.js +32 -0
  10. package/dist/configFile.d.ts +148 -0
  11. package/dist/configFile.js +135 -0
  12. package/dist/configLoader.d.ts +3 -0
  13. package/dist/configLoader.js +12 -0
  14. package/dist/configMerger.d.ts +21 -0
  15. package/dist/configMerger.js +190 -0
  16. package/dist/consoleDiffReporter.d.ts +3 -0
  17. package/dist/consoleDiffReporter.js +172 -0
  18. package/dist/consoleFormatter.d.ts +10 -0
  19. package/dist/consoleFormatter.js +103 -0
  20. package/dist/fileDiff.d.ts +41 -0
  21. package/dist/fileDiff.js +163 -0
  22. package/dist/fileLoader.d.ts +25 -0
  23. package/dist/fileLoader.js +105 -0
  24. package/dist/fileUpdater.d.ts +27 -0
  25. package/dist/fileUpdater.js +264 -0
  26. package/dist/htmlReporter.d.ts +27 -0
  27. package/dist/htmlReporter.js +600 -0
  28. package/dist/index.d.ts +1 -0
  29. package/dist/index.js +91 -0
  30. package/dist/jsonReporter.d.ts +70 -0
  31. package/dist/jsonReporter.js +122 -0
  32. package/dist/stopRulesValidator.d.ts +33 -0
  33. package/dist/stopRulesValidator.js +168 -0
  34. package/dist/utils/deepEqual.d.ts +1 -0
  35. package/dist/utils/deepEqual.js +48 -0
  36. package/dist/utils/diffGenerator.d.ts +1 -0
  37. package/dist/utils/diffGenerator.js +8 -0
  38. package/dist/utils/errors.d.ts +23 -0
  39. package/dist/utils/errors.js +39 -0
  40. package/dist/utils/fileType.d.ts +1 -0
  41. package/dist/utils/fileType.js +8 -0
  42. package/dist/utils/index.d.ts +7 -0
  43. package/dist/utils/index.js +18 -0
  44. package/dist/utils/jsonPath.d.ts +2 -0
  45. package/dist/utils/jsonPath.js +29 -0
  46. package/dist/utils/serialization.d.ts +2 -0
  47. package/dist/utils/serialization.js +40 -0
  48. package/dist/utils/transformer.d.ts +21 -0
  49. package/dist/utils/transformer.js +60 -0
  50. package/dist/yamlFormatter.d.ts +20 -0
  51. package/dist/yamlFormatter.js +315 -0
  52. package/package.json +89 -0
package/README.md ADDED
@@ -0,0 +1,1128 @@
1
+ # HelmEnvDelta
2
+
3
+ [![npm version](https://img.shields.io/npm/v/helm-env-delta.svg)](https://www.npmjs.com/package/helm-env-delta)
4
+ [![License: ISC](https://img.shields.io/badge/License-ISC-blue.svg)](https://opensource.org/licenses/ISC)
5
+ [![Node.js Version](https://img.shields.io/badge/node-%3E%3D22-brightgreen.svg)](https://nodejs.org/)
6
+
7
+ **Environment-aware YAML delta and sync for GitOps workflows**
8
+
9
+ HelmEnvDelta (`helm-env-delta` or `hed`) is a CLI tool that safely synchronizes YAML configuration files across different environments (UAT → Production, Dev → Staging, etc.) while respecting environment-specific differences and enforcing validation rules.
10
+
11
+ ---
12
+
13
+ ## Table of Contents
14
+
15
+ - [Why HelmEnvDelta?](#why-helmenvdelta)
16
+ - [Key Features](#key-features)
17
+ - [Installation](#installation)
18
+ - [Quick Start](#quick-start)
19
+ - [Use Cases](#use-cases)
20
+ - [Configuration Guide](#configuration-guide)
21
+ - [Core Settings](#core-settings)
22
+ - [Path Filtering (skipPath)](#path-filtering-skippath)
23
+ - [Transformations (transforms)](#transformations-transforms)
24
+ - [Stop Rules (stopRules)](#stop-rules-stoprules)
25
+ - [Output Formatting (outputFormat)](#output-formatting-outputformat)
26
+ - [Config Inheritance (extends)](#config-inheritance-extends)
27
+ - [CLI Usage](#cli-usage)
28
+ - [Complete Workflow Example](#complete-workflow-example)
29
+ - [Advanced Features](#advanced-features)
30
+ - [Advantages & Benefits](#advantages--benefits)
31
+ - [Real-World Configuration Examples](#real-world-configuration-examples)
32
+ - [Mermaid Diagrams](#mermaid-diagrams)
33
+ - [JSON Output Schema](#json-output-schema)
34
+ - [Troubleshooting](#troubleshooting)
35
+ - [License & Links](#license--links)
36
+
37
+ ---
38
+
39
+ ## Why HelmEnvDelta?
40
+
41
+ Managing multiple Kubernetes/Helm environments in GitOps workflows presents several challenges:
42
+
43
+ **Problems:**
44
+
45
+ - **Manual Syncing is Error-Prone**: Copying changes between environments manually leads to mistakes, missed files, and inconsistencies
46
+ - **Environment-Specific Config Gets Lost**: Accidentally overwriting production-specific values (namespaces, secrets, scaling) causes deployment failures
47
+ - **Dangerous Changes Slip Through**: Major version upgrades, resource scaling beyond limits, or forbidden configurations can be deployed without review
48
+ - **YAML Formatting Becomes Inconsistent**: Different team members format YAML differently, making diffs noisy and reviews difficult
49
+ - **No Audit Trail**: Manual changes lack clear visibility into what changed and why
50
+
51
+ **HelmEnvDelta solves these problems by:**
52
+
53
+ - Automating synchronization while respecting environment differences
54
+ - Filtering out environment-specific paths that should never be synced
55
+ - Validating changes against safety rules before applying them
56
+ - Enforcing consistent YAML formatting across all environments
57
+ - Providing clear diff reports for audit and review
58
+
59
+ ---
60
+
61
+ ## Key Features
62
+
63
+ ```mermaid
64
+ flowchart LR
65
+ A[Source Files] --> B[Load & Parse]
66
+ B --> C[Apply Transforms]
67
+ C --> D[Apply skipPath]
68
+ D --> E[Normalize YAML]
69
+ E --> F[Deep Comparison]
70
+ F --> G[Validate Stop Rules]
71
+ G --> H{Violations?}
72
+ H -->|Yes| I[Fail or Force]
73
+ H -->|No| J[Deep Merge]
74
+ J --> K[Apply Output Format]
75
+ K --> L[Write Destination]
76
+ ```
77
+
78
+ - **Intelligent YAML Diff & Sync**: Deep comparison of YAML content, ignoring formatting differences
79
+ - **Path Filtering (`skipPath`)**: Exclude environment-specific JSON paths from synchronization
80
+ - **Transformations (`transforms`)**: Regex-based find/replace for environment-specific values (DB URLs, service names)
81
+ - **Stop Rules (`stopRules`)**: Prevent dangerous changes (major version upgrades, scaling violations, forbidden patterns)
82
+ - **YAML Output Formatting**: Enforce consistent formatting (key ordering, indentation, value quoting, array sorting)
83
+ - **Config Inheritance (`extends`)**: Hierarchical configuration with base + environment-specific overrides
84
+ - **Multiple Reporting Formats**: Console diff, HTML report (visual side-by-side), JSON output (CI/CD integration)
85
+ - **Prune Mode**: Remove destination files not present in source
86
+ - **Dry-Run Preview**: Review all changes before applying them
87
+
88
+ ---
89
+
90
+ ## Installation
91
+
92
+ ```bash
93
+ # Global installation
94
+ npm install -g helm-env-delta
95
+
96
+ # Verify installation
97
+ helm-env-delta --version
98
+ ```
99
+
100
+ **Prerequisites:**
101
+
102
+ - Node.js >= 22
103
+ - npm >= 9
104
+
105
+ ---
106
+
107
+ ## Quick Start
108
+
109
+ **1. Create a configuration file (`config.yaml`):**
110
+
111
+ ```yaml
112
+ source: './uat'
113
+ destination: './prod'
114
+
115
+ # Skip environment-specific fields
116
+ skipPath:
117
+ '**/*.yaml':
118
+ - 'metadata.namespace'
119
+ - 'spec.destination.namespace'
120
+
121
+ # Transform environment names
122
+ transforms:
123
+ '**/*.yaml':
124
+ - find: "-uat\\b"
125
+ replace: '-prod'
126
+ ```
127
+
128
+ **2. Run dry-run to preview changes:**
129
+
130
+ ```bash
131
+ helm-env-delta --config config.yaml --dry-run --diff
132
+ ```
133
+
134
+ **3. Execute the sync:**
135
+
136
+ ```bash
137
+ helm-env-delta --config config.yaml
138
+ ```
139
+
140
+ ---
141
+
142
+ ## Use Cases
143
+
144
+ ### 1. Multi-Environment Promotion (UAT → Production)
145
+
146
+ ```mermaid
147
+ flowchart TD
148
+ A[UAT Environment] --> B[helm-env-delta --dry-run]
149
+ B --> C{Review Changes}
150
+ C -->|Approve| D[helm-env-delta sync]
151
+ C -->|Reject| E[Adjust Config]
152
+ E --> B
153
+ D --> F[Production Files Updated]
154
+ F --> G[Git Commit & Push]
155
+ G --> H[ArgoCD Auto-Sync]
156
+ H --> I[Production Deployed]
157
+ ```
158
+
159
+ Safely promote tested configurations from UAT to Production while preserving production-specific settings.
160
+
161
+ ### 2. Helm Values Management
162
+
163
+ Synchronize Helm values files across environments while maintaining environment-specific overrides:
164
+
165
+ - Database connection strings
166
+ - Replica counts
167
+ - Resource limits
168
+ - Feature flags
169
+
170
+ ### 3. Kubernetes Configuration
171
+
172
+ - **ArgoCD Applications**: Sync application manifests while preserving destination namespaces
173
+ - **Service Mesh Configs**: Istio, Linkerd configurations with environment-specific routing
174
+ - **Custom Resources**: CRDs with environment-specific parameters
175
+
176
+ ### 4. Configuration Standardization
177
+
178
+ - Enforce consistent YAML formatting across all environments
179
+ - Apply naming convention transformations
180
+ - Standardize key ordering for better readability
181
+
182
+ ### 5. CI/CD Integration
183
+
184
+ ```bash
185
+ # Pipeline validation step
186
+ helm-env-delta --config config.yaml --dry-run --diff-json | jq '.summary'
187
+
188
+ # Check for violations
189
+ helm-env-delta --config config.yaml --diff-json | jq '.stopRuleViolations | length'
190
+ ```
191
+
192
+ Integrate with CI/CD pipelines for pre-deployment validation and automated reporting.
193
+
194
+ ---
195
+
196
+ ## Configuration Guide
197
+
198
+ ### Core Settings
199
+
200
+ ```yaml
201
+ # Required for final config
202
+ source: './uat' # Source folder path
203
+ destination: './prod' # Destination folder path
204
+
205
+ # File selection (optional)
206
+ include: # Patterns to include (default: all files)
207
+ - '**/*.yaml'
208
+ - '**/README.md'
209
+ exclude: # Patterns to exclude (default: none)
210
+ - '**/skip*.yaml'
211
+
212
+ # Pruning (optional)
213
+ prune: false # Remove dest files not in source (default: false)
214
+ ```
215
+
216
+ **Notes:**
217
+
218
+ - `source` and `destination` are mandatory in the final config (can be omitted in base configs)
219
+ - `include`/`exclude` use glob patterns (`**` = recursive, `*` = wildcard)
220
+ - `prune: true` will delete files in destination that don't exist in source
221
+
222
+ ---
223
+
224
+ ### Path Filtering (skipPath)
225
+
226
+ Skip specific JSON paths during synchronization to preserve environment-specific values.
227
+
228
+ ```yaml
229
+ skipPath:
230
+ # Pattern: file glob
231
+ 'apps/*.yaml':
232
+ - 'apiVersion' # Top-level field
233
+ - 'spec.destination.namespace' # Nested field
234
+ - 'spec.ignoreDifferences[*].jsonPointers' # Array wildcards
235
+
236
+ 'svc/**/Chart.yaml':
237
+ - 'annotations.createdAt'
238
+ - 'annotations.lastModified'
239
+
240
+ 'svc/**/values.yaml':
241
+ - 'microservice.env[*].value' # All array items
242
+ ```
243
+
244
+ **JSON Path Syntax:**
245
+
246
+ - Use dot notation: `spec.destination.namespace`
247
+ - Array wildcards: `env[*].name` matches all items
248
+ - Nested arrays: `spec.items[*].subitems[*].value`
249
+
250
+ **When to use `skipPath`:**
251
+
252
+ - Environment-specific namespaces
253
+ - Timestamps and auto-generated metadata
254
+ - Environment-specific secrets references
255
+ - Scaling parameters that differ per environment
256
+
257
+ ---
258
+
259
+ ### Transformations (transforms)
260
+
261
+ Regex-based find/replace that applies to **all string values** in matched files.
262
+
263
+ ```yaml
264
+ transforms:
265
+ 'svc/**/values.yaml':
266
+ - find: "uat-db\\.(.+)\\.internal" # Regex with escaped dots
267
+ replace: 'prod-db.$1.internal' # Capture group $1
268
+ - find: 'uat-redis'
269
+ replace: 'prod-redis'
270
+
271
+ 'apps/*.yaml':
272
+ - find: "-uat\\b" # Word boundary suffix
273
+ replace: '-prod'
274
+ - find: "\\buat/" # Prefix with slash
275
+ replace: 'prod/'
276
+ ```
277
+
278
+ **Features:**
279
+
280
+ - **Regex Support**: Full regex patterns with escaping
281
+ - **Capture Groups**: Use `$1`, `$2`, etc. for captured values
282
+ - **Sequential Application**: Rules apply in order (first rule's output becomes input for second)
283
+ - **Global Scope**: Transforms ALL string values in matched files, not just specific paths
284
+
285
+ **Common Use Cases:**
286
+
287
+ - Database URLs: `uat-db.example.internal` → `prod-db.example.internal`
288
+ - Service names: `my-service-uat` → `my-service-prod`
289
+ - Domain names: `uat.example.com` → `prod.example.com`
290
+ - Environment prefixes/suffixes in any string field
291
+
292
+ ---
293
+
294
+ ### Stop Rules (stopRules)
295
+
296
+ Validation rules that prevent dangerous changes from being applied.
297
+
298
+ #### Rule Types
299
+
300
+ | Rule Type | Purpose | Example Use Case |
301
+ | -------------------- | ----------------------------- | ---------------------------------- |
302
+ | `semverMajorUpgrade` | Block major version increases | Prevent `v1.x.x` → `v2.0.0` |
303
+ | `semverDowngrade` | Block major version decreases | Prevent `v2.x.x` → `v1.0.0` |
304
+ | `numeric` | Validate numeric ranges | Ensure `replicaCount` between 2-10 |
305
+ | `regex` | Block pattern matches | Reject production URLs in staging |
306
+
307
+ #### Configuration Examples
308
+
309
+ ```yaml
310
+ stopRules:
311
+ 'apps/*.yaml':
312
+ - type: 'semverMajorUpgrade'
313
+ path: 'spec.source.targetRevision'
314
+ # Blocks: v1.2.3 → v2.0.0
315
+
316
+ 'svc/**/Chart.yaml':
317
+ - type: 'semverDowngrade'
318
+ path: 'version'
319
+ # Blocks: v2.1.0 → v1.9.9
320
+
321
+ 'svc/**/values.yaml':
322
+ - type: 'numeric'
323
+ path: 'replicaCount'
324
+ min: 2
325
+ max: 10
326
+ # Blocks: values < 2 or > 10
327
+
328
+ - type: 'regex'
329
+ path: 'image.tag'
330
+ regex: "^v0\\."
331
+ # Blocks: any tag starting with "v0."
332
+ ```
333
+
334
+ **Overriding Stop Rules:**
335
+
336
+ Use `--force` flag to override stop rules when intentional dangerous changes are needed:
337
+
338
+ ```bash
339
+ helm-env-delta --config config.yaml --force
340
+ ```
341
+
342
+ ---
343
+
344
+ ### Output Formatting (outputFormat)
345
+
346
+ Enforce consistent YAML formatting across all output files.
347
+
348
+ ```yaml
349
+ outputFormat:
350
+ # Indentation
351
+ indent: 2 # YAML indent size (default: 2)
352
+
353
+ # Key separator
354
+ keySeparator: true # Blank line between top-level keys (default: false)
355
+
356
+ # Value quoting
357
+ quoteValues:
358
+ 'svc/**/values.yaml':
359
+ - 'microservice.env[*].value' # Quote environment variable values
360
+
361
+ # Custom key ordering (hierarchical JSONPath)
362
+ keyOrders:
363
+ 'apps/*.yaml':
364
+ - 'apiVersion'
365
+ - 'kind'
366
+ - 'metadata.namespace'
367
+ - 'metadata.name'
368
+ - 'spec.project'
369
+ - 'spec.source'
370
+ - 'spec.destination'
371
+
372
+ 'svc/**/Chart.yaml':
373
+ - 'apiVersion'
374
+ - 'name'
375
+ - 'description'
376
+ - 'version'
377
+ - 'dependencies'
378
+
379
+ # Array sorting
380
+ arraySort:
381
+ 'svc/**/values.yaml':
382
+ - path: 'microservice.env'
383
+ sortBy: 'name'
384
+ order: 'asc' # or "desc"
385
+ ```
386
+
387
+ **Benefits:**
388
+
389
+ - **Consistent Formatting**: Same YAML structure across all environments
390
+ - **Better Diffs**: Format changes don't show up as content changes
391
+ - **Readability**: Logical key ordering makes files easier to understand
392
+ - **Safety**: Value quoting protects special characters
393
+
394
+ ---
395
+
396
+ ### Config Inheritance (extends)
397
+
398
+ Hierarchical configuration with base + environment-specific overrides.
399
+
400
+ ```mermaid
401
+ flowchart TD
402
+ A[base.yaml] --> B[uat.yaml extends base]
403
+ A --> C[prod.yaml extends base]
404
+ B --> D[Arrays Concatenated]
405
+ B --> E[Objects Deep Merged]
406
+ C --> D
407
+ C --> E
408
+ ```
409
+
410
+ #### Base Configuration (`config.base.yaml`)
411
+
412
+ ```yaml
413
+ # Partial config (source/dest optional in base)
414
+ include:
415
+ - '**/*.yaml'
416
+ exclude:
417
+ - '**/skip*.yaml'
418
+ prune: true
419
+
420
+ skipPath:
421
+ 'apps/*.yaml':
422
+ - 'spec.destination.namespace'
423
+
424
+ outputFormat:
425
+ indent: 2
426
+ keySeparator: true
427
+ ```
428
+
429
+ #### Environment-Specific Config (`config.prod.yaml`)
430
+
431
+ ```yaml
432
+ extends: './config.base.yaml'
433
+
434
+ # Required in final config
435
+ source: './uat'
436
+ destination: './prod'
437
+
438
+ # Additional includes (concatenated with base)
439
+ include:
440
+ - 'config/*'
441
+
442
+ # Additional skipPath rules (merged with base)
443
+ skipPath:
444
+ 'apps/*.yaml': # Adds to base rule
445
+ - 'metadata.annotations'
446
+ 'svc/*.yaml': # New pattern
447
+ - 'spec.env[*].value'
448
+
449
+ # Environment-specific transforms
450
+ transforms:
451
+ '**/*.yaml':
452
+ - find: "-uat\\b"
453
+ replace: '-prod'
454
+ ```
455
+
456
+ **Merging Rules:**
457
+
458
+ - **Arrays**: Concatenated (child adds to parent)
459
+ - **Objects**: Deep merged (child overrides parent)
460
+ - **Per-file rules**: Merged (child adds/overrides parent patterns)
461
+ - **Max depth**: 5 levels of nesting
462
+ - **Circular dependencies**: Detected and rejected
463
+
464
+ ---
465
+
466
+ ## CLI Usage
467
+
468
+ ### Command Syntax
469
+
470
+ ```bash
471
+ helm-env-delta --config <file> [options]
472
+
473
+ # Short alias
474
+ hed --config <file> [options]
475
+ ```
476
+
477
+ ### Options
478
+
479
+ | Option | Short | Description | Default |
480
+ | ----------------- | ----- | ---------------------------------------- | ------------ |
481
+ | `--config <path>` | `-c` | Path to YAML configuration file | **required** |
482
+ | `--dry-run` | | Preview changes without writing files | `false` |
483
+ | `--force` | | Override stop rules and proceed | `false` |
484
+ | `--diff` | | Display console diff for changed files | `false` |
485
+ | `--diff-html` | | Generate HTML report and open in browser | `false` |
486
+ | `--diff-json` | | Output diff as JSON to stdout | `false` |
487
+ | `--version` | `-V` | Show version number | |
488
+ | `--help` | `-h` | Display help | |
489
+
490
+ ### Examples
491
+
492
+ ```bash
493
+ # Basic sync
494
+ helm-env-delta --config config.yaml
495
+
496
+ # Dry-run with console diff
497
+ helm-env-delta --config config.yaml --dry-run --diff
498
+
499
+ # Generate HTML report
500
+ helm-env-delta --config config.yaml --diff-html
501
+
502
+ # JSON output for CI/CD
503
+ helm-env-delta --config config.yaml --diff-json | jq '.summary'
504
+
505
+ # Combine multiple diff formats
506
+ helm-env-delta --config config.yaml --diff --diff-html --diff-json
507
+
508
+ # Override stop rules (use with caution)
509
+ helm-env-delta --config config.yaml --force
510
+
511
+ # Pipe JSON to jq for filtering
512
+ helm-env-delta --config config.yaml --diff-json | jq '.files.changed[0].changes'
513
+ ```
514
+
515
+ ---
516
+
517
+ ## Complete Workflow Example
518
+
519
+ ### Step 1: Create Configuration
520
+
521
+ ```yaml
522
+ # config.yaml
523
+ source: './helm/uat'
524
+ destination: './helm/prod'
525
+
526
+ include:
527
+ - 'apps/**/*.yaml'
528
+ - 'services/**/*.yaml'
529
+
530
+ skipPath:
531
+ 'apps/*.yaml':
532
+ - 'spec.destination.namespace'
533
+ - 'metadata.annotations[kubernetes.io/last-applied-at]'
534
+
535
+ transforms:
536
+ 'services/**/values.yaml':
537
+ - find: "uat-database\\.(.+)\\.internal"
538
+ replace: 'prod-database.$1.internal'
539
+ - find: "\\.uat\\."
540
+ replace: '.prod.'
541
+
542
+ stopRules:
543
+ 'services/**/values.yaml':
544
+ - type: 'semverMajorUpgrade'
545
+ path: 'image.tag'
546
+ - type: 'numeric'
547
+ path: 'replicaCount'
548
+ min: 3
549
+ max: 20
550
+
551
+ outputFormat:
552
+ indent: 2
553
+ keySeparator: true
554
+ keyOrders:
555
+ 'apps/*.yaml':
556
+ - 'apiVersion'
557
+ - 'kind'
558
+ - 'metadata'
559
+ - 'spec'
560
+ ```
561
+
562
+ ### Step 2: Dry-Run with Diff
563
+
564
+ ```bash
565
+ helm-env-delta --config config.yaml --dry-run --diff
566
+ ```
567
+
568
+ **Output:**
569
+
570
+ ```
571
+ Configuration loaded: ./helm/uat -> ./helm/prod
572
+
573
+ ⏳ Loading files...
574
+ ✓ Loaded 15 source file(s)
575
+ ✓ Loaded 15 destination file(s)
576
+
577
+ ℹ Computing differences...
578
+ New files: 2
579
+ Deleted files: 0
580
+ Changed files: 5
581
+ Unchanged files: 8
582
+
583
+ --- apps/my-app.yaml
584
+ +++ apps/my-app.yaml
585
+ @@ -12,7 +12,7 @@
586
+ - targetRevision: v1.5.0
587
+ + targetRevision: v1.6.0
588
+ ```
589
+
590
+ ### Step 3: Review HTML Report
591
+
592
+ ```bash
593
+ helm-env-delta --config config.yaml --diff-html
594
+ ```
595
+
596
+ Opens browser with visual side-by-side diff report.
597
+
598
+ ### Step 4: Execute Sync
599
+
600
+ ```bash
601
+ helm-env-delta --config config.yaml
602
+ ```
603
+
604
+ **Output:**
605
+
606
+ ```
607
+ ✓ Files updated successfully:
608
+ 2 files added
609
+ 5 files updated
610
+ 0 files formatted
611
+ 0 files deleted
612
+ ```
613
+
614
+ ### Step 5: Commit and Deploy
615
+
616
+ ```bash
617
+ git add helm/prod
618
+ git commit -m "Sync UAT changes to prod"
619
+ git push origin main
620
+ ```
621
+
622
+ ---
623
+
624
+ ## Advanced Features
625
+
626
+ ### Deep YAML Merge
627
+
628
+ HelmEnvDelta uses intelligent deep merging to preserve destination values:
629
+
630
+ 1. Source content is processed (transforms + skipPath applied)
631
+ 2. Destination is read in full (including skipped paths)
632
+ 3. Processed source is deep-merged into destination
633
+ 4. Result: Destination keeps values for skipped paths
634
+
635
+ **Example:**
636
+
637
+ ```yaml
638
+ # Source (UAT)
639
+ metadata:
640
+ namespace: uat
641
+ spec:
642
+ replicas: 3
643
+
644
+ # Destination (Prod) before sync
645
+ metadata:
646
+ namespace: prod
647
+ spec:
648
+ replicas: 5
649
+
650
+ # Config
651
+ skipPath:
652
+ "*.yaml":
653
+ - "metadata.namespace"
654
+ - "spec.replicas"
655
+
656
+ # Destination after sync (preserved!)
657
+ metadata:
658
+ namespace: prod # ← Preserved
659
+ spec:
660
+ replicas: 5 # ← Preserved
661
+ ```
662
+
663
+ ### Multiple Diff Formats
664
+
665
+ Combine diff formats for comprehensive review:
666
+
667
+ ```bash
668
+ # Console + JSON
669
+ helm-env-delta --config config.yaml --diff --diff-json > report.json
670
+
671
+ # All three formats
672
+ helm-env-delta --config config.yaml --diff --diff-html --diff-json
673
+ ```
674
+
675
+ **Piping JSON to jq:**
676
+
677
+ ```bash
678
+ # Summary only
679
+ helm-env-delta --config config.yaml --diff-json | jq '.summary'
680
+
681
+ # Stop rule violations
682
+ helm-env-delta --config config.yaml --diff-json | jq '.stopRuleViolations'
683
+
684
+ # Changed files only
685
+ helm-env-delta --config config.yaml --diff-json | jq '.files.changed[].path'
686
+
687
+ # Field-level changes
688
+ helm-env-delta --config config.yaml --diff-json | jq '.files.changed[0].changes'
689
+ ```
690
+
691
+ ### Prune Mode
692
+
693
+ Remove files in destination that don't exist in source:
694
+
695
+ ```yaml
696
+ prune: true
697
+ ```
698
+
699
+ **Safety Considerations:**
700
+
701
+ - Use with caution in production environments
702
+ - Always run `--dry-run` first to review deletions
703
+ - Consider using version control for rollback capability
704
+
705
+ ```bash
706
+ # Preview what will be deleted
707
+ helm-env-delta --config config.yaml --dry-run --diff
708
+
709
+ # Check deleted files
710
+ helm-env-delta --config config.yaml --diff-json | jq '.files.deleted'
711
+ ```
712
+
713
+ ---
714
+
715
+ ## Advantages & Benefits
716
+
717
+ ### Safety
718
+
719
+ - **Stop Rules**: Prevent dangerous changes (version upgrades, scaling violations) before deployment
720
+ - **Dry-Run Mode**: Preview all changes before applying them
721
+ - **Validation**: Type-safe configuration with helpful error messages
722
+
723
+ ### Consistency
724
+
725
+ - **YAML Formatting**: Enforce uniform formatting across all environments
726
+ - **Key Ordering**: Logical structure for better readability
727
+ - **Value Quoting**: Protect special characters automatically
728
+
729
+ ### Efficiency
730
+
731
+ - **Automated Sync**: Save hours of manual file copying and editing
732
+ - **Parallel Processing**: Fast file loading and comparison
733
+ - **Batch Operations**: Sync multiple files at once
734
+
735
+ ### Auditability
736
+
737
+ - **Clear Diff Reports**: See exactly what changed and why
738
+ - **Multiple Formats**: Console, HTML, JSON for different review needs
739
+ - **Field-Level Detection**: Track changes at individual field level
740
+
741
+ ### Flexibility
742
+
743
+ - **Highly Configurable**: Per-file patterns for skipPath, transforms, stopRules
744
+ - **Config Inheritance**: Reuse base configs across environments
745
+ - **Regex Transforms**: Powerful pattern-based replacements
746
+
747
+ ### Integration
748
+
749
+ - **JSON Output**: Seamless CI/CD pipeline integration
750
+ - **Exit Codes**: Non-zero exit on stop rule violations
751
+ - **Pipeable**: Works with jq, grep, and other CLI tools
752
+
753
+ ### Reliability
754
+
755
+ - **60%+ Test Coverage**: 429 comprehensive tests ensure stability
756
+ - **Error Handling**: Clear, actionable error messages
757
+ - **Binary File Detection**: Safely handle non-text files
758
+
759
+ ### Performance
760
+
761
+ - **Parallel I/O**: Fast file loading with concurrent operations
762
+ - **Efficient Glob**: Optimized pattern matching with tinyglobby
763
+ - **Memory Efficient**: Streams large files when possible
764
+
765
+ ### Developer Experience
766
+
767
+ - **Type-Safe Config**: Zod schema validation with inference
768
+ - **Helpful Errors**: Contextual error messages with hints
769
+ - **Short Alias**: Use `hed` for faster typing
770
+
771
+ ---
772
+
773
+ ## Real-World Configuration Examples
774
+
775
+ ### Basic: Simple UAT → Prod Sync
776
+
777
+ ```yaml
778
+ # config.yaml
779
+ source: './uat'
780
+ destination: './prod'
781
+
782
+ skipPath:
783
+ '**/*.yaml':
784
+ - 'metadata.namespace'
785
+
786
+ transforms:
787
+ '**/*.yaml':
788
+ - find: "-uat\\b"
789
+ replace: '-prod'
790
+ ```
791
+
792
+ ### Intermediate: With Stop Rules
793
+
794
+ ```yaml
795
+ # config.yaml
796
+ source: './helm/uat'
797
+ destination: './helm/prod'
798
+
799
+ include:
800
+ - 'apps/**/*.yaml'
801
+ - 'svc/**/*.yaml'
802
+
803
+ skipPath:
804
+ 'apps/*.yaml':
805
+ - 'spec.destination.namespace'
806
+ - 'spec.ignoreDifferences[*].jsonPointers'
807
+
808
+ 'svc/**/values.yaml':
809
+ - 'microservice.env[*].value'
810
+
811
+ transforms:
812
+ 'svc/**/values.yaml':
813
+ - find: "uat-db\\.(.+)\\.internal"
814
+ replace: 'prod-db.$1.internal'
815
+
816
+ stopRules:
817
+ 'svc/**/values.yaml':
818
+ - type: 'semverMajorUpgrade'
819
+ path: 'image.tag'
820
+ - type: 'numeric'
821
+ path: 'replicaCount'
822
+ min: 2
823
+ max: 10
824
+
825
+ outputFormat:
826
+ indent: 2
827
+ keySeparator: true
828
+ ```
829
+
830
+ ### Advanced: Config Inheritance
831
+
832
+ **Base Config (`config.base.yaml`):**
833
+
834
+ ```yaml
835
+ include:
836
+ - 'apps/**/*.yaml'
837
+ - 'svc/**/*.yaml'
838
+ exclude:
839
+ - '**/test*.yaml'
840
+ prune: true
841
+
842
+ skipPath:
843
+ 'apps/*.yaml':
844
+ - 'spec.destination.namespace'
845
+
846
+ outputFormat:
847
+ indent: 2
848
+ keySeparator: true
849
+ keyOrders:
850
+ 'apps/*.yaml':
851
+ - 'apiVersion'
852
+ - 'kind'
853
+ - 'metadata'
854
+ - 'spec'
855
+ ```
856
+
857
+ **Production Config (`config.prod.yaml`):**
858
+
859
+ ```yaml
860
+ extends: './config.base.yaml'
861
+
862
+ source: './helm/uat'
863
+ destination: './helm/prod'
864
+
865
+ transforms:
866
+ '**/*.yaml':
867
+ - find: "-uat\\b"
868
+ replace: '-prod'
869
+ - find: "\\.uat\\."
870
+ replace: '.prod.'
871
+
872
+ stopRules:
873
+ 'svc/**/values.yaml':
874
+ - type: 'semverMajorUpgrade'
875
+ path: 'image.tag'
876
+ - type: 'numeric'
877
+ path: 'replicaCount'
878
+ min: 3
879
+ max: 20
880
+ ```
881
+
882
+ ### CI/CD Integration
883
+
884
+ **GitHub Actions Workflow:**
885
+
886
+ ```yaml
887
+ name: Sync UAT to Prod
888
+
889
+ on:
890
+ workflow_dispatch:
891
+ push:
892
+ branches: [main]
893
+
894
+ jobs:
895
+ sync:
896
+ runs-on: ubuntu-latest
897
+ steps:
898
+ - uses: actions/checkout@v3
899
+
900
+ - uses: actions/setup-node@v3
901
+ with:
902
+ node-version: '22'
903
+
904
+ - name: Install helm-env-delta
905
+ run: npm install -g helm-env-delta
906
+
907
+ - name: Dry-run sync
908
+ run: |
909
+ helm-env-delta --config config.yaml --dry-run --diff-json > report.json
910
+ cat report.json | jq '.summary'
911
+
912
+ - name: Check stop rule violations
913
+ run: |
914
+ VIOLATIONS=$(cat report.json | jq '.stopRuleViolations | length')
915
+ if [ "$VIOLATIONS" -gt 0 ]; then
916
+ echo "Stop rule violations detected!"
917
+ cat report.json | jq '.stopRuleViolations'
918
+ exit 1
919
+ fi
920
+
921
+ - name: Execute sync
922
+ run: helm-env-delta --config config.yaml
923
+
924
+ - name: Commit changes
925
+ run: |
926
+ git config user.name "GitHub Actions"
927
+ git config user.email "actions@github.com"
928
+ git add helm/prod
929
+ git commit -m "Sync UAT to Prod" || echo "No changes"
930
+ git push
931
+ ```
932
+
933
+ ---
934
+
935
+ ## JSON Output Schema
936
+
937
+ When using `--diff-json`, the tool outputs structured JSON to stdout:
938
+
939
+ ```json
940
+ {
941
+ "metadata": {
942
+ "timestamp": "2025-12-18T10:30:00.000Z",
943
+ "source": "./uat",
944
+ "destination": "./prod",
945
+ "dryRun": true,
946
+ "version": "0.0.1"
947
+ },
948
+ "summary": {
949
+ "added": 2,
950
+ "deleted": 1,
951
+ "changed": 3,
952
+ "formatted": 5,
953
+ "unchanged": 15
954
+ },
955
+ "files": {
956
+ "added": ["prod/new-service.yaml"],
957
+ "deleted": ["prod/old-service.yaml"],
958
+ "changed": [
959
+ {
960
+ "path": "prod/app-values.yaml",
961
+ "diff": "unified diff string...",
962
+ "changes": [
963
+ {
964
+ "path": "$.image.tag",
965
+ "oldValue": "v1.2.3",
966
+ "updatedValue": "v1.3.0"
967
+ },
968
+ {
969
+ "path": "$.replicaCount",
970
+ "oldValue": 2,
971
+ "updatedValue": 3
972
+ }
973
+ ]
974
+ }
975
+ ],
976
+ "formatted": ["prod/config.yaml"],
977
+ "unchanged": ["prod/service.yaml"]
978
+ },
979
+ "stopRuleViolations": [
980
+ {
981
+ "file": "prod/app-values.yaml",
982
+ "rule": {
983
+ "type": "semverMajorUpgrade",
984
+ "path": "image.tag"
985
+ },
986
+ "path": "image.tag",
987
+ "oldValue": "v1.2.3",
988
+ "updatedValue": "v2.0.0",
989
+ "message": "Major version upgrade detected: v1.2.3 → v2.0.0"
990
+ }
991
+ ]
992
+ }
993
+ ```
994
+
995
+ **Field Descriptions:**
996
+
997
+ - `metadata`: Execution context (timestamp, paths, dry-run status, version)
998
+ - `summary`: Counts for each file category
999
+ - `files.changed[].changes`: Field-level changes with JSONPath notation
1000
+ - `stopRuleViolations`: All validation failures with context
1001
+
1002
+ ---
1003
+
1004
+ ## Troubleshooting
1005
+
1006
+ ### Config Validation Errors
1007
+
1008
+ **Error: "source is required"**
1009
+
1010
+ ```
1011
+ Config Validation Error: source is required
1012
+ File: config.yaml
1013
+ ```
1014
+
1015
+ **Solution:** Add `source` field to your config (or use `extends` from a base config).
1016
+
1017
+ ---
1018
+
1019
+ **Error: "Invalid JSON path syntax"**
1020
+
1021
+ ```
1022
+ Config Validation Error: skipPath pattern 'apps/*.yaml' contains invalid path
1023
+ ```
1024
+
1025
+ **Solution:** Check JSON path syntax:
1026
+
1027
+ - Use dot notation: `spec.replicas` not `spec/replicas`
1028
+ - Array wildcards: `env[*].name` not `env.*.name`
1029
+
1030
+ ---
1031
+
1032
+ ### Stop Rule Violations
1033
+
1034
+ **Error: "Major version upgrade detected"**
1035
+
1036
+ ```
1037
+ 🛑 Stop Rule Violation (semverMajorUpgrade)
1038
+ File: svc/my-service/values.yaml
1039
+ Path: image.tag
1040
+ Change: v1.2.3 → v2.0.0
1041
+ ```
1042
+
1043
+ **Solutions:**
1044
+
1045
+ - Review the change carefully
1046
+ - If intentional, use `--force` to override
1047
+ - Update the stop rule configuration if needed
1048
+
1049
+ ---
1050
+
1051
+ ### Transform Pattern Issues
1052
+
1053
+ **Problem:** Transform not applying
1054
+
1055
+ **Check:**
1056
+
1057
+ 1. File pattern matches: `svc/**/values.yaml` vs `svc/*/values.yaml`
1058
+ 2. Regex escaping: Use `\\.` for literal dots
1059
+ 3. Word boundaries: Use `\\b` for word boundaries
1060
+ 4. Order matters: Rules apply sequentially
1061
+
1062
+ **Example:**
1063
+
1064
+ ```yaml
1065
+ # Wrong: . matches any character
1066
+ - find: 'uat.internal'
1067
+
1068
+ # Correct: escaped dot
1069
+ - find: "uat\\.internal"
1070
+ ```
1071
+
1072
+ ---
1073
+
1074
+ ### JSONPath Syntax Problems
1075
+
1076
+ **Common Mistakes:**
1077
+
1078
+ ```yaml
1079
+ # ❌ Wrong
1080
+ skipPath:
1081
+ "*.yaml":
1082
+ - "$.spec.replicas" # Don't use $. prefix
1083
+ - "env.*.name" # Use [*] not .*
1084
+
1085
+ # ✓ Correct
1086
+ skipPath:
1087
+ "*.yaml":
1088
+ - "spec.replicas" # No $. prefix
1089
+ - "env[*].name" # Array wildcard
1090
+ ```
1091
+
1092
+ ---
1093
+
1094
+ ### File Glob Patterns Not Matching
1095
+
1096
+ **Glob Pattern Reference:**
1097
+
1098
+ | Pattern | Matches |
1099
+ | ---------------- | -------------------------------------------------------- |
1100
+ | `*.yaml` | `app.yaml` (current directory only) |
1101
+ | `**/*.yaml` | `apps/app.yaml`, `svc/my-svc/values.yaml` (recursive) |
1102
+ | `apps/*.yaml` | `apps/app.yaml` (one level deep) |
1103
+ | `apps/**/*.yaml` | `apps/foo/app.yaml`, `apps/foo/bar/app.yaml` (recursive) |
1104
+
1105
+ **Debugging:**
1106
+
1107
+ ```bash
1108
+ # Check which files match your pattern
1109
+ find . -name "*.yaml"
1110
+ ```
1111
+
1112
+ ---
1113
+
1114
+ ## License & Links
1115
+
1116
+ **License:** [ISC](https://opensource.org/licenses/ISC)
1117
+
1118
+ **Links:**
1119
+
1120
+ - **npm Package**: [helm-env-delta](https://www.npmjs.com/package/helm-env-delta)
1121
+ - **GitHub Repository**: [BCsabaEngine/helm-env-delta](https://github.com/BCsabaEngine/helm-env-delta)
1122
+ - **Issue Tracker**: [GitHub Issues](https://github.com/BCsabaEngine/helm-env-delta/issues)
1123
+
1124
+ **Author:** BCsabaEngine
1125
+
1126
+ ---
1127
+
1128
+ **Made for DevOps and Platform teams managing multi-environment Kubernetes and Helm deployments in GitOps workflows.**