dpl-thib 1.10.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +1 -0
  3. data/.github/CONTRIBUTING.md +173 -0
  4. data/.github/stale.yml +53 -0
  5. data/.gitignore +13 -0
  6. data/.rspec +2 -0
  7. data/.travis.yml +55 -0
  8. data/CODE_OF_CONDUCT.md +74 -0
  9. data/Gemfile +5 -0
  10. data/LICENSE +22 -0
  11. data/README.md +968 -0
  12. data/Rakefile +208 -0
  13. data/bin/dpl +5 -0
  14. data/dpl-anynines.gemspec +3 -0
  15. data/dpl-atlas.gemspec +3 -0
  16. data/dpl-azure_webapps.gemspec +3 -0
  17. data/dpl-bintray.gemspec +3 -0
  18. data/dpl-bitballoon.gemspec +3 -0
  19. data/dpl-bluemix_cloud_foundry.gemspec +3 -0
  20. data/dpl-boxfuse.gemspec +3 -0
  21. data/dpl-cargo.gemspec +3 -0
  22. data/dpl-catalyze.gemspec +3 -0
  23. data/dpl-chef_supermarket.gemspec +10 -0
  24. data/dpl-cloud66.gemspec +3 -0
  25. data/dpl-cloud_files.gemspec +3 -0
  26. data/dpl-cloud_foundry.gemspec +3 -0
  27. data/dpl-code_deploy.gemspec +3 -0
  28. data/dpl-deis.gemspec +3 -0
  29. data/dpl-elastic_beanstalk.gemspec +3 -0
  30. data/dpl-engine_yard.gemspec +3 -0
  31. data/dpl-firebase.gemspec +3 -0
  32. data/dpl-gae.gemspec +3 -0
  33. data/dpl-gcs.gemspec +3 -0
  34. data/dpl-hackage.gemspec +3 -0
  35. data/dpl-hephy.gemspec +3 -0
  36. data/dpl-heroku.gemspec +3 -0
  37. data/dpl-lambda.gemspec +3 -0
  38. data/dpl-launchpad.gemspec +3 -0
  39. data/dpl-npm.gemspec +3 -0
  40. data/dpl-openshift.gemspec +3 -0
  41. data/dpl-ops_works.gemspec +3 -0
  42. data/dpl-packagecloud.gemspec +3 -0
  43. data/dpl-pages.gemspec +3 -0
  44. data/dpl-puppet_forge.gemspec +3 -0
  45. data/dpl-pypi.gemspec +3 -0
  46. data/dpl-releases.gemspec +3 -0
  47. data/dpl-rubygems.gemspec +3 -0
  48. data/dpl-s3.gemspec +3 -0
  49. data/dpl-scalingo.gemspec +3 -0
  50. data/dpl-script.gemspec +3 -0
  51. data/dpl-snap.gemspec +3 -0
  52. data/dpl-surge.gemspec +3 -0
  53. data/dpl-testfairy.gemspec +3 -0
  54. data/dpl-transifex.gemspec +3 -0
  55. data/dpl.gemspec +3 -0
  56. data/gemspec_helper.rb +51 -0
  57. data/lib/dpl/cli.rb +66 -0
  58. data/lib/dpl/error.rb +3 -0
  59. data/lib/dpl/provider.rb +308 -0
  60. data/lib/dpl/version.rb +3 -0
  61. data/notes/engine_yard.md +1 -0
  62. data/notes/heroku.md +3 -0
  63. data/spec/cli_spec.rb +36 -0
  64. data/spec/provider_spec.rb +191 -0
  65. data/spec/spec_helper.rb +20 -0
  66. metadata +237 -0
