hem 1.0.1.beta1

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