bourdain 1.2.13
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 +7 -0
- data/.gitignore +12 -0
- data/Gemfile +11 -0
- data/Rakefile +19 -0
- data/Readme.md +1 -0
- data/TODO.md +41 -0
- data/VERSION +1 -0
- data/bin/tony +54 -0
- data/bin/tony-bump +3 -0
- data/bin/tony-check +3 -0
- data/bin/tony-generate +3 -0
- data/bourdain.gemspec +25 -0
- data/install-or-upgrade.sh +4 -0
- data/lib/bourdain/helpers/config.rb +12 -0
- data/lib/bourdain/helpers/locals.rb +17 -0
- data/lib/bourdain/helpers/logger.rb +41 -0
- data/lib/bourdain/helpers/parser.rb +76 -0
- data/lib/bourdain/helpers/registry.rb +53 -0
- data/lib/bourdain/helpers.rb +32 -0
- data/lib/bourdain/metadata.rb +19 -0
- data/lib/bourdain/resources/checks/bourdain.rb +71 -0
- data/lib/bourdain/resources/checks/chef.rb +35 -0
- data/lib/bourdain/resources/checks/cookbooks.rb +97 -0
- data/lib/bourdain/resources/checks/hooks.rb +67 -0
- data/lib/bourdain/resources/checks/ssh_config.rb +61 -0
- data/lib/bourdain/resources/checks.rb +36 -0
- data/lib/bourdain/resources/commands/bump.rb +74 -0
- data/lib/bourdain/resources/commands/check.rb +103 -0
- data/lib/bourdain/resources/commands/generate.rb +33 -0
- data/lib/bourdain/resources/commands.rb +10 -0
- data/lib/bourdain/resources/generators/attribute.rb +43 -0
- data/lib/bourdain/resources/generators/cookbook.rb +125 -0
- data/lib/bourdain/resources/generators/recipe.rb +54 -0
- data/lib/bourdain/resources/generators.rb +22 -0
- data/lib/bourdain/resources.rb +104 -0
- data/lib/bourdain.rb +3 -0
- data/templates/chef/environment.json +8 -0
- data/templates/chef/role.json +9 -0
- data/templates/cookbook/Berksfile +3 -0
- data/templates/cookbook/Readme.md +1 -0
- data/templates/cookbook/VERSION +1 -0
- data/templates/cookbook/Vagrantfile +19 -0
- data/templates/cookbook/attributes/example.rb +24 -0
- data/templates/cookbook/busser_minitest.rb +7 -0
- data/templates/cookbook/gitignore +26 -0
- data/templates/cookbook/kitchen.yml +23 -0
- data/templates/cookbook/metadata.rb +10 -0
- data/templates/cookbook/pre-commit +80 -0
- data/templates/cookbook/recipes/example.rb +38 -0
- data/test.sh +12 -0
- metadata +165 -0
@@ -0,0 +1,67 @@
|
|
1
|
+
module Bourdain
|
2
|
+
module Checks
|
3
|
+
|
4
|
+
class HooksCheck < Check
|
5
|
+
usage :check, <<-END
|
6
|
+
Check the local copy of Kitchen hooks
|
7
|
+
hooks
|
8
|
+
END
|
9
|
+
|
10
|
+
|
11
|
+
def initialize _
|
12
|
+
super []
|
13
|
+
return unless require_chef!
|
14
|
+
check_hooks!
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
private
|
20
|
+
def check_hooks!
|
21
|
+
# Ensure we have an up-to-date copy of Kitchen hooks
|
22
|
+
hooks = File.join('utils', 'hooks')
|
23
|
+
|
24
|
+
ahead_of_remote = false
|
25
|
+
unless Dir.exists? hooks
|
26
|
+
log.warn "Hm, I don't see a copy of Kitchen hooks. I'll fix that for you..."
|
27
|
+
%x| git clone git@git.bluejeansnet.com:kitchen-hooks.git #{hooks} |
|
28
|
+
log.info "Your copy of Kitchen hooks is now up-to-date."
|
29
|
+
|
30
|
+
else
|
31
|
+
if youre_dirty? hooks
|
32
|
+
log.warn "Your copy of Kitchen hooks is dirty."
|
33
|
+
elsif youre_ahead? hooks
|
34
|
+
log.warn "Your copy of Kitchen hooks is ahead of the remote."
|
35
|
+
ahead_of_remote = true
|
36
|
+
elsif youre_behind? hooks
|
37
|
+
log.warn "Hey, looks like your copy of Kitchen hooks is out-of-date. I'll fix that for you..."
|
38
|
+
Dir.chdir(bourdain) { %x| git pull | }
|
39
|
+
log.info "Your copy of Kitchen hooks is now up-to-date."
|
40
|
+
else
|
41
|
+
log.info "Your copy of Kitchen hooks looks up-to-date."
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
matches = File.read('Gemfile.lock').match(/kitchen_hooks \((.*?)\)$/)
|
46
|
+
|
47
|
+
if matches.nil?
|
48
|
+
log.warn "Couldn't find Kitchen hooks in your Gemfile lock. Something is amiss..."
|
49
|
+
error!
|
50
|
+
|
51
|
+
else
|
52
|
+
repo_version = matches[1].strip
|
53
|
+
local_version = File.read(File.join(hooks, 'VERSION')).strip
|
54
|
+
|
55
|
+
if repo_version == local_version
|
56
|
+
log.info "Your Chef repo is bundled with the latest Kitchen hooks."
|
57
|
+
elsif ahead_of_remote
|
58
|
+
# Don't worry about it, we've already warned them
|
59
|
+
elsif local_version < repo_version
|
60
|
+
log.error 'Your Chef repo is bundled with an older Kitchen hooks. Try "bundle update".'
|
61
|
+
error!
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Bourdain
|
4
|
+
module Checks
|
5
|
+
|
6
|
+
class SSHConfigCheck < Check
|
7
|
+
usage :check, <<-END
|
8
|
+
Ensure all nodes are enterened into the local SSH config
|
9
|
+
ssh_config
|
10
|
+
END
|
11
|
+
|
12
|
+
|
13
|
+
def initialize cookbook_config
|
14
|
+
super []
|
15
|
+
return unless require_chef!
|
16
|
+
check_ssh_config!
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
private
|
22
|
+
def check_ssh_config! ssh_config=File.join(ENV['HOME'], '.ssh', 'config')
|
23
|
+
unless File::exist?(ssh_config)
|
24
|
+
log.warn 'Skipping SSH config check. File does not exist: %s' % ssh_config.inspect
|
25
|
+
return
|
26
|
+
end
|
27
|
+
|
28
|
+
nodes = Dir[File.join('nodes', '*.json')]
|
29
|
+
nodes = nodes.map do |path|
|
30
|
+
JSON::parse File.read(path)
|
31
|
+
end
|
32
|
+
|
33
|
+
config = File.read(ssh_config)
|
34
|
+
|
35
|
+
hosts = []
|
36
|
+
config.lines.select do |l|
|
37
|
+
l =~ /Host (\S+)/
|
38
|
+
hosts << $1 if $1
|
39
|
+
end
|
40
|
+
|
41
|
+
unconfigured_nodes = nodes.select do |n|
|
42
|
+
!hosts.include? n['name']
|
43
|
+
end
|
44
|
+
|
45
|
+
File.open(ssh_config, 'a') do |f|
|
46
|
+
f.puts unless unconfigured_nodes.empty?
|
47
|
+
unconfigured_nodes.each do |n|
|
48
|
+
log.info 'Adding %s to %s' % [ n['name'].inspect, ssh_config ]
|
49
|
+
f.puts "Host %s" % n['name']
|
50
|
+
f.puts "\tHostName\t%s" % n['name']
|
51
|
+
f.puts "\tPort\t22"
|
52
|
+
f.puts "\tUser\tvagrant"
|
53
|
+
f.puts "\tStrictHostKeyChecking\tno"
|
54
|
+
f.puts "\tIdentityFile\t~/.vagrant.d/insecure_private_key"
|
55
|
+
f.puts
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'erb'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
|
5
|
+
module Bourdain
|
6
|
+
module Checks
|
7
|
+
class Check < Bourdain::Resource
|
8
|
+
protected
|
9
|
+
def work_tree repo
|
10
|
+
"--work-tree=#{File.join(Dir.pwd, repo)}"
|
11
|
+
end
|
12
|
+
|
13
|
+
def git_dir repo
|
14
|
+
"--git-dir=#{File.join(Dir.pwd, repo, '.git')}"
|
15
|
+
end
|
16
|
+
|
17
|
+
def youre_behind? repo
|
18
|
+
`git #{git_dir repo} log ..origin/master --oneline`.split("\n").length > 0
|
19
|
+
end
|
20
|
+
|
21
|
+
def youre_ahead? repo
|
22
|
+
`git #{git_dir repo} log origin/master.. --oneline`.split("\n").length > 0
|
23
|
+
end
|
24
|
+
|
25
|
+
def youre_dirty? repo
|
26
|
+
`git #{git_dir repo} #{work_tree repo} diff HEAD --numstat`.split("\n").length > 0
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
require_relative 'checks/chef'
|
33
|
+
require_relative 'checks/hooks'
|
34
|
+
require_relative 'checks/bourdain'
|
35
|
+
require_relative 'checks/cookbooks'
|
36
|
+
require_relative 'checks/ssh_config'
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module Bourdain
|
2
|
+
module Commands
|
3
|
+
|
4
|
+
class BumpCommand < Command
|
5
|
+
usage :command, <<-END
|
6
|
+
Bump a VERSION file (patch by default)
|
7
|
+
bump [<options>] [<version-spec=major|minor|patch|x.y.z>]
|
8
|
+
END
|
9
|
+
|
10
|
+
def initialize argv
|
11
|
+
super
|
12
|
+
version_spec = argv.shift
|
13
|
+
version_spec = 'patch' if version_spec.nil?
|
14
|
+
verify! version_spec
|
15
|
+
return unless require_versionfile!
|
16
|
+
current_version = get_cookbook_version
|
17
|
+
new_version = bump_version version_spec, current_version
|
18
|
+
set_cookbook_version new_version
|
19
|
+
log.info "Bumped to #{new_version}."
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
private
|
24
|
+
def set_cookbook_version version
|
25
|
+
File.open('VERSION', 'w') { |f| f.write version }
|
26
|
+
end
|
27
|
+
|
28
|
+
def get_cookbook_version
|
29
|
+
File.open('VERSION').read.strip
|
30
|
+
end
|
31
|
+
|
32
|
+
def verify! version_spec
|
33
|
+
case version_spec
|
34
|
+
when /major/
|
35
|
+
:major
|
36
|
+
when /minor/
|
37
|
+
:minor
|
38
|
+
when /patch/
|
39
|
+
:patch
|
40
|
+
when /\d+\.\d+\.\d+/
|
41
|
+
:manual
|
42
|
+
else
|
43
|
+
Trollop::die 'Invalid <version-spec> provided'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def bump_version version_spec, version
|
48
|
+
type = verify! version_spec
|
49
|
+
|
50
|
+
# I'm not really that thinky, so I stole this from knife-spork:
|
51
|
+
#
|
52
|
+
# https://github.com/jonlives/knife-spork/blob/master/lib/chef/knife/spork-bump.rb
|
53
|
+
#
|
54
|
+
if type == :manual
|
55
|
+
version_array = version_spec.split('.')
|
56
|
+
|
57
|
+
else
|
58
|
+
field = case type
|
59
|
+
when :patch ; 2
|
60
|
+
when :minor ; 1
|
61
|
+
when :major ; 0
|
62
|
+
end
|
63
|
+
|
64
|
+
version_array = version.split('.').map(&:to_i)
|
65
|
+
version_array[field] += 1
|
66
|
+
((field + 1)..2).each { |i| version_array[i] = 0 }
|
67
|
+
end
|
68
|
+
|
69
|
+
version_array.join('.')
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
require 'pmap'
|
5
|
+
require 'gitlab'
|
6
|
+
|
7
|
+
|
8
|
+
module Bourdain
|
9
|
+
module Commands
|
10
|
+
|
11
|
+
class CheckCommand < Command
|
12
|
+
usage :command, <<-END
|
13
|
+
Check the state of the Kitchen, Bourdain and other things
|
14
|
+
check [<options>] [<check>]
|
15
|
+
<check>
|
16
|
+
END
|
17
|
+
|
18
|
+
|
19
|
+
|
20
|
+
def initialize argv
|
21
|
+
super
|
22
|
+
checks = Bourdain::Registry.specs('check')
|
23
|
+
maybe_check_position = checks.map { |c| argv.index c[:name].to_s }.compact.shift
|
24
|
+
check_position = maybe_check_position.nil? ? argv.length : maybe_check_position
|
25
|
+
|
26
|
+
options = argv.slice(0, check_position)
|
27
|
+
argv = argv.slice(check_position, argv.length)
|
28
|
+
|
29
|
+
super options
|
30
|
+
|
31
|
+
begin
|
32
|
+
gitlab_token = Bourdain::Config.items[:gitlab][:token]
|
33
|
+
rescue
|
34
|
+
log.fatal "Couldn't find your GitLab token in your config, bailing!"
|
35
|
+
error!
|
36
|
+
return
|
37
|
+
end
|
38
|
+
|
39
|
+
Gitlab.configure do |gitlab|
|
40
|
+
gitlab.endpoint = "http://#{Bourdain::GITLAB_HOST}/api/v3"
|
41
|
+
gitlab.private_token = gitlab_token
|
42
|
+
end
|
43
|
+
|
44
|
+
check = argv.shift
|
45
|
+
|
46
|
+
unless check.nil?
|
47
|
+
check = Bourdain::Registry.klass('check', check)
|
48
|
+
Trollop::die 'Invalid <check> provided' if check.nil?
|
49
|
+
end
|
50
|
+
|
51
|
+
return unless require_chef!
|
52
|
+
|
53
|
+
if check.nil?
|
54
|
+
@status = Bourdain::Registry.map('check') do |c|
|
55
|
+
c.new(cookbook_config_from_gitlab).status
|
56
|
+
end.sort.last
|
57
|
+
else
|
58
|
+
@status = check.new(cookbook_config_from_gitlab).status
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
|
64
|
+
private
|
65
|
+
def cookbook_config_from_gitlab
|
66
|
+
cookbook_configs = []
|
67
|
+
|
68
|
+
# Have to page results as GitLab absolutely will not return more than
|
69
|
+
# 100 results per page (even if we ask for more)
|
70
|
+
1.upto(25) do |page|
|
71
|
+
Gitlab.projects(per_page: 50, page: page).each do |project|
|
72
|
+
namespace, name = project.name_with_namespace.split(' / ', 2)
|
73
|
+
namespace = nil if name.nil?
|
74
|
+
next unless namespace == 'chef'
|
75
|
+
next if %w[ chef kitchen bourdain ].include? name
|
76
|
+
|
77
|
+
cookbook_name = name.sub(/^\w+?_/, '')
|
78
|
+
cookbook_path = name.sub(/^(\w+?)_/, '\1s/bjn_')
|
79
|
+
|
80
|
+
# Fork names shouldn't have the bjn_ prefix
|
81
|
+
if name =~ /^fork_/
|
82
|
+
cookbook_name.sub!(/(bjn|fork)_/, '')
|
83
|
+
cookbook_path.sub!(/(bjn|fork)_/, '')
|
84
|
+
end
|
85
|
+
|
86
|
+
name =~ /^(\w+?)_/
|
87
|
+
cookbook_type = $1.to_sym
|
88
|
+
|
89
|
+
cookbook_configs << {
|
90
|
+
name: cookbook_name,
|
91
|
+
type: cookbook_type,
|
92
|
+
path: cookbook_path,
|
93
|
+
repo: "#{namespace}/#{name}.git",
|
94
|
+
project: project
|
95
|
+
}
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
cookbook_configs
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Bourdain
|
2
|
+
module Commands
|
3
|
+
|
4
|
+
class GenerateCommand < Command
|
5
|
+
usage :command, <<-END
|
6
|
+
Generate various things. Take that, Chef DK!
|
7
|
+
generate [<options>] <generator>
|
8
|
+
<generator>
|
9
|
+
END
|
10
|
+
|
11
|
+
def initialize argv
|
12
|
+
generators = Bourdain::Registry.specs('generator')
|
13
|
+
maybe_generator_position = generators.map { |c| argv.index c[:name].to_s }.compact.shift
|
14
|
+
generator_position = maybe_generator_position.nil? ? argv.length : maybe_generator_position
|
15
|
+
generator_name = argv[generator_position]
|
16
|
+
|
17
|
+
options = argv.slice(0, generator_position)
|
18
|
+
argv = argv.slice(generator_position, argv.length)
|
19
|
+
|
20
|
+
super options
|
21
|
+
|
22
|
+
generator = nil
|
23
|
+
generator = argv.shift unless maybe_generator_position.nil?
|
24
|
+
Trollop::die 'Invalid <generator> provided' if generator.nil?
|
25
|
+
generator = Bourdain::Registry.klass('generator', generator_name)
|
26
|
+
Trollop::die 'Invalid <generator> provided' if generator.nil?
|
27
|
+
|
28
|
+
@status = generator.new(argv).status
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Bourdain
|
2
|
+
module Generators
|
3
|
+
|
4
|
+
class AttributeGenerator < Generator
|
5
|
+
usage :generator, <<-END
|
6
|
+
Generate a new attribute file in the current cookbook
|
7
|
+
attribute [<options>] <name>
|
8
|
+
END
|
9
|
+
|
10
|
+
|
11
|
+
def initialize argv
|
12
|
+
super
|
13
|
+
|
14
|
+
name = argv.shift
|
15
|
+
Trollop::die 'No <name> provided' if name.nil?
|
16
|
+
Trollop::die 'Invalid <name> provided' unless valid? name
|
17
|
+
name = normalized(name)
|
18
|
+
|
19
|
+
return unless require_cookbook!
|
20
|
+
|
21
|
+
FileUtils.mkdir_p 'attributes'
|
22
|
+
path = File.join('attributes', name + '.rb')
|
23
|
+
|
24
|
+
if File::exists? path
|
25
|
+
log.warn "Attribute file already exists. Doing nothing."
|
26
|
+
return
|
27
|
+
end
|
28
|
+
|
29
|
+
cookbook_name = File.basename Dir.pwd
|
30
|
+
|
31
|
+
apply_template path, \
|
32
|
+
template: %w[ cookbook attributes example.rb ],
|
33
|
+
locals: {
|
34
|
+
cookbook_name: cookbook_name,
|
35
|
+
name: name
|
36
|
+
}
|
37
|
+
|
38
|
+
log.info "Generated attribute file at #{path}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require 'trollop'
|
2
|
+
|
3
|
+
|
4
|
+
module Bourdain
|
5
|
+
module Generators
|
6
|
+
|
7
|
+
class CookbookGenerator < Generator
|
8
|
+
usage :generator, <<-END
|
9
|
+
Generate a new cookbook in the current repo
|
10
|
+
cookbook [<options>] <path>
|
11
|
+
--dot-chef (-c) :: Generate a .chef directory (default: false)
|
12
|
+
--git-init :: Initialize a git repository (default: true)
|
13
|
+
--attributes :: Generate a default attribute file (default: true)
|
14
|
+
--recipe :: Generate a default recipe (default: true)
|
15
|
+
--berksfile :: Generate a Berksfile (default: true)
|
16
|
+
--gitignore (-i) :: Generate a .gitignore (default: true)
|
17
|
+
--metadata :: Generate cookbook metadata (default: true)
|
18
|
+
--readme (-m) :: Generate a Readme (default: true)
|
19
|
+
--kitchenfile :: Generate a Test Kitchen file (default: true)
|
20
|
+
--vagrantfile :: Generate a Vagrantfile (default: true)
|
21
|
+
--versionfile (-z) :: Generate a VERSION file (default: true)
|
22
|
+
--pre-commit :: Generate a pre-commit hook (default: true)
|
23
|
+
--description (-p) <s> :: Description for resources
|
24
|
+
END
|
25
|
+
|
26
|
+
def initialize argv
|
27
|
+
super
|
28
|
+
|
29
|
+
path = argv.shift
|
30
|
+
Trollop::die 'No <path> provided' if path.nil?
|
31
|
+
Trollop::die 'Invalid <path> provided' unless valid? path
|
32
|
+
|
33
|
+
return unless require_chef!
|
34
|
+
|
35
|
+
if Dir::exists? path
|
36
|
+
log.warn "Cookbook already exists. Doing nothing."
|
37
|
+
return
|
38
|
+
end
|
39
|
+
|
40
|
+
name = File.basename(normalized(path))
|
41
|
+
|
42
|
+
FileUtils.mkdir_p path
|
43
|
+
|
44
|
+
if opts[:dot_chef]
|
45
|
+
FileUtils.mkdir_p File.join(path, '.chef/data_bags')
|
46
|
+
FileUtils.mkdir_p File.join(path, '.chef/nodes')
|
47
|
+
end
|
48
|
+
|
49
|
+
if opts[:attributes]
|
50
|
+
FileUtils.mkdir_p File.join(path, 'attributes')
|
51
|
+
apply_template File.join(path, 'attributes', 'default.rb'), \
|
52
|
+
template: %w[ cookbook attributes example.rb ], locals: {
|
53
|
+
name: 'default', cookbook_name: name
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
57
|
+
if opts[:recipe]
|
58
|
+
FileUtils.mkdir_p File.join(path, 'recipes')
|
59
|
+
apply_template File.join(path, 'recipes', 'default.rb'), \
|
60
|
+
template: %w[ cookbook recipes example.rb ], locals: {
|
61
|
+
name: 'default', cookbook_name: name
|
62
|
+
}
|
63
|
+
end
|
64
|
+
|
65
|
+
if opts[:berksfile]
|
66
|
+
apply_template File.join(path, 'Berksfile'), \
|
67
|
+
template: %w[ cookbook Berksfile ]
|
68
|
+
end
|
69
|
+
|
70
|
+
if opts[:gitignore]
|
71
|
+
apply_template File.join(path, '.gitignore'), \
|
72
|
+
template: %w[ cookbook gitignore ]
|
73
|
+
end
|
74
|
+
|
75
|
+
if opts[:metadata]
|
76
|
+
apply_template File.join(path, 'metadata.rb'), \
|
77
|
+
template: %w[ cookbook metadata.rb ], locals: { name: name }
|
78
|
+
end
|
79
|
+
|
80
|
+
if opts[:readme]
|
81
|
+
apply_template File.join(path, 'Readme.md'), \
|
82
|
+
template: %w[ cookbook Readme.md ], locals: { name: name }
|
83
|
+
end
|
84
|
+
|
85
|
+
if opts[:kitchenfile]
|
86
|
+
minitest_path = File.join(path, 'test', 'integration', 'default', 'minitest')
|
87
|
+
FileUtils.mkdir_p minitest_path
|
88
|
+
apply_template File.join(minitest_path, 'test_default.rb'), \
|
89
|
+
template: %w[ cookbook busser_minitest.rb ], locals: {
|
90
|
+
cookbook_name: name, recipe_name: 'default'
|
91
|
+
}
|
92
|
+
apply_template File.join(path, '.kitchen.yml'), \
|
93
|
+
template: %w[ cookbook kitchen.yml ], locals: { name: name }
|
94
|
+
end
|
95
|
+
|
96
|
+
if opts[:vagrantfile]
|
97
|
+
apply_template File.join(path, 'Vagrantfile'), \
|
98
|
+
template: %w[ cookbook Vagrantfile ], locals: { name: name }
|
99
|
+
end
|
100
|
+
|
101
|
+
if opts[:versionfile]
|
102
|
+
apply_template File.join(path, 'VERSION'), \
|
103
|
+
template: %w[ cookbook VERSION ]
|
104
|
+
end
|
105
|
+
|
106
|
+
if opts[:pre_commit]
|
107
|
+
hooks = File.join(path, '.git', 'hooks')
|
108
|
+
FileUtils.mkdir_p hooks
|
109
|
+
pre_commit_hook = File.join(hooks, 'pre-commit')
|
110
|
+
apply_template pre_commit_hook, template: %w[ cookbook pre-commit ]
|
111
|
+
FileUtils.chmod 0755, pre_commit_hook
|
112
|
+
end
|
113
|
+
|
114
|
+
if opts[:git_init]
|
115
|
+
Dir.chdir(path) do
|
116
|
+
`git init .`
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
log.info "Generated cookbook at #{path}."
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Bourdain
|
2
|
+
module Generators
|
3
|
+
|
4
|
+
class RecipeGenerator < Generator
|
5
|
+
usage :generator, <<-END
|
6
|
+
Generate a new recipe in the current cookbook
|
7
|
+
recipe [<options>] <name>
|
8
|
+
--minitest :: Generate a minitest file (default: true)
|
9
|
+
END
|
10
|
+
|
11
|
+
|
12
|
+
def initialize argv
|
13
|
+
super
|
14
|
+
|
15
|
+
name = argv.shift
|
16
|
+
Trollop::die 'No <name> provided' if name.nil?
|
17
|
+
Trollop::die 'Invalid <name> provided' unless valid? name
|
18
|
+
name = normalized(name)
|
19
|
+
|
20
|
+
return unless require_cookbook!
|
21
|
+
|
22
|
+
FileUtils.mkdir_p 'recipes'
|
23
|
+
path = File.join('recipes', name + '.rb')
|
24
|
+
|
25
|
+
if File::exists? path
|
26
|
+
log.warn 'Recipe already exists. Doing nothing.'
|
27
|
+
return
|
28
|
+
end
|
29
|
+
|
30
|
+
cookbook_name = File.basename Dir.pwd
|
31
|
+
|
32
|
+
apply_template path, \
|
33
|
+
template: %w[ cookbook recipes example.rb ],
|
34
|
+
locals: {
|
35
|
+
cookbook_name: cookbook_name,
|
36
|
+
name: name
|
37
|
+
}
|
38
|
+
|
39
|
+
if opts[:minitest]
|
40
|
+
minitest_path = File.join('test', 'integration', 'default', 'minitest', "test_#{name}.rb")
|
41
|
+
FileUtils.mkdir_p File.dirname(minitest_path)
|
42
|
+
apply_template minitest_path, \
|
43
|
+
template: %w[ cookbook busser_minitest.rb ], locals: {
|
44
|
+
cookbook_name: cookbook_name, recipe_name: name
|
45
|
+
}
|
46
|
+
log.info "Generated test for recipe at #{minitest_path}."
|
47
|
+
end
|
48
|
+
|
49
|
+
log.info "Generated recipe at #{path}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'erb'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
|
5
|
+
module Bourdain
|
6
|
+
module Generators
|
7
|
+
class Generator < Bourdain::Resource
|
8
|
+
protected
|
9
|
+
def valid? name
|
10
|
+
name =~ /[_a-z]+/
|
11
|
+
end
|
12
|
+
|
13
|
+
def normalized name
|
14
|
+
File::basename(name, '.rb')
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
require_relative 'generators/attribute'
|
21
|
+
require_relative 'generators/cookbook'
|
22
|
+
require_relative 'generators/recipe'
|