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,140 @@
1
+ desc "VM related commands"
2
+ project_only
3
+ namespace :vm do
4
+ def vagrantfile &block
5
+ locate "*Vagrantfile" do
6
+ yield
7
+ end
8
+ end
9
+
10
+ def vagrant_exec *args
11
+ opts = { :realtime => true, :indent => 2 }
12
+ color = Hem.ui.supports_color? ? '--color' : '--no-color'
13
+
14
+ if Hem.windows?
15
+ opts[:env] = { 'VAGRANT_HOME' => windows_short(dir) } if ENV['HOME'].match(/\s+/) && !ENV['VAGRANT_HOME']
16
+ end
17
+
18
+ args.unshift 'vagrant'
19
+ args.push color
20
+ args.push opts
21
+
22
+ shell *args
23
+ end
24
+
25
+ def windows_short dir
26
+ segments = dir.gsub(/\\/, '/').split('/')
27
+ segments.map do |segment|
28
+ if segment.match /\s+/
29
+ # This may fail in some edge cases but better than naught
30
+ # See the following link for the correct solution
31
+ # http://stackoverflow.com/questions/10224572/convert-long-filename-to-short-filename-8-3
32
+ segment.upcase.gsub(/\s+/, '')[0...6] + '~1'
33
+ else
34
+ segment
35
+ end
36
+ end.join('/')
37
+ end
38
+
39
+ desc "Start & provision VM"
40
+ task :up => [ 'assets:download', 'vm:start', 'vm:provision', 'deps:composer', 'assets:apply' ]
41
+
42
+ desc "Stop VM"
43
+ task :stop do
44
+ vagrantfile do
45
+ Hem.ui.title "Stopping VM"
46
+ vagrant_exec 'halt'
47
+ Hem.ui.separator
48
+ end
49
+ end
50
+
51
+ desc "Rebuild VM"
52
+ task :rebuild => [ 'vm:destroy', 'vm:up' ]
53
+
54
+ desc "Destroy VM"
55
+ task :destroy do
56
+ vagrantfile do
57
+ Hem.ui.title "Destroying VM"
58
+ vagrant_exec 'destroy', '--force'
59
+ Hem.ui.separator
60
+ end
61
+ end
62
+
63
+ desc "Start VM without provision"
64
+ task :start => [ "deps:gems", "deps:chef", "deps:vagrant_plugins" ] do
65
+ vagrantfile do
66
+ state = shell("vagrant --machine-readable status | grep ,state, | cut -d, -f4", :capture => true).strip
67
+ unless state == 'running'
68
+ Hem.ui.title "Starting vagrant VM"
69
+ args = ['up', '--no-provision']
70
+
71
+ provider = maybe(Hem.user_config.vm.provider)
72
+ provider ||= maybe(Hem.project_config.vm.provider)
73
+
74
+ if provider
75
+ args.concat ['--provider', provider]
76
+ end
77
+
78
+ vagrant_exec *args
79
+ Hem.ui.separator
80
+ end
81
+ end
82
+ end
83
+
84
+ desc "Reload VM"
85
+ task :reload do
86
+ vagrantfile do
87
+ Hem.ui.title "Reloading VM"
88
+ vagrant_exec 'reload', '--no-provision'
89
+ Hem.ui.separator
90
+ end
91
+ end
92
+
93
+ desc "Provision VM"
94
+ task :provision => [ "deps:chef" ] do
95
+ vagrantfile do
96
+ Hem.ui.title "Provisioning VM"
97
+ vagrant_exec 'provision'
98
+ Hem.ui.separator
99
+ end
100
+ end
101
+
102
+ desc "Open an SSH connection"
103
+ task :ssh do |task|
104
+ execute = task.opts[:_unparsed]
105
+ opts = { :psuedo_tty => STDIN.tty? }
106
+
107
+ Hem.ui.success "Determining VM connection details..." if STDOUT.tty?
108
+ command = execute.empty? ? vm_command(nil, opts) : vm_command(execute, opts)
109
+ Hem.logger.debug "vm:ssh: #{command}"
110
+
111
+ Hem.ui.success "Connecting..." if STDOUT.tty?
112
+ exec command
113
+ end
114
+
115
+ desc "Open a MySQL cli connection"
116
+ option '-D=', '--db=', 'Database'
117
+ task :mysql do |task|
118
+ opts = { :psuedo_tty => STDIN.tty? }
119
+ opts[:db] = task.opts[:db] if task.opts[:db]
120
+
121
+ Hem.ui.success "Determining VM connection details..." if STDOUT.tty?
122
+ command = vm_mysql(opts)
123
+ Hem.logger.debug "vm:mysql: #{command}"
124
+
125
+ Hem.ui.success "Connecting..." if STDOUT.tty?
126
+ exec command
127
+ end
128
+
129
+ desc "Open a Redis cli connection"
130
+ task :redis do
131
+ opts = { :psuedo_tty => STDIN.tty? }
132
+
133
+ Hem.ui.success "Determining VM connection details..." if STDOUT.tty?
134
+ command = vm_command("redis-cli", opts)
135
+ Hem.logger.debug "vm:redis: #{command}"
136
+
137
+ Hem.ui.success "Connecting..." if STDOUT.tty?
138
+ exec command
139
+ end
140
+ end
data/lib/hem/ui.rb ADDED
@@ -0,0 +1,182 @@
1
+ module Hem
2
+ class << self
3
+ attr_accessor :ui
4
+ end
5
+
6
+ class Ui
7
+ include Hem::Logging
8
+
9
+ attr_accessor :interactive
10
+
11
+ COLORS = {
12
+ :debug => [ ],
13
+ :info => [ ],
14
+ :warning => [:yellow],
15
+ :error => [:red],
16
+ :success => [:green],
17
+ :opt => [:green],
18
+ :command => [:green],
19
+ :special => [:blue],
20
+ :title => [:green],
21
+ :help_title => [:yellow],
22
+ :description => [:bold]
23
+ }
24
+
25
+ def initialize input = $stdin, output = $stdout, error = $stderr
26
+ require 'highline'
27
+ HighLine.color_scheme = HighLine::ColorScheme.new COLORS
28
+ @output_io = output
29
+ @out = ::HighLine.new input, output
30
+ @error = ::HighLine.new input, error
31
+ use_color supports_color?
32
+ end
33
+
34
+ def color_scheme scheme = nil
35
+ HighLine.color_scheme = scheme if scheme
36
+ HighLine.color_scheme
37
+ end
38
+
39
+ def supports_color?
40
+ return @output_io.tty? unless Hem.windows?
41
+ return (ENV['ANSICON'] || ENV['TERM'] == 'xterm') && @output_io.tty? # ANSICON or MinTTY && output is TTY
42
+ end
43
+
44
+ def use_color opt = nil
45
+ HighLine.use_color = opt unless opt.nil?
46
+ HighLine.use_color?
47
+ end
48
+
49
+ def ask question, opts = {}
50
+ opts = {
51
+ :validate => nil,
52
+ :default => nil,
53
+ :echo => true
54
+ }.merge(opts)
55
+
56
+ unless @interactive
57
+ raise Hem::NonInteractiveError.new(question) if opts[:default].nil?
58
+ return opts[:default].to_s
59
+ end
60
+
61
+ question = "#{question} [#{opts[:default]}]" if opts[:default]
62
+ question += ": "
63
+ begin
64
+ answer = @out.ask(question) do |q|
65
+ q.validate = opts[:validate] if opts[:validate]
66
+ q.echo = opts[:echo]
67
+ q.readline
68
+ end
69
+ answer = answer.to_s
70
+ answer.strip.empty? ? opts[:default].to_s : answer.strip
71
+ rescue EOFError
72
+ Hem.ui.info ""
73
+ ""
74
+ end
75
+ end
76
+
77
+ def ask_choice question, choices, opts = {}
78
+ unless @interactive
79
+ raise Hem::NonInteractiveError.new(question) if opts[:default].nil?
80
+ return opts[:default].to_s
81
+ end
82
+
83
+ question = "#{question} [#{opts[:default]}]" if opts[:default]
84
+ question += ":"
85
+ info question
86
+
87
+ choice_map = {}
88
+ choices.to_enum.with_index(1) do |choice, index|
89
+ choice_map[index.to_s] = choice
90
+ info "#{index}] #{choice}"
91
+ end
92
+
93
+ begin
94
+ answer = @out.ask("? ") do |q|
95
+ q.validate = lambda do |a|
96
+ s = a.strip
97
+ s.empty? || (choice_map.keys + choices).include?(s)
98
+ end
99
+ q.readline
100
+ end
101
+ answer = answer.to_s
102
+ answer = choice_map[answer] if /^\d+$/.match(answer.strip)
103
+ answer.strip.empty? ? opts[:default].to_s : answer.strip
104
+ rescue EOFError
105
+ Hem.ui.info ""
106
+ ""
107
+ end
108
+ end
109
+
110
+ def editor initial_text
111
+ editor = Hem.user_config.editor.nil? ? ENV['EDITOR'] : Hem.user_config.editor
112
+ if editor.nil?
113
+ raise Hem::UndefinedEditorError.new
114
+ end
115
+
116
+ tmp = Tempfile.new('hem_tmp')
117
+ begin
118
+ tmp.write initial_text
119
+ tmp.close
120
+ system([editor, tmp.path].join(' '))
121
+ tmp.open
122
+ return tmp.read
123
+ rescue Exception => e
124
+ raise Hem::Error.new e.message
125
+ ensure
126
+ tmp.close
127
+ tmp.unlink
128
+ end
129
+ end
130
+
131
+ def section title
132
+ Hem.ui.title title
133
+ yield
134
+ Hem.ui.separator
135
+ end
136
+
137
+ def separator
138
+ info(supports_color? ? "" : "\n")
139
+ end
140
+
141
+ def color *args
142
+ @out.color *args
143
+ end
144
+
145
+ def debug message
146
+ say @out, message, :debug
147
+ end
148
+
149
+ def info message
150
+ say @out, message, :info
151
+ end
152
+
153
+ def warning message
154
+ say @error, message, :warning
155
+ end
156
+
157
+ def error message
158
+ say @error, message, :error
159
+ end
160
+
161
+ def success message
162
+ say @out, message, :success
163
+ end
164
+
165
+ def output message
166
+ say @out, message, nil
167
+ end
168
+
169
+ def title message
170
+ say @out, message, :title
171
+ end
172
+
173
+ private
174
+
175
+ def say channel, message, color
176
+ return if message.nil?
177
+ message = color ? channel.color(message, color) : message
178
+ channel.say(message) unless logger.level <= Logger::DEBUG
179
+ logger.debug(message)
180
+ end
181
+ end
182
+ end
data/lib/hem/util.rb ADDED
@@ -0,0 +1,76 @@
1
+ module Hem
2
+ class << self
3
+
4
+ attr_accessor :project_bar_cache
5
+
6
+ def relaunch! env = {}
7
+ Kernel.exec(env, 'hem', '--skip-host-checks', *$HEM_ARGV)
8
+ end
9
+
10
+ def in_project?
11
+ !!Hem.project_path
12
+ end
13
+
14
+ def progress file, increment, total, type, opts = {}
15
+ require 'ruby-progressbar'
16
+
17
+ opts = {
18
+ :title => File.basename(file),
19
+ :total => total,
20
+ :format => "%t [%B] %p%% %e"
21
+ }.merge(opts)
22
+
23
+ # Hack to stop newline spam on windows
24
+ opts[:length] = 79 if Gem::win_platform?
25
+
26
+ @progress_bar_cache ||= {}
27
+
28
+ if type == :reset
29
+ type = :update
30
+ @progress_bar_cache.delete file
31
+ end
32
+
33
+ @progress_bar_cache[file] ||= ProgressBar.create(opts)
34
+
35
+ case type
36
+ when :update
37
+ @progress_bar_cache[file].progress += increment
38
+ when :finished
39
+ @progress_bar_cache[file].finish
40
+ end
41
+
42
+ return @progress_bar_cache[file]
43
+ end
44
+
45
+ def aws_credentials
46
+ {
47
+ :access_key_id => maybe(Hem.user_config.aws.access_key_id) || ENV['AWS_ACCESS_KEY_ID'],
48
+ :secret_access_key => maybe(Hem.user_config.aws.secret_access_key) || ENV['AWS_SECRET_ACCESS_KEY']
49
+ }
50
+ end
51
+
52
+ def windows?
53
+ require 'rbconfig'
54
+ !!(RbConfig::CONFIG['host_os'] =~ /mswin|msys|mingw|cygwin|bccwin|wince|emc/)
55
+ end
56
+
57
+ def system_ruby?
58
+ require 'rbconfig'
59
+ File.join(RbConfig::CONFIG["bindir"], RbConfig::CONFIG["ruby_install_name"]).match(/\/rvm\/|\/\.rvm\/|\/\.rbenv/) != nil
60
+ end
61
+
62
+ def chefdk_compat
63
+ return if maybe(Hem.user_config.hem.disable_chefdk_compat) || ENV['HEM_DISABLE_CHEFDK_COMPAT']
64
+ return if Hem.windows?
65
+ which_ruby = File.join(RbConfig::CONFIG["bindir"], RbConfig::CONFIG["ruby_install_name"])
66
+ if which_ruby =~ /rbenv/
67
+ split_path = ENV['PATH'].split ':'
68
+ paths = split_path.reject do |p|
69
+ p =~ /chefdk/
70
+ end
71
+ chef_paths = split_path - paths
72
+ ENV['PATH'] = (chef_paths + paths).join ':'
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,3 @@
1
+ module Hem
2
+ VERSION = '1.0.1-beta1'
3
+ end
data/lib/hem.rb ADDED
@@ -0,0 +1,72 @@
1
+ # External deps
2
+ require 'slop'
3
+ require 'rake'
4
+ require 'deepstruct'
5
+ require 'logger'
6
+
7
+ require 'shellwords'
8
+ require 'fileutils'
9
+
10
+ # DSL enhancements
11
+ require 'hem/metadata'
12
+ require 'hem/patches/rake'
13
+ require 'hem/patches/slop'
14
+ require 'hem/patches/deepstruct'
15
+
16
+ # Basics
17
+ require 'hem/version'
18
+ require 'hem/null'
19
+ require 'hem/paths'
20
+ require 'hem/errors'
21
+ require 'hem/logging'
22
+ require 'hem/ui'
23
+ require 'hem/util'
24
+ require 'hem/help_formatter'
25
+ require 'hem/error_handlers/exit_code_map'
26
+ require 'hem/error_handlers/debug'
27
+ require 'hem/error_handlers/friendly'
28
+ require 'hem/config/file'
29
+ require 'hem/config'
30
+
31
+ # Asset sync
32
+ require 'hem/lib/s3/sync'
33
+ require 'hem/lib/s3/local/file'
34
+ require 'hem/lib/s3/local/iohandler'
35
+ require 'hem/lib/s3/remote/file'
36
+ require 'hem/lib/s3/remote/iohandler'
37
+
38
+ # Task helpers
39
+ require 'hem/helper/shell'
40
+ require 'hem/helper/file_locator'
41
+ require 'hem/helper/github'
42
+ require 'hem/helper/http_download'
43
+ require 'hem/helper/vm_command'
44
+
45
+ require 'hem/lib/vm/inspector'
46
+ require 'hem/lib/vm/command'
47
+
48
+ # Asset applicators
49
+ require 'hem/asset_applicator'
50
+ require 'hem/asset_applicators/sqldump'
51
+ require 'hem/asset_applicators/files'
52
+
53
+ # Libs
54
+ require 'hem/lib/seed/project'
55
+ require 'hem/lib/seed/replacer'
56
+ require 'hem/lib/seed/seed'
57
+ require 'hem/lib/self_signed_cert_generator'
58
+ require 'hem/lib/github/api'
59
+ require 'hem/lib/github/client'
60
+
61
+ # Host checks
62
+ require 'hem/lib/host_check/git'
63
+ require 'hem/lib/host_check/vagrant'
64
+ require 'hem/lib/host_check/ruby'
65
+ require 'hem/lib/host_check/deps'
66
+ require 'hem/lib/host_check'
67
+
68
+ # App
69
+ require 'hem/cli'
70
+
71
+ # Hobo BC
72
+ Hobo = Hem
@@ -0,0 +1,3 @@
1
+ Hem.ui.warning 'require \'hobo/tasks/magento\' in Hobofile is deprecated, and will be removed in a future release.'
2
+
3
+ require 'hem/tasks/magento'
@@ -0,0 +1,30 @@
1
+
2
+ describe Hem::AssetApplicatorRegistry do
3
+ describe "asset_applicators accessor" do
4
+ it "should initialize registry if none exists" do
5
+ Hem.asset_applicators = nil
6
+ Hem.asset_applicators.should be_an_instance_of Hem::AssetApplicatorRegistry
7
+ end
8
+
9
+ it "should return registry if exists" do
10
+ Hem.asset_applicators.register "test" do
11
+ "test"
12
+ end
13
+
14
+ Hem.asset_applicators["test"].should be_an_instance_of Proc
15
+ Hem.asset_applicators["test"].call.should match "test"
16
+ end
17
+ end
18
+
19
+ describe "register" do
20
+ it "should store passed block with pattern" do
21
+ registry = Hem::AssetApplicatorRegistry.new
22
+ registry.register "abc" do
23
+ "block"
24
+ end
25
+
26
+ registry["abc"].should be_an_instance_of Proc
27
+ registry["abc"].call.should match "block"
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,166 @@
1
+
2
+ describe Hem::Cli do
3
+ cli = nil
4
+ help = nil
5
+ hemfile = nil
6
+
7
+ def test_args args
8
+ args.concat([])
9
+ end
10
+
11
+ before do
12
+ Rake::Task.tasks.each do |task|
13
+ task.clear
14
+ end
15
+
16
+ Hem.ui = double(Hem::Ui).as_null_object
17
+ help = double(Hem::HelpFormatter).as_null_object
18
+ host_check = double(Hem::Lib::HostCheck).as_null_object
19
+ cli = Hem::Cli.new help: help, host_check: host_check
20
+
21
+ hemfile = File.read(File.join(File.dirname(__FILE__), '../../Hemfile'))
22
+
23
+ Hem.project_path = nil
24
+ FakeFS.activate!
25
+
26
+ File.write('Hemfile', hemfile)
27
+ end
28
+
29
+ after do
30
+ FakeFS::FileSystem.clear
31
+ FakeFS.deactivate!
32
+ end
33
+
34
+ it "should load the hemfile if present" do
35
+ cli.start test_args([])
36
+ Rake::Task["test:non-interactive"].should_not be nil
37
+ end
38
+
39
+ it "should load the user hemfile if present" do
40
+ FileUtils.mkdir_p(File.dirname(Hem.user_hemfile_path))
41
+ File.write(Hem.user_hemfile_path, "namespace :user do\ntask :user do\nend\nend")
42
+ cli.start test_args([])
43
+ Rake::Task["user:user"].should_not be nil
44
+ end
45
+
46
+ it "should present Hemfile path in eval error" do
47
+ FileUtils.mkdir_p(File.dirname(Hem.hemfile_path))
48
+ File.write(Hem.hemfile_path, "An invalid hemfile")
49
+ begin
50
+ cli.start test_args([])
51
+ rescue Exception => e
52
+ e.backtrace[0].should match 'Hemfile'
53
+ end
54
+ end
55
+
56
+ it "should load project config if present" do
57
+ FileUtils.mkdir_p("tools/hem/")
58
+ File.write("tools/hem/config.yaml", YAML::dump({ :project => "project_config" }))
59
+ cli.start test_args([])
60
+ Hem.project_config.project.should match "project_config"
61
+ end
62
+
63
+ it "should load user config if present" do
64
+ FileUtils.mkdir_p(Hem.config_path)
65
+ File.write(Hem.user_config_file, YAML::dump({ :user => "user_config" }))
66
+ cli.start test_args([])
67
+ Hem.user_config.user.should match "user_config"
68
+ end
69
+
70
+ it "should set command map on help formatter" do
71
+ help.should_recieve('command_map=')
72
+ cli.start test_args(["test", "subcommand"])
73
+ end
74
+
75
+ it "should propagate description metadata" do
76
+ map = nil
77
+ allow(help).to receive("command_map=") { |i| map = i }
78
+ cli.start test_args([])
79
+ map["test:metadata"].description.should match "description"
80
+ end
81
+
82
+ it "should propagate long description metadata" do
83
+ map = nil
84
+ allow(help).to receive("command_map=") { |i| map = i }
85
+ cli.start test_args([])
86
+ map["test:metadata"].long_description.should match "long description"
87
+ end
88
+
89
+ it "should propagate arg list metadata" do
90
+ map = nil
91
+ allow(help).to receive("command_map=") { |i| map = i }
92
+ cli.start test_args([])
93
+ expect(map["test:metadata"].arg_list).to eq [ :arg ]
94
+ end
95
+
96
+ it "should propagate option metadata" do
97
+ map = nil
98
+ allow(help).to receive("command_map=") { |i| map = i }
99
+ cli.start test_args([])
100
+ map["test:metadata"].options.length.should be 2
101
+ expect(map["test:metadata"].options.map(&:short)).to eq [ 'o', 'h' ]
102
+ expect(map["test:metadata"].options.map(&:long)).to eq [ 'option', 'help' ]
103
+ expect(map["test:metadata"].options.map(&:description)).to eq [ 'Option description', 'Display help' ]
104
+ end
105
+
106
+ it "should propagate hidden metadata" do
107
+ map = nil
108
+ allow(help).to receive("command_map=") { |i| map = i }
109
+ cli.start test_args([])
110
+ map["test:metadata"].hidden.should be true
111
+ end
112
+
113
+ it "should show help if no args or opts passed" do
114
+ help.should_receive(:help)
115
+ cli.start(test_args([]))
116
+ end
117
+
118
+ it "should show help for --help" do
119
+ help.should_receive(:help)
120
+ cli.start test_args(["--help"])
121
+ end
122
+
123
+ it "should execute a top level command" do
124
+ Hem.ui.should_recieve(:info).with("top level")
125
+ cli.start test_args(["top-level"])
126
+ end
127
+
128
+ it "should execute a subcommand" do
129
+ Hem.ui.should_recieve(:info).with("Subcommand test")
130
+ cli.start test_args(["test", "subcommand"])
131
+ end
132
+
133
+ it "should show help for a namespace" do
134
+ help.should_receive(:help).with(all: nil, target: "test")
135
+ cli.start test_args(["test"])
136
+ end
137
+
138
+ it "should show command help for --help" do
139
+ help.should_receive(:help).with(all: nil, target: "test:subcommand")
140
+ cli.start test_args(["test", "subcommand", "--help"])
141
+ end
142
+
143
+ it "should propagate --all option to help" do
144
+ help.should_receive(:help).with(all: true, target: "test")
145
+ cli.start test_args(["test", "--all"])
146
+ end
147
+
148
+ it "should propagate command opts to command" do
149
+ Hem.ui.should_receive(:info).with("1234")
150
+ cli.start test_args(["test", "option-test", "--testing=1234"])
151
+ end
152
+
153
+ it "should propagate arguments to command" do
154
+ Hem.ui.should_receive(:info).with("1234")
155
+ cli.start test_args(["test", "argument-test", "1234"])
156
+ end
157
+
158
+ it "should propagate unparsed arguments in :_unparsed opt" do
159
+ Hem.ui.should_receive(:info).with("'ls' '--help'")
160
+ cli.start ["test", "unparsed", "--", "ls", "--help"]
161
+ end
162
+
163
+ it "should raise an exception if not enough arguments were passed" do
164
+ expect { cli.start(test_args(["test", "metadata"])) }.to raise_error Hem::MissingArgumentsError
165
+ end
166
+ end