itamae 1.6.3 → 1.7.0.pre

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
  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