daptiv-chef-ci 0.0.15 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (30) hide show
  1. checksums.yaml +4 -4
  2. data/daptiv-chef-ci.gemspec +21 -20
  3. data/lib/daptiv-chef-ci/clone_environment_task.rb +69 -0
  4. data/lib/daptiv-chef-ci/logger.rb +9 -10
  5. data/lib/daptiv-chef-ci/raketask_helper.rb +5 -6
  6. data/lib/daptiv-chef-ci/shell.rb +50 -28
  7. data/lib/daptiv-chef-ci/upload_cookbook_task.rb +62 -0
  8. data/lib/daptiv-chef-ci/vagrant_destroy_task.rb +11 -12
  9. data/lib/daptiv-chef-ci/vagrant_driver.rb +47 -56
  10. data/lib/daptiv-chef-ci/vagrant_provision_task.rb +12 -15
  11. data/lib/daptiv-chef-ci/vagrant_task.rb +34 -57
  12. data/lib/daptiv-chef-ci/vagrant_up_task.rb +14 -16
  13. data/lib/daptiv-chef-ci/version_cookbook_task.rb +69 -0
  14. data/lib/daptiv-chef-ci/virtualbox_driver.rb +11 -12
  15. data/spec/daptiv-chef-ci/logger_spec.rb +11 -15
  16. data/spec/daptiv-chef-ci/shell_spec.rb +23 -27
  17. data/spec/daptiv-chef-ci/vagrant_destroy_task_spec.rb +5 -7
  18. data/spec/daptiv-chef-ci/vagrant_driver_spec.rb +34 -72
  19. data/spec/daptiv-chef-ci/vagrant_provision_task_spec.rb +9 -13
  20. data/spec/daptiv-chef-ci/vagrant_task_spec.rb +29 -21
  21. data/spec/daptiv-chef-ci/vagrant_up_task_spec.rb +9 -12
  22. data/spec/daptiv-chef-ci/virtualbox_driver_spec.rb +21 -16
  23. data/spec/shared_contexts/rake.rb +7 -7
  24. metadata +21 -14
  25. data/lib/daptiv-chef-ci/basebox_builder_factory.rb +0 -19
  26. data/lib/daptiv-chef-ci/virtualbox_basebox_builder.rb +0 -33
  27. data/lib/daptiv-chef-ci/vmware_basebox_builder.rb +0 -103
  28. data/spec/daptiv-chef-ci/basebox_builder_factory_spec.rb +0 -25
  29. data/spec/daptiv-chef-ci/virtualbox_basebox_builder_spec.rb +0 -20
  30. data/spec/daptiv-chef-ci/vmware_basebox_builder_spec.rb +0 -20
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 829ea781a4a70546ff1b3ec4b548c30567bb6344
4
- data.tar.gz: 56e8f9b1dda7737427467d842b06e9b6543eea85
3
+ metadata.gz: cfeeac6ae1094f6d486f92af9fca0fc1a1915ec9
4
+ data.tar.gz: 489147267747924a25c9e1f6e350881f01996a35
5
5
  SHA512:
6
- metadata.gz: 7e2b012c9f7dacb4e49165af23db194dd201ed1c50e89e37cdb0dac6955f80cdb28f476d9c7af7d66b78cf5a696046ae901ab5a14f97a07b12ced9ab0f1656d7
7
- data.tar.gz: 5f72fd850b5d95a72184d84f1904d2605a6456c1a38763fffda62683b29adb2eb695801c1399f8a84258199dd22a56b5feaaea834cdfcf892940fed085581287
6
+ metadata.gz: 5707f54b532a6299e7f446add8ceaef337840207d337190cd8a7c9772e7e87362cbf922ee7f92342506d015459fa9d30f9601def5dee61ba93d1d8450eb5374b
7
+ data.tar.gz: 41db757953a4c6ce7100eff2217719354d71667763367b4969acb1d87e344f904c56ac0e7bd98759f1358c514df8d146ac37bb8d5e6f82be7ab213089f5b4b0f
@@ -1,11 +1,11 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
 
3
3
  Gem::Specification.new do |gem|
4
- gem.authors = ["Shawn Neal"]
5
- gem.email = ["sneal@daptiv.com"]
6
- gem.description = %q{Vagrant automation for CI}
7
- gem.summary = %q{A small gem to reduce Rake duplication}
8
- gem.homepage = ""
4
+ gem.authors = ['Shawn Neal']
5
+ gem.email = ['sneal@daptiv.com']
6
+ gem.description = 'Vagrant automation for CI'
7
+ gem.summary = 'A small gem to reduce Rake duplication'
8
+ gem.homepage = ''
9
9
 
10
10
  # The following block of code determines the files that should be included
11
11
  # in the gem. It does this by reading all the files in the directory where
@@ -13,9 +13,9 @@ Gem::Specification.new do |gem|
13
13
  # Note that the entire gitignore(5) syntax is not supported, specifically
14
14
  # the "!" syntax, but it should mostly work correctly.
15
15
  root_path = File.dirname(__FILE__)
16
- all_files = Dir.chdir(root_path) { Dir.glob("**/{*,.*}") }
17
- all_files.reject! { |file| [".", ".."].include?(File.basename(file)) }
18
- gitignore_path = File.join(root_path, ".gitignore")
16
+ all_files = Dir.chdir(root_path) { Dir.glob('**/{*,.*}') }
17
+ all_files.reject! { |file| ['.', '..'].include?(File.basename(file)) }
18
+ gitignore_path = File.join(root_path, '.gitignore')
19
19
  gitignore = File.readlines(gitignore_path)
20
20
  gitignore.map! { |line| line.chomp.strip }
21
21
  gitignore.reject! { |line| line.empty? || line =~ /^(#|!)/ }
@@ -34,22 +34,23 @@ Gem::Specification.new do |gem|
34
34
  #
35
35
  gitignore.any? do |ignore|
36
36
  File.fnmatch(ignore, file, File::FNM_PATHNAME) ||
37
- File.fnmatch(ignore, File.basename(file), File::FNM_PATHNAME)
37
+ File.fnmatch(ignore, File.basename(file), File::FNM_PATHNAME)
38
38
  end
39
39
  end
40
40
 
41
41
  gem.files = unignored_files
42
- gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
42
+ gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
43
43
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
44
- gem.name = "daptiv-chef-ci"
45
- gem.require_paths = ["lib"]
46
- gem.version = '0.0.15'
47
-
48
- gem.add_runtime_dependency "log4r", "~> 1.1.10"
49
- gem.add_runtime_dependency "mixlib-shellout", "~> 1.6.0"
44
+ gem.name = 'daptiv-chef-ci'
45
+ gem.require_paths = ['lib']
46
+ gem.version = '0.1.0'
50
47
 
51
- gem.add_development_dependency "rake"
52
- gem.add_development_dependency "rspec-core", "~> 2.12.2"
53
- gem.add_development_dependency "rspec-expectations", "~> 2.12.1"
54
- gem.add_development_dependency "rspec-mocks", "~> 2.12.1"
48
+ gem.add_runtime_dependency 'log4r', '~> 1.1.10'
49
+ gem.add_runtime_dependency 'mixlib-shellout', '~> 1.2'
50
+ gem.add_runtime_dependency 'versionomy', '~> 0.4.4'
51
+
52
+ gem.add_development_dependency 'rake'
53
+ gem.add_development_dependency 'rspec-core', '~> 2.12.2'
54
+ gem.add_development_dependency 'rspec-expectations', '~> 2.12.1'
55
+ gem.add_development_dependency 'rspec-mocks', '~> 2.12.1'
55
56
  end
@@ -0,0 +1,69 @@
1
+ require 'rake'
2
+ require 'rake/tasklib'
3
+ require 'rake/dsl_definition'
4
+ require 'json'
5
+ require 'tempfile'
6
+ require_relative 'raketask_helper'
7
+ require_relative 'shell'
8
+
9
+ class CloneEnvironment
10
+ # Example usage, copies a Chef environment definition to another
11
+ # environment.
12
+ #
13
+ # CloneEnvironment::RakeTask.new do |t|
14
+ # t.src_env = 'dev'
15
+ # t.dest_env = "vagrant-#{ENV['LOGNAME']}-dotnetframework"
16
+ # end
17
+ #
18
+ # This class lets you define Rake tasks to clone Chef environments.
19
+ class RakeTask < ::Rake::TaskLib
20
+ include ::Rake::DSL if defined? ::Rake::DSL
21
+ include DaptivChefCI::RakeTaskHelpers
22
+
23
+ attr_accessor :src_env
24
+ attr_accessor :dest_env
25
+
26
+ # @param [String] name The task name.
27
+ # @param [String] desc Description of the task.
28
+ def initialize(name = 'clone_environment', desc = 'Clone environment task')
29
+ @logger = Log4r::Logger.new('daptiv_chef_ci::clone_environment_task')
30
+ @shell = DaptivChefCI::Shell.new
31
+ @name, @desc = name, desc
32
+ yield self if block_given?
33
+ define_task
34
+ end
35
+
36
+ private
37
+
38
+ def define_task
39
+ desc @desc
40
+ task @name do
41
+ execute do
42
+ fail 'src_env must be specified' unless @src_env
43
+ fail 'dest_env must be specified' unless @dest_env
44
+ clone_environment
45
+ end
46
+ end
47
+ end
48
+
49
+ def clone_environment
50
+ out = @shell.exec_cmd_in_context(
51
+ "knife environment show #{@src_env} -F json").join(' ')
52
+
53
+ env = JSON.parse(out)
54
+ env['name'] = @dest_env
55
+ env['description'] = "The #{dest_env} environment"
56
+
57
+ env_file = Tempfile.new([@dest_env, '.json'])
58
+ begin
59
+ IO.write(env_file.path, JSON.pretty_generate(env))
60
+
61
+ @shell.exec_cmd_in_context(
62
+ "knife environment from file '#{env_file.path}'")
63
+ ensure
64
+ env_file.close
65
+ env_file.unlink
66
+ end
67
+ end
68
+ end
69
+ end
@@ -1,35 +1,34 @@
1
1
  module DaptivChefCI
2
+ # Chef CI logger class
2
3
  class Logger
3
-
4
4
  # Initializes and enables logging to the given environments level
5
5
  # By default logging only occurs at ERROR level or higher.
6
6
  # Set CHEF_CI_LOG env var to change logging levels
7
- def self.init()
7
+ def self.init
8
8
  require 'log4r'
9
-
9
+
10
10
  # Set the logging level on all "chef-ci" namespaced
11
11
  # logs as long as we have a valid level.
12
- logger = Log4r::Logger.new("daptiv_chef_ci")
12
+ logger = Log4r::Logger.new('daptiv_chef_ci')
13
13
  logger.outputters = Log4r::Outputter.stderr
14
- logger.level = log_level()
14
+ logger.level = log_level
15
15
  logger = nil
16
16
  end
17
-
17
+
18
18
  # LogLevels = ['DEBUG', 'INFO', 'WARN', 'ERROR', 'FATAL']
19
19
  # DEBUG = 1
20
20
  # INFO = 2
21
21
  # WARN = 3
22
22
  # ERROR = 4
23
23
  # FATAL = 5
24
- def self.log_level()
25
- level = ENV['CHEF_CI_LOG'].upcase().to_s()
24
+ def self.log_level
25
+ level = ENV['CHEF_CI_LOG'].upcase.to_s
26
26
  level_i = Log4r::Log4rConfig::LogLevels.index(level)
27
27
  level_i + 1
28
28
  rescue
29
29
  return 2 # info
30
30
  end
31
-
32
31
  end
33
32
  end
34
33
 
35
- DaptivChefCI::Logger.init()
34
+ DaptivChefCI::Logger.init
@@ -1,17 +1,17 @@
1
1
  module DaptivChefCI
2
2
  module RakeTaskHelpers
3
3
  extend self
4
-
4
+
5
5
  @@exit_on_failure = true
6
-
6
+
7
7
  def exit_on_failure
8
8
  @@exit_on_failure
9
9
  end
10
-
10
+
11
11
  def exit_on_failure=(exit_on_failure)
12
12
  @@exit_on_failure = exit_on_failure
13
13
  end
14
-
14
+
15
15
  def execute(&block)
16
16
  begin
17
17
  block.call()
@@ -31,6 +31,5 @@ module DaptivChefCI
31
31
  end
32
32
  end
33
33
  end
34
-
35
34
  end
36
- end
35
+ end
@@ -3,61 +3,83 @@ require 'bundler'
3
3
  require 'mixlib/shellout'
4
4
 
5
5
  module DaptivChefCI
6
+ # Command shell wrapper
6
7
  class Shell
7
-
8
- def initialize()
9
- @logger = Log4r::Logger.new("daptiv_chef_ci::shell")
8
+ def initialize
9
+ @logger = Log4r::Logger.new('daptiv_chef_ci::shell')
10
10
  end
11
-
11
+
12
12
  # Executes the specified shell command and returns the stdout.
13
13
  #
14
14
  # This method ensure that any invoked command use the same PATH environment
15
15
  # that the user has outside Ruby/Bundler.
16
16
  #
17
17
  # @param [String] The command line to execute
18
- # @param [Int] The number of seconds to wait for the command to finish, defaults to 600
19
- # @param [Hash] Key value pairs of environment variables to pass to the command's environment.
18
+ # @param [Int] The number of seconds to wait for the command to finish,
19
+ # defaults to 600
20
+ # @param [Hash] Key value pairs of environment variables to pass to the
21
+ # command's environment.
20
22
  # @return [Array] Each entry represents a line from the stdout
21
- def exec_cmd(command, timeout = nil, environment = {})
23
+ def exec_cmd_in_context(command, timeout = nil, environment = {})
22
24
  timeout ||= 600
23
25
  environment = Hash[ environment.map{ |k, v| [k.to_s, v.to_s] } ]
24
- environment['LC_ALL'] = ENV['LC_ALL'] if !environment.has_key?('LC_ALL')
26
+ environment['LC_ALL'] = ENV['LC_ALL'] unless environment.key?('LC_ALL')
27
+
28
+ @logger.info("Executing: '#{command}'")
29
+ @logger.debug("\n\ttimeout: #{timeout}\n\tenvironment: #{environment}")
30
+
31
+ shell_out = Mixlib::ShellOut.new(
32
+ command, timeout: timeout, environment: environment)
33
+ shell_out.live_stream = STDOUT
34
+
35
+ shell_out.run_command
36
+ shell_out.invalid! if shell_out.exitstatus != 0
37
+ @logger.info(shell_out.stdout)
38
+ shell_out.stdout.split("\n")
39
+ end
40
+
41
+ # Executes the specified shell command and returns the stdout.
42
+ #
43
+ # This method ensure that any invoked command use the same PATH environment
44
+ # that the user has outside Ruby/Bundler.
45
+ #
46
+ # @param [String] The command line to execute
47
+ # @param [Int] The number of seconds to wait for the command to finish,
48
+ # defaults to 600
49
+ # @param [Hash] Key value pairs of environment variables to pass to the
50
+ # command's environment.
51
+ # @return [Array] Each entry represents a line from the stdout
52
+ def exec_cmd(command, timeout = nil, environment = {})
25
53
  path_at_start = ENV['PATH']
26
54
  begin
27
- ENV['PATH'] = path_without_gem_dir()
28
- @logger.debug("Temporarily setting PATH: #{ENV['PATH']}")
29
-
30
- @logger.info("Executing: '#{command}'\n\ttimeout: #{timeout}\n\tenvironment: #{environment}")
31
- shell_out = Mixlib::ShellOut.new(command, :timeout => timeout, :environment => environment)
32
- shell_out.run_command()
33
- shell_out.invalid! if shell_out.exitstatus != 0
34
-
35
- @logger.info(shell_out.stdout)
36
- shell_out.stdout.split("\n")
55
+ ENV['PATH'] = path_without_gem_dir
56
+ @logger.debug("Setting PATH: #{ENV['PATH']}")
57
+ exec_cmd_in_context(command, timeout, environment)
37
58
  ensure
38
59
  @logger.debug("Resetting PATH: #{path_at_start}")
39
60
  ENV['PATH'] = path_at_start
40
61
  end
41
62
  end
42
-
63
+
43
64
  # Returns the PATH environment variable as it was before Bundler prepended
44
65
  # the system gem directory to it.
45
66
  #
46
- # This can happen if the user has invoked "require 'bundler/setup'" somewhere,
47
- # like in this gems Rakefile.
67
+ # This can happen if the user has invoked "require 'bundler/setup'"
68
+ # somewhere, like in this gems Rakefile.
48
69
  #
49
- # This is needed because sometimes a user will have the Vagrant gem installed
50
- # on their system and we don't want to use it, we should use the one that's in
51
- # their PATH as if they invoked vagrant themselves (i.e. the installed version)
70
+ # This is needed because sometimes a user will have the Vagrant gem
71
+ # installed on their system and we don't want to use it, we should use the
72
+ # one that's in their PATH as if they invoked vagrant themselves
73
+ # (i.e. the installed version)
52
74
  #
53
- # @return [String] The ENV['PATH] without the Bundler system gem dir prepended
75
+ # @return [String] The ENV['PATH] without the Bundler system gem dir
76
+ # prepended
54
77
  def path_without_gem_dir
55
78
  paths = ENV['PATH'].split(':')
56
79
  system_gem_dir = "#{Bundler.bundle_path}/bin"
57
80
  @logger.debug("System gem dir: #{system_gem_dir}")
58
- paths.delete_if { |p| p.downcase() == system_gem_dir.downcase() }
81
+ paths.delete_if { |p| p.downcase == system_gem_dir.downcase }
59
82
  paths.join(':')
60
83
  end
61
-
62
84
  end
63
- end
85
+ end
@@ -0,0 +1,62 @@
1
+ require 'rake'
2
+ require 'rake/tasklib'
3
+ require 'rake/dsl_definition'
4
+ require_relative 'raketask_helper'
5
+ require_relative 'shell'
6
+
7
+ class UploadCookbook
8
+ # Example usage, uploads the current cookbook to the Chef server freezing
9
+ # it to the Canary environment.
10
+ #
11
+ # UploadCookbook::RakeTask.new do |t|
12
+ # t.environment = 'canary'
13
+ # t.freeze = true
14
+ # end
15
+ #
16
+ # This class lets you define Rake tasks to upload cookbooks to Chef.
17
+ class RakeTask < ::Rake::TaskLib
18
+ include ::Rake::DSL if defined? ::Rake::DSL
19
+ include DaptivChefCI::RakeTaskHelpers
20
+
21
+ attr_accessor :environment
22
+ attr_accessor :freeze
23
+
24
+ # @param [String] name The task name.
25
+ # @param [String] desc Description of the task.
26
+ def initialize(name = 'upload_cookbook', desc = 'Upload cookbook task')
27
+ @logger = Log4r::Logger.new('daptiv_chef_ci::upload_cookbook_task')
28
+ @shell = DaptivChefCI::Shell.new
29
+ @name, @desc = name, desc
30
+ @freeze = false
31
+ yield self if block_given?
32
+ define_task
33
+ end
34
+
35
+ private
36
+
37
+ def define_task
38
+ desc @desc
39
+ task @name do
40
+ execute do
41
+ upload_cookbook
42
+ end
43
+ end
44
+ end
45
+
46
+ def upload_cookbook
47
+ cmd = "knife cookbook upload #{cookbook_name} -o ../"
48
+ cmd << " -E #{environment}" if @environment
49
+ @shell.exec_cmd_in_context(cmd)
50
+ end
51
+
52
+ def cookbook_name
53
+ unless @cookbook_name
54
+ metadata = IO.read(File.join(Dir.pwd, 'metadata.rb'))
55
+ @cookbook_name = /name\s+['|"](\w+)/.match(metadata)[1]
56
+ fail 'Cannot find cookbook name in metadata.rb' unless @cookbook_name
57
+ @logger.debug("found cookbook name: #{@cookbook_name}")
58
+ end
59
+ @cookbook_name
60
+ end
61
+ end
62
+ end
@@ -6,7 +6,6 @@ require_relative 'raketask_helper'
6
6
  require_relative 'logger'
7
7
 
8
8
  class VagrantDestroy
9
-
10
9
  # Example usage, destroys a Vagrant box.
11
10
  #
12
11
  # VagrantUp::RakeTask.new 'up' do |t|
@@ -17,11 +16,11 @@ class VagrantDestroy
17
16
  class RakeTask < ::Rake::TaskLib
18
17
  include ::Rake::DSL if defined? ::Rake::DSL
19
18
  include DaptivChefCI::RakeTaskHelpers
20
-
19
+
21
20
  attr_accessor :vagrant_driver
22
21
  attr_accessor :destroy_timeout_in_seconds
23
22
  attr_accessor :environment
24
-
23
+
25
24
  # @param [String] name The task name.
26
25
  # @param [String] desc Description of the task.
27
26
  def initialize(name = 'vagrant_destroy', desc = 'Vagrant destroy task')
@@ -31,22 +30,22 @@ class VagrantDestroy
31
30
  yield self if block_given?
32
31
  define_task
33
32
  end
34
-
33
+
35
34
  private
36
35
 
37
36
  def define_task
38
37
  desc @desc
39
38
  task @name do
40
- execute { vagrant_driver.destroy({
41
- :cmd_timeout_in_seconds => @destroy_timeout_in_seconds,
42
- :environment => @environment }) }
39
+ execute do
40
+ vagrant_driver.destroy(
41
+ cmd_timeout_in_seconds: @destroy_timeout_in_seconds,
42
+ environment: @environment)
43
+ end
43
44
  end
44
45
  end
45
-
46
- def vagrant_driver()
47
- @vagrant_driver ||= DaptivChefCI::VagrantDriver.new()
48
- end
49
46
 
47
+ def vagrant_driver
48
+ @vagrant_driver ||= DaptivChefCI::VagrantDriver.new
49
+ end
50
50
  end
51
51
  end
52
-