hem 1.0.1.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (111) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +10 -0
  3. data/.gitignore +3 -0
  4. data/.rspec +2 -0
  5. data/CHANGELOG.md +125 -0
  6. data/DoD.md +5 -0
  7. data/Gemfile +4 -0
  8. data/Gemfile.lock +71 -0
  9. data/Guardfile +14 -0
  10. data/Hemfile +43 -0
  11. data/LICENSE +21 -0
  12. data/README.md +42 -0
  13. data/Rakefile +23 -0
  14. data/bin/hem +64 -0
  15. data/features/deps.feature +43 -0
  16. data/features/hem/basic.feature +43 -0
  17. data/features/hem/help.feature +16 -0
  18. data/features/hem/subcommands.feature +15 -0
  19. data/features/seed/plant.feature +64 -0
  20. data/features/step_definitions/env.rb +6 -0
  21. data/features/step_definitions/seed.rb +11 -0
  22. data/features/support/env.rb +6 -0
  23. data/hem.gemspec +47 -0
  24. data/lib/hem/asset_applicator.rb +33 -0
  25. data/lib/hem/asset_applicators/files.rb +5 -0
  26. data/lib/hem/asset_applicators/sqldump.rb +38 -0
  27. data/lib/hem/cli.rb +252 -0
  28. data/lib/hem/config/file.rb +22 -0
  29. data/lib/hem/config.rb +5 -0
  30. data/lib/hem/error_handlers/debug.rb +12 -0
  31. data/lib/hem/error_handlers/exit_code_map.rb +17 -0
  32. data/lib/hem/error_handlers/friendly.rb +58 -0
  33. data/lib/hem/errors.rb +89 -0
  34. data/lib/hem/help_formatter.rb +118 -0
  35. data/lib/hem/helper/file_locator.rb +44 -0
  36. data/lib/hem/helper/github.rb +10 -0
  37. data/lib/hem/helper/http_download.rb +41 -0
  38. data/lib/hem/helper/shell.rb +101 -0
  39. data/lib/hem/helper/vm_command.rb +30 -0
  40. data/lib/hem/lib/github/api.rb +48 -0
  41. data/lib/hem/lib/github/client.rb +52 -0
  42. data/lib/hem/lib/host_check/deps.rb +39 -0
  43. data/lib/hem/lib/host_check/git.rb +76 -0
  44. data/lib/hem/lib/host_check/ruby.rb +53 -0
  45. data/lib/hem/lib/host_check/vagrant.rb +45 -0
  46. data/lib/hem/lib/host_check.rb +34 -0
  47. data/lib/hem/lib/s3/local/file.rb +40 -0
  48. data/lib/hem/lib/s3/local/iohandler.rb +36 -0
  49. data/lib/hem/lib/s3/remote/file.rb +57 -0
  50. data/lib/hem/lib/s3/remote/iohandler.rb +38 -0
  51. data/lib/hem/lib/s3/sync.rb +134 -0
  52. data/lib/hem/lib/seed/project.rb +71 -0
  53. data/lib/hem/lib/seed/replacer.rb +56 -0
  54. data/lib/hem/lib/seed/seed.rb +111 -0
  55. data/lib/hem/lib/self_signed_cert_generator.rb +38 -0
  56. data/lib/hem/lib/vm/command.rb +131 -0
  57. data/lib/hem/lib/vm/inspector.rb +73 -0
  58. data/lib/hem/logging.rb +20 -0
  59. data/lib/hem/metadata.rb +42 -0
  60. data/lib/hem/null.rb +31 -0
  61. data/lib/hem/patches/deepstruct.rb +21 -0
  62. data/lib/hem/patches/rake.rb +101 -0
  63. data/lib/hem/patches/rubygems.rb +6 -0
  64. data/lib/hem/patches/slop.rb +69 -0
  65. data/lib/hem/paths.rb +96 -0
  66. data/lib/hem/tasks/assets.rb +92 -0
  67. data/lib/hem/tasks/config.rb +15 -0
  68. data/lib/hem/tasks/deps.rb +103 -0
  69. data/lib/hem/tasks/exec.rb +3 -0
  70. data/lib/hem/tasks/magento.rb +281 -0
  71. data/lib/hem/tasks/ops.rb +6 -0
  72. data/lib/hem/tasks/pr.rb +45 -0
  73. data/lib/hem/tasks/seed.rb +61 -0
  74. data/lib/hem/tasks/self.rb +45 -0
  75. data/lib/hem/tasks/shell_init.rb +25 -0
  76. data/lib/hem/tasks/system/completions.rb +76 -0
  77. data/lib/hem/tasks/system.rb +18 -0
  78. data/lib/hem/tasks/tools.rb +17 -0
  79. data/lib/hem/tasks/vm.rb +140 -0
  80. data/lib/hem/ui.rb +182 -0
  81. data/lib/hem/util.rb +76 -0
  82. data/lib/hem/version.rb +3 -0
  83. data/lib/hem.rb +72 -0
  84. data/lib/hobo/tasks/magento.rb +3 -0
  85. data/spec/hem/asset_applicator_spec.rb +30 -0
  86. data/spec/hem/cli_spec.rb +166 -0
  87. data/spec/hem/config/file_spec.rb +55 -0
  88. data/spec/hem/error_handlers/debug_spec.rb +43 -0
  89. data/spec/hem/error_handlers/friendly_spec.rb +97 -0
  90. data/spec/hem/error_spec.rb +0 -0
  91. data/spec/hem/help_formatter_spec.rb +162 -0
  92. data/spec/hem/helpers/file_locator_spec.rb +11 -0
  93. data/spec/hem/helpers/github_spec.rb +31 -0
  94. data/spec/hem/helpers/shell_spec.rb +22 -0
  95. data/spec/hem/helpers/vm_command_spec.rb +96 -0
  96. data/spec/hem/lib/github/api_spec.rb +92 -0
  97. data/spec/hem/lib/s3/sync_spec.rb +16 -0
  98. data/spec/hem/lib/seed/project_spec.rb +80 -0
  99. data/spec/hem/lib/seed/replacer_spec.rb +45 -0
  100. data/spec/hem/lib/seed/seed_spec.rb +127 -0
  101. data/spec/hem/logging_spec.rb +27 -0
  102. data/spec/hem/metadata_spec.rb +55 -0
  103. data/spec/hem/null_spec.rb +30 -0
  104. data/spec/hem/patches/rake_spec.rb +230 -0
  105. data/spec/hem/paths_spec.rb +75 -0
  106. data/spec/hem/ui_spec.rb +189 -0
  107. data/spec/hem/util_spec.rb +74 -0
  108. data/spec/spec_helper.rb +12 -0
  109. data/ssl/ca-bundle-s3.crt +3554 -0
  110. data/test_files/vagrant_fail/vagrant +2 -0
  111. metadata +339 -0
