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.
- checksums.yaml +7 -0
- data/.editorconfig +10 -0
- data/.gitignore +3 -0
- data/.rspec +2 -0
- data/CHANGELOG.md +125 -0
- data/DoD.md +5 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +71 -0
- data/Guardfile +14 -0
- data/Hemfile +43 -0
- data/LICENSE +21 -0
- data/README.md +42 -0
- data/Rakefile +23 -0
- data/bin/hem +64 -0
- data/features/deps.feature +43 -0
- data/features/hem/basic.feature +43 -0
- data/features/hem/help.feature +16 -0
- data/features/hem/subcommands.feature +15 -0
- data/features/seed/plant.feature +64 -0
- data/features/step_definitions/env.rb +6 -0
- data/features/step_definitions/seed.rb +11 -0
- data/features/support/env.rb +6 -0
- data/hem.gemspec +47 -0
- data/lib/hem/asset_applicator.rb +33 -0
- data/lib/hem/asset_applicators/files.rb +5 -0
- data/lib/hem/asset_applicators/sqldump.rb +38 -0
- data/lib/hem/cli.rb +252 -0
- data/lib/hem/config/file.rb +22 -0
- data/lib/hem/config.rb +5 -0
- data/lib/hem/error_handlers/debug.rb +12 -0
- data/lib/hem/error_handlers/exit_code_map.rb +17 -0
- data/lib/hem/error_handlers/friendly.rb +58 -0
- data/lib/hem/errors.rb +89 -0
- data/lib/hem/help_formatter.rb +118 -0
- data/lib/hem/helper/file_locator.rb +44 -0
- data/lib/hem/helper/github.rb +10 -0
- data/lib/hem/helper/http_download.rb +41 -0
- data/lib/hem/helper/shell.rb +101 -0
- data/lib/hem/helper/vm_command.rb +30 -0
- data/lib/hem/lib/github/api.rb +48 -0
- data/lib/hem/lib/github/client.rb +52 -0
- data/lib/hem/lib/host_check/deps.rb +39 -0
- data/lib/hem/lib/host_check/git.rb +76 -0
- data/lib/hem/lib/host_check/ruby.rb +53 -0
- data/lib/hem/lib/host_check/vagrant.rb +45 -0
- data/lib/hem/lib/host_check.rb +34 -0
- data/lib/hem/lib/s3/local/file.rb +40 -0
- data/lib/hem/lib/s3/local/iohandler.rb +36 -0
- data/lib/hem/lib/s3/remote/file.rb +57 -0
- data/lib/hem/lib/s3/remote/iohandler.rb +38 -0
- data/lib/hem/lib/s3/sync.rb +134 -0
- data/lib/hem/lib/seed/project.rb +71 -0
- data/lib/hem/lib/seed/replacer.rb +56 -0
- data/lib/hem/lib/seed/seed.rb +111 -0
- data/lib/hem/lib/self_signed_cert_generator.rb +38 -0
- data/lib/hem/lib/vm/command.rb +131 -0
- data/lib/hem/lib/vm/inspector.rb +73 -0
- data/lib/hem/logging.rb +20 -0
- data/lib/hem/metadata.rb +42 -0
- data/lib/hem/null.rb +31 -0
- data/lib/hem/patches/deepstruct.rb +21 -0
- data/lib/hem/patches/rake.rb +101 -0
- data/lib/hem/patches/rubygems.rb +6 -0
- data/lib/hem/patches/slop.rb +69 -0
- data/lib/hem/paths.rb +96 -0
- data/lib/hem/tasks/assets.rb +92 -0
- data/lib/hem/tasks/config.rb +15 -0
- data/lib/hem/tasks/deps.rb +103 -0
- data/lib/hem/tasks/exec.rb +3 -0
- data/lib/hem/tasks/magento.rb +281 -0
- data/lib/hem/tasks/ops.rb +6 -0
- data/lib/hem/tasks/pr.rb +45 -0
- data/lib/hem/tasks/seed.rb +61 -0
- data/lib/hem/tasks/self.rb +45 -0
- data/lib/hem/tasks/shell_init.rb +25 -0
- data/lib/hem/tasks/system/completions.rb +76 -0
- data/lib/hem/tasks/system.rb +18 -0
- data/lib/hem/tasks/tools.rb +17 -0
- data/lib/hem/tasks/vm.rb +140 -0
- data/lib/hem/ui.rb +182 -0
- data/lib/hem/util.rb +76 -0
- data/lib/hem/version.rb +3 -0
- data/lib/hem.rb +72 -0
- data/lib/hobo/tasks/magento.rb +3 -0
- data/spec/hem/asset_applicator_spec.rb +30 -0
- data/spec/hem/cli_spec.rb +166 -0
- data/spec/hem/config/file_spec.rb +55 -0
- data/spec/hem/error_handlers/debug_spec.rb +43 -0
- data/spec/hem/error_handlers/friendly_spec.rb +97 -0
- data/spec/hem/error_spec.rb +0 -0
- data/spec/hem/help_formatter_spec.rb +162 -0
- data/spec/hem/helpers/file_locator_spec.rb +11 -0
- data/spec/hem/helpers/github_spec.rb +31 -0
- data/spec/hem/helpers/shell_spec.rb +22 -0
- data/spec/hem/helpers/vm_command_spec.rb +96 -0
- data/spec/hem/lib/github/api_spec.rb +92 -0
- data/spec/hem/lib/s3/sync_spec.rb +16 -0
- data/spec/hem/lib/seed/project_spec.rb +80 -0
- data/spec/hem/lib/seed/replacer_spec.rb +45 -0
- data/spec/hem/lib/seed/seed_spec.rb +127 -0
- data/spec/hem/logging_spec.rb +27 -0
- data/spec/hem/metadata_spec.rb +55 -0
- data/spec/hem/null_spec.rb +30 -0
- data/spec/hem/patches/rake_spec.rb +230 -0
- data/spec/hem/paths_spec.rb +75 -0
- data/spec/hem/ui_spec.rb +189 -0
- data/spec/hem/util_spec.rb +74 -0
- data/spec/spec_helper.rb +12 -0
- data/ssl/ca-bundle-s3.crt +3554 -0
- data/test_files/vagrant_fail/vagrant +2 -0
- 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
|