@@ -0,0 +1,66 @@
1
+ require 'dpl/error'
2
+ require 'dpl/provider'
3
+
4
+ module DPL
5
+ class CLI
6
+ def self.run(*args)
7
+ new(args).run
8
+ end
9
+
10
+ OPTION_PATTERN = /\A--([a-z][a-z_\-]*)(?:=(.+))?\z/
11
+ attr_accessor :options, :fold_count
12
+
13
+ def initialize(*args)
14
+ options = {}
15
+ args.flatten.each do |arg|
16
+ next options.update(arg) if arg.is_a? Hash
17
+ die("invalid option %p" % arg) unless match = OPTION_PATTERN.match(arg)
18
+ key = match[1].tr('-', '_').to_sym
19
+ if options.include? key
20
+ options[key] = Array(options[key]) << match[2]
21
+ else
22
+ options[key] = match[2] || true
23
+ end
24
+ end
25
+
26
+ self.fold_count = 0
27
+ self.options = default_options.merge(options)
28
+ end
29
+
30
+ def run
31
+ provider = Provider.new(self, options)
32
+ provider.deploy
33
+ rescue Error => error
34
+ options[:debug] ? raise(error) : die(error.message)
35
+ end
36
+
37
+ def fold(message)
38
+ self.fold_count += 1
39
+ print "travis_fold:start:dpl.#{fold_count}\r" if options[:fold]
40
+ puts "\e[33m#{message}\e[0m"
41
+ yield
42
+ ensure
43
+ print "\ntravis_fold:end:dpl.#{fold_count}\r" if options[:fold]
44
+ end
45
+
46
+ def default_options
47
+ {
48
+ :app => File.basename(Dir.pwd),
49
+ :key_name => %x[hostname].strip
50
+ }
51
+ end
52
+
53
+ def shell(command)
54
+ system(command)
55
+ end
56
+
57
+ def die(message)
58
+ $stderr.puts(message)
59
+ exit 1
60
+ end
61
+
62
+ def env
63
+ ENV
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,3 @@
1
+ module DPL
2
+ Error = Class.new(StandardError)
3
+ end
@@ -0,0 +1,308 @@
1
+ require 'dpl/error'
2
+ require 'dpl/version'
3
+ require 'fileutils'
4
+
5
+ module DPL
6
+ class Provider
7
+ include FileUtils
8
+
9
+ # map of DPL provider class name constants to their corresponding
10
+ # file names. There is no simple rule to map them automatically
11
+ # (camel-cases, snake-cases, call-caps, etc.), so we need an explicit
12
+ # map.
13
+ GEM_NAME_OF = {
14
+ 'Anynines' => 'anynines',
15
+ 'Appfog' => 'appfog',
16
+ 'Atlas' => 'atlas',
17
+ 'AzureWebApps' => 'azure_webapps',
18
+ 'Bintray' => 'bintray',
19
+ 'BitBalloon' => 'bitballoon',
20
+ 'BluemixCloudFoundry' => 'bluemix_cloud_foundry',
21
+ 'Boxfuse' => 'boxfuse',
22
+ 'Catalyze' => 'catalyze',
23
+ 'ChefSupermarket' => 'chef_supermarket',
24
+ 'Cloud66' => 'cloud66',
25
+ 'CloudFiles' => 'cloud_files',
26
+ 'CloudFoundry' => 'cloud_foundry',
27
+ 'CodeDeploy' => 'code_deploy',
28
+ 'Cargo' => 'cargo',
29
+ 'Deis' => 'deis',
30
+ 'ElasticBeanstalk' => 'elastic_beanstalk',
31
+ 'EngineYard' => 'engine_yard',
32
+ 'Firebase' => 'firebase',
33
+ 'GAE' => 'gae',
34
+ 'GCS' => 'gcs',
35
+ 'Hackage' => 'hackage',
36
+ 'Hephy' => 'hephy',
37
+ 'Heroku' => 'heroku',
38
+ 'Lambda' => 'lambda',
39
+ 'Launchpad' => 'launchpad',
40
+ 'Nodejitsu' => 'nodejitsu',
41
+ 'NPM' => 'npm',
42
+ 'Openshift' => 'openshift',
43
+ 'OpsWorks' => 'ops_works',
44
+ 'Packagecloud' => 'packagecloud',
45
+ 'Pages' => 'pages',
46
+ 'PuppetForge' => 'puppet_forge',
47
+ 'PyPI' => 'pypi',
48
+ 'Releases' => 'releases',
49
+ 'RubyGems' => 'rubygems',
50
+ 'S3' => 's3',
51
+ 'Scalingo' => 'scalingo',
52
+ 'Script' => 'script',
53
+ 'Snap' => 'snap',
54
+ 'Surge' => 'surge',
55
+ 'TestFairy' => 'testfairy',
56
+ 'Transifex' => 'transifex',
57
+ }
58
+
59
+ def self.new(context, options)
60
+ return super if self < Provider
61
+
62
+ # when requiring the file corresponding to the provider name
63
+ # given in the options, the general strategy is to normalize
64
+ # the option to lower-case alphanumeric, then
65
+ # use that key to find the file name using the GEM_NAME_OF map.
66
+
67
+ context.fold("Installing deploy dependencies") do
68
+ begin
69
+ opt_lower = super.option(:provider).to_s.downcase
70
+ opt = opt_lower.gsub(/[^a-z0-9]/, '')
71
+ class_name = class_of(opt)
72
+ raise Error, "could not find provider %p" % opt unless class_name
73
+ require "dpl/provider/#{GEM_NAME_OF[class_name]}"
74
+ provider = const_get(class_name).new(context, options)
75
+ rescue NameError, LoadError => e
76
+ if /uninitialized constant DPL::Provider::(?<provider_wanted>\S+)/ =~ e.message
77
+ provider_gem_name = GEM_NAME_OF[provider_wanted]
78
+ elsif %r(cannot load such file -- dpl/provider/(?<provider_file_name>\S+)) =~ e.message
79
+ provider_gem_name = GEM_NAME_OF[class_name]
80
+ else
81
+ # don't know what to do with this error
82
+ raise e
83
+ end
84
+ install_cmd = "gem install dpl-#{provider_gem_name || opt} -v #{ENV['DPL_VERSION'] || DPL::VERSION}"
85
+
86
+ if File.exist?(local_gem = File.join(Dir.pwd, "dpl-#{GEM_NAME_OF[provider_gem_name] || opt_lower}-#{ENV['DPL_VERSION'] || DPL::VERSION}.gem"))
87
+ install_cmd = "gem install #{local_gem}"
88
+ end
89
+
90
+ context.shell(install_cmd)
91
+ Gem.clear_paths
92
+
93
+ require "dpl/provider/#{GEM_NAME_OF[class_name]}"
94
+ provider = const_get(class_name).new(context, options)
95
+ rescue DPL::Error
96
+ if opt_lower
97
+ provider = const_get(opt.capitalize).new(context, options)
98
+ else
99
+ raise Error, 'missing provider'
100
+ end
101
+ end
102
+
103
+ if options[:no_deploy]
104
+ def provider.deploy; end
105
+ else
106
+ provider.install_deploy_dependencies if provider.respond_to? :install_deploy_dependencies
107
+ end
108
+
109
+ provider
110
+ end
111
+ end
112
+
113
+ def self.experimental(name)
114
+ puts "", "!!! #{name} support is experimental !!!", ""
115
+ end
116
+
117
+ def self.deprecated(*lines)
118
+ puts ''
119
+ lines.each do |line|
120
+ puts "\e[31;1m#{line}\e[0m"
121
+ end
122
+ puts ''
123
+ end
124
+
125
+ def self.context
126
+ self
127
+ end
128
+
129
+ def self.shell(command, options = {})
130
+ system(command)
131
+ end
132
+
133
+ def self.apt_get(name, command = name)
134
+ context.shell("sudo apt-get -qq install #{name}", retry: true) if `which #{command}`.chop.empty?
135
+ end
136
+
137
+ def self.pip(name, command = name, version = nil)
138
+ if version
139
+ puts "pip install --user #{name}==#{version}"
140
+ context.shell("pip uninstall --user -y #{name}") unless `which #{command}`.chop.empty?
141
+ context.shell("pip install --user #{name}==#{version}", retry: true)
142
+ else
143
+ puts "pip install --user #{name}"
144
+ context.shell("pip install --user #{name}", retry: true) if `which #{command}`.chop.empty?
145
+ end
146
+ context.shell("export PATH=$PATH:$HOME/.local/bin")
147
+ end
148
+
149
+ def self.npm_g(name, command = name)
150
+ context.shell("npm install -g #{name}", retry: true) if `which #{command}`.chop.empty?
151
+ end
152
+
153
+ def self.class_of(filename)
154
+ GEM_NAME_OF.keys.detect { |p| p.to_s.downcase == filename }
155
+ end
156
+
157
+ attr_reader :context, :options
158
+
159
+ def initialize(context, options)
160
+ @context, @options = context, options
161
+ context.env['GIT_HTTP_USER_AGENT'] = user_agent(git: `git --version`[/[\d\.]+/])
162
+ end
163
+
164
+ def user_agent(*strings)
165
+ strings.unshift "dpl/#{DPL::VERSION}"
166
+ strings.unshift "travis/0.1.0" if context.env['TRAVIS']
167
+ strings = strings.flat_map { |e| Hash === e ? e.map { |k,v| "#{k}/#{v}" } : e }
168
+ strings.join(" ").gsub(/\s+/, " ").strip
169
+ end
170
+
171
+ def option(name, *alternatives)
172
+ options.fetch(name) do
173
+ alternatives.any? ? option(*alternatives) : raise(Error, "missing #{name}")
174
+ end
175
+ end
176
+
177
+ def deploy
178
+ setup_git_credentials
179
+ rm_rf ".dpl"
180
+ mkdir_p ".dpl"
181
+
182
+ context.fold("Preparing deploy") do
183
+ check_auth
184
+ check_app
185
+
186
+ if needs_key?
187
+ create_key(".dpl/id_rsa")
188
+ setup_key(".dpl/id_rsa.pub")
189
+ setup_git_ssh(".dpl/git-ssh", ".dpl/id_rsa")
190
+ end
191
+
192
+ cleanup
193
+ end
194
+
195
+ context.fold("Deploying application") { push_app }
196
+
197
+ Array(options[:run]).each do |command|
198
+ if command == 'restart'
199
+ context.fold("Restarting application") { restart }
200
+ else
201
+ context.fold("Running %p" % command) { run(command) }
202
+ end
203
+ end
204
+ ensure
205
+ if needs_key?
206
+ remove_key rescue nil
207
+ end
208
+ uncleanup
209
+ end
210
+
211
+ def sha
212
+ @sha ||= context.env['TRAVIS_COMMIT'] || `git rev-parse HEAD`.strip
213
+ end
214
+
215
+ def commit_msg
216
+ @commit_msg ||= %x{git log #{sha} -n 1 --pretty=%B}.strip
217
+ end
218
+
219
+ def cleanup
220
+ return if options[:skip_cleanup]
221
+ context.shell "mv .dpl ~/dpl"
222
+ log "Cleaning up git repository with `git stash --all`. " \
223
+ "If you need build artifacts for deployment, set `deploy.skip_cleanup: true`. " \
224
+ "See https://docs.travis-ci.com/user/deployment#Uploading-Files-and-skip_cleanup."
225
+ context.shell "git stash --all"
226
+ context.shell "mv ~/dpl .dpl"
227
+ end
228
+
229
+ def uncleanup
230
+ return if options[:skip_cleanup]
231
+ context.shell "git stash pop"
232
+ end
233
+
234
+ def needs_key?
235
+ true
236
+ end
237
+
238
+ def check_app
239
+ end
240
+
241
+ def create_key(file)
242
+ context.shell "ssh-keygen -t rsa -N \"\" -C #{option(:key_name)} -f #{file}"
243
+ end
244
+
245
+ def setup_git_credentials
246
+ context.shell "git config user.email >/dev/null 2>/dev/null || git config user.email `whoami`@localhost"
247
+ context.shell "git config user.name >/dev/null 2>/dev/null || git config user.name `whoami`@localhost"
248
+ end
249
+
250
+ def setup_git_ssh(path, key_path)
251
+ key_path = File.expand_path(key_path)
252
+ path = File.expand_path(path)
253
+
254
+ File.open(path, 'w') do |file|
255
+ file.write "#!/bin/sh\n"
256
+ file.write "exec ssh -o StrictHostKeychecking=no -o CheckHostIP=no -o UserKnownHostsFile=/dev/null -i #{key_path} -- \"$@\"\n"
257
+ end
258
+
259
+ chmod(0740, path)
260
+ context.env['GIT_SSH'] = path
261
+ end
262
+
263
+ def detect_encoding?
264
+ options[:detect_encoding]
265
+ end
266
+
267
+ def default_text_charset?
268
+ options[:default_text_charset]
269
+ end
270
+
271
+ def default_text_charset
272
+ options[:default_text_charset].downcase
273
+ end
274
+
275
+ def install_deploy_dependencies
276
+ end
277
+
278
+ def encoding_for(path)
279
+ file_cmd_output = `file '#{path}'`
280
+ case file_cmd_output
281
+ when /gzip compressed/
282
+ 'gzip'
283
+ when /compress'd/
284
+ 'compress'
285
+ when /text/
286
+ 'text'
287
+ when /data/
288
+ # Shrugs?
289
+ end
290
+ end
291
+
292
+ def log(message)
293
+ $stderr.puts(message)
294
+ end
295
+
296
+ def warn(message)
297
+ log "\e[31;1m#{message}\e[0m"
298
+ end
299
+
300
+ def run(command)
301
+ error "running commands not supported"
302
+ end
303
+
304
+ def error(message)
305
+ raise Error, message
306
+ end
307
+ end
308
+ end
@@ -0,0 +1,3 @@
1
+ module DPL
2
+ VERSION = '1.10.5'
3
+ end
@@ -0,0 +1 @@
1
+ EY has a a special deploy app. Get in touch with Kevin Holler if we don't hear back from them.
@@ -0,0 +1,3 @@
1
+ Heroku might send out emails for new deploy keys (doesn't do it for me, but for some others).
2
+
3
+ Alternative is Anvil, but it's not perfect, as it duplicates a lot of Heroku logic internally (and failed for me in one case).
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+ require 'dpl/cli'
3
+
4
+ describe DPL::CLI do
5
+ describe "#options" do
6
+ example { expect(described_class.new.options[:app]) .to eq(File.basename(Dir.pwd)) }
7
+ example { expect(described_class.new(:app => 'foo') .options[:app]).to eq('foo') }
8
+ example { expect(described_class.new("--app=foo") .options[:app]).to eq('foo') }
9
+ example { expect(described_class.new("--app") .options[:app]).to eq(true) }
10
+ example { expect(described_class.new("--app=foo", "--app=bar") .options[:app]).to eq(['foo', 'bar']) }
11
+
12
+ example "error handling" do
13
+ expect($stderr).to receive(:puts).with('invalid option "app"')
14
+ expect { described_class.new("app") }.to raise_error(SystemExit)
15
+ end
16
+ end
17
+
18
+ describe "#run" do
19
+ example "triggers deploy" do
20
+ provider = double('provider')
21
+ expect(DPL::Provider).to receive(:new).and_return(provider)
22
+ expect(provider).to receive(:deploy)
23
+
24
+ described_class.run("--provider=foo")
25
+ end
26
+
27
+ example "error handling" do
28
+ expect($stderr).to receive(:puts).with('missing provider')
29
+ expect { described_class.run }.to raise_error(SystemExit)
30
+ end
31
+
32
+ example "error handling in debug mode" do
33
+ expect { described_class.run("--debug") }.to raise_error(DPL::Error, 'missing provider')
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,191 @@
1
+ require 'spec_helper'
2
+ require 'dpl/provider'
3
+
4
+ describe DPL::Provider do
5
+ let(:example_provider) { Class.new(described_class)}
6
+ let(:context) { DummyContext.new }
7
+ subject(:provider) { example_provider.new(context, :app => 'example', :key_name => 'foo', :run => ["foo", "bar"]) }
8
+
9
+ before { stub_const "DPL::Provider::Example", example_provider }
10
+
11
+ describe "#new" do
12
+ example { expect(described_class.new(context, :provider => "example")) .to be_an(example_provider) }
13
+ example { expect(described_class.new(context, :provider => "Example")) .to be_an(example_provider) }
14
+ example { expect(described_class.new(context, :provider => "exa_mple")).to be_an(example_provider) }
15
+ example { expect(described_class.new(context, :provider => "exa-mple")).to be_an(example_provider) }
16
+ example { expect(described_class.new(context, :provider => "scri_pt")).to be_an(DPL::Provider::Script) }
17
+ example { expect(described_class.new(context, :provider => "scri _pt")).to be_an(DPL::Provider::Script) }
18
+ example { expect(described_class.new(context, :provider => "cloudfoundry")).to be_an(DPL::Provider::CloudFoundry) }
19
+ example "install deployment dependencies" do
20
+ expect_any_instance_of(described_class).to receive(:respond_to?).with(:install_deploy_dependencies).and_return(true)
21
+ expect_any_instance_of(described_class).to receive(:install_deploy_dependencies)
22
+ described_class.new(context, :provider => "example")
23
+ end
24
+
25
+ it "installs correct gem when provider name does not match" do
26
+ expect(context).to receive(:shell).with("gem install dpl-cloud_foundry -v #{ENV['DPL_VERSION'] || DPL::VERSION}")
27
+ expect(described_class).to receive(:require).with("dpl/provider/cloud_foundry").and_raise LoadError.new("cannot load such file -- dpl/provider/cloud_foundry")
28
+ expect(described_class).to receive(:require).with("dpl/provider/cloud_foundry").and_call_original
29
+ described_class.new(context, :provider => 'cloudfoundry')
30
+ end
31
+
32
+ end
33
+
34
+ describe "#pip" do
35
+ example "installed" do
36
+ expect(example_provider).to receive(:`).with("which foo").and_return("/bin/foo\n")
37
+ expect(example_provider).not_to receive(:system)
38
+ expect(example_provider.context).to receive(:shell).with("export PATH=$PATH:$HOME/.local/bin")
39
+ example_provider.pip("foo")
40
+ end
41
+
42
+ example "missing" do
43
+ expect(example_provider).to receive(:`).with("which foo").and_return("")
44
+ expect(example_provider.context).to receive(:shell).with("pip install --user foo", retry: true)
45
+ expect(example_provider.context).to receive(:shell).with("export PATH=$PATH:$HOME/.local/bin")
46
+ example_provider.pip("foo")
47
+ end
48
+
49
+ example "specific version" do
50
+ expect(example_provider).to receive(:`).with("which foo").and_return("")
51
+ expect(example_provider.context).to receive(:shell).with("pip install --user foo==1.0", retry: true)
52
+ expect(example_provider.context).to receive(:shell).with("export PATH=$PATH:$HOME/.local/bin")
53
+ example_provider.pip("foo", "foo", "1.0")
54
+ end
55
+ end
56
+
57
+ describe "#deploy" do
58
+ before do
59
+ expect(provider).to receive(:check_auth)
60
+ expect(provider).to receive(:check_app)
61
+ expect(provider).to receive(:push_app)
62
+ expect(provider).to receive(:run).with("foo")
63
+ expect(provider).to receive(:run).with("bar")
64
+ end
65
+
66
+ example "needs key" do
67
+ expect(provider).to receive(:remove_key)
68
+ expect(provider).to receive(:create_key)
69
+ expect(provider).to receive(:setup_key)
70
+ expect(provider).to receive(:setup_git_ssh)
71
+ provider.deploy
72
+ end
73
+
74
+ example "does not need key" do
75
+ allow(provider).to receive_messages(:needs_key? => false)
76
+ provider.deploy
77
+ end
78
+ end
79
+
80
+ describe "#cleanup" do
81
+ example do
82
+ expect(provider.context).to receive(:shell).with('mv .dpl ~/dpl')
83
+ expect(provider.context).to receive(:shell).with('git stash --all')
84
+ expect(provider.context).to receive(:shell).with('mv ~/dpl .dpl')
85
+ provider.cleanup
86
+ end
87
+
88
+ example "skip cleanup" do
89
+ expect(provider.options).to receive(:[]).with(:skip_cleanup).and_return("true")
90
+ expect(provider.context).not_to receive(:shell)
91
+ provider.cleanup
92
+ end
93
+ end
94
+
95
+ describe "#uncleanup" do
96
+ example do
97
+ expect(provider.context).to receive(:shell).with('git stash pop')
98
+ provider.uncleanup
99
+ end
100
+
101
+ example "skip cleanup" do
102
+ expect(provider.options).to receive(:[]).with(:skip_cleanup).and_return("true")
103
+ expect(provider.context).not_to receive(:shell)
104
+ provider.uncleanup
105
+ end
106
+ end
107
+
108
+ describe "#create_key" do
109
+ example do
110
+ expect(provider.context).to receive(:shell).with('ssh-keygen -t rsa -N "" -C foo -f thekey')
111
+ provider.create_key('thekey')
112
+ end
113
+ end
114
+
115
+ describe "#setup_git_ssh" do
116
+ after { FileUtils.rm provider.context.env.delete('GIT_SSH') }
117
+
118
+ example do
119
+ provider.setup_git_ssh('foo', 'bar')
120
+ expect(provider.context.env['GIT_SSH']).to eq(File.expand_path('foo'))
121
+ end
122
+ end
123
+
124
+ describe "#detect_encoding?" do
125
+ example do
126
+ provider.options.update(:detect_encoding => true)
127
+ expect(provider.detect_encoding?).to eq(true)
128
+ end
129
+ end
130
+
131
+ describe "#encoding_for" do
132
+ example do
133
+ path = 'foo.js'
134
+ expect(provider).to receive(:`).at_least(1).times.with("file '#{path}'").and_return("#{path}: gzip compressed")
135
+ expect(provider.encoding_for(path)).to eq('gzip')
136
+ end
137
+
138
+ example do
139
+ path = 'file with a space'
140
+ expect(provider).to receive(:`).at_least(1).times.with("file '#{path}'").and_return("#{path}: empty")
141
+ expect(provider.encoding_for(path)).to be_nil
142
+ end
143
+
144
+ example do
145
+ path = 'foo.js'
146
+ expect(provider).to receive(:`).at_least(1).times.with("file '#{path}'").and_return("#{path}: ASCII text, with very long line")
147
+ expect(provider.encoding_for(path)).to eq('text')
148
+ end
149
+
150
+ example do
151
+ path = 'foo.js'
152
+ provider.options.update(:default_text_charset => 'UTF-8')
153
+ expect(provider).to receive(:`).at_least(1).times.with("file '#{path}'").and_return("#{path}: ASCII text, with very long line")
154
+ expect(provider.encoding_for(path)).to eq('text')
155
+ end
156
+ end
157
+
158
+ describe "#log" do
159
+ example do
160
+ expect($stderr).to receive(:puts).with("foo")
161
+ provider.log("foo")
162
+ end
163
+ end
164
+
165
+ describe "#shell" do
166
+ example do
167
+ expect(example_provider).to receive(:system).with("command")
168
+ example_provider.shell("command")
169
+ end
170
+ end
171
+
172
+ describe "#npm_g" do
173
+ example do
174
+ expect(example_provider.context).to receive(:shell).with("npm install -g foo", retry: true)
175
+ example_provider.npm_g("foo")
176
+ end
177
+ end
178
+
179
+ describe "#run" do
180
+ example do
181
+ expect(provider).to receive(:error).with("running commands not supported")
182
+ provider.run "blah"
183
+ end
184
+ end
185
+
186
+ describe "#error" do
187
+ example do
188
+ expect { provider.error("Foo") }.to raise_error("Foo")
189
+ end
190
+ end
191
+ end