itamae-mitsurin 0.24 → 0.26

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: baac90f0f5aa705c0c2d1e3a9bdd222b1ce47e3b
4
- data.tar.gz: 1d112209337e4cb63cd2f6d00962db1d78e28b10
3
+ metadata.gz: 3aa5cbb917a9a7142ee4869e8e37db1afa8a2faa
4
+ data.tar.gz: c1907411f6c07ad790e73826d0e5febacb3ee530
5
5
  SHA512:
6
- metadata.gz: 5b0823ffe5231992c98be804f49a5b0f1c667855a747867a2088151ae58a359916d5e6989dad0eeb8bdafd3169e7009d0f80b273fc90fa831cfdb54f10f7a44b
7
- data.tar.gz: 4ee53138a35fb70339e09d5675c37f9baeca35c6d7dd08a7951ee0d1aaedf83d43820bc9c7b0c1b2c99e9aadd99226b386598de83c1b176e525b429b05853be8
6
+ metadata.gz: 9615f64653565c2c8b5684de05797d28c4f13667ec41a27ffdca70af1a24e4aa2ede985d268fad6d588bb5068f64ee7df8a91ef4e714135e7ebdc38647410357
7
+ data.tar.gz: 14e0d357b6985d32919b4887213f298ecd251c995e41ea00756477e4be4fd562ad0e39081ba3d33cb9732edd5264f676ea4c6170dedecab8633e81a1eb655306
@@ -23,6 +23,9 @@ module ItamaeMitsurin
23
23
  option :shell, type: :string, default: "/bin/sh"
24
24
  option :ohai, type: :boolean, default: false, desc: "This option is DEPRECATED and will be unavailable."
25
25
  option :profile, type: :string, desc: "[EXPERIMENTAL] Save profiling data", banner: "PATH"
26
+ option :detailed_exitcode, type: :boolean, default: false, desc: "exit code 0 - The run succeeded with no changes or failures, exit code 1 - The run failed, exit code 2 - The run succeeded, and some resources were changed"
27
+
28
+
26
29
  end
27
30
 
28
31
  desc "local RECIPE [RECIPE...]", "Run Itamae locally"
@@ -32,7 +35,7 @@ module ItamaeMitsurin
32
35
  raise "Please specify recipe files."
33
36
  end
34
37
 
35
- Runner.run(recipe_files, :local, options)
38
+ run(recipe_files, :local, options)
36
39
  end
37
40
 
38
41
  desc "ssh RECIPE [RECIPE...]", "Run Itamae via ssh"
@@ -53,7 +56,7 @@ module ItamaeMitsurin
53
56
  raise "Please set '-h <hostname>' or '--vagrant'"
54
57
  end
55
58
 
56
- Runner.run(recipe_files, :ssh, options)
59
+ run(recipe_files, :local, options)
57
60
  end
58
61
 
59
62
  desc "docker RECIPE [RECIPE...]", "Create Docker image"
@@ -66,7 +69,7 @@ module ItamaeMitsurin
66
69
  raise "Please specify recipe files."
67
70
  end
68
71
 
69
- Runner.run(recipe_files, :docker, options)
72
+ run(recipe_files, :local, options)
70
73
  end
71
74
 
72
75
  desc "version", "Print version"
@@ -82,5 +85,12 @@ module ItamaeMitsurin
82
85
  end
83
86
  end
84
87
  end
88
+
89
+ def run(recipe_files, backend_type, options)
90
+ runner = Runner.run(recipe_files, backend_type, options)
91
+ if options[:detailed_exitcode] && runner.diff?
92
+ exit 2
93
+ end
94
+ end
85
95
  end
86
96
  end
@@ -9,7 +9,7 @@ module ItamaeMitsurin
9
9
 
10
10
  def event(type, payload = {})
11
11
  super
12
- @f.puts({'time' => Time.now.iso8601, 'event' => type, 'payload' => payload}.to_json)
12
+ @f.puts({'time' => Time.now.iso8601, 'event' => type, 'payload' => payload}.to_s.encode.to_json)
13
13
  end
14
14
 
15
15
  private
@@ -73,12 +73,9 @@ module ItamaeMitsurin
73
73
  attr_accessor :colored
74
74
 
75
75
  def call(severity, datetime, progname, msg)
76
- log = "%s : %s\n" % ["%5s" % severity, msg2str(msg)]
77
- if colored
78
- colorize(log, severity)
79
- else
80
- log
81
- end
76
+ log = "%s : %s" % ["%5s" % severity, msg2str(msg)]
77
+
78
+ (colored ? colorize(log, severity) : log) + "\n"
82
79
  end
83
80
 
84
81
  def color(code)
@@ -31,3 +31,5 @@ options[:port] = ENV['SSH_PORT']
31
31
  set :host, options[:host_name] || host
32
32
  set :shell, '/bin/bash'
33
33
  set :ssh_options, options
34
+
35
+ set :request_pty, true
@@ -119,7 +119,13 @@ module ItamaeMitsurin
119
119
 
120
120
  puts TaskBase.hl.color(%!Run Itamae to \"#{bname}\"!, :red)
121
121
  run_list_noti = []
122
- command_recipe.each {|c_recipe| run_list_noti << c_recipe.split("/") [2]}
122
+ command_recipe.each { |c_recipe|
123
+ unless c_recipe.split("/")[4].split(".")[0] == 'default'
124
+ run_list_noti << c_recipe.split("/")[2] + "::#{c_recipe.split("/")[4].split(".")[0]}"
125
+ else
126
+ run_list_noti << c_recipe.split("/")[2]
127
+ end
128
+ }
123
129
  puts TaskBase.hl.color(%!Run List to \"#{run_list_noti.uniq.join(", ")}\"!, :green)
124
130
  puts TaskBase.hl.color(%!#{command}!, :white)
125
131
  st = system command
@@ -136,7 +136,13 @@ module ItamaeMitsurin
136
136
 
137
137
  puts TaskBase.hl.color(%!Run Itamae to \"#{bname}\"!, :red)
138
138
  run_list_noti = []
139
- command_recipe.each {|c_recipe| run_list_noti << c_recipe.split("/") [2]}
139
+ command_recipe.each { |c_recipe|
140
+ unless c_recipe.split("/")[4].split(".")[0] == 'default'
141
+ run_list_noti << c_recipe.split("/")[2] + "::#{c_recipe.split("/")[4].split(".")[0]}"
142
+ else
143
+ run_list_noti << c_recipe.split("/")[2]
144
+ end
145
+ }
140
146
  puts TaskBase.hl.color(%!Run List to \"#{run_list_noti.uniq.join(", ")}\"!, :green)
141
147
  puts TaskBase.hl.color(%!#{command}!, :white)
142
148
  st = system command
@@ -114,7 +114,13 @@ module ItamaeMitsurin
114
114
 
115
115
  puts TaskBase.hl.color(%!Run Itamae to \"#{bname}\"!, :red)
116
116
  run_list_noti = []
117
- command_recipe.each {|c_recipe| run_list_noti << c_recipe.split("/") [2]}
117
+ command_recipe.each { |c_recipe|
118
+ unless c_recipe.split("/")[4].split(".")[0] == 'default'
119
+ run_list_noti << c_recipe.split("/")[2] + "::#{c_recipe.split("/")[4].split(".")[0]}"
120
+ else
121
+ run_list_noti << c_recipe.split("/")[2]
122
+ end
123
+ }
118
124
  puts TaskBase.hl.color(%!Run List to \"#{run_list_noti.uniq.join(", ")}\"!, :green)
119
125
  puts TaskBase.hl.color(%!#{command}!, :white)
120
126
  begin
@@ -72,7 +72,13 @@ module Itamae
72
72
  spec_pattern.sort_by! {|item| File.dirname(item)}
73
73
  specs << spec_pattern.join
74
74
  run_list_noti = []
75
- spec_pattern.each {|c_spec| run_list_noti << c_spec.split("/") [2]}
75
+ spec_pattern.each { |c_spec|
76
+ unless c_spec.split("/")[4].split(".")[0] == 'default'
77
+ run_list_noti << c_spec.split("/")[2] + "::#{c_spec.split("/")[4].split(".")[0]}"
78
+ else
79
+ run_list_noti << c_spec.split("/")[2]
80
+ end
81
+ }
76
82
  puts TaskBase.hl.color(%!Run Serverspec to \"#{node_name}\"!, :red)
77
83
  puts TaskBase.hl.color(%!Run List to \"#{run_list_noti.uniq.join(", ")}\"!, :green)
78
84
  st = system specs
@@ -139,6 +139,7 @@ module ItamaeMitsurin
139
139
 
140
140
  verify unless runner.dry_run?
141
141
  if updated?
142
+ runner.diff_found!
142
143
  notify
143
144
  runner.handler.event(:resource_updated)
144
145
  end
@@ -0,0 +1,185 @@
1
+ require 'itamae-mitsurin'
2
+
3
+ module ItamaeMitsurin
4
+ module Resource
5
+ class File < Base
6
+ define_attribute :action, default: :create
7
+ define_attribute :path, type: String, default_name: true
8
+ define_attribute :content, type: String, default: nil
9
+ define_attribute :mode, type: String
10
+ define_attribute :owner, type: String
11
+ define_attribute :group, type: String
12
+ define_attribute :block, type: Proc, default: proc {}
13
+
14
+ def pre_action
15
+ case @current_action
16
+ when :create
17
+ attributes.exist = true
18
+ when :delete
19
+ attributes.exist = false
20
+ when :edit
21
+ attributes.exist = true
22
+
23
+ unless runner.dry_run?
24
+ content = backend.receive_file(attributes.path)
25
+ attributes.block.call(content)
26
+ attributes.content = content
27
+ end
28
+ end
29
+
30
+ send_tempfile
31
+ end
32
+
33
+ def set_current_attributes
34
+ current.exist = run_specinfra(:check_file_is_file, attributes.path)
35
+
36
+ if current.exist
37
+ current.mode = run_specinfra(:get_file_mode, attributes.path).stdout.chomp
38
+ current.owner = run_specinfra(:get_file_owner_user, attributes.path).stdout.chomp
39
+ current.group = run_specinfra(:get_file_owner_group, attributes.path).stdout.chomp
40
+ else
41
+ current.mode = nil
42
+ current.owner = nil
43
+ current.group = nil
44
+ end
45
+ end
46
+
47
+ def show_differences
48
+ current.mode = current.mode.rjust(4, '0') if current.mode
49
+ attributes.mode = attributes.mode.rjust(4, '0') if attributes.mode
50
+
51
+ super
52
+
53
+ if @temppath && @current_action != :delete
54
+ compare_file
55
+ end
56
+ end
57
+
58
+ def action_create(options)
59
+ if !current.exist && !@temppath
60
+ run_command(["touch", attributes.path])
61
+ end
62
+
63
+ if @temppath
64
+ if run_specinfra(:check_file_is_file, attributes.path)
65
+ unless check_command(["diff", "-q", @temppath, attributes.path])
66
+ # the file is modified
67
+ updated!
68
+ end
69
+ else
70
+ # new file
71
+ updated!
72
+ end
73
+ end
74
+
75
+ change_target = @temppath && updated? ? @temppath : attributes.path
76
+
77
+ if attributes.mode
78
+ run_specinfra(:change_file_mode, change_target, attributes.mode)
79
+ end
80
+
81
+ if attributes.owner || attributes.group
82
+ run_specinfra(:change_file_owner, change_target, attributes.owner, attributes.group)
83
+ end
84
+
85
+ if @temppath && updated?
86
+ run_specinfra(:move_file, @temppath, attributes.path)
87
+ end
88
+ end
89
+
90
+ def action_delete(options)
91
+ if run_specinfra(:check_file_is_file, attributes.path)
92
+ run_specinfra(:remove_file, attributes.path)
93
+ end
94
+ end
95
+
96
+ def action_edit(options)
97
+ if attributes.mode
98
+ run_specinfra(:change_file_mode, @temppath, attributes.mode)
99
+ else
100
+ mode = run_specinfra(:get_file_mode, attributes.path).stdout.chomp
101
+ run_specinfra(:change_file_mode, @temppath, mode)
102
+ end
103
+
104
+ if attributes.owner || attributes.group
105
+ run_specinfra(:change_file_owner, @temppath, attributes.owner, attributes.group)
106
+ else
107
+ owner = run_specinfra(:get_file_owner_user, attributes.path).stdout.chomp
108
+ group = run_specinfra(:get_file_owner_group, attributes.path).stdout.chomp
109
+ run_specinfra(:change_file_owner, @temppath, owner)
110
+ run_specinfra(:change_file_group, @temppath, group)
111
+ end
112
+
113
+ unless check_command(["diff", "-q", @temppath, attributes.path])
114
+ # the file is modified
115
+ updated!
116
+ end
117
+
118
+ run_specinfra(:move_file, @temppath, attributes.path)
119
+ end
120
+
121
+ private
122
+
123
+ def compare_file
124
+ compare_to = if current.exist
125
+ attributes.path
126
+ else
127
+ '/dev/null'
128
+ end
129
+
130
+ diff = run_command(["diff", "-u", compare_to, @temppath], error: false)
131
+ if diff.exit_status == 0
132
+ # no change
133
+ ItamaeMitsurin.logger.debug "file content will not change"
134
+ else
135
+ ItamaeMitsurin.logger.info "diff:"
136
+ diff.stdout.each_line do |line|
137
+ color = if line.start_with?('+')
138
+ :green
139
+ elsif line.start_with?('-')
140
+ :red
141
+ else
142
+ :clear
143
+ end
144
+ ItamaeMitsurin.logger.color(color) do
145
+ ItamaeMitsurin.logger.info line.chomp
146
+ end
147
+ end
148
+ runner.handler.event(:file_content_changed, diff: diff.stdout)
149
+ end
150
+ end
151
+
152
+ # will be overridden
153
+ def content_file
154
+ nil
155
+ end
156
+
157
+ def send_tempfile
158
+ if !attributes.content && !content_file
159
+ @temppath = nil
160
+ return
161
+ end
162
+
163
+ begin
164
+ src = if content_file
165
+ content_file
166
+ else
167
+ f = Tempfile.open('itamae')
168
+ f.write(attributes.content)
169
+ f.close
170
+ f.path
171
+ end
172
+
173
+ @temppath = ::File.join(runner.tmpdir, Time.now.to_f.to_s)
174
+
175
+ run_command(["touch", @temppath])
176
+ run_specinfra(:change_file_mode, @temppath, '0600')
177
+ backend.send_file(src, @temppath)
178
+ run_specinfra(:change_file_mode, @temppath, '0600')
179
+ ensure
180
+ f.unlink if f
181
+ end
182
+ end
183
+ end
184
+ end
185
+ end
@@ -12,6 +12,8 @@ module ItamaeMitsurin
12
12
  define_attribute :block, type: Proc, default: proc {}
13
13
 
14
14
  def pre_action
15
+ current.exist = run_specinfra(:check_file_is_file, attributes.path)
16
+
15
17
  case @current_action
16
18
  when :create
17
19
  attributes.exist = true
@@ -20,7 +22,7 @@ module ItamaeMitsurin
20
22
  when :edit
21
23
  attributes.exist = true
22
24
 
23
- unless runner.dry_run?
25
+ if !runner.dry_run? || current.exist
24
26
  content = backend.receive_file(attributes.path)
25
27
  attributes.block.call(content)
26
28
  attributes.content = content
@@ -28,11 +30,11 @@ module ItamaeMitsurin
28
30
  end
29
31
 
30
32
  send_tempfile
33
+ compare_file
31
34
  end
32
35
 
33
36
  def set_current_attributes
34
- current.exist = run_specinfra(:check_file_is_file, attributes.path)
35
-
37
+ current.modified = false
36
38
  if current.exist
37
39
  current.mode = run_specinfra(:get_file_mode, attributes.path).stdout.chomp
38
40
  current.owner = run_specinfra(:get_file_owner_user, attributes.path).stdout.chomp
@@ -51,7 +53,7 @@ module ItamaeMitsurin
51
53
  super
52
54
 
53
55
  if @temppath && @current_action != :delete
54
- compare_file
56
+ show_content_diff
55
57
  end
56
58
  end
57
59
 
@@ -60,19 +62,7 @@ module ItamaeMitsurin
60
62
  run_command(["touch", attributes.path])
61
63
  end
62
64
 
63
- if @temppath
64
- if run_specinfra(:check_file_is_file, attributes.path)
65
- unless check_command(["diff", "-q", @temppath, attributes.path])
66
- # the file is modified
67
- updated!
68
- end
69
- else
70
- # new file
71
- updated!
72
- end
73
- end
74
-
75
- change_target = @temppath && updated? ? @temppath : attributes.path
65
+ change_target = attributes.modified ? @temppath : attributes.path
76
66
 
77
67
  if attributes.mode
78
68
  run_specinfra(:change_file_mode, change_target, attributes.mode)
@@ -82,7 +72,7 @@ module ItamaeMitsurin
82
72
  run_specinfra(:change_file_owner, change_target, attributes.owner, attributes.group)
83
73
  end
84
74
 
85
- if @temppath && updated?
75
+ if attributes.modified
86
76
  run_specinfra(:move_file, @temppath, attributes.path)
87
77
  end
88
78
  end
@@ -110,29 +100,39 @@ module ItamaeMitsurin
110
100
  run_specinfra(:change_file_group, @temppath, group)
111
101
  end
112
102
 
113
- unless check_command(["diff", "-q", @temppath, attributes.path])
114
- # the file is modified
115
- updated!
116
- end
117
-
118
103
  run_specinfra(:move_file, @temppath, attributes.path)
119
104
  end
120
105
 
121
106
  private
122
107
 
123
- def compare_file
124
- compare_to = if current.exist
125
- attributes.path
126
- else
127
- '/dev/null'
128
- end
129
-
130
- diff = run_command(["diff", "-u", compare_to, @temppath], error: false)
131
- if diff.exit_status == 0
132
- # no change
133
- ItamaeMitsurin.logger.debug "file content will not change"
108
+ def compare_to
109
+ if current.exist
110
+ attributes.path
134
111
  else
112
+ '/dev/null'
113
+ end
114
+ end
115
+
116
+ def compare_file
117
+ attributes.modified = false
118
+ unless @temppath
119
+ return
120
+ end
121
+
122
+ case run_command(["diff", "-q", compare_to, @temppath], error: false).exit_status
123
+ when 1
124
+ # diff found
125
+ attributes.modified = true
126
+ when 2
127
+ # error
128
+ raise ItamaeMitsurin::Backend::CommandExecutionError, "diff command exited with 2"
129
+ end
130
+ end
131
+
132
+ def show_content_diff
133
+ if attributes.modified
135
134
  ItamaeMitsurin.logger.info "diff:"
135
+ diff = run_command(["diff", "-u", compare_to, @temppath], error: false)
136
136
  diff.stdout.each_line do |line|
137
137
  color = if line.start_with?('+')
138
138
  :green
@@ -146,6 +146,9 @@ module ItamaeMitsurin
146
146
  end
147
147
  end
148
148
  runner.handler.event(:file_content_changed, diff: diff.stdout)
149
+ else
150
+ # no change
151
+ ItamaeMitsurin.logger.debug "file content will not change"
149
152
  end
150
153
  end
151
154
 
@@ -72,7 +72,11 @@ module ItamaeMitsurin
72
72
  end
73
73
 
74
74
  def run_command_in_repo(*args)
75
- run_command(*args, cwd: attributes.destination)
75
+ unless args.last.is_a?(Hash)
76
+ args << {}
77
+ end
78
+ args.last[:cwd] = attributes.destination
79
+ run_command(*args)
76
80
  end
77
81
 
78
82
  def current_branch
@@ -80,7 +84,11 @@ module ItamaeMitsurin
80
84
  end
81
85
 
82
86
  def get_revision(branch)
83
- run_command_in_repo("git rev-list #{shell_escape(branch)} | head -n1").stdout.strip
87
+ result = run_command_in_repo("git rev-list #{shell_escape(branch)}", error: false)
88
+ unless result.exit_status == 0
89
+ fetch_origin!
90
+ end
91
+ run_command_in_repo("git rev-list #{shell_escape(branch)}").stdout.lines.first.strip
84
92
  end
85
93
 
86
94
  def fetch_origin!
@@ -7,6 +7,9 @@ module ItamaeMitsurin
7
7
  class HttpRequest < File
8
8
  RedirectLimitExceeded = Class.new(StandardError)
9
9
 
10
+ alias_method :_action_create, :action_create
11
+ undef_method :action_create, :action_delete, :action_edit
12
+
10
13
  define_attribute :action, default: :get
11
14
  define_attribute :headers, type: Hash, default: {}
12
15
  define_attribute :message, type: String, default: ""
@@ -14,6 +17,23 @@ module ItamaeMitsurin
14
17
  define_attribute :url, type: String, required: true
15
18
 
16
19
  def pre_action
20
+ attributes.exist = true
21
+ attributes.content = fetch_content
22
+
23
+ send_tempfile
24
+ compare_file
25
+ end
26
+
27
+ def show_differences
28
+ current.mode = current.mode.rjust(4, '0') if current.mode
29
+ attributes.mode = attributes.mode.rjust(4, '0') if attributes.mode
30
+
31
+ super
32
+
33
+ show_content_diff
34
+ end
35
+
36
+ def fetch_content
17
37
  uri = URI.parse(attributes.url)
18
38
  response = nil
19
39
  redirects_followed = 0
@@ -45,26 +65,27 @@ module ItamaeMitsurin
45
65
  attributes.content = response.body
46
66
 
47
67
  super
68
+ response.body
48
69
  end
49
70
 
50
71
  def action_delete(options)
51
- action_create(options)
72
+ _action_create(options)
52
73
  end
53
74
 
54
75
  def action_get(options)
55
- action_create(options)
76
+ _action_create(options)
56
77
  end
57
78
 
58
79
  def action_options(options)
59
- action_create(options)
80
+ _action_create(options)
60
81
  end
61
82
 
62
83
  def action_post(options)
63
- action_create(options)
84
+ _action_create(options)
64
85
  end
65
86
 
66
87
  def action_put(options)
67
- action_create(options)
88
+ _action_create(options)
68
89
  end
69
90
  end
70
91
  end
@@ -18,6 +18,11 @@ module ItamaeMitsurin
18
18
  when :create
19
19
  attributes.exist = true
20
20
  end
21
+
22
+ if attributes.gid.is_a?(String)
23
+ # convert name to gid
24
+ attributes.gid = run_specinfra(:get_group_gid, attributes.gid).stdout.to_i
25
+ end
21
26
  end
22
27
 
23
28
  def set_current_attributes
@@ -12,6 +12,8 @@ module ItamaeMitsurin
12
12
  runner = self.new(backend, options)
13
13
  runner.load_recipes(recipe_files)
14
14
  runner.run
15
+
16
+ runner
15
17
  end
16
18
  end
17
19
 
@@ -31,6 +33,7 @@ module ItamaeMitsurin
31
33
  @node = create_node
32
34
  @tmpdir = "/tmp/itamae_tmp"
33
35
  @children = RecipeChildren.new
36
+ @diff = false
34
37
 
35
38
  @backend.run_command(["mkdir", "-p", @tmpdir])
36
39
  @backend.run_command(["chmod", "777", @tmpdir])
@@ -80,6 +83,14 @@ module ItamaeMitsurin
80
83
  end
81
84
  end
82
85
 
86
+ def diff?
87
+ @diff
88
+ end
89
+
90
+ def diff_found!
91
+ @diff = true
92
+ end
93
+
83
94
  private
84
95
  def create_node
85
96
  hash = {}
@@ -1 +1 @@
1
- 0.24
1
+ 0.26
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: itamae-mitsurin
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.24'
4
+ version: '0.26'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Akihiro Kamiyama
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-04-06 00:00:00.000000000 Z
11
+ date: 2016-04-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -347,6 +347,7 @@ files:
347
347
  - lib/itamae-mitsurin/resource/base.rb
348
348
  - lib/itamae-mitsurin/resource/directory.rb
349
349
  - lib/itamae-mitsurin/resource/execute.rb
350
+ - lib/itamae-mitsurin/resource/file.org
350
351
  - lib/itamae-mitsurin/resource/file.rb
351
352
  - lib/itamae-mitsurin/resource/gem_package.rb
352
353
  - lib/itamae-mitsurin/resource/git.rb