dpl-thib 1.10.5

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