helmsnap 0.2.0 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d23d2a85913e1acb605cf90521fdcf9f9ce6a3c95bfcecc24b1aae69a68d33a6
4
- data.tar.gz: 927df5851020d802c04de2c2ebcb8e0c8078869087e7db735c39f02d1168b6bf
3
+ metadata.gz: 926b5a2923e842e0fe10f3d2050e785a0a140edbb0c3de40c30880e9e7dac3ba
4
+ data.tar.gz: 5f99aaac6f14b66727365bbde866896f9c75bd98e129d48de07d76ebdd7ff6a2
5
5
  SHA512:
6
- metadata.gz: 25a1d7514779a13e738169c2119bfc9ea27b1f5f092d2ac15fc381749763a5210efc07a8b52546eb7bc4045b3a6330d0e37176c8eea8bfb756176564551dfdda
7
- data.tar.gz: 3ae5fe678eb301418175f688adc06478b7ac5b7e775d9a9e16e1bf5fcb97c8d48ed763fd7895ccddabe21d2e72e26acfb3616340ce1b4ab630d1ad0898b8baff
6
+ metadata.gz: 1ba861f010040454c80b4413f3b5e7b74213e0ad041f6c8311ca8295bfb06b71a04a98323f2b6714691e2450f0ce54897ff340a2534cfa66cd79f73884741614
7
+ data.tar.gz: 4e164358cf3084a01fc026fcf44670939c6871035883afde758624f31b31739a6fc48d610e9a6a81204fef8535e9c417c95e705c02998a07edf7913e28a16745
data/.dockerignore ADDED
@@ -0,0 +1,8 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
data/Dockerfile ADDED
@@ -0,0 +1,12 @@
1
+ FROM alpine/helm
2
+
3
+ RUN apk add --update --no-cache ruby git colordiff
4
+
5
+ WORKDIR /app
6
+
7
+ COPY . .
8
+
9
+ RUN gem install colorize && gem build && gem install helmsnap --local
10
+
11
+ ENTRYPOINT []
12
+ CMD []
data/Gemfile.lock CHANGED
@@ -1,7 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- helmsnap (0.1.0)
4
+ helmsnap (0.3.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.31
100
+ 2.2.32
data/README.md CHANGED
@@ -1,38 +1,69 @@
1
1
  # Helmsnap
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/helmsnap`. To experiment with that code, run `bin/console` for an interactive prompt.
3
+ ## About
4
4
 
5
- TODO: Delete this and the text above, and describe your gem
5
+ Helmsnap is a tool for generating and checking helm chart snapshots. Example:
6
6
 
7
- ## Installation
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
+ ```
8
12
 
9
- Add this line to your application's Gemfile:
13
+ Generate snapshots in some temp directory and check (diff) them against existing snapshots in `helm/snapshots` directory:
10
14
 
11
- ```ruby
12
- gem 'helmsnap'
15
+ ```sh
16
+ helmsnap check -c helm/mychart -s helm/snapshots -v helm/values/production.yaml
13
17
  ```
14
18
 
15
- And then execute:
19
+ Get the full description of possible arguments:
20
+
21
+ ```sh
22
+ helmsnap --help
23
+ ```
24
+
25
+ The typical usage flow:
26
+
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`.
16
30
 
17
- $ bundle install
31
+ ## Features
18
32
 
19
- Or install it yourself as:
33
+ ### Helm dependency management
20
34
 
21
- $ gem install helmsnap
35
+ 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.
22
36
 
23
- ## Usage
37
+ ### Timestamp replacement
24
38
 
25
- TODO: Write usage instructions here
39
+ 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.
26
40
 
27
- ## Development
41
+ ## Installation
42
+
43
+ Just install a gem and use the provided `helmsnap` binary.
44
+
45
+ ```sh
46
+ gem install helmsnap
47
+ ```
28
48
 
29
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
49
+ 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.
30
50
 
31
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
51
+ ## CI example
52
+
53
+ Example job for Gitlab CI:
54
+
55
+ ```yaml
56
+ check-snapshots:
57
+ stage: test
58
+ image:
59
+ name: ghcr.io/tycooon/helmsnap:master
60
+ entrypoint: []
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 on GitHub at https://github.com/tycooon/helmsnap.
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
@@ -30,5 +30,7 @@ Gem::Specification.new do |spec|
30
30
  spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
31
31
  spec.require_paths = ["lib"]
32
32
 
33
+ spec.add_dependency "colorize"
34
+
33
35
  spec.add_development_dependency "rubocop-config-umbrellio"
34
36
  end
@@ -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
- puts msg, nil
25
- puts parser.help
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
- puts opts
59
+ print_help!(nil)
54
60
  exit
55
61
  end
56
62
  end
@@ -13,7 +13,7 @@ class Helmsnap::Check
13
13
 
14
14
  def call
15
15
  Dir.mktmpdir do |temp_dir|
16
- pp temp_dir_path = Pathname.new(temp_dir)
16
+ temp_dir_path = Pathname.new(temp_dir)
17
17
 
18
18
  Helmsnap::Generate.call(
19
19
  chart_path: chart_path,
@@ -21,7 +21,11 @@ class Helmsnap::Check
21
21
  values_path: values_path,
22
22
  )
23
23
 
24
- Helmsnap.run_cmd!("colordiff", "-r", temp_dir_path, snapshots_path)
24
+ result = Helmsnap.run_cmd("which", "colordiff", allow_failure: true)
25
+ util = result.success ? "colordiff" : "diff"
26
+
27
+ diff = Helmsnap.run_cmd(util, "-r", temp_dir_path, snapshots_path, allow_failure: true).output
28
+ diff.strip.empty?
25
29
  end
26
30
  end
27
31
 
@@ -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
- puts "\e[1m\e[33m#{cmd}\e[0m\e[22m"
18
+ Helmsnap::Console.info(stdout, "> #{cmd}")
19
+ run_command
20
+ end
21
+
22
+ private
14
23
 
15
- Open3.popen3(cmd) do |_stdin, stdout, stderr, wait_thr|
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 = stdout.gets)
19
- $stdout.print(chunk)
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
- unless exit_status.success?
26
- $stderr.print(stderr.read)
27
- abort "Command failed with status #{exit_status.to_i}"
38
+ if !success && !allow_failure
39
+ Helmsnap::Console.error(stderr, err.read, :red)
40
+ Helmsnap::Console.error(stderr, "Command failed with status #{exit_status.to_i}", :red)
41
+ abort
28
42
  end
29
43
 
30
- puts
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
@@ -12,21 +12,21 @@ class Helmsnap::Generate
12
12
  end
13
13
 
14
14
  def call
15
- dep_list = run_cmd!("helm", "dependency", "list", "--max-col-width", 0, chart_path)
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!("helm", "dependency", "update", "--skip-refresh", chart_path.join(dep_path.first))
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!("helm", "repo", "add", Digest::MD5.hexdigest(dep_path.first), dep_path.first)
22
+ run_cmd("helm", "repo", "add", Digest::MD5.hexdigest(dep_path.first), dep_path.first)
23
23
  end
24
24
 
25
- run_cmd!("helm", "dependency", "update", "--skip-refresh", chart_path)
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
@@ -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
- Helmsnap::Generate.call(**options.to_h)
28
+ generate!
29
29
  when "check"
30
- Helmsnap::Check.call(**options.to_h)
30
+ check!
31
31
  else
32
32
  parser.print_help!("Unknown command: #{cmd}.")
33
33
  end
@@ -35,5 +35,24 @@ 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
+ Helmsnap::Console.error(
50
+ $stdout,
51
+ "Snapshots are outdated, you should check the diff above and either fix your chart or " \
52
+ "update the snapshots using `helmsnap generate` command.",
53
+ )
54
+
55
+ exit 1
56
+ end
57
+ end
39
58
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Helmsnap
4
- VERSION = "0.2.0"
4
+ VERSION = "0.3.0"
5
5
  end
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!(*cmd_parts)
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,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: helmsnap
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yuri Smirnov
@@ -10,6 +10,20 @@ bindir: exe
10
10
  cert_chain: []
11
11
  date: 2021-11-27 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.31
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.