@@ -0,0 +1,55 @@
1
+
2
+ describe Hem::Config::File do
3
+ before do
4
+ Hem.project_path = nil
5
+ FakeFS.activate!
6
+ end
7
+
8
+ after do
9
+ FakeFS::FileSystem.clear
10
+ FakeFS.deactivate!
11
+ end
12
+
13
+ def fake_config
14
+ {
15
+ :string => "string",
16
+ :integer => 0,
17
+ :boolean => true,
18
+ :hash => { :test => true },
19
+ :array => [ 1 ]
20
+ }
21
+ end
22
+
23
+ describe "save" do
24
+ it "should save config hash to specified file" do
25
+ Hem::Config::File.save "test.yaml", fake_config
26
+ File.read("test.yaml").should match /string: string/
27
+ end
28
+
29
+ it "should automatically unwrap deepstruct" do
30
+ Hem::Config::File.save "test.yaml", DeepStruct.wrap(fake_config)
31
+ File.read("test.yaml").should match /string: string/
32
+ end
33
+ end
34
+
35
+ describe "load" do
36
+ it "should wrap loaded config with DeepStruct::HashWrapper" do
37
+ Hem::Config::File.save "test.yaml", fake_config
38
+ Hem::Config::File.load("test.yaml").should be_an_instance_of DeepStruct::HashWrapper
39
+ end
40
+
41
+ it "should load config hash from file" do
42
+ Hem::Config::File.save "test.yaml", fake_config
43
+ fake_config().should eq Hem::Config::File.load("test.yaml").unwrap
44
+ end
45
+
46
+ it "should return empty config if file does not exist" do
47
+ Hem::Config::File.load("test.yaml").unwrap.should eq({})
48
+ end
49
+
50
+ it "should raise error if file can't be parsed" do
51
+ File.write("test.yaml", "##Invalid yaml file")
52
+ expect { Hem::Config::File.load("test.yaml") }.to raise_error(RuntimeError, "Invalid hem configuration (test.yaml)")
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,43 @@
1
+
2
+ describe Hem::ErrorHandlers::Debug do
3
+ before do
4
+ Hem.ui = double(Hem::Ui.new).as_null_object
5
+ end
6
+
7
+ def faked_exception(error_template)
8
+ error = nil
9
+ begin
10
+ raise error_template
11
+ rescue Exception => error
12
+ end
13
+
14
+ return error
15
+ end
16
+
17
+ describe "handle" do
18
+ it "should dump the error" do
19
+ error = nil
20
+ begin
21
+ raise Exception.new('error_message')
22
+ rescue Exception => error
23
+ end
24
+
25
+ Hem.ui.should_receive(:error).with(/\(Exception\).*error_message.*debug_spec.rb.*/m)
26
+ Hem::ErrorHandlers::Debug.new.handle(error)
27
+ end
28
+
29
+ it "should return exit code according to exit_code_map" do
30
+ File.write("temp_log", "command output")
31
+ output = Struct.new(:path).new
32
+ output.path = "temp_log"
33
+
34
+ Hem::ErrorHandlers::Debug.new.handle(faked_exception Interrupt.new).should eq 1
35
+ Hem::ErrorHandlers::Debug.new.handle(faked_exception Hem::ExternalCommandError.new("command", 128, output)).should eq 3
36
+ Hem::ErrorHandlers::Debug.new.handle(faked_exception Hem::InvalidCommandOrOpt.new("command")).should eq 4
37
+ Hem::ErrorHandlers::Debug.new.handle(faked_exception Hem::MissingArgumentsError.new("command", ["arg1"])).should eq 5
38
+ Hem::ErrorHandlers::Debug.new.handle(faked_exception Hem::UserError.new("user error")).should eq 6
39
+ Hem::ErrorHandlers::Debug.new.handle(faked_exception Hem::ProjectOnlyError.new).should eq 7
40
+ Hem::ErrorHandlers::Debug.new.handle(faked_exception Exception.new "general").should eq 128
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,97 @@
1
+
2
+ describe Hem::ErrorHandlers::Friendly do
3
+ before do
4
+ Hem.ui = double(Hem::Ui.new).as_null_object
5
+ FakeFS.activate!
6
+ FileUtils.mkdir '/tmp'
7
+ end
8
+
9
+ after do
10
+ FakeFS::FileSystem.clear
11
+ FakeFS.deactivate!
12
+ end
13
+
14
+ def faked_exception(error_template)
15
+ error = nil
16
+ begin
17
+ raise error_template
18
+ rescue Exception => error
19
+ end
20
+
21
+ return error
22
+ end
23
+
24
+ describe "handle" do
25
+ it "should display specialized error for Interrupt" do
26
+ error = faked_exception(Interrupt.new)
27
+ Hem.ui.should_receive(:warning).with(/Caught Interrupt/)
28
+ Hem::ErrorHandlers::Friendly.new.handle(error)
29
+ end
30
+
31
+ it "should display specialized error for an external command error" do
32
+ File.write("temp_log", "command output")
33
+ output = Struct.new(:path).new
34
+ output.path = "temp_log"
35
+
36
+ error = faked_exception Hem::ExternalCommandError.new("command", 128, output)
37
+
38
+ Hem.ui.should_receive(:error).with(/The following external command appears to have failed \(exit status 128\)/)
39
+ Hem::ErrorHandlers::Friendly.new.handle(error)
40
+ end
41
+
42
+ it "should write command output to /tmp/hem_error.log for external command error" do
43
+ File.write("temp_log", "command output")
44
+ output = Struct.new(:path).new
45
+ output.path = "temp_log"
46
+
47
+ error = faked_exception Hem::ExternalCommandError.new("command", 128, output)
48
+
49
+ Hem::ErrorHandlers::Friendly.new.handle(error)
50
+ File.read(File.join(Dir.tmpdir, 'hem_error.log')).should match "command output"
51
+ end
52
+
53
+ it "should display specialized error for invalid command or opt error" do
54
+ error = faked_exception Hem::InvalidCommandOrOpt.new("command")
55
+ Hem.ui.should_receive(:error).with(/Invalid command or option specified: 'command'/)
56
+ Hem::ErrorHandlers::Friendly.new.handle(error)
57
+ end
58
+
59
+ it "should display specialized error for missing argument error" do
60
+ error = faked_exception Hem::MissingArgumentsError.new("command", ["arg1"])
61
+ Hem.ui.should_receive(:error).with(/Not enough arguments for command/)
62
+ Hem::ErrorHandlers::Friendly.new.handle(error)
63
+ end
64
+
65
+ it "should display specialized error for user error" do
66
+ error = faked_exception Hem::UserError.new("user error")
67
+ Hem.ui.should_receive(:error).with(/user error/)
68
+ Hem::ErrorHandlers::Friendly.new.handle(error)
69
+ end
70
+
71
+ it "should display generic error for other exception" do
72
+ error = faked_exception Exception.new("general error")
73
+ Hem.ui.should_receive(:error).with(/An unexpected error has occured/)
74
+ Hem::ErrorHandlers::Friendly.new.handle(error)
75
+ end
76
+
77
+ it "should write error backtrace to /tmp/hem_error.log for other exception" do
78
+ error = faked_exception Exception.new("general error")
79
+ Hem::ErrorHandlers::Friendly.new.handle(error)
80
+ File.read(File.join(Dir.tmpdir, 'hem_error.log')).should match /\(Exception\) general error/
81
+ end
82
+
83
+ it "should return exit code according to exit_code_map" do
84
+ File.write("temp_log", "command output")
85
+ output = Struct.new(:path).new
86
+ output.path = "temp_log"
87
+
88
+ Hem::ErrorHandlers::Friendly.new.handle(faked_exception Interrupt.new).should eq 1
89
+ Hem::ErrorHandlers::Friendly.new.handle(faked_exception Hem::ExternalCommandError.new("command", 128, output)).should eq 3
90
+ Hem::ErrorHandlers::Friendly.new.handle(faked_exception Hem::InvalidCommandOrOpt.new("command")).should eq 4
91
+ Hem::ErrorHandlers::Friendly.new.handle(faked_exception Hem::MissingArgumentsError.new("command", ["arg1"])).should eq 5
92
+ Hem::ErrorHandlers::Friendly.new.handle(faked_exception Hem::UserError.new("user error")).should eq 6
93
+ Hem::ErrorHandlers::Friendly.new.handle(faked_exception Hem::ProjectOnlyError.new).should eq 7
94
+ Hem::ErrorHandlers::Friendly.new.handle(faked_exception Exception.new "general").should eq 128
95
+ end
96
+ end
97
+ end
File without changes
@@ -0,0 +1,162 @@
1
+
2
+ describe Hem::HelpFormatter do
3
+ help = nil
4
+ slop = nil
5
+
6
+ before do
7
+ map = {}
8
+ slop = Slop.new
9
+ slop.instance_eval do
10
+ opt "-g", "--global", "Global option"
11
+
12
+ map["test"] = command "test" do
13
+ description "Testing1"
14
+ opt "-t", "--test", "Test description", :invertable => true
15
+ opt "-x", "--longer-option", "Longer option"
16
+
17
+ map["test:test"] = command "test" do
18
+ description "Testing2"
19
+ arg_list [:arg]
20
+ opt "-a=", "--a-test=", "Arg with value"
21
+ opt "-b=", "--b-test=", "Arg with optional value", argument: :optional
22
+ end
23
+
24
+ map["test:long_desc"] = command "long_desc" do
25
+ long_description "This is a long_desc"
26
+ end
27
+
28
+ map["test:desc"] = command "desc" do
29
+ description "This is a desc"
30
+ end
31
+
32
+ map["test:no_desc"] = command "no_desc" do
33
+ description nil
34
+ end
35
+ end
36
+ end
37
+
38
+ help = Hem::HelpFormatter.new slop
39
+ help.command_map = map
40
+ Hem.ui = Hem::Ui.new
41
+ Hem.ui.use_color false
42
+ end
43
+
44
+ describe "help" do
45
+
46
+ it "should return global help if no target passed" do
47
+ help.help.should match(/test\s+Testing1/)
48
+ end
49
+
50
+ it "should return command help if target passed" do
51
+ help.help(target: "test").should match /^Testing1$/
52
+ end
53
+
54
+ describe "usage format" do
55
+ it "should include generic usage for global help" do
56
+ help.help.should match /Usage:\n\s+rspec \[command\] \[options\]/
57
+ end
58
+
59
+ it "should include command usage for command help" do
60
+ help.help(target: "test:test").should match /Usage:\n\s+rspec test test <arg> \[options\]/
61
+ end
62
+ end
63
+
64
+ describe "option format" do
65
+ it "should include short, long and description" do
66
+ help.help(target: "test").should match /\s+-t, --test\s+Test description/
67
+ end
68
+
69
+ it "should append token value to options that take an argument" do
70
+ help.help(target: "test:test").should match /--a-test=A-TEST/
71
+ end
72
+
73
+ it "should surround token value qith square brackets for option with optional argument" do
74
+ help.help(target: "test:test").should match /--b-test=\[B-TEST\]/
75
+ end
76
+
77
+ it "should have description aligned to longest option or command" do
78
+ len = "--longer-option".length - "--test".length + 4 # ALIGN_PAD
79
+ help.help(target: "test").should match /\s+-t, --test\s{#{len}}Test description/
80
+ end
81
+
82
+ it "should include invertable note if option is invertable" do
83
+ help.help(target: "test").should match /--test.*\(Disable with --no-test\)/
84
+ end
85
+ end
86
+
87
+ describe "command format" do
88
+ it "should have name and description" do
89
+ help.help.should match /\s+test\s+Testing1/
90
+ end
91
+ end
92
+
93
+ describe "global" do
94
+ it "should include usage" do
95
+ help.help.should match /Usage:/
96
+ end
97
+
98
+ it "should include global options" do
99
+ help.help.should match /Global options:\n\s+-g/
100
+ end
101
+
102
+ it "should include top level command list" do
103
+ help.help.should match /Commands:\n\s+test/
104
+ end
105
+ end
106
+
107
+ describe "namespace" do
108
+ it "should include usage" do
109
+ help.help(target: "test").should match /Usage:/
110
+ end
111
+
112
+ it "should include global options" do
113
+ help.help(target: "test").should match /Global options:/
114
+ end
115
+
116
+ it "should include namespace level command list" do
117
+ help.help(target: "test").should match /Commands:/
118
+ end
119
+ end
120
+
121
+ describe "command" do
122
+ it "should include long command description if set" do
123
+ help.help(target: "test:long_desc").should match /^\s+This is a long_desc/
124
+ end
125
+
126
+ it "should fall back to short command description if long description not set" do
127
+ help.help(target: "test:desc").should match /^\s+This is a desc/
128
+ end
129
+
130
+ it "should not display extra blank lines if no description set" do
131
+ help.help(target: "test:no_desc").should match /^Usage/m
132
+ end
133
+
134
+ it "should include usage" do
135
+ help.help(target: "test:no_desc").should match /Usage:/
136
+ end
137
+
138
+ it "should include global options" do
139
+ help.help(target: "test:test").should match /^Global options:/
140
+ end
141
+
142
+ it "should include command options" do
143
+ help.help(target: "test:test").should match /^Command options:/
144
+ end
145
+
146
+ it "should not include -h command option" do
147
+ help.help(target: "test:test").should_not match /Command options:.*--help/m
148
+ end
149
+ end
150
+
151
+
152
+ describe "filtering" do
153
+ it "should not show commands that do not have descriptions" do
154
+ help.help(target: "test").should_not match /Commands:.*no_desc/m
155
+ end
156
+
157
+ it "should show commands that do not have descriptions if :all is set" do
158
+ help.help(target: "test", all: true).should match /Commands:.*no_desc/m
159
+ end
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,11 @@
1
+
2
+ describe Hem::Helper do
3
+ describe "locate" do
4
+ it "should yield filename and path for matches"
5
+ it "should match files in git"
6
+ it "should fallback to files not in git if no matches from git"
7
+ it "should chdir to file path before yielding"
8
+ it "should yield once for each matching file"
9
+ it "should return path array if block not supplied"
10
+ end
11
+ end
@@ -0,0 +1,31 @@
1
+
2
+ describe Hem::Helper do
3
+ describe 'parse_github_url' do
4
+
5
+ it 'should return the parts of a git protocol url' do
6
+ url = 'git://github.com/foo/bar'
7
+ expect(parse_github_url(url)).to eq({:owner => 'foo', :repo => 'bar'})
8
+ end
9
+
10
+ it 'should return the parts of an https url' do
11
+ url = 'https://github.com/foo/bar'
12
+ expect(parse_github_url(url)).to eq({:owner => 'foo', :repo => 'bar'})
13
+ end
14
+
15
+ it 'should return the parts of a git ssh url' do
16
+ url = 'git@github.com:foo/bar'
17
+ expect(parse_github_url(url)).to eq({:owner => 'foo', :repo => 'bar'})
18
+ end
19
+
20
+ it 'should trim the .git https url ending if present' do
21
+ url = 'https://github.com/foo/bar.git'
22
+ expect(parse_github_url(url)).to eq({:owner => 'foo', :repo => 'bar'})
23
+ end
24
+
25
+ it 'should trim the .git ssh url ending if present' do
26
+ url = 'git@github.com:foo/bar.git'
27
+ expect(parse_github_url(url)).to eq({:owner => 'foo', :repo => 'bar'})
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,22 @@
1
+
2
+ describe Hem::Helper do
3
+ describe "bundle_shell" do
4
+ it "should execute command with bundle exec if bundle present"
5
+ it "should execte command normally if no bundle present"
6
+ end
7
+
8
+ describe "shell" do
9
+ it "should run the specified external command"
10
+ it "should return captured output if :capture specified"
11
+ it "should display output if :realtime specified"
12
+ it "should indent output if :realtime and :indent specified"
13
+ it "should apply block to each line if block passed"
14
+ it "should not display lines for which the filter block returned nil"
15
+ it "should buffer all command output in a temporary file"
16
+ it "should throw Hem::ExternalCommandError on non-zero exit code"
17
+ it "should colour stderr output with red"
18
+ it "should set ENV args for command if specified with :env"
19
+ it "should strip leading and trailing whitespace in captured output"
20
+ it "should preserve whitespace in captured output if :strip false"
21
+ end
22
+ end
@@ -0,0 +1,96 @@
1
+
2
+ describe Hem::Helper do
3
+ before do
4
+ Hem.project_config = DeepStruct.wrap({
5
+ :hostname => "test_hostname",
6
+ :mysql => {
7
+ :username => "test_user",
8
+ :password => "test_pass"
9
+ },
10
+ :vm => {
11
+ :project_mount_path => '/'
12
+ }
13
+ })
14
+
15
+ Hem.ui = Hem::Ui.new
16
+
17
+ vmi_double = double(Hem::Lib::Vm::Inspector).as_null_object
18
+ vmi_double.should_receive(:ssh_config).and_return({
19
+ :ssh_host => 'fakehost',
20
+ :ssh_user => 'fakeuser',
21
+ :ssh_port => '999',
22
+ :ssh_identity => 'fakeidentity'
23
+ })
24
+
25
+ Hem::Lib::Vm::Command.class_eval do
26
+ class_variable_set '@@vm_inspector', vmi_double
27
+ end
28
+ end
29
+
30
+ describe "vm_command" do
31
+ it "should create a new vm command wrapper with specified command" do
32
+ vm_command("my_command", :pwd => '/').to_s.should match /-c my_command/
33
+ end
34
+
35
+ it "should default to not using a psuedo tty" do
36
+ vm_command("my_command", :pwd => '/').to_s.should_not match /\s-t\s/
37
+ end
38
+
39
+ it "should default to ssh_config user" do
40
+ vm_command("my_command", :pwd => '/').to_s.should match /fakeuser@/
41
+ end
42
+
43
+ it "should default to ssh_config host name" do
44
+ vm_command("my_command", :pwd => '/').to_s.should match /@fakehost/
45
+ end
46
+
47
+ it "should not wrap piped commands with echo by default" do
48
+ c = vm_command("my_command", :pwd => '/')
49
+ c << "test"
50
+ c.to_s.should_not match /^echo test/
51
+ end
52
+ end
53
+
54
+ describe "vm_mysql" do
55
+ it "should use mysql command by default" do
56
+ vm_mysql(:pwd => '/').to_s.should match /-c mysql/
57
+ end
58
+
59
+ it "should use project config mysql username & password if set" do
60
+ vm_mysql(:pwd => '/').to_s.should match /-c mysql.*-utest_user.*-ptest_pass/
61
+ end
62
+
63
+ it "should not pass user / pass if project config mysql credentials not set" do
64
+ Hem.project_config = DeepStruct.wrap({})
65
+ vm_mysql(:pwd => '/').to_s.should match /-c mysql'/
66
+ end
67
+
68
+ it "should allow specifying the database in options" do
69
+ vm_mysql(:pwd => '/', :db => "test_db").to_s.should match /-c mysql.*test_db'/
70
+ end
71
+
72
+ it "should enable auto echo of piped commands" do
73
+ c = vm_mysql(:pwd => '/')
74
+ c << "SELECT 1"
75
+ c.to_s.should match /^echo SELECT\\ 1/
76
+ end
77
+ end
78
+
79
+ describe "vm_shell" do
80
+ it "should execute the command using the shell helper" do
81
+ Hem::Helper.class_eval do
82
+ alias :old_shell :shell
83
+ def shell command, opts
84
+ command.to_s.should match /ssh.* -c my_command/
85
+ end
86
+ end
87
+
88
+ vm_shell "my_command", :pwd => '/'
89
+
90
+ Hem::Helper.class_eval do
91
+ remove_method :shell
92
+ alias :shell :old_shell
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,92 @@
1
+
2
+ describe Hem::Lib::Github::Api do
3
+
4
+ default_config = {}
5
+ token = 'abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd'
6
+
7
+ before do
8
+ default_config = {
9
+ :ui => double(Hem::Ui).as_null_object,
10
+ :user_config => {},
11
+ :client => double(Hem::Lib::Github::Client).as_null_object,
12
+ :config_class => double(Hem::Config::File).as_null_object
13
+ }
14
+ end
15
+
16
+ describe 'connect' do
17
+
18
+ it 'should request credentials if a token is not saved' do
19
+ expect(default_config[:ui]).to receive(:info).with(kind_of(String))
20
+ expect(default_config[:ui]).to receive(:ask).with('Github username')
21
+ expect(default_config[:ui]).to receive(:ask).with('Github password', echo: false)
22
+
23
+ api = Hem::Lib::Github::Api.new(default_config)
24
+ api.connect
25
+ end
26
+
27
+ it 'should use the credentials to request a token' do
28
+ allow(default_config[:ui]).to receive(:ask).and_return('username', 'password')
29
+ expect(default_config[:client]).to receive(:get_token_for_credentials).with('username', 'password')
30
+
31
+ api = Hem::Lib::Github::Api.new(default_config)
32
+ api.connect
33
+ end
34
+
35
+ it 'should save a new token to user config' do
36
+ allow(default_config[:client]).to receive(:get_token_for_credentials).and_return(token)
37
+ expect(default_config[:config_class]).to receive(:save).with(Hem.user_config_file, {
38
+ :github => {
39
+ :token => token
40
+ }
41
+ })
42
+
43
+ api = Hem::Lib::Github::Api.new(default_config)
44
+ api.connect
45
+ end
46
+
47
+ it 'should use a stored token if one is found' do
48
+ default_config[:user_config] = {
49
+ :github => {
50
+ :token => token
51
+ }
52
+ }
53
+
54
+ expect(default_config[:client]).to receive(:authenticate_with_token).with(token)
55
+
56
+ api = Hem::Lib::Github::Api.new(default_config)
57
+ api.connect
58
+ end
59
+
60
+ end
61
+
62
+ describe 'create_pull_request' do
63
+
64
+ it 'should create a pull request if connected' do
65
+ default_config[:user_config] = {
66
+ :github => {
67
+ :token => token
68
+ }
69
+ }
70
+
71
+ expect(default_config[:client]).to receive(:create_pull_request).with('repo', 'source', 'target', 'title', 'body')
72
+
73
+ api = Hem::Lib::Github::Api.new(default_config)
74
+ api.create_pull_request('repo', 'source', 'target', 'title', 'body')
75
+ end
76
+
77
+ it 'should return the url to the pull request' do
78
+ default_config[:user_config] = {
79
+ :github => {
80
+ :token => token
81
+ }
82
+ }
83
+
84
+ allow(default_config[:client]).to receive(:create_pull_request).and_return('url')
85
+
86
+ api = Hem::Lib::Github::Api.new(default_config)
87
+ expect(api.create_pull_request('repo', 'source', 'target', 'title', 'body')).to eq('url')
88
+ end
89
+
90
+ end
91
+
92
+ end
@@ -0,0 +1,16 @@
1
+
2
+ describe Hem::Lib::S3::Sync do
3
+ before do
4
+ AWS.stub!
5
+ end
6
+
7
+ describe "sync" do
8
+ it "should synchronize s3 files to local"
9
+ it "should synchronize local files to s3"
10
+ it "should add files that only exist in source"
11
+ it "should update files that have changed"
12
+ it "should remove files that do not exist in source"
13
+ it "should keep files that do not exist in source if :delete false"
14
+ it "should update progress as files are transferred"
15
+ end
16
+ end