helmsnap 0.5.1 → 0.6.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: 5f9aee0530e4f99cd1d96fbc07be33606ed5462ebbc08540c568a30848274b85
4
- data.tar.gz: e2937f100b5e2008d3db5d720a3e4d79393cc760da004bb1453ddab3485a5d50
3
+ metadata.gz: 00d1a53c6e09960c8a7b6d21e9998aba27e0765959b4450f2e433754440fe65b
4
+ data.tar.gz: 0f9fc47f9897eb76745e817528646ac340e43e39fad563a8370560bde810274f
5
5
  SHA512:
6
- metadata.gz: 872efd529c6367ca4dfe4468eae9a9d2164e844273a14e9cacea55e07c5c5a795509c7ece536c83e0be75e319651f44ef55d05816e967c4e841b4007d74d67c2
7
- data.tar.gz: fdb9c9d45daea1554f0d03083e582b6f57be0f78da265b39e4eb11f62e54a0b02fdb5e5abc91f6881c041aad3c47e5501736bd97bc244e0341342d6a4c33dce5
6
+ metadata.gz: d014a938da2ea497e3e751f5cb600940ccb77a1d7bd297399a7b3380ac74c2d5a47bb9b4c31f6a540992c72d3e1012540d19b264e49d3498ffc282cb4f63b68a
7
+ data.tar.gz: 17614166a76919b0353d7bf322062047c546c3256826758ef5d0991bf66e30ee7ad0552c117ebad489ecba205e7c4771340dde7c947975cd1101895954eb8fe9
data/Dockerfile CHANGED
@@ -2,8 +2,9 @@ FROM alpine/helm
2
2
 
3
3
  RUN apk add --update --no-cache ruby git colordiff
4
4
 
5
- WORKDIR /app
5
+ WORKDIR /wd
6
6
 
7
+ COPY --from=quay.io/roboll/helmfile:v0.142.0 /usr/local/bin/helmfile /usr/local/bin/helmfile
7
8
  COPY . .
8
9
 
9
10
  RUN gem install colorize && gem build && gem install helmsnap --local
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- helmsnap (0.5.1)
4
+ helmsnap (0.6.0)
5
5
  colorize
6
6
 
7
7
  GEM
@@ -23,7 +23,7 @@ GEM
23
23
  method_source (1.0.0)
24
24
  minitest (5.14.4)
25
25
  parallel (1.21.0)
26
- parser (3.0.3.0)
26
+ parser (3.0.3.1)
27
27
  ast (~> 2.4.1)
28
28
  pry (0.14.1)
29
29
  coderay (~> 1.1)
@@ -31,7 +31,7 @@ GEM
31
31
  rack (2.2.3)
32
32
  rainbow (3.0.0)
33
33
  rake (13.0.6)
34
- regexp_parser (2.1.1)
34
+ regexp_parser (2.2.0)
35
35
  rexml (3.2.5)
36
36
  rspec (3.10.0)
37
37
  rspec-core (~> 3.10.0)
@@ -55,7 +55,7 @@ GEM
55
55
  rubocop-ast (>= 1.7.0, < 2.0)
56
56
  ruby-progressbar (~> 1.7)
57
57
  unicode-display_width (>= 1.4.0, < 3.0)
58
- rubocop-ast (1.13.0)
58
+ rubocop-ast (1.14.0)
59
59
  parser (>= 3.0.1.1)
60
60
  rubocop-config-umbrellio (1.17.0.53)
61
61
  rubocop (= 1.17.0)
data/README.md CHANGED
@@ -4,16 +4,16 @@
4
4
 
5
5
  Helmsnap is a tool for generating and checking helm chart snapshots. Example:
6
6
 
7
- Generate snapshots (uses `helm template` under the hood):
7
+ Generate snapshots (uses `helmfile template` under the hood):
8
8
 
9
9
  ```sh
10
- helmsnap generate -c helm/mychart -s helm/snapshots -v helm/values/production.yaml
10
+ helmsnap generate
11
11
  ```
