Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create a basic CLI for rendering templates #20

Merged
merged 1 commit into from
Jan 2, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,16 @@ Pre-existing copies of files generated by Consult (such as `secrets.yml`, `datab

If this gem is included in a Rails, the templates will render on Rails boot. Configuration or credential changes can be picked up by restarting your app.

### CLI

Render templates on demand with the CLI. By default, this will bypass template TTLs to force rendering and provide verbose output. See `consult --help` for options.

```bash
$ bundle exec consult
Consult: Rendered my_config
Consult: Rendered secrets
```

### Configuration

```yaml
Expand Down
7 changes: 7 additions & 0 deletions bin/consult
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/env ruby

require_relative '../lib/consult/cli'

cli = Consult::CLI.instance
cli.parse
cli.render
7 changes: 3 additions & 4 deletions consult.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,18 @@ Gem::Specification.new do |spec|
spec.files = `git ls-files -z`.split("\x0").reject do |f|
f.match(%r{^(test|spec|features)/})
end
spec.bindir = 'exe'
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
spec.bindir = 'bin'
spec.executables = ['consult']
spec.require_paths = ['lib']

spec.add_dependency 'activesupport', '> 4', '< 6'
spec.add_dependency 'diplomat', '~> 2.0.2'
spec.add_dependency 'vault', '>= 0.10.0', '< 1.0.0'

spec.add_development_dependency 'bundler', '~> 1.16'
spec.add_development_dependency 'byebug'
spec.add_development_dependency 'guard'
spec.add_development_dependency 'guard-rspec'
spec.add_development_dependency 'pry'
spec.add_development_dependency 'pry-byebug'
spec.add_development_dependency 'rake', '~> 10.0'
spec.add_development_dependency 'rspec', '~> 3.0'
spec.add_development_dependency 'simplecov'
Expand Down
11 changes: 7 additions & 4 deletions lib/consult.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,19 @@ module Consult
CONSUL_DISK_TOKEN = Pathname.new("#{Dir.home}/.consul-token").freeze

class << self
attr_reader :config, :templates
def load(config_dir: nil)
attr_reader :config, :templates, :force_render

def load(config_dir: nil, force_render: false, verbose: nil)
root directory: config_dir
yaml = root.join('config', 'consult.yml')

@all_config = yaml.exist? ? YAML.safe_load(ERB.new(yaml.read).result, [], [], true).to_h : {}
@all_config.deep_symbolize_keys!

@config = @all_config[:shared].to_h.deep_merge @all_config[env&.to_sym].to_h
@templates = @config[:templates]&.map { |name, config| Template.new(name, config) } || []
@templates = @config[:templates]&.map { |name, config| Template.new(name, config.merge(verbose: verbose)) } || []

@force_render = force_render

configure_consul
configure_vault
Expand Down Expand Up @@ -71,7 +74,7 @@ def env

# Return only the templates that are relevant for the current environment
def active_templates
templates.select(&:should_render?)
force_render ? templates : templates.select(&:should_render?)
end

# Render templates.
Expand Down
55 changes: 55 additions & 0 deletions lib/consult/cli.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# frozen_string_literal: true

$stdout.sync = true

require 'singleton'
require 'optparse'

require_relative '../consult'

module Consult
class CLI
include Singleton

attr_reader :opts

def parse(args = ARGV)
@opts = parse_options(args)
Consult.load @opts
end

def render
Consult.render!
end

def parse_options(argv)
opts = {
config_dir: Dir.pwd,
force_render: true,
verbose: true
}

@parser = OptionParser.new do |o|
o.on '-d', '--directory=DIR', 'Path to directory containing the config directory' do |arg|
opts[:config_dir] = arg
end

o.on '-f', '--[no-]force', TrueClass, 'Ignore template TTLs and force rendering' do |arg|
opts[:force_render] = arg
end

o.on '-v', '--quiet', FalseClass, 'Silence output' do |arg|
opts[:verbose] = arg
end
end

@parser.on_tail "-h", "--help", "Show help" do
puts @parser
exit 1
end

@parser.parse! argv
opts
end
end
end
5 changes: 5 additions & 0 deletions lib/consult/template.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ def render(save: true)
result = renderer.result(binding)

File.open(dest, 'w') { |f| f << result } if save
puts "Consult: Rendered #{name}" if verbose?
result
rescue StandardError => e
STDERR.puts "Error rendering template: #{name}"
Expand Down Expand Up @@ -55,6 +56,10 @@ def expired?
dest.mtime < (Time.now - @config[:ttl].to_i)
end

def verbose?
@config[:verbose]
end

def ordered_locations
@config.keys & LOCATIONS
end
Expand Down
28 changes: 28 additions & 0 deletions spec/bin/cli_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# frozen_string_literal: true

require 'consult/cli'

RSpec.describe Consult::CLI do
let(:cli) { Consult::CLI.instance }

describe 'options' do
it 'parses --directory' do
options = cli.parse ['--directory', 'spec/support']
expect(cli.opts[:config_dir]).to eq 'spec/support'
end

it 'parses --force' do
options = cli.parse ['--force']
expect(cli.opts[:force_render]).to be true
end

it 'parses --quiet' do
options = cli.parse ['--quiet']
expect(cli.opts[:verbose]).to be false
end
end

it 'renders' do
expect {cli.render}.not_to raise_exception
end
end
12 changes: 12 additions & 0 deletions spec/consult_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,16 @@
expect(FileUtils.compare_file("spec/support/expected/#{template}", "spec/support/rendered/#{template}")).to be true
end
end

it 'obeys TTLs' do
Consult.load config_dir: directory, force_render: false
Consult.render!
expect(Consult.active_templates).not_to eq(Consult.templates)
end

it 'can force template rendering' do
Consult.load config_dir: directory, force_render: true
Consult.render!
expect(Consult.active_templates).to eq Consult.templates
end
end
6 changes: 6 additions & 0 deletions spec/lib/template_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@
expect(template.should_render?).to be(true)
end

it 'supports verbose output' do
t = Consult::Template.new 'verbose', config.merge(verbose: true)
expect(t.verbose?).to be(true)
expect { t.render }.to output(/Consult: Rendered verbose/i).to_stdout_from_any_process
end

it 'outputs render failures to stderr' do
expect { fail_template.render }.to output(/Error rendering template*/).to_stderr_from_any_process
end
Expand Down