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.
- package/LICENSE +15 -0
- package/README.md +1128 -0
- package/bin/index.js +2 -0
- package/dist/ZodError.d.ts +8 -0
- package/dist/ZodError.js +33 -0
- package/dist/arrayDiffer.d.ts +8 -0
- package/dist/arrayDiffer.js +47 -0
- package/dist/commandLine.d.ts +9 -0
- package/dist/commandLine.js +32 -0
- package/dist/configFile.d.ts +148 -0
- package/dist/configFile.js +135 -0
- package/dist/configLoader.d.ts +3 -0
- package/dist/configLoader.js +12 -0
- package/dist/configMerger.d.ts +21 -0
- package/dist/configMerger.js +190 -0
- package/dist/consoleDiffReporter.d.ts +3 -0
- package/dist/consoleDiffReporter.js +172 -0
- package/dist/consoleFormatter.d.ts +10 -0
- package/dist/consoleFormatter.js +103 -0
- package/dist/fileDiff.d.ts +41 -0
- package/dist/fileDiff.js +163 -0
- package/dist/fileLoader.d.ts +25 -0
- package/dist/fileLoader.js +105 -0
- package/dist/fileUpdater.d.ts +27 -0
- package/dist/fileUpdater.js +264 -0
- package/dist/htmlReporter.d.ts +27 -0
- package/dist/htmlReporter.js +600 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +91 -0
- package/dist/jsonReporter.d.ts +70 -0
- package/dist/jsonReporter.js +122 -0
- package/dist/stopRulesValidator.d.ts +33 -0
- package/dist/stopRulesValidator.js +168 -0
- package/dist/utils/deepEqual.d.ts +1 -0
- package/dist/utils/deepEqual.js +48 -0
- package/dist/utils/diffGenerator.d.ts +1 -0
- package/dist/utils/diffGenerator.js +8 -0
- package/dist/utils/errors.d.ts +23 -0
- package/dist/utils/errors.js +39 -0
- package/dist/utils/fileType.d.ts +1 -0
- package/dist/utils/fileType.js +8 -0
- package/dist/utils/index.d.ts +7 -0
- package/dist/utils/index.js +18 -0
- package/dist/utils/jsonPath.d.ts +2 -0
- package/dist/utils/jsonPath.js +29 -0
- package/dist/utils/serialization.d.ts +2 -0
- package/dist/utils/serialization.js +40 -0
- package/dist/utils/transformer.d.ts +21 -0
- package/dist/utils/transformer.js +60 -0
- package/dist/yamlFormatter.d.ts +20 -0
- package/dist/yamlFormatter.js +315 -0
- package/package.json +89 -0
package/README.md
ADDED
|
@@ -0,0 +1,1128 @@
|
|
|
1
|
+
# HelmEnvDelta
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/helm-env-delta)
|
|
4
|
+
[](https://opensource.org/licenses/ISC)
|
|
5
|
+
[](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.**
|