12
12
 
13
- Generate snapshots in some temp directory and check (diff) them against existing snapshots in `helm/snapshots` directory:
13
+ Generate snapshots in a temporary directory and check (diff) them against existing snapshots in `helm/snapshots` directory:
14
14
 
15
15
  ```sh
16
- helmsnap check -c helm/mychart -s helm/snapshots -v helm/values/production.yaml
16
+ helmsnap check
17
17
  ```
18
18
 
19
19
  Get the full description of possible arguments:
@@ -30,6 +30,23 @@ The typical usage flow:
30
30
 
31
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.
32
32
 
33
+ ## Configuration
34
+
35
+ By default, helmsnap will render your helmfile using `default` environment and will place snapshots in `helm/snapshots` directory. If you want to configure that, create a `.helmsnap.yaml` file and put there configuration that looks like this:
36
+
37
+ ```yaml
38
+ envs: [staging, production] # `[default]` by default
39
+ snapshotsPath: somedir/snapshots # `helm/snapshots` by default
40
+ ```
41
+
42
+ You can also override configuration file location using `--config` option.
43
+
44
+ ## Dependencies
45
+
46
+ - Ruby 2.7+.
47
+ - [Helmfile](https://github.com/roboll/helmfile), which in turn relies on [Helm](https://github.com/helm/helm).
48
+ - Colordiff or diff utility.
49
+
33
50
  ## Features
34
51
 
35
52
  ### Helm dependency management
@@ -58,7 +75,7 @@ Example job for Gitlab CI:
58
75
  check-snapshots:
59
76
  stage: test
60
77
  image: ghcr.io/tycooon/helmsnap:latest
61
- script: helmsnap check -c helm/mychart -s helm/snapshots -v helm/values/production.yaml
78
+ script: helmsnap check
62
79
  ```
63
80
 
64
81
  ## Contributing
@@ -1,22 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Helmsnap::ArgsParser
4
- Args = Struct.new(:chart_path, :snapshots_path, :values_path, keyword_init: true)
5
- MissingOption = Class.new(OptionParser::ParseError)
4
+ Args = Struct.new(:config_path)
6
5
 
6
+ DEFAULT_CONFIG_PATH = ".helmsnap.yaml"
7
+ CONFIG_PATH_HELP = %{Path to config (default: "#{DEFAULT_CONFIG_PATH}")}
7
8
  BANNER = "Usage: helmsnap CMD [options]"
8
9
 
9
10
  def initialize(options)
10
11
  self.options = options
11
- self.args = Args.new
12
+ self.args = Args.new(DEFAULT_CONFIG_PATH)
12
13
  self.parser = build_parser
13
14
  end
14
15
 
15
16
  def get_options!
16
17
  parser.parse!(options)
17
- raise MissingOption, "Missing option: CHARTDIR" unless args.chart_path
18
- raise MissingOption, "Missing option: SNAPDIR" unless args.snapshots_path
19
- raise MissingOption, "Missing option: VALUES" unless args.values_path
20
18
  args
21
19
  rescue OptionParser::ParseError => error
22
20
  print_help!(error)
@@ -32,22 +30,14 @@ class Helmsnap::ArgsParser
32
30
 
33
31
  attr_accessor :options, :parser, :args
34
32
 
35
- def build_parser # rubocop:disable Metrics/MethodLength
33
+ def build_parser
36
34
  OptionParser.new(BANNER, 50) do |opts|
37
35
  opts.separator("Supported commands: `generate` and `check`.")
38
36
  opts.separator("")
39
37
  opts.separator("Specific options:")
40
38
 
41
- opts.on("-c", "--chart-dir CHARTDIR", "Chart directory") do |option|
42
- args.chart_path = pn(option)
43
- end
44
-
45
- opts.on("-s", "--snapshots-dir SNAPDIR", "Snapshots directory") do |option|
46
- args.snapshots_path = pn(option)
47
- end
48
-
49
- opts.on("-v", "--values VALUES", "Values file") do |option|
50
- args.values_path = pn(option)
39
+ opts.on("-c", "--config CONFIG_PATH", CONFIG_PATH_HELP) do |val|
40
+ args.config_path = Pathname.new(val)
51
41
  end
52
42
 
53
43
  opts.on("--version", "Show version") do
@@ -61,8 +51,4 @@ class Helmsnap::ArgsParser
61
51
  end
62
52
  end
63
53
  end
64
-
65
- def pn(...)
66
- Pathname.new(...)
67
- end
68
54
  end
@@ -1,26 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Helmsnap::Check < Helmsnap::Service
4
- def initialize(chart_path:, snapshots_path:, values_path:)
4
+ def initialize(config)
5
5
  super()
6
- self.chart_path = chart_path
7
- self.snapshots_path = snapshots_path
8
- self.values_path = values_path
6
+ self.config = config
9
7
  end
10
8
 
11
9
  def call
12
10
  temp_dir_path = Pathname.new(Dir.mktmpdir)
13
11
 
14
- Helmsnap::Generate.call(
15
- chart_path: chart_path,
16
- snapshots_path: temp_dir_path,
17
- values_path: values_path,
18
- )
12
+ Helmsnap::Generate.call(config, snapshots_path: temp_dir_path)
19
13
 
20
14
  result = run_cmd("which", "colordiff", allow_failure: true)
21
15
  util = result.success ? "colordiff" : "diff"
22
16
 
23
- cmd_parts = [util, "--unified", "--recursive", snapshots_path, temp_dir_path]
17
+ cmd_parts = [util, "--unified", "--recursive", config.snapshots_path, temp_dir_path]
24
18
  diff = run_cmd(*cmd_parts, allow_failure: true).output
25
19
 
26
20
  diff.strip.empty?
@@ -30,5 +24,5 @@ class Helmsnap::Check < Helmsnap::Service
30
24
 
31
25
  private
32
26
 
33
- attr_accessor :chart_path, :snapshots_path, :values_path
27
+ attr_accessor :config
34
28
  end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Helmsnap::Config
4
+ attr_reader :envs, :snapshots_path
5
+
6
+ DEFAULT_ENV = "default"
7
+
8
+ def initialize(config_path)
9
+ yaml = YAML.load_file(config_path.to_s)
10
+ self.envs = parse_envs(yaml)
11
+ self.snapshots_path = parse_snaphots_path(yaml)
12
+ end
13
+
14
+ private
15
+
16
+ attr_writer :envs, :snapshots_path
17
+
18
+ def parse_envs(yaml)
19
+ # TODO: check value type
20
+ value = yaml.fetch("envs", [DEFAULT_ENV])
21
+ value.map { |x| Helmsnap::Env.new(x) }
22
+ end
23
+
24
+ def parse_snaphots_path(yaml)
25
+ # TODO: chekc value type/presence
26
+ Pathname.new(yaml.fetch("snapshotsPath"))
27
+ end
28
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Helmsnap::Env
4
+ attr_reader :name, :release_paths
5
+
6
+ def initialize(name)
7
+ self.name = name
8
+ self.release_paths = get_release_paths
9
+ end
10
+
11
+ private
12
+
13
+ attr_writer :name, :release_paths
14
+
15
+ def get_release_paths
16
+ json = Helmsnap.run_cmd("helmfile", "--environment", name, "list", "--output", "json").output
17
+ YAML.load(json).map { |x| x.fetch("chart") }
18
+ end
19
+ end
@@ -1,21 +1,30 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Helmsnap::Generate < Helmsnap::Service
4
- def initialize(chart_path:, snapshots_path:, values_path:)
4
+ def initialize(config, snapshots_path: nil)
5
5
  super()
6
- self.chart_path = chart_path
7
- self.snapshots_path = snapshots_path
8
- self.values_path = values_path
6
+ self.config = config
7
+ self.snapshots_path = snapshots_path || config.snapshots_path
9
8
  end
10
9
 
11
10
  def call
12
- Helmsnap::SetupDependencies.call(chart_path)
13
-
14
11
  FileUtils.rmtree(snapshots_path)
15
12
 
16
- run_cmd(
17
- "helm", "template", chart_path, "--values", values_path, "--output-dir", snapshots_path
18
- )
13
+ config.envs.flat_map(&:release_paths).uniq.each do |release_path|
14
+ Helmsnap::SetupDependencies.call(release_path)
15
+ end
16
+
17
+ config.envs.each do |env|
18
+ run_cmd(
19
+ "helmfile",
20
+ "--environment",
21
+ env.name,
22
+ "template",
23
+ "--output-dir-template",
24
+ snapshots_path.join(env.name).join("{{ .Release.Name }}"),
25
+ "--skip-deps",
26
+ )
27
+ end
19
28
 
20
29
  snapshots_path.glob(["**/*yaml", "**/*.yml"]).each do |path|
21
30
  content = path.read
@@ -26,5 +35,5 @@ class Helmsnap::Generate < Helmsnap::Service
26
35
 
27
36
  private
28
37
 
29
- attr_accessor :chart_path, :snapshots_path, :values_path
38
+ attr_accessor :config, :snapshots_path
30
39
  end
@@ -9,6 +9,7 @@ class Helmsnap::Runner < Helmsnap::Service
9
9
  def call
10
10
  parser = Helmsnap::ArgsParser.new(args)
11
11
  self.options = parser.get_options!
12
+ self.config = Helmsnap::Config.new(options.config_path)
12
13
 
13
14
  cmd, *rest = args
14
15
 
@@ -32,25 +33,18 @@ class Helmsnap::Runner < Helmsnap::Service
32
33
 
33
34
  private
34
35
 
35
- attr_accessor :args, :options
36
+ attr_accessor :args, :options, :config
36
37
 
37
38
  def generate!
38
- Helmsnap::Generate.call(**options.to_h)
39
+ Helmsnap::Generate.call(config)
39
40
  Helmsnap::Console.info($stdout, "Snapshots generated successfully.")
40
41
  end
41
42
 
42
43
  def check!
43
- if Helmsnap::Check.call(**options.to_h)
44
+ if Helmsnap::Check.call(config)
44
45
  Helmsnap::Console.info($stdout, "Snapshots are up-to-date.")
45
46
  else
46
- example_cmd = Shellwords.join(
47
- [
48
- "helmsnap", "generate",
49
- "--chart-dir", options.chart_path,
50
- "--snapshots-dir", options.snapshots_path,
51
- "--values", options.values_path
52
- ],
53
- )
47
+ example_cmd = Shellwords.join(["helmsnap", "generate", "--config", options.config_path])
54
48
 
55
49
  Helmsnap::Console.error(
56
50
  $stdout,
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Helmsnap
4
- VERSION = "0.5.1"
4
+ VERSION = "0.6.0"
5
5
  end
data/lib/helmsnap.rb CHANGED
@@ -7,10 +7,13 @@ require "optparse"
7
7
  require "pathname"
8
8
  require "shellwords"
9
9
  require "tmpdir"
10
+ require "yaml"
10
11
 
11
12
  require "colorized_string"
12
13
 
13
14
  module Helmsnap
15
+ require_relative "helmsnap/config"
16
+ require_relative "helmsnap/env"
14
17
  require_relative "helmsnap/service"
15
18
  require_relative "helmsnap/version"
16
19
 
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.5.1
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yuri Smirnov
@@ -63,7 +63,9 @@ files:
63
63
  - lib/helmsnap/args_parser.rb
64
64
  - lib/helmsnap/check.rb
65
65
  - lib/helmsnap/command.rb
66
+ - lib/helmsnap/config.rb
66
67
  - lib/helmsnap/console.rb
68
+ - lib/helmsnap/env.rb
67
69
  - lib/helmsnap/generate.rb
68
70
  - lib/helmsnap/runner.rb
69
71
  - lib/helmsnap/service.rb