philiprehberger-env_diff 0.3.0 → 0.5.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/README.md +20 -1
- data/lib/philiprehberger/env_diff/diff.rb +13 -0
- data/lib/philiprehberger/env_diff/version.rb +1 -1
- data/lib/philiprehberger/env_diff.rb +43 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8fa424560bb3f733e97c91a5e643f04306eb81aa032184970889e71d987910c6
|
|
4
|
+
data.tar.gz: 32748ed41ac378a1dd96fdf74a91ebd1f7e72fa74628510cd2fcdbb61e4d3c74
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1738b36b798d79c436f4471ee7a44f755d8d83ef4d2ba89ffcee2f7724de895573cdc3b198f7943c3c9d49c8737a9cc1887b76a0c035129a8f9b047d882469a1
|
|
7
|
+
data.tar.gz: bf909ac4ba6905c9889ce456b7c29d1ef087618562954305a553f58690c0f635dc32c9a8278de0946936ac33e27d0019e3ee3510535c3621482913aff8878c6a
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.5.0] - 2026-05-08
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- `EnvDiff.to_csv(diff, mask: [])` — exports a structured `key,status,source,target` CSV (RFC 4180 quoting). Complements the existing `to_markdown` and `to_html` exports for spreadsheet review. Supports the same `mask:` substring redaction as `Diff#summary`.
|
|
14
|
+
|
|
15
|
+
## [0.4.0] - 2026-04-24
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
- `Diff#status_for(key)` — returns the status of a single key as a Symbol (`:added`, `:removed`, `:changed`, `:unchanged`), or `nil` if the key is absent from both sides
|
|
19
|
+
|
|
10
20
|
## [0.3.0] - 2026-04-14
|
|
11
21
|
|
|
12
22
|
### Added
|
data/README.md
CHANGED
|
@@ -82,6 +82,16 @@ diff.stats
|
|
|
82
82
|
# => { added: 1, removed: 1, changed: 1, unchanged: 1, total: 4 }
|
|
83
83
|
```
|
|
84
84
|
|
|
85
|
+
### Per-key status
|
|
86
|
+
|
|
87
|
+
```ruby
|
|
88
|
+
diff.status_for("NEW_KEY") # => :added
|
|
89
|
+
diff.status_for("OLD_KEY") # => :removed
|
|
90
|
+
diff.status_for("DATABASE_URL") # => :changed
|
|
91
|
+
diff.status_for("SECRET") # => :unchanged
|
|
92
|
+
diff.status_for("NOT_THERE") # => nil
|
|
93
|
+
```
|
|
94
|
+
|
|
85
95
|
### Validation
|
|
86
96
|
|
|
87
97
|
Check that all required keys exist in a target hash or `.env` file:
|
|
@@ -112,7 +122,7 @@ diff.unchanged # => ["DB_HOST"]
|
|
|
112
122
|
|
|
113
123
|
### Export Formats
|
|
114
124
|
|
|
115
|
-
Format a diff result as a Markdown or
|
|
125
|
+
Format a diff result as a Markdown, HTML, or CSV table:
|
|
116
126
|
|
|
117
127
|
```ruby
|
|
118
128
|
diff = Philiprehberger::EnvDiff.compare(source, target)
|
|
@@ -131,6 +141,13 @@ puts Philiprehberger::EnvDiff.to_html(diff)
|
|
|
131
141
|
# <tr><td>NEW_KEY</td><td>added</td><td></td><td>added</td></tr>
|
|
132
142
|
# ...
|
|
133
143
|
# </table>
|
|
144
|
+
|
|
145
|
+
puts Philiprehberger::EnvDiff.to_csv(diff, mask: ['SECRET'])
|
|
146
|
+
# key,status,source,target
|
|
147
|
+
# NEW_KEY,added,,added
|
|
148
|
+
# OLD_KEY,removed,remove_me,
|
|
149
|
+
# DATABASE_URL,changed,postgres://localhost/dev,postgres://prod-host/app
|
|
150
|
+
# SECRET,unchanged,***,***
|
|
134
151
|
```
|
|
135
152
|
|
|
136
153
|
### Compare against system ENV
|
|
@@ -170,6 +187,7 @@ ENV
|
|
|
170
187
|
| `EnvDiff.validate(target, required:)` | Check that all required keys exist in target; returns `{ valid:, missing: }` |
|
|
171
188
|
| `EnvDiff.to_markdown(diff)` | Format a diff result as a Markdown table string |
|
|
172
189
|
| `EnvDiff.to_html(diff)` | Format a diff result as an HTML table string |
|
|
190
|
+
| `EnvDiff.to_csv(diff, mask: [])` | Format a diff result as a `key,status,source,target` CSV; supports value masking |
|
|
173
191
|
| `Diff#added` | Array of keys in target but not source |
|
|
174
192
|
| `Diff#removed` | Array of keys in source but not target |
|
|
175
193
|
| `Diff#changed` | Hash of keys with different values |
|
|
@@ -180,6 +198,7 @@ ENV
|
|
|
180
198
|
| `Diff#to_json` | JSON serialization of the structured hash |
|
|
181
199
|
| `Diff#filter(pattern:)` | New `Diff` containing only keys matching the regex pattern |
|
|
182
200
|
| `Diff#stats` | Hash of counts: `:added`, `:removed`, `:changed`, `:unchanged`, `:total` |
|
|
201
|
+
| `Diff#status_for(key)` | Status of a single key as `:added`, `:removed`, `:changed`, `:unchanged`, or `nil` |
|
|
183
202
|
| `Parser.parse(content)` | Parse `.env` string into a hash |
|
|
184
203
|
| `Parser.parse_file(path:)` | Read and parse a `.env` file |
|
|
185
204
|
|
|
@@ -92,6 +92,19 @@ module Philiprehberger
|
|
|
92
92
|
}
|
|
93
93
|
end
|
|
94
94
|
|
|
95
|
+
# Status of a single key in this diff.
|
|
96
|
+
#
|
|
97
|
+
# @param key [String] the key to look up
|
|
98
|
+
# @return [Symbol, nil] one of :added, :removed, :changed, :unchanged, or nil if absent from both sides
|
|
99
|
+
def status_for(key)
|
|
100
|
+
return :added if @added.include?(key)
|
|
101
|
+
return :removed if @removed.include?(key)
|
|
102
|
+
return :changed if @changed.key?(key)
|
|
103
|
+
return :unchanged if @unchanged.include?(key)
|
|
104
|
+
|
|
105
|
+
nil
|
|
106
|
+
end
|
|
107
|
+
|
|
95
108
|
private
|
|
96
109
|
|
|
97
110
|
def build_changed(source, target)
|
|
@@ -63,6 +63,49 @@ module Philiprehberger
|
|
|
63
63
|
lines.join("\n")
|
|
64
64
|
end
|
|
65
65
|
|
|
66
|
+
# Format a diff result as a CSV string with header `key,status,source,target`.
|
|
67
|
+
#
|
|
68
|
+
# Values containing commas, quotes, or newlines are quoted per RFC 4180.
|
|
69
|
+
# Keys whose name contains any of `mask` (substring match, case-insensitive)
|
|
70
|
+
# have their source and target values redacted to `***`.
|
|
71
|
+
#
|
|
72
|
+
# @param diff [Diff] the diff to format
|
|
73
|
+
# @param mask [Array<String>] substrings to match against keys for redaction
|
|
74
|
+
# @return [String] CSV body with a trailing newline
|
|
75
|
+
def self.to_csv(diff, mask: [])
|
|
76
|
+
data = diff.to_h
|
|
77
|
+
lines = ['key,status,source,target']
|
|
78
|
+
|
|
79
|
+
diff.added.each { |key| lines << csv_row(key, 'added', '', data[:added][key], mask) }
|
|
80
|
+
diff.removed.each { |key| lines << csv_row(key, 'removed', data[:removed][key], '', mask) }
|
|
81
|
+
diff.changed.each do |key, vals|
|
|
82
|
+
lines << csv_row(key, 'changed', vals[:source], vals[:target], mask)
|
|
83
|
+
end
|
|
84
|
+
diff.unchanged.each do |key|
|
|
85
|
+
val = data[:unchanged][key]
|
|
86
|
+
lines << csv_row(key, 'unchanged', val, val, mask)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
"#{lines.join("\n")}\n"
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def self.csv_row(key, status, source, target, mask)
|
|
93
|
+
masked = mask.any? { |m| key.to_s.downcase.include?(m.to_s.downcase) }
|
|
94
|
+
source = '***' if masked && source.to_s != ''
|
|
95
|
+
target = '***' if masked && target.to_s != ''
|
|
96
|
+
[key, status, source, target].map { |cell| csv_escape(cell) }.join(',')
|
|
97
|
+
end
|
|
98
|
+
private_class_method :csv_row
|
|
99
|
+
|
|
100
|
+
def self.csv_escape(value)
|
|
101
|
+
string = value.to_s
|
|
102
|
+
return string unless string.match?(/[",\n\r]/)
|
|
103
|
+
|
|
104
|
+
escaped = string.gsub('"', '""')
|
|
105
|
+
"\"#{escaped}\""
|
|
106
|
+
end
|
|
107
|
+
private_class_method :csv_escape
|
|
108
|
+
|
|
66
109
|
# Format a diff result as an HTML table string.
|
|
67
110
|
#
|
|
68
111
|
# @param diff [Diff] the diff to format
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: philiprehberger-env_diff
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Philip Rehberger
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-05-08 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: Parse .env files or environment hashes, compare them, and get a clear
|
|
14
14
|
report of added, removed, changed, and unchanged variables.
|