helmsnap 0.2.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.dockerignore +8 -0
- data/Dockerfile +12 -0
- data/Gemfile.lock +5 -2
- data/README.md +47 -16
- data/bin/setup +0 -0
- data/helmsnap.gemspec +2 -0
- data/lib/helmsnap/args_parser.rb +12 -6
- data/lib/helmsnap/check.rb +9 -2
- data/lib/helmsnap/command.rb +24 -14
- data/lib/helmsnap/console.rb +19 -0
- data/lib/helmsnap/generate.rb +7 -7
- data/lib/helmsnap/runner.rb +32 -4
- data/lib/helmsnap/version.rb +1 -1
- data/lib/helmsnap.rb +5 -2
- metadata +20 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ae526f7e855d2833a340fc35f9363f212fcfe687aebca504dc0e99e704c6393e
|
4
|
+
data.tar.gz: 41787e81ec544fc491d2273763a837594415a7792c823faf07fab94e72388845
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 65fc8371b350ab030be1503d392b0a2fd5abbe9d68c64bffa1b44662d1c8339e3358b3e15d63de723498732e67540c8d1768272983213cbd7d0f0be47a6c4b1b
|
7
|
+
data.tar.gz: 3370e09e93f1a0d6b43eb2913046ce44c73905c8f61f6ce79601b627795b2aa69f67c1f7f110fa0f9ef39e0eabe6bf926633d2431d7250ac714d94ed819db3b0
|
data/.dockerignore
ADDED
data/Dockerfile
ADDED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
helmsnap (0.
|
4
|
+
helmsnap (0.4.0)
|
5
|
+
colorize
|
5
6
|
|
6
7
|
GEM
|
7
8
|
remote: https://rubygems.org/
|
@@ -14,6 +15,7 @@ GEM
|
|
14
15
|
zeitwerk (~> 2.3)
|
15
16
|
ast (2.4.2)
|
16
17
|
coderay (1.1.3)
|
18
|
+
colorize (0.8.1)
|
17
19
|
concurrent-ruby (1.1.9)
|
18
20
|
diff-lcs (1.4.4)
|
19
21
|
i18n (1.8.11)
|
@@ -84,6 +86,7 @@ GEM
|
|
84
86
|
|
85
87
|
PLATFORMS
|
86
88
|
x86_64-darwin-20
|
89
|
+
x86_64-linux
|
87
90
|
|
88
91
|
DEPENDENCIES
|
89
92
|
helmsnap!
|
@@ -94,4 +97,4 @@ DEPENDENCIES
|
|
94
97
|
rubocop-config-umbrellio
|
95
98
|
|
96
99
|
BUNDLED WITH
|
97
|
-
2.2.
|
100
|
+
2.2.32
|
data/README.md
CHANGED
@@ -1,38 +1,69 @@
|
|
1
1
|
# Helmsnap
|
2
2
|
|
3
|
-
|
3
|
+
## About
|
4
4
|
|
5
|
-
|
5
|
+
Helmsnap is a tool for generating and checking helm chart snapshots. Example:
|
6
6
|
|
7
|
-
|
7
|
+
Generate snapshots (uses `helm template` under the hood):
|
8
|
+
|
9
|
+
```sh
|
10
|
+
helmsnap generate -c helm/mychart -s helm/snapshots -v helm/values/production.yaml
|
11
|
+
```
|
12
|
+
|
13
|
+
Generate snapshots in some temp directory and check (diff) them against existing snapshots in `helm/snapshots` directory:
|
8
14
|
|
9
|
-
|
15
|
+
```sh
|
16
|
+
helmsnap check -c helm/mychart -s helm/snapshots -v helm/values/production.yaml
|
17
|
+
```
|
18
|
+
|
19
|
+
Get the full description of possible arguments:
|
10
20
|
|
11
|
-
```
|
12
|
-
|
21
|
+
```sh
|
22
|
+
helmsnap --help
|
13
23
|
```
|
14
24
|
|
15
|
-
|
25
|
+
The typical usage flow:
|
16
26
|
|
17
|
-
|
27
|
+
1. You generate some snapshots using `helmsnap generate` command and check them into your git repo.
|
28
|
+
2. You add `helmsnap check` command to your CI (or run it manually on every commit).
|
29
|
+
3. In case snapshots differ, you should carefully check the updates and either fix your chart or update the snapshots using `helmsnap generate`.
|
18
30
|
|
19
|
-
|
31
|
+
This tool can also be useful when you are developing a new chart or updating an existing one: you can generate snapshots and see what is rendered without need to deploy the chart in your cluster.
|
20
32
|
|
21
|
-
|
33
|
+
## Features
|
22
34
|
|
23
|
-
|
35
|
+
### Helm dependency management
|
24
36
|
|
25
|
-
|
37
|
+
Helmsnap will automically rebuild your chart dependencies on every snapshot generation or check. In case your dependency is using url to some local helm repo and you don't have a proper repo added, it will add it automically which is useful in CI. It also will detect local dependencies (those that start with `file://`) and rebuild their dependencies as well.
|
26
38
|
|
27
|
-
|
39
|
+
### Timestamp replacement
|
28
40
|
|
29
|
-
|
41
|
+
Helmsnap will automically replace all occurencies of patterns that look like timestamps (format like `2022-01-01 00:00:00.000`) in your templates. This is useful in case you have some annotations like `releaseTime` that would break your snapshots checks otherwise.
|
42
|
+
|
43
|
+
## Installation
|
30
44
|
|
31
|
-
|
45
|
+
Just install a gem and use the provided `helmsnap` binary.
|
46
|
+
|
47
|
+
```sh
|
48
|
+
gem install helmsnap
|
49
|
+
```
|
50
|
+
|
51
|
+
Alaternatively, you can use a [Docker image](https://github.com/tycooon/helmsnap/pkgs/container/helmsnap) with Ruby, helm and helmsnap gem preinstalled. This is useful for CIs or if you don't want to install Ruby locally.
|
52
|
+
|
53
|
+
## CI example
|
54
|
+
|
55
|
+
Example job for Gitlab CI:
|
56
|
+
|
57
|
+
```yaml
|
58
|
+
check-snapshots:
|
59
|
+
stage: test
|
60
|
+
image: ghcr.io/tycooon/helmsnap:latest
|
61
|
+
script: helmsnap check -c helm/mychart -s helm/snapshots -v helm/values/production.yaml
|
62
|
+
```
|
32
63
|
|
33
64
|
## Contributing
|
34
65
|
|
35
|
-
Bug reports and pull requests are welcome
|
66
|
+
Bug reports and pull requests are welcome.
|
36
67
|
|
37
68
|
## License
|
38
69
|
|
data/bin/setup
CHANGED
File without changes
|
data/helmsnap.gemspec
CHANGED
data/lib/helmsnap/args_parser.rb
CHANGED
@@ -4,6 +4,8 @@ class Helmsnap::ArgsParser
|
|
4
4
|
Args = Struct.new(:chart_path, :snapshots_path, :values_path, keyword_init: true)
|
5
5
|
MissingOption = Class.new(OptionParser::ParseError)
|
6
6
|
|
7
|
+
BANNER = "Usage: helmsnap CMD [options]"
|
8
|
+
|
7
9
|
def initialize(options)
|
8
10
|
self.options = options
|
9
11
|
self.args = Args.new
|
@@ -21,8 +23,8 @@ class Helmsnap::ArgsParser
|
|
21
23
|
end
|
22
24
|
|
23
25
|
def print_help!(msg)
|
24
|
-
|
25
|
-
|
26
|
+
Helmsnap::Console.error($stderr, "#{msg}\n") if msg
|
27
|
+
Helmsnap::Console.print($stdout, parser.help)
|
26
28
|
exit 1
|
27
29
|
end
|
28
30
|
|
@@ -30,9 +32,8 @@ class Helmsnap::ArgsParser
|
|
30
32
|
|
31
33
|
attr_accessor :options, :parser, :args
|
32
34
|
|
33
|
-
def build_parser
|
34
|
-
OptionParser.new do |opts|
|
35
|
-
opts.banner = "Usage: helmsnap CMD [options]"
|
35
|
+
def build_parser # rubocop:disable Metrics/MethodLength
|
36
|
+
OptionParser.new(BANNER, 50) do |opts|
|
36
37
|
opts.separator("Supported commands: `generate` and `check`.")
|
37
38
|
opts.separator("")
|
38
39
|
opts.separator("Specific options:")
|
@@ -49,8 +50,13 @@ class Helmsnap::ArgsParser
|
|
49
50
|
args.values_path = pn(option)
|
50
51
|
end
|
51
52
|
|
53
|
+
opts.on("--version", "Show version") do
|
54
|
+
Helmsnap::Console.print($stdout, "#{Helmsnap::VERSION}\n")
|
55
|
+
exit
|
56
|
+
end
|
57
|
+
|
52
58
|
opts.on("-h", "--help", "Show this message") do
|
53
|
-
|
59
|
+
print_help!(nil)
|
54
60
|
exit
|
55
61
|
end
|
56
62
|
end
|
data/lib/helmsnap/check.rb
CHANGED
@@ -13,7 +13,7 @@ class Helmsnap::Check
|
|
13
13
|
|
14
14
|
def call
|
15
15
|
Dir.mktmpdir do |temp_dir|
|
16
|
-
|
16
|
+
temp_dir_path = Pathname.new(temp_dir)
|
17
17
|
|
18
18
|
Helmsnap::Generate.call(
|
19
19
|
chart_path: chart_path,
|
@@ -21,7 +21,14 @@ class Helmsnap::Check
|
|
21
21
|
values_path: values_path,
|
22
22
|
)
|
23
23
|
|
24
|
-
Helmsnap.run_cmd
|
24
|
+
result = Helmsnap.run_cmd("which", "colordiff", allow_failure: true)
|
25
|
+
util = result.success ? "colordiff" : "diff"
|
26
|
+
|
27
|
+
diff = Helmsnap.run_cmd(
|
28
|
+
util, "--unified", "--recursive", snapshots_path, temp_dir_path, allow_failure: true
|
29
|
+
).output
|
30
|
+
|
31
|
+
diff.strip.empty?
|
25
32
|
end
|
26
33
|
end
|
27
34
|
|
data/lib/helmsnap/command.rb
CHANGED
@@ -1,38 +1,48 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class Helmsnap::Command
|
4
|
+
Result = Struct.new(:success, :output)
|
5
|
+
|
4
6
|
def self.call(...)
|
5
7
|
new(...).call
|
6
8
|
end
|
7
9
|
|
8
|
-
def initialize(cmd)
|
10
|
+
def initialize(cmd, stdout: $stdout, stderr: $stderr, allow_failure: false)
|
9
11
|
self.cmd = cmd
|
12
|
+
self.stdout = stdout
|
13
|
+
self.stderr = stderr
|
14
|
+
self.allow_failure = allow_failure
|
10
15
|
end
|
11
16
|
|
12
17
|
def call
|
13
|
-
|
18
|
+
Helmsnap::Console.info(stdout, "> #{cmd}")
|
19
|
+
run_command
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
14
23
|
|
15
|
-
|
24
|
+
attr_accessor :cmd, :stdout, :stderr, :allow_failure
|
25
|
+
|
26
|
+
def run_command
|
27
|
+
Open3.popen3(cmd) do |_in, out, err, wait_thr|
|
16
28
|
output = +""
|
17
29
|
|
18
|
-
while (chunk =
|
19
|
-
|
30
|
+
while (chunk = out.gets)
|
31
|
+
Helmsnap::Console.print(stdout, chunk)
|
20
32
|
output << chunk
|
21
33
|
end
|
22
34
|
|
23
35
|
exit_status = wait_thr.value
|
36
|
+
success = exit_status.success?
|
24
37
|
|
25
|
-
|
26
|
-
|
27
|
-
|
38
|
+
if !success && !allow_failure
|
39
|
+
Helmsnap::Console.error(stderr, err.read)
|
40
|
+
Helmsnap::Console.error(stderr, "Command failed with status #{exit_status.to_i}")
|
41
|
+
abort
|
28
42
|
end
|
29
43
|
|
30
|
-
|
31
|
-
output
|
44
|
+
Helmsnap::Console.print(stdout, "\n")
|
45
|
+
Result.new(success, output)
|
32
46
|
end
|
33
47
|
end
|
34
|
-
|
35
|
-
private
|
36
|
-
|
37
|
-
attr_accessor :cmd
|
38
48
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Helmsnap::Console
|
4
|
+
extend self
|
5
|
+
|
6
|
+
def print(stream, msg)
|
7
|
+
stream.print(msg)
|
8
|
+
end
|
9
|
+
|
10
|
+
def info(stream, msg)
|
11
|
+
msg = ColorizedString[msg].colorize(:light_yellow)
|
12
|
+
stream.puts(msg)
|
13
|
+
end
|
14
|
+
|
15
|
+
def error(stream, msg)
|
16
|
+
msg = ColorizedString[msg].colorize(:light_red)
|
17
|
+
stream.puts(msg)
|
18
|
+
end
|
19
|
+
end
|
data/lib/helmsnap/generate.rb
CHANGED
@@ -12,21 +12,21 @@ class Helmsnap::Generate
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def call
|
15
|
-
dep_list = run_cmd
|
15
|
+
dep_list = run_cmd("helm", "dependency", "list", "--max-col-width", 0, chart_path).output
|
16
16
|
|
17
17
|
dep_list.scan(%r{file://(.+?)\t}) do |dep_path|
|
18
|
-
run_cmd
|
18
|
+
run_cmd("helm", "dependency", "update", "--skip-refresh", chart_path.join(dep_path.first))
|
19
19
|
end
|
20
20
|
|
21
21
|
dep_list.scan(%r{(https?://.+?)\t}) do |dep_path|
|
22
|
-
run_cmd
|
22
|
+
run_cmd("helm", "repo", "add", Digest::MD5.hexdigest(dep_path.first), dep_path.first)
|
23
23
|
end
|
24
24
|
|
25
|
-
run_cmd
|
25
|
+
run_cmd("helm", "dependency", "update", "--skip-refresh", chart_path)
|
26
26
|
|
27
27
|
FileUtils.rmtree(snapshots_path)
|
28
28
|
|
29
|
-
run_cmd
|
29
|
+
run_cmd(
|
30
30
|
"helm", "template", chart_path, "--values", values_path, "--output-dir", snapshots_path
|
31
31
|
)
|
32
32
|
|
@@ -41,7 +41,7 @@ class Helmsnap::Generate
|
|
41
41
|
|
42
42
|
attr_accessor :chart_path, :snapshots_path, :values_path
|
43
43
|
|
44
|
-
def run_cmd
|
45
|
-
Helmsnap.run_cmd
|
44
|
+
def run_cmd(...)
|
45
|
+
Helmsnap.run_cmd(...)
|
46
46
|
end
|
47
47
|
end
|
data/lib/helmsnap/runner.rb
CHANGED
@@ -11,7 +11,7 @@ class Helmsnap::Runner
|
|
11
11
|
|
12
12
|
def call
|
13
13
|
parser = Helmsnap::ArgsParser.new(args)
|
14
|
-
options = parser.get_options!
|
14
|
+
self.options = parser.get_options!
|
15
15
|
|
16
16
|
cmd, *rest = args
|
17
17
|
|
@@ -25,9 +25,9 @@ class Helmsnap::Runner
|
|
25
25
|
|
26
26
|
case cmd
|
27
27
|
when "generate"
|
28
|
-
|
28
|
+
generate!
|
29
29
|
when "check"
|
30
|
-
|
30
|
+
check!
|
31
31
|
else
|
32
32
|
parser.print_help!("Unknown command: #{cmd}.")
|
33
33
|
end
|
@@ -35,5 +35,33 @@ class Helmsnap::Runner
|
|
35
35
|
|
36
36
|
private
|
37
37
|
|
38
|
-
attr_accessor :args
|
38
|
+
attr_accessor :args, :options
|
39
|
+
|
40
|
+
def generate!
|
41
|
+
Helmsnap::Generate.call(**options.to_h)
|
42
|
+
Helmsnap::Console.info($stdout, "Snapshots generated successfully.")
|
43
|
+
end
|
44
|
+
|
45
|
+
def check!
|
46
|
+
if Helmsnap::Check.call(**options.to_h)
|
47
|
+
Helmsnap::Console.info($stdout, "Snapshots are up-to-date.")
|
48
|
+
else
|
49
|
+
example_cmd = Shellwords.join(
|
50
|
+
[
|
51
|
+
"helmsnap", "generate",
|
52
|
+
"--chart-dir", options.chart_path,
|
53
|
+
"--snapshots-dir", options.snapshots_path,
|
54
|
+
"--values", options.values_path
|
55
|
+
],
|
56
|
+
)
|
57
|
+
|
58
|
+
Helmsnap::Console.error(
|
59
|
+
$stdout,
|
60
|
+
"Snapshots are outdated. You should check the diff above and either fix your chart or " \
|
61
|
+
"update the snapshots using the following command:\n> #{example_cmd}",
|
62
|
+
)
|
63
|
+
|
64
|
+
exit 1
|
65
|
+
end
|
66
|
+
end
|
39
67
|
end
|
data/lib/helmsnap/version.rb
CHANGED
data/lib/helmsnap.rb
CHANGED
@@ -8,9 +8,12 @@ require "pathname"
|
|
8
8
|
require "shellwords"
|
9
9
|
require "tmpdir"
|
10
10
|
|
11
|
+
require "colorized_string"
|
12
|
+
|
11
13
|
module Helmsnap
|
12
14
|
require_relative "helmsnap/args_parser"
|
13
15
|
require_relative "helmsnap/check"
|
16
|
+
require_relative "helmsnap/console"
|
14
17
|
require_relative "helmsnap/command"
|
15
18
|
require_relative "helmsnap/generate"
|
16
19
|
require_relative "helmsnap/runner"
|
@@ -18,8 +21,8 @@ module Helmsnap
|
|
18
21
|
|
19
22
|
class Error < StandardError; end
|
20
23
|
|
21
|
-
def self.run_cmd
|
24
|
+
def self.run_cmd(*cmd_parts, **options)
|
22
25
|
cmd = Shellwords.join(cmd_parts)
|
23
|
-
Helmsnap::Command.call(cmd)
|
26
|
+
Helmsnap::Command.call(cmd, **options)
|
24
27
|
end
|
25
28
|
end
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: helmsnap
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yuri Smirnov
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-12-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: colorize
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: rubocop-config-umbrellio
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -32,8 +46,10 @@ executables:
|
|
32
46
|
extensions: []
|
33
47
|
extra_rdoc_files: []
|
34
48
|
files:
|
49
|
+
- ".dockerignore"
|
35
50
|
- ".rspec"
|
36
51
|
- ".rubocop.yml"
|
52
|
+
- Dockerfile
|
37
53
|
- Gemfile
|
38
54
|
- Gemfile.lock
|
39
55
|
- LICENSE.txt
|
@@ -47,6 +63,7 @@ files:
|
|
47
63
|
- lib/helmsnap/args_parser.rb
|
48
64
|
- lib/helmsnap/check.rb
|
49
65
|
- lib/helmsnap/command.rb
|
66
|
+
- lib/helmsnap/console.rb
|
50
67
|
- lib/helmsnap/generate.rb
|
51
68
|
- lib/helmsnap/runner.rb
|
52
69
|
- lib/helmsnap/version.rb
|
@@ -71,7 +88,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
71
88
|
- !ruby/object:Gem::Version
|
72
89
|
version: '0'
|
73
90
|
requirements: []
|
74
|
-
rubygems_version: 3.2.
|
91
|
+
rubygems_version: 3.2.32
|
75
92
|
signing_key:
|
76
93
|
specification_version: 4
|
77
94
|
summary: A tool for creating and checking helm chart snapshots.
|