itamae 1.6.3 → 1.7.0.pre

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c517c9de5fc2f44be1ad04227c37925ccb82423d
4
- data.tar.gz: 4dbd70a0f470a4f5cdad0e3e67aef8cf137ee860
3
+ metadata.gz: c693dfeb747bd80dffef33f292b26a2a8e075f81
4
+ data.tar.gz: b11be7c402d731d2444cf79600b63e82987b2c1f
5
5
  SHA512:
6
- metadata.gz: b17b31eb7091de71bfd2f8fbd13e460a54d0592e3ff47a599fae0a31116834ef93dcef811997d14279825bd03a5af125aee994e44e73f2c310de7e27ebb6ab6c
7
- data.tar.gz: c1a18658f08ea4c9e49e9c9883d33de00117256b33df6262472dde2cb9888f2853664e6a9a55a8ce9a3667d239e36fdd6585e44fe417cd6cc2f8defd4ce7b764
6
+ metadata.gz: 85df294c1e5860f42b81ddcff13ef64245504d65a063a0061ac72a513af4af3d5d0fe1d416b095d9b8cf11c12e67aa9a1f5dc5cba711e08c9427cdd9cde4223c
7
+ data.tar.gz: 11d1f27227fa148d113222f3bc03a14058edcdc071e93dcc5a026928aae06c78ab3e3a4160c08b4671e3636da53168572f9fe1f31186ba9a4a59d2d2b9e5277f
data/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ ## v1.6.4.pre
2
+
3
+ Features
4
+
5
+ - `--profile` option (experimental)
6
+ - `--profile PATH` saves executed commands to `PATH` in JSON format
7
+
8
+ Bugfixes
9
+
10
+ - [Suppress errors of `edit` action of `file` resource when the target file doesn't exist in `dry-run` mode](https://github.com/itamae-kitchen/itamae/pull/144)
11
+
1
12
  ## v1.6.3
2
13
 
3
14
  Features
data/Gemfile CHANGED
@@ -3,6 +3,9 @@ source 'https://rubygems.org'
3
3
  # Specify your gem's dependencies in itamae.gemspec
4
4
  gemspec
5
5
 
6
+ gem 'vagrant', github: 'mitchellh/vagrant'
7
+ gem 'vagrant-digitalocean'
8
+
6
9
  path = Pathname.new("Gemfile.local")
7
10
  eval(path.read) if path.exist?
8
11
 
@@ -11,4 +14,3 @@ group :test do
11
14
  gem 'growl'
12
15
  end
13
16
  end
14
-
data/Rakefile CHANGED
@@ -3,7 +3,7 @@ require 'rspec/core/rake_task'
3
3
  require 'tempfile'
4
4
  require 'net/ssh'
5
5
 
6
- vagrant_bin = ENV['CI'] ? 'vagrant' : '/usr/bin/vagrant'
6
+ vagrant_bin = 'vagrant'
7
7
 
8
8
  desc 'Run unit and integration specs.'
9
9
  task :spec => ['spec:unit', 'spec:integration:all']
@@ -16,10 +16,13 @@ namespace :spec do
16
16
 
17
17
  namespace :integration do
18
18
  targets = []
19
- Bundler.with_clean_env do
20
- `cd spec/integration && #{vagrant_bin} status`.split("\n\n")[1].each_line do |line|
21
- targets << line.match(/^[^ ]+/)[0]
22
- end
19
+ status = `cd spec/integration && #{vagrant_bin} status`
20
+ unless $?.exitstatus == 0
21
+ raise "vagrant status failed.\n#{status}"
22
+ end
23
+
24
+ status.split("\n\n")[1].each_line do |line|
25
+ targets << line.match(/^[^ ]+/)[0]
23
26
  end
24
27
 
25
28
  task :all => targets
@@ -30,27 +33,37 @@ namespace :spec do
30
33
 
31
34
  namespace :provision do
32
35
  task target do
33
- Bundler.with_clean_env do
34
- config = Tempfile.new('', Dir.tmpdir)
35
- env = {"VAGRANT_CWD" => File.expand_path('./spec/integration')}
36
- system env, "#{vagrant_bin} up #{target}"
37
- system env, "#{vagrant_bin} ssh-config #{target} > #{config.path}"
38
- options = Net::SSH::Config.for(target, [config.path])
36
+ config = Tempfile.new('', Dir.tmpdir)
37
+ env = {"VAGRANT_CWD" => File.expand_path('./spec/integration')}
38
+ system env, "#{vagrant_bin} up #{target}"
39
+ system env, "#{vagrant_bin} ssh-config #{target} > #{config.path}"
40
+ options = Net::SSH::Config.for(target, [config.path])
39
41
 
40
- cmd = "bundle exec bin/itamae ssh"
41
- cmd << " -h #{options[:host_name]}"
42
- cmd << " -u #{options[:user]}"
43
- cmd << " -p #{options[:port]}"
44
- cmd << " -i #{options[:keys].first}"
45
- cmd << " -l #{ENV['LOG_LEVEL'] || 'debug'}"
46
- cmd << " -j spec/integration/recipes/node.json"
47
- cmd << " spec/integration/recipes/default.rb"
48
- cmd << " spec/integration/recipes/default2.rb"
49
- cmd << " spec/integration/recipes/redefine.rb"
42
+ suites = [
43
+ [
44
+ "spec/integration/recipes/default.rb",
45
+ "spec/integration/recipes/default2.rb",
46
+ "spec/integration/recipes/redefine.rb",
47
+ ],
48
+ [
49
+ "--dry-run",
50
+ "spec/integration/recipes/dry_run.rb",
51
+ ],
52
+ ]
53
+ suites.each do |suite|
54
+ cmd = %w!bundle exec bin/itamae ssh!
55
+ cmd << "-h" << options[:host_name]
56
+ cmd << "-u" << options[:user]
57
+ cmd << "-p" << options[:port].to_s
58
+ cmd << "-i" << options[:keys].first
59
+ cmd << "-l" << (ENV['LOG_LEVEL'] || 'debug')
60
+ cmd << "-j" << "spec/integration/recipes/node.json"
61
+ cmd += suite
50
62
 
51
- puts cmd
52
- system cmd
53
- abort unless $?.exitstatus == 0
63
+ p cmd
64
+ unless system(*cmd)
65
+ raise "#{cmd} failed"
66
+ end
54
67
  end
55
68
  end
56
69
  end
@@ -86,4 +99,3 @@ namespace :release do
86
99
  system "git commit -m 'Bump up version'"
87
100
  end
88
101
  end
89
-
@@ -35,9 +35,12 @@ module Itamae
35
35
  end
36
36
 
37
37
  class Base
38
+ attr_reader :executed_commands
39
+
38
40
  def initialize(options)
39
41
  @options = options
40
42
  @backend = create_specinfra_backend
43
+ @executed_commands = []
41
44
  end
42
45
 
43
46
  def run_command(commands, options = {})
@@ -50,7 +53,9 @@ module Itamae
50
53
 
51
54
  Itamae.logger.with_indent do
52
55
  reset_output_handler
53
- result = @backend.run_command(command)
56
+
57
+ result = run_command_with_profiling(command)
58
+
54
59
  flush_output_handler_buffer
55
60
 
56
61
  if result.exit_status == 0 || !options[:error]
@@ -186,6 +191,16 @@ module Itamae
186
191
  def shell
187
192
  @options[:shell]
188
193
  end
194
+
195
+ def run_command_with_profiling(command)
196
+ start_at = Time.now
197
+ result = @backend.run_command(command)
198
+ duration = Time.now.to_f - start_at.to_f
199
+
200
+ @executed_commands << {command: command, duration: duration}
201
+
202
+ result
203
+ end
189
204
  end
190
205
 
191
206
  class Local < Base
data/lib/itamae/cli.rb CHANGED
@@ -15,12 +15,13 @@ module Itamae
15
15
  end
16
16
 
17
17
  def self.define_exec_options
18
- option :dot, type: :string, default: nil, desc: "Only write dependency graph in DOT", banner: "PATH"
18
+ option :dot, type: :string, default: nil, desc: "[EXPERIMENTAL] Only write dependency graph in DOT", banner: "PATH"
19
19
  option :node_json, type: :string, aliases: ['-j']
20
20
  option :node_yaml, type: :string, aliases: ['-y']
21
21
  option :dry_run, type: :boolean, aliases: ['-n']
22
22
  option :shell, type: :string, default: "/bin/sh"
23
- option :ohai, type: :boolean, default: false, desc: "This option is DEPRECATED and will be inavailable."
23
+ option :ohai, type: :boolean, default: false, desc: "This option is DEPRECATED and will be unavailable."
24
+ option :profile, type: :string, desc: "[EXPERIMENTAL] Save profiling data", banner: "PATH"
24
25
  end
25
26
 
26
27
  desc "local RECIPE [RECIPE...]", "Run Itamae locally"
@@ -10,8 +10,8 @@ module Itamae
10
10
  runner.children.find_resource_by_description(target_resource_desc)
11
11
  end
12
12
 
13
- def run(options)
14
- action_resource.run(action, options)
13
+ def run
14
+ action_resource.run(action)
15
15
  end
16
16
 
17
17
  def action_resource
data/lib/itamae/recipe.rb CHANGED
@@ -58,24 +58,24 @@ module Itamae
58
58
  context.instance_eval(File.read(path), path, 1)
59
59
  end
60
60
 
61
- def run(options = {})
61
+ def run
62
62
  show_banner
63
63
 
64
64
  Itamae.logger.with_indent do
65
- @children.run(options)
66
- run_delayed_notifications(options)
65
+ @children.run
66
+ run_delayed_notifications
67
67
  end
68
68
  end
69
69
 
70
70
  private
71
71
 
72
- def run_delayed_notifications(options)
72
+ def run_delayed_notifications
73
73
  @delayed_notifications.uniq! do |notification|
74
74
  [notification.action, notification.action_resource]
75
75
  end
76
76
 
77
77
  while notification = @delayed_notifications.shift
78
- notification.run(options)
78
+ notification.run
79
79
  end
80
80
  end
81
81
 
@@ -53,14 +53,9 @@ module Itamae
53
53
  end.flatten
54
54
  end
55
55
 
56
- def run(options)
56
+ def run
57
57
  self.each do |resource|
58
- case resource
59
- when Resource::Base
60
- resource.run(nil, dry_run: options[:dry_run])
61
- when Recipe
62
- resource.run(options)
63
- end
58
+ resource.run
64
59
  end
65
60
  end
66
61
 
@@ -120,7 +120,7 @@ module Itamae
120
120
  process_attributes
121
121
  end
122
122
 
123
- def run(specific_action = nil, options = {})
123
+ def run(specific_action = nil)
124
124
  Itamae.logger.debug "#{resource_type}[#{resource_name}]"
125
125
 
126
126
  Itamae.logger.with_indent_if(Itamae.logger.debug?) do
@@ -133,11 +133,11 @@ module Itamae
133
133
  end
134
134
 
135
135
  [specific_action || attributes.action].flatten.each do |action|
136
- run_action(action, options)
136
+ run_action(action)
137
137
  end
138
138
 
139
- verify unless options[:dry_run]
140
- notify(options) if updated?
139
+ verify unless runner.dry_run?
140
+ notify if updated?
141
141
  end
142
142
 
143
143
  @updated = false
@@ -146,7 +146,7 @@ module Itamae
146
146
  exit 2
147
147
  end
148
148
 
149
- def action_nothing(options)
149
+ def action_nothing
150
150
  # do nothing
151
151
  end
152
152
 
@@ -166,7 +166,7 @@ module Itamae
166
166
 
167
167
  alias_method :current, :current_attributes
168
168
 
169
- def run_action(action, options)
169
+ def run_action(action)
170
170
  original_attributes = @attributes # preserve and restore later
171
171
  @current_action = action
172
172
 
@@ -187,12 +187,18 @@ module Itamae
187
187
  show_differences
188
188
 
189
189
  method_name = "action_#{action}"
190
- if options[:dry_run]
190
+ if runner.dry_run?
191
191
  unless respond_to?(method_name)
192
192
  Itamae.logger.error "action #{action.inspect} is unavailable"
193
193
  end
194
194
  else
195
- public_send(method_name, options)
195
+ args = [method_name]
196
+ if method(method_name).arity == 1
197
+ # for plugin compatibility
198
+ args << runner.options
199
+ end
200
+
201
+ public_send(*args)
196
202
  end
197
203
 
198
204
  updated! if different?
@@ -327,7 +333,7 @@ module Itamae
327
333
  @updated
328
334
  end
329
335
 
330
- def notify(options)
336
+ def notify
331
337
  (notifications + recipe.children.subscribing(self)).each do |notification|
332
338
  message = "Notifying #{notification.action} to #{notification.action_resource.resource_type} resource '#{notification.action_resource.resource_name}'"
333
339
 
@@ -346,7 +352,7 @@ module Itamae
346
352
  if notification.delayed?
347
353
  @recipe.delayed_notifications << notification
348
354
  elsif notification.immediately?
349
- notification.run(options)
355
+ notification.run
350
356
  end
351
357
  end
352
358
  end
@@ -24,4 +24,3 @@ module Itamae
24
24
  end
25
25
  end
26
26
  end
27
-
@@ -20,9 +20,11 @@ module Itamae
20
20
  when :edit
21
21
  attributes.exist = true
22
22
 
23
- content = backend.receive_file(attributes.path)
24
- attributes.block.call(content)
25
- attributes.content = content
23
+ unless runner.dry_run?
24
+ content = backend.receive_file(attributes.path)
25
+ attributes.block.call(content)
26
+ attributes.content = content
27
+ end
26
28
  end
27
29
 
28
30
  send_tempfile
@@ -163,4 +165,3 @@ module Itamae
163
165
  end
164
166
  end
165
167
  end
166
-
data/lib/itamae/runner.rb CHANGED
@@ -13,18 +13,20 @@ module Itamae
13
13
  runner.load_recipes(recipe_files)
14
14
 
15
15
  if dot_file = options[:dot]
16
- Itamae.logger.info "Writing dependency graph in DOT to #{dot_file}..."
17
- open(dot_file, 'w') do |f|
18
- f.write(runner.children.deps_in_dot)
19
- end
16
+ runner.save_dependency_graph(dot_file)
20
17
  return
21
18
  end
22
19
 
23
- runner.run(dry_run: options[:dry_run])
20
+ runner.run
21
+
22
+ if profile = options[:profile]
23
+ runner.save_profile(profile)
24
+ end
24
25
  end
25
26
  end
26
27
 
27
28
  attr_reader :backend
29
+ attr_reader :options
28
30
  attr_reader :node
29
31
  attr_reader :tmpdir
30
32
  attr_reader :children
@@ -55,11 +57,28 @@ module Itamae
55
57
  end
56
58
  end
57
59
 
58
- def run(options)
59
- children.run(options)
60
+ def run
61
+ children.run
60
62
  @backend.finalize
61
63
  end
62
64
 
65
+ def dry_run?
66
+ @options[:dry_run]
67
+ end
68
+
69
+ def save_dependency_graph(path)
70
+ Itamae.logger.info "Writing dependency graph in DOT to #{path}..."
71
+ open(path, 'w') do |f|
72
+ f.write(runner.children.deps_in_dot)
73
+ end
74
+ end
75
+
76
+ def save_profile(path)
77
+ open(path, 'w', 0600) do |f|
78
+ f.write(@backend.executed_commands.to_json)
79
+ end
80
+ end
81
+
63
82
  private
64
83
  def create_node
65
84
  hash = {}
@@ -91,4 +110,3 @@ module Itamae
91
110
  end
92
111
  end
93
112
  end
94
-
@@ -1 +1 @@
1
- 1.6.3
1
+ 1.7.0.pre
@@ -1,5 +1,6 @@
1
1
  # -*- mode: ruby -*-
2
2
  # vi: set ft=ruby :
3
+ require 'vagrant-digitalocean'
3
4
 
4
5
  # Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
5
6
  VAGRANTFILE_API_VERSION = "2"
@@ -0,0 +1,6 @@
1
+ file "/tmp/it_does_not_exist" do
2
+ action :edit
3
+ block do |content|
4
+ content.gsub!("foo", "bar")
5
+ end
6
+ end
@@ -5,10 +5,8 @@ require 'tempfile'
5
5
  set :backend, :ssh
6
6
 
7
7
  def vagrant(cmd)
8
- Bundler.with_clean_env do
9
- env = {"VAGRANT_CWD" => File.dirname(__FILE__)}
10
- system env, "/usr/bin/vagrant #{cmd}"
11
- end
8
+ env = {"VAGRANT_CWD" => File.dirname(__FILE__)}
9
+ system(env, "vagrant #{cmd}")
12
10
  end
13
11
 
14
12
  if ENV['ASK_SUDO_PASSWORD']
@@ -38,8 +36,7 @@ set :ssh_options, options
38
36
  # set :disable_sudo, true
39
37
 
40
38
  # Set environment variables
41
- # set :env, :LANG => 'C', :LC_MESSAGES => 'C'
39
+ # set :env, :LANG => 'C', :LC_MESSAGES => 'C'
42
40
 
43
41
  # Set PATH
44
42
  # set :path, '/sbin:/usr/local/sbin:$PATH'
45
-
@@ -102,7 +102,9 @@ describe TestResource do
102
102
 
103
103
  let(:commands) { double(:commands) }
104
104
  let(:runner) do
105
- double(:runner)
105
+ instance_double(Itamae::Runner).tap do |r|
106
+ allow(r).to receive(:dry_run?).and_return(false)
107
+ end
106
108
  end
107
109
  let(:recipe) do
108
110
  double(:recipe).tap do |r|
@@ -120,14 +122,5 @@ describe TestResource do
120
122
  expect(subject).to receive(:action_name)
121
123
  subject.run
122
124
  end
123
-
124
- context 'with dry_run' do
125
- context 'when specified action is unavailable' do
126
- it 'logs error' do
127
- expect(Itamae.logger).to receive(:error).with(/action :name is unavailable/)
128
- subject.run(nil, dry_run: true)
129
- end
130
- end
131
- end
132
125
  end
133
126
  end
data/wercker.yml CHANGED
@@ -47,25 +47,17 @@ build:
47
47
  name: chmod 600 id_rsa
48
48
  code: chmod 600 $HOME/.ssh/id_rsa.vagrant
49
49
 
50
- - script:
51
- name: download vagrant
52
- code: wget https://dl.bintray.com/mitchellh/vagrant/vagrant_1.6.3_x86_64.deb
53
-
54
- - script:
55
- name: install vagrant
56
- code: sudo dpkg -i vagrant_1.6.3_x86_64.deb
57
-
58
50
  - script:
59
51
  name: install libxml and libxslt
60
52
  code: sudo apt-get install libxml2-dev libxslt1-dev
61
53
 
62
54
  - script:
63
- name: install vagrant-digitalocean
64
- code: NOKOGIRI_USE_SYSTEM_LIBRARIES=1 vagrant plugin install vagrant-digitalocean
55
+ name: bundle install
56
+ code: bundle install --deployment -j4
65
57
 
66
58
  - script:
67
59
  name: start vm
68
- code: vagrant up --provider=digital_ocean
60
+ code: bundle exec vagrant up --provider=digital_ocean
69
61
  cwd: spec/integration
70
62
 
71
63
  # Add more steps here:
@@ -76,10 +68,10 @@ build:
76
68
  after-steps:
77
69
  - script:
78
70
  name: shutdown vm
79
- code: vagrant destroy -f
71
+ code: bundle exec vagrant destroy -f
80
72
  cwd: spec/integration
81
73
 
82
74
  - script:
83
75
  name: shutdown old vms
84
- code: ruby ci/destroy_old_droplets.rb
76
+ code: bundle exec ruby ci/destroy_old_droplets.rb
85
77
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: itamae
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.3
4
+ version: 1.7.0.pre
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryota Arai
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-10-21 00:00:00.000000000 Z
11
+ date: 2015-11-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -244,6 +244,7 @@ files:
244
244
  - spec/integration/recipes/default2.rb
245
245
  - spec/integration/recipes/define/default.rb
246
246
  - spec/integration/recipes/define/files/remote_file_in_definition
247
+ - spec/integration/recipes/dry_run.rb
247
248
  - spec/integration/recipes/files/remote_file_auto
248
249
  - spec/integration/recipes/hello.erb
249
250
  - spec/integration/recipes/hello.txt
@@ -276,9 +277,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
276
277
  version: '0'
277
278
  required_rubygems_version: !ruby/object:Gem::Requirement
278
279
  requirements:
279
- - - ">="
280
+ - - ">"
280
281
  - !ruby/object:Gem::Version
281
- version: '0'
282
+ version: 1.3.1
282
283
  requirements: []
283
284
  rubyforge_project:
284
285
  rubygems_version: 2.4.5
@@ -292,6 +293,7 @@ test_files:
292
293
  - spec/integration/recipes/default2.rb
293
294
  - spec/integration/recipes/define/default.rb
294
295
  - spec/integration/recipes/define/files/remote_file_in_definition
296
+ - spec/integration/recipes/dry_run.rb
295
297
  - spec/integration/recipes/files/remote_file_auto
296
298
  - spec/integration/recipes/hello.erb
297
299
  - spec/integration/recipes/hello.txt