mamiya 0.0.1.alpha2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +16 -0
  5. data/Gemfile +8 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +43 -0
  8. data/Rakefile +6 -0
  9. data/bin/mamiya +17 -0
  10. data/config.example.yml +11 -0
  11. data/docs/sequences/deploy.png +0 -0
  12. data/docs/sequences/deploy.uml +58 -0
  13. data/example.rb +74 -0
  14. data/lib/mamiya.rb +5 -0
  15. data/lib/mamiya/agent.rb +181 -0
  16. data/lib/mamiya/agent/actions.rb +12 -0
  17. data/lib/mamiya/agent/fetcher.rb +137 -0
  18. data/lib/mamiya/agent/handlers/abstract.rb +20 -0
  19. data/lib/mamiya/agent/handlers/fetch.rb +68 -0
  20. data/lib/mamiya/cli.rb +322 -0
  21. data/lib/mamiya/cli/client.rb +172 -0
  22. data/lib/mamiya/config.rb +57 -0
  23. data/lib/mamiya/dsl.rb +192 -0
  24. data/lib/mamiya/helpers/git.rb +75 -0
  25. data/lib/mamiya/logger.rb +190 -0
  26. data/lib/mamiya/master.rb +118 -0
  27. data/lib/mamiya/master/agent_monitor.rb +146 -0
  28. data/lib/mamiya/master/agent_monitor_handlers.rb +44 -0
  29. data/lib/mamiya/master/web.rb +148 -0
  30. data/lib/mamiya/package.rb +122 -0
  31. data/lib/mamiya/script.rb +117 -0
  32. data/lib/mamiya/steps/abstract.rb +19 -0
  33. data/lib/mamiya/steps/build.rb +72 -0
  34. data/lib/mamiya/steps/extract.rb +26 -0
  35. data/lib/mamiya/steps/fetch.rb +24 -0
  36. data/lib/mamiya/steps/push.rb +34 -0
  37. data/lib/mamiya/storages.rb +17 -0
  38. data/lib/mamiya/storages/abstract.rb +48 -0
  39. data/lib/mamiya/storages/mock.rb +61 -0
  40. data/lib/mamiya/storages/s3.rb +127 -0
  41. data/lib/mamiya/util/label_matcher.rb +38 -0
  42. data/lib/mamiya/version.rb +3 -0
  43. data/mamiya.gemspec +35 -0
  44. data/misc/logger_test.rb +12 -0
  45. data/spec/agent/actions_spec.rb +37 -0
  46. data/spec/agent/fetcher_spec.rb +199 -0
  47. data/spec/agent/handlers/fetch_spec.rb +121 -0
  48. data/spec/agent_spec.rb +255 -0
  49. data/spec/config_spec.rb +50 -0
  50. data/spec/dsl_spec.rb +291 -0
  51. data/spec/fixtures/dsl_test_load.rb +1 -0
  52. data/spec/fixtures/dsl_test_use.rb +1 -0
  53. data/spec/fixtures/helpers/foo.rb +1 -0
  54. data/spec/fixtures/test-package-source/.mamiya.meta.json +1 -0
  55. data/spec/fixtures/test-package-source/greeting +1 -0
  56. data/spec/fixtures/test-package.tar.gz +0 -0
  57. data/spec/fixtures/test.yml +4 -0
  58. data/spec/logger_spec.rb +68 -0
  59. data/spec/master/agent_monitor_spec.rb +269 -0
  60. data/spec/master/web_spec.rb +121 -0
  61. data/spec/master_spec.rb +94 -0
  62. data/spec/package_spec.rb +394 -0
  63. data/spec/script_spec.rb +78 -0
  64. data/spec/spec_helper.rb +38 -0
  65. data/spec/steps/build_spec.rb +261 -0
  66. data/spec/steps/extract_spec.rb +68 -0
  67. data/spec/steps/fetch_spec.rb +96 -0
  68. data/spec/steps/push_spec.rb +73 -0
  69. data/spec/storages/abstract_spec.rb +22 -0
  70. data/spec/storages/s3_spec.rb +342 -0
  71. data/spec/storages_spec.rb +33 -0
  72. data/spec/support/dummy_serf.rb +70 -0
  73. data/spec/util/label_matcher_spec.rb +85 -0
  74. metadata +272 -0
@@ -0,0 +1,78 @@
1
+ require 'spec_helper'
2
+ require 'tmpdir'
3
+
4
+ require 'mamiya/script'
5
+ require 'mamiya/dsl'
6
+
7
+ describe Mamiya::Script do
8
+ it "inherits Mamiya::DSL" do
9
+ expect(described_class.ancestors).to include(Mamiya::DSL)
10
+ end
11
+
12
+ subject(:script) { described_class.new }
13
+ let(:log) { [] }
14
+
15
+ let(:logger) {
16
+ double("logger").tap do |_|
17
+ _.stub(:[]) { _ }
18
+ %i(info warn debug).each do |severity|
19
+ _.stub(severity) { |*args| log << [severity, *args]; _ }
20
+ end
21
+ end
22
+ }
23
+
24
+ before do
25
+ script.set :logger, logger
26
+ end
27
+
28
+ describe "#run" do
29
+ it "runs command" do
30
+ tmpdir = Dir.mktmpdir('akane-script-spec')
31
+ testee = File.join(tmpdir, 'test')
32
+
33
+ expect {
34
+ script.run("touch", testee)
35
+ } \
36
+ .to change { File.exists?(testee) } \
37
+ .from(false).to(true)
38
+ end
39
+
40
+ context "when the command failed" do
41
+ it "raises error" do
42
+ expect {
43
+ script.run("false")
44
+ }.to raise_error(Mamiya::Script::CommandFailed)
45
+ end
46
+
47
+ context "with allow_failure" do
48
+ it "ignores error" do
49
+ expect {
50
+ script.run("false", allow_failure: true)
51
+ }.not_to raise_error
52
+ end
53
+ end
54
+ end
55
+
56
+
57
+ it "logs command as information" do
58
+ script.run("echo", "foo", "bar'", " baz")
59
+ expect(log).to include([:info, "$ echo foo bar\\' \\ baz"])
60
+ end
61
+
62
+ it "logs stdout as debug" do
63
+ script.run("echo", "foo")
64
+ expect(log).to include([:debug, "foo"])
65
+ end
66
+
67
+ it "logs stderr as warn" do
68
+ script.run("ruby", "-e", "warn 'bar'")
69
+ expect(log).to include([:warn, "bar"])
70
+ end
71
+
72
+ it "returns captured output as String" do
73
+ out = script.run("ruby", "-e", "puts 'foo'; warn 'bar'")
74
+ expect(out).to match(/^foo$/)
75
+ expect(out).to match(/^bar$/)
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,38 @@
1
+ require 'rack/test'
2
+ require 'mamiya/storages/mock'
3
+ require 'mamiya/logger'
4
+
5
+ module Rack
6
+ module Test
7
+ class Session
8
+ def envs
9
+ @envs ||= {}
10
+ end
11
+
12
+ alias_method :default_env_orig, :default_env
13
+ def default_env
14
+ default_env_orig.merge(envs)
15
+ end
16
+ end
17
+ end
18
+ end
19
+
20
+ unless ENV["ENABLE_LOG"]
21
+ Mamiya::Logger.defaults[:outputs] = []
22
+ end
23
+
24
+ RSpec.configure do |config|
25
+ config.treat_symbols_as_metadata_keys_with_true_values = true
26
+ config.run_all_when_everything_filtered = true
27
+ config.filter_run :focus
28
+
29
+ # Run specs in random order to surface order dependencies. If you find an
30
+ # order dependency and want to debug it, you can fix the order by providing
31
+ # the seed, which is printed after each run.
32
+ # --seed 1234
33
+ config.order = 'random'
34
+
35
+ config.after(:each) do
36
+ Mamiya::Storages::Mock.clear
37
+ end
38
+ end
@@ -0,0 +1,261 @@
1
+ require 'spec_helper'
2
+ require 'tmpdir'
3
+ require 'pathname'
4
+ require 'fileutils'
5
+
6
+ require 'mamiya/package'
7
+
8
+ require 'mamiya/steps/build'
9
+
10
+ describe Mamiya::Steps::Build do
11
+ let!(:tmpdir) { Dir.mktmpdir("mamiya-steps-build-spec") }
12
+ after { FileUtils.remove_entry_secure tmpdir }
13
+
14
+ let(:build_dir) { Pathname.new(tmpdir).join('build') }
15
+ let(:package_dir) { Pathname.new(tmpdir).join('pkg') }
16
+ let(:extract_dir) { Pathname.new(tmpdir).join('extract') }
17
+
18
+ let(:exclude_from_package) { [] }
19
+ let(:package_under) { nil }
20
+ let(:dereference_symlinks) { false }
21
+ let(:skip_prepare_build) { false }
22
+
23
+ let(:package_name) { nil }
24
+ let(:script) do
25
+ double('script',
26
+ application: 'app',
27
+ build_from: build_dir,
28
+ build_to: package_dir,
29
+ before_build: proc {},
30
+ prepare_build: proc {},
31
+ build: proc {},
32
+ after_build: proc {},
33
+ package_name: proc { |_| package_name || _ },
34
+ package_meta: proc { |_| _ },
35
+ package_under: package_under,
36
+ dereference_symlinks: dereference_symlinks,
37
+ exclude_from_package: exclude_from_package,
38
+ skip_prepare_build: skip_prepare_build,
39
+ )
40
+ end
41
+
42
+ subject(:build_step) { described_class.new(script: script) }
43
+
44
+ describe "#run!" do
45
+ before do
46
+ Dir.mkdir(build_dir)
47
+ Dir.mkdir(package_dir)
48
+ Dir.mkdir(extract_dir)
49
+
50
+ File.write(build_dir.join('greeting'), 'hello')
51
+ end
52
+
53
+ it "calls hooks with proper order" do
54
+ hooks = %i(before_build prepare_build build after_build)
55
+
56
+ flags = []
57
+ hooks.each do |sym|
58
+ allow(script).to receive(sym).and_return(proc { flags << sym })
59
+ end
60
+
61
+ expect { build_step.run! }.
62
+ to change { flags }.
63
+ from([]).
64
+ to(hooks)
65
+ end
66
+
67
+ it "calls after_build hook even if exception occured" do
68
+ e = Exception.new("Good bye, the cruel world")
69
+ allow(script).to receive(:build).and_return(proc { raise e })
70
+
71
+ received = nil
72
+ allow(script).to receive(:after_build).and_return(proc { |_| received = _ })
73
+
74
+ expect {
75
+ begin
76
+ build_step.run!
77
+ rescue Exception; end
78
+ }.
79
+ to change { received }.
80
+ from(nil).to(e)
81
+ end
82
+
83
+ it "calls build hook in :build_from (pwd)" do
84
+ pwd = nil
85
+ script.stub(build: proc { pwd = Dir.pwd })
86
+
87
+ expect {
88
+ build_step.run!
89
+ }.not_to change { Dir.pwd }
90
+
91
+ expect(File.realpath(pwd)).to eq script.build_from.realpath.to_s
92
+ end
93
+
94
+ it "creates package using Package after :build called" do
95
+ built = false
96
+ allow(script).to receive(:build).and_return(proc { built = true })
97
+ allow(script).to receive(:exclude_from_package).and_return(['test'])
98
+ allow(script).to receive(:dereference_symlinks).and_return(true)
99
+ allow(script).to receive(:package_under).and_return('foo')
100
+
101
+ expect_any_instance_of(Mamiya::Package).to \
102
+ receive(:build!).with(
103
+ build_dir,
104
+ hash_including(
105
+ exclude_from_package: ['test'],
106
+ dereference_symlinks: true,
107
+ package_under: 'foo',
108
+ )
109
+ ) {
110
+ expect(built).to be_true
111
+ }
112
+
113
+ build_step.run!
114
+ end
115
+
116
+ it "creates package with metadata including application" do
117
+ meta = {}
118
+ allow_any_instance_of(Mamiya::Package).to receive(:meta).and_return(meta)
119
+ expect_any_instance_of(Mamiya::Package).to receive(:build!) {
120
+ expect(meta[:application]).to eq 'app'
121
+ }
122
+
123
+ build_step.run!
124
+ end
125
+
126
+ context "with package name determiner" do
127
+ it "calls package name determiner with current candidate" do
128
+ received = nil
129
+ allow(script).to receive(:package_name).and_return(proc { |arg| received = arg })
130
+
131
+ build_step.run!
132
+
133
+ expect(received).to be_a_kind_of(Array)
134
+
135
+ # Default candidates
136
+ expect(received.size).to eq 2
137
+ expect(received[0]).to match(/\A\d{4}-\d{2}-\d{2}_\d{2}\.\d{2}\.\d{2}\z/)
138
+ expect(received[1]).to eq script.application
139
+ end
140
+
141
+ it "uses result by joining with '-' as package name to be built" do
142
+ allow(script).to receive(:package_name).and_return(proc { |arg| %w(veni vidi vici) })
143
+
144
+ build_step.run!
145
+
146
+ expect(package_dir.join('veni-vidi-vici.tar.gz')).to be_exist
147
+ end
148
+
149
+ it "calls the determiner in build dir" do
150
+ pwd = nil
151
+ allow(script).to receive(:package_name).and_return(proc { |arg| pwd = Dir.pwd; arg })
152
+
153
+ expect {
154
+ build_step.run!
155
+ }.not_to change { Dir.pwd }
156
+
157
+ expect(File.realpath(pwd)).to eq script.build_from.realpath.to_s
158
+ end
159
+
160
+ context "when the determiner returned non-Array" do
161
+ it "wraps with Array before calling next determiner"
162
+ end
163
+ end
164
+
165
+ context "with package meta determiner" do
166
+ it "calls determiners with current candidate" do
167
+ received = nil
168
+ allow(script).to receive(:package_meta).and_return(proc { |arg| received = arg })
169
+
170
+ build_step.run!
171
+
172
+ expect(received).to be_a_kind_of(Hash)
173
+ end
174
+
175
+ it "uses result as package metadata" do
176
+ meta = {}
177
+ allow_any_instance_of(Mamiya::Package).to receive(:meta).and_return(meta)
178
+ allow_any_instance_of(Mamiya::Package).to receive(:build!) { }
179
+
180
+ allow(script).to receive(:package_meta).and_return(proc { |arg| {'test' => 'hello'} })
181
+
182
+ build_step.run!
183
+
184
+ expect(meta['test']).to eq 'hello'
185
+ end
186
+
187
+ it "calls the determiner in build dir" do
188
+ pwd = nil
189
+ allow(script).to receive(:package_meta).and_return(proc { |arg| pwd = Dir.pwd; arg })
190
+
191
+ expect {
192
+ build_step.run!
193
+ }.not_to change { Dir.pwd }
194
+
195
+ expect(File.realpath(pwd)).to eq script.build_from.realpath.to_s
196
+ end
197
+ end
198
+
199
+ context "when build_from directory exist" do
200
+ it "calls prepare_build with update=true" do
201
+ arg = nil
202
+ allow(script).to receive(:prepare_build).and_return(proc { |update| arg = update })
203
+
204
+ expect {
205
+ build_step.run!
206
+ }.to change { arg }.
207
+ from(nil).to(true)
208
+ end
209
+ end
210
+
211
+ context "when build_from directory doesn't exist" do
212
+ before do
213
+ FileUtils.remove_entry_secure(build_dir)
214
+ end
215
+
216
+ it "calls prepare_build with update=false" do
217
+ arg = nil
218
+ allow(script).to receive(:prepare_build).and_return(proc { |update| arg = update })
219
+
220
+ expect {
221
+ begin
222
+ build_step.run!
223
+ rescue Errno::ENOENT; end
224
+ }.to change { arg }.
225
+ from(nil).to(false)
226
+ end
227
+
228
+ it "raises error" do
229
+ expect {
230
+ build_step.run!
231
+ }.to raise_error(Errno::ENOENT)
232
+ end
233
+ end
234
+
235
+
236
+ context "with skip_prepare_build option" do
237
+ context "when the option is false" do
238
+ let(:skip_prepare_build) { false }
239
+
240
+ it "calls prepare_build" do
241
+ flag = false
242
+ allow(script).to receive(:prepare_build).and_return(proc { flag = true })
243
+
244
+ expect { build_step.run! }.to change { flag }.
245
+ from(false).to(true)
246
+ end
247
+ end
248
+
249
+ context "when the option is true" do
250
+ let(:skip_prepare_build) { true }
251
+
252
+ it "doesn't call prepare_build" do
253
+ flag = false
254
+ allow(script).to receive(:prepare_build).and_return(proc { flag = true })
255
+
256
+ expect { build_step.run! }.not_to change { flag }
257
+ end
258
+ end
259
+ end
260
+ end
261
+ end
@@ -0,0 +1,68 @@
1
+ require 'spec_helper'
2
+ require 'tmpdir'
3
+ require 'pathname'
4
+ require 'fileutils'
5
+
6
+ require 'mamiya/package'
7
+ require 'mamiya/steps/extract'
8
+
9
+ describe Mamiya::Steps::Extract do
10
+ let!(:tmpdir) { Dir.mktmpdir("mamiya-steps-extract-spec") }
11
+ after { FileUtils.remove_entry_secure tmpdir }
12
+
13
+ let(:package_dir) { Pathname.new(tmpdir).join('pkg').tap(&:mkdir) }
14
+
15
+ let(:target_package) { package_dir.join('test-package.tar.gz').to_s }
16
+ let(:script) do
17
+ double('script',
18
+ application: 'myapp',
19
+ )
20
+ end
21
+
22
+ let(:destination) { Pathname.new(tmpdir).join('dst') }
23
+
24
+ let(:options) do
25
+ {
26
+ package: target_package,
27
+ destination: destination.to_s,
28
+ }
29
+ end
30
+
31
+ subject(:extract_step) { described_class.new(script: script, **options) }
32
+
33
+ describe "#run!" do
34
+ before do
35
+ FileUtils.cp File.join(__dir__, '..', 'fixtures', 'test-package.tar.gz'), target_package
36
+ File.write target_package.gsub(/\.tar\.gz$/,'.json'), "{}\n"
37
+ end
38
+
39
+ context "when destination exists" do
40
+ before do
41
+ destination.mkdir()
42
+ allow_any_instance_of(Mamiya::Package).to receive(:name).and_return('package-name')
43
+ end
44
+
45
+ it "extracts package on sub-directory named as same as package name" do
46
+ extract_step.run!
47
+ expect(destination.join('package-name')).to be_a_directory
48
+ expect(destination.join('package-name', 'greeting')).to be_exist
49
+ end
50
+ end
51
+
52
+ context "when destination not exists" do
53
+ it "extracts package on destination" do
54
+ extract_step.run!
55
+ expect(destination).to be_a_directory
56
+ expect(destination.join('greeting')).to be_exist
57
+ end
58
+ end
59
+
60
+ context "with verify option" do
61
+ it "verifies"
62
+ end
63
+
64
+ context "when package not exists" do
65
+ it "-"
66
+ end
67
+ end
68
+ end