dpl 1.10.17.travis.6637.6 → 2.0.0.alpha.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (140) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +74 -0
  3. data/CONTRIBUTING.md +392 -0
  4. data/Gemfile +17 -3
  5. data/Gemfile.lock +373 -0
  6. data/LICENSE +16 -19
  7. data/NOTES.md +275 -0
  8. data/README.md +1977 -707
  9. data/Rakefile +2 -2
  10. data/bin/dpl +7 -3
  11. data/lib/dpl.rb +20 -0
  12. data/lib/dpl/assets/atlas/install +19 -0
  13. data/lib/dpl/assets/dpl/README.erb.md +133 -0
  14. data/lib/dpl/assets/dpl/git_ssh +2 -0
  15. data/lib/dpl/assets/git/detect_private_key +8 -0
  16. data/lib/dpl/assets/hephy/filter_log +3 -0
  17. data/lib/dpl/assets/pypi/install +4 -0
  18. data/lib/dpl/assets/scalingo/install +6 -0
  19. data/lib/dpl/cli.rb +36 -48
  20. data/lib/dpl/ctx.rb +2 -0
  21. data/lib/dpl/ctx/bash.rb +543 -0
  22. data/lib/dpl/ctx/test.rb +242 -0
  23. data/lib/dpl/helper/assets.rb +36 -0
  24. data/lib/dpl/helper/cmd.rb +167 -0
  25. data/lib/dpl/helper/config_file.rb +47 -0
  26. data/lib/dpl/helper/env.rb +39 -0
  27. data/lib/dpl/helper/interpolate.rb +126 -0
  28. data/lib/dpl/helper/memoize.rb +20 -0
  29. data/lib/dpl/helper/squiggle.rb +22 -0
  30. data/lib/dpl/helper/zip.rb +69 -0
  31. data/lib/dpl/provider.rb +562 -234
  32. data/lib/dpl/provider/dsl.rb +369 -0
  33. data/lib/dpl/provider/examples.rb +128 -0
  34. data/lib/dpl/provider/status.rb +59 -0
  35. data/lib/dpl/providers.rb +40 -0
  36. data/lib/dpl/providers/anynines.rb +65 -0
  37. data/lib/dpl/providers/atlas.rb +49 -0
  38. data/lib/dpl/providers/azure_web_apps.rb +59 -0
  39. data/lib/dpl/providers/bintray.rb +313 -0
  40. data/lib/dpl/providers/bluemixcloudfoundry.rb +92 -0
  41. data/lib/dpl/providers/boxfuse.rb +48 -0
  42. data/lib/dpl/providers/cargo.rb +19 -0
  43. data/lib/dpl/providers/chef_supermarket.rb +128 -0
  44. data/lib/dpl/providers/cloud66.rb +40 -0
  45. data/lib/dpl/providers/cloudfiles.rb +56 -0
  46. data/lib/dpl/providers/cloudfoundry.rb +81 -0
  47. data/lib/dpl/providers/codedeploy.rb +179 -0
  48. data/lib/dpl/providers/datica.rb +60 -0
  49. data/lib/dpl/providers/elasticbeanstalk.rb +195 -0
  50. data/lib/dpl/providers/engineyard.rb +107 -0
  51. data/lib/dpl/providers/firebase.rb +41 -0
  52. data/lib/dpl/providers/gae.rb +74 -0
  53. data/lib/dpl/providers/gcs.rb +105 -0
  54. data/lib/dpl/providers/hackage.rb +47 -0
  55. data/lib/dpl/providers/hephy.rb +101 -0
  56. data/lib/dpl/providers/heroku.rb +111 -0
  57. data/lib/dpl/providers/heroku/api.rb +119 -0
  58. data/lib/dpl/providers/heroku/git.rb +50 -0
  59. data/lib/dpl/providers/lambda.rb +202 -0
  60. data/lib/dpl/providers/launchpad.rb +74 -0
  61. data/lib/dpl/providers/netlify.rb +30 -0
  62. data/lib/dpl/providers/npm.rb +88 -0
  63. data/lib/dpl/providers/openshift.rb +46 -0
  64. data/lib/dpl/providers/opsworks.rb +142 -0
  65. data/lib/dpl/providers/packagecloud.rb +190 -0
  66. data/lib/dpl/providers/pages.rb +17 -0
  67. data/lib/dpl/providers/pages/api.rb +102 -0
  68. data/lib/dpl/providers/pages/git.rb +251 -0
  69. data/lib/dpl/providers/puppetforge.rb +44 -0
  70. data/lib/dpl/providers/pypi.rb +120 -0
  71. data/lib/dpl/providers/releases.rb +214 -0
  72. data/lib/dpl/providers/rubygems.rb +89 -0
  73. data/lib/dpl/providers/s3.rb +243 -0
  74. data/lib/dpl/providers/scalingo.rb +63 -0
  75. data/lib/dpl/providers/script.rb +28 -0
  76. data/lib/dpl/providers/snap.rb +59 -0
  77. data/lib/dpl/providers/surge.rb +55 -0
  78. data/lib/dpl/providers/testfairy.rb +93 -0
  79. data/lib/dpl/providers/transifex.rb +66 -0
  80. data/lib/dpl/support/aws_sdk_patch.rb +23 -0
  81. data/lib/dpl/support/gems.rb +69 -0
  82. data/lib/dpl/support/gstore_patch.rb +6 -0
  83. data/lib/dpl/support/version.rb +83 -0
  84. data/lib/dpl/version.rb +2 -2
  85. metadata +98 -169
  86. data/.coveralls.yml +0 -1
  87. data/.github/CONTRIBUTING.md +0 -173
  88. data/.github/stale.yml +0 -53
  89. data/.gitignore +0 -13
  90. data/.rspec +0 -2
  91. data/.travis.yml +0 -56
  92. data/dpl-anynines.gemspec +0 -3
  93. data/dpl-atlas.gemspec +0 -3
  94. data/dpl-azure_webapps.gemspec +0 -3
  95. data/dpl-bintray.gemspec +0 -3
  96. data/dpl-bitballoon.gemspec +0 -3
  97. data/dpl-bluemix_cloud_foundry.gemspec +0 -3
  98. data/dpl-boxfuse.gemspec +0 -3
  99. data/dpl-cargo.gemspec +0 -3
  100. data/dpl-catalyze.gemspec +0 -3
  101. data/dpl-chef_supermarket.gemspec +0 -20
  102. data/dpl-cloud66.gemspec +0 -3
  103. data/dpl-cloud_files.gemspec +0 -3
  104. data/dpl-cloud_foundry.gemspec +0 -3
  105. data/dpl-code_deploy.gemspec +0 -3
  106. data/dpl-deis.gemspec +0 -3
  107. data/dpl-elastic_beanstalk.gemspec +0 -3
  108. data/dpl-engine_yard.gemspec +0 -3
  109. data/dpl-firebase.gemspec +0 -3
  110. data/dpl-gae.gemspec +0 -3
  111. data/dpl-gcs.gemspec +0 -3
  112. data/dpl-hackage.gemspec +0 -3
  113. data/dpl-hephy.gemspec +0 -3
  114. data/dpl-heroku.gemspec +0 -3
  115. data/dpl-lambda.gemspec +0 -3
  116. data/dpl-launchpad.gemspec +0 -3
  117. data/dpl-npm.gemspec +0 -3
  118. data/dpl-openshift.gemspec +0 -3
  119. data/dpl-ops_works.gemspec +0 -3
  120. data/dpl-packagecloud.gemspec +0 -3
  121. data/dpl-pages.gemspec +0 -3
  122. data/dpl-puppet_forge.gemspec +0 -3
  123. data/dpl-pypi.gemspec +0 -3
  124. data/dpl-releases.gemspec +0 -8
  125. data/dpl-rubygems.gemspec +0 -3
  126. data/dpl-s3.gemspec +0 -3
  127. data/dpl-scalingo.gemspec +0 -3
  128. data/dpl-script.gemspec +0 -3
  129. data/dpl-snap.gemspec +0 -3
  130. data/dpl-surge.gemspec +0 -3
  131. data/dpl-testfairy.gemspec +0 -3
  132. data/dpl-transifex.gemspec +0 -3
  133. data/dpl.gemspec +0 -3
  134. data/gemspec_helper.rb +0 -51
  135. data/lib/dpl/error.rb +0 -3
  136. data/notes/engine_yard.md +0 -1
  137. data/notes/heroku.md +0 -3
  138. data/spec/cli_spec.rb +0 -36
  139. data/spec/provider_spec.rb +0 -191
  140. data/spec/spec_helper.rb +0 -20
@@ -0,0 +1,119 @@
1
+ module Dpl
2
+ module Providers
3
+ class Heroku
4
+ class Api < Heroku
5
+ status :alpha
6
+
7
+ full_name 'Heroku API'
8
+
9
+ description sq(<<-str)
10
+ tbd
11
+ str
12
+
13
+ opt '--api_key KEY', 'Heroku API key', required: true, secret: true
14
+ opt '--version VERSION', internal: true # used in triggering a build, not sure this should be exposed?
15
+
16
+ msgs pack: 'Creating application archive',
17
+ upload: 'Uploading application archive',
18
+ build: 'Triggering Heroku build (deployment)',
19
+ pending: 'Heroku build still pending',
20
+ failed: 'Heroku build failed'
21
+
22
+ cmds pack: 'tar -zcf %{escaped_archive_file} --exclude .git .',
23
+ upload: 'curl %{curl_opts} %{escaped_put_url} -X PUT -H "Content-Type:" -H "Accept: application/vnd.heroku+json; version=3" -H "User-Agent: %{user_agent}" --data-binary @%{escaped_archive_file}',
24
+ log: 'curl %{curl_opts} %{escaped_output_stream_url} -H "Accept: application/vnd.heroku+json; version=3" -H "User-Agent: %{user_agent}"'
25
+
26
+ attr_reader :data
27
+
28
+ def deploy
29
+ pack
30
+ upload
31
+ build
32
+ log
33
+ verify
34
+ end
35
+
36
+ private
37
+
38
+ def pack
39
+ shell :pack
40
+ end
41
+
42
+ def upload
43
+ shell :upload
44
+ end
45
+
46
+ def build
47
+ info :build
48
+ res = http.post("/apps/#{app}/builds") do |req|
49
+ req.headers['Content-Type'] = 'application/json'
50
+ req.body = JSON.dump(source_blob: { url: get_url, version: version })
51
+ end
52
+ handle_error(res) unless res.success?
53
+ @data = symbolize(JSON.parse(res.body))
54
+ end
55
+
56
+ def log
57
+ shell :log
58
+ end
59
+
60
+ def verify
61
+ loop do
62
+ case build_status
63
+ when 'pending'
64
+ info :pending
65
+ sleep 5
66
+ when 'succeeded'
67
+ break
68
+ else
69
+ error :failed
70
+ end
71
+ end
72
+ end
73
+
74
+ def build_status
75
+ res = http.get("/apps/#{app}/builds/#{build_id}")
76
+ JSON.parse(res.body)['status']
77
+ end
78
+
79
+ def archive_file
80
+ expand("~/.dpl.#{app}.tgz")
81
+ end
82
+
83
+ def get_url
84
+ source['get_url']
85
+ end
86
+
87
+ def put_url
88
+ source['put_url']
89
+ end
90
+
91
+ def source
92
+ # this says the endpoint /sources is deprecated: https://devcenter.heroku.com/articles/platform-api-reference#source
93
+ # this says to use /apps/example-app/sources: https://devcenter.heroku.com/articles/build-and-release-using-the-api#sources-endpoint
94
+ @source ||= begin
95
+ res = http.post('/sources')
96
+ handle_error(res) unless res.success?
97
+ JSON.parse(res.body)['source_blob']
98
+ end
99
+ end
100
+
101
+ def build_id
102
+ data[:id]
103
+ end
104
+
105
+ def output_stream_url
106
+ data[:output_stream_url]
107
+ end
108
+
109
+ def version
110
+ super || git_sha
111
+ end
112
+
113
+ def curl_opts
114
+ tty? ? '' : '-sS'
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,50 @@
1
+ module Dpl
2
+ module Providers
3
+ class Heroku
4
+ class Git < Heroku
5
+ status :alpha
6
+
7
+ full_name 'Heroku Git'
8
+
9
+ description sq(<<-str)
10
+ tbd
11
+ str
12
+
13
+ required :api_key, [:username, :password]
14
+
15
+ opt '--api_key KEY', 'Heroku API key', secret: true
16
+ opt '--username USER', 'Heroku username', alias: :user
17
+ opt '--password PASS', 'Heroku password', secret: true
18
+ opt '--git URL'
19
+
20
+ needs :git, :git_http_user_agent
21
+
22
+ cmds fetch: 'git fetch origin $TRAVIS_BRANCH --unshallow',
23
+ push: 'git push %{remote} HEAD:refs/heads/master -f'
24
+
25
+ def prepare
26
+ write_netrc if write_netrc?
27
+ end
28
+
29
+ def deploy
30
+ shell :fetch, assert: false
31
+ shell :push
32
+ end
33
+
34
+ private
35
+
36
+ def remote
37
+ git || "https://git.heroku.com/#{app}.git"
38
+ end
39
+
40
+ def write_netrc?
41
+ remote.start_with?('https://')
42
+ end
43
+
44
+ def write_netrc
45
+ super('git.heroku.com', email, api_key || password)
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,202 @@
1
+ require 'dpl/helper/zip'
2
+
3
+ module Dpl
4
+ module Providers
5
+ class Lambda < Provider
6
+ status :alpha
7
+
8
+ full_name 'AWS Lambda'
9
+
10
+ description sq(<<-str)
11
+ tbd
12
+ str
13
+
14
+ gem 'aws-sdk-lambda', '~> 1.0'
15
+ gem 'rubyzip', '~> 1.2.2', require: 'zip'
16
+
17
+ env :aws
18
+ config '~/.aws/credentials', '~/.aws/config', prefix: 'aws'
19
+
20
+ opt '--access_key_id ID', 'AWS access key id', required: true, secret: true
21
+ opt '--secret_access_key KEY', 'AWS secret key', required: true, secret: true
22
+ opt '--region REGION', 'AWS region the Lambda function is running in', default: 'us-east-1'
23
+ opt '--function_name FUNC', 'Name of the Lambda being created or updated', required: true
24
+ opt '--role ROLE', 'ARN of the IAM role to assign to the Lambda function', note: 'required for creating a new function'
25
+ opt '--handler_name NAME', 'Function the Lambda calls to begin execution.', note: 'required for creating a new function'
26
+ opt '--module_name NAME', 'Name of the module that exports the handler', default: 'index', requires: :handler_name
27
+ opt '--description DESCR', 'Description of the Lambda being created or updated'
28
+ opt '--timeout SECS', 'Function execution time (in seconds) at which Lambda should terminate the function', default: 3
29
+ opt '--memory_size MB', 'Amount of memory in MB to allocate to this Lambda', default: 128
30
+ opt '--subnet_ids IDS', 'List of subnet IDs to be added to the function', type: :array, note: 'Needs the ec2:DescribeSubnets and ec2:DescribeVpcs permission for the user of the access/secret key to work'
31
+ opt '--security_group_ids IDS', 'List of security group IDs to be added to the function', type: :array, note: 'Needs the ec2:DescribeSecurityGroups and ec2:DescribeVpcs permission for the user of the access/secret key to work'
32
+ opt '--environment VARS', 'List of Environment Variables to add to the function', type: :array, format: /[\w\-]+=.+/, note: 'Can be encrypted for added security', alias: :environment_variables
33
+ opt '--runtime NAME', 'Lambda runtime to use', default: 'nodejs8.10', enum: %w(java8 nodejs8.10 nodejs10.x python2.7 python3.6 python3.7 dotnetcore2.1 go1.x ruby2.5)
34
+ opt '--dead_letter_arn ARN', 'ARN to an SNS or SQS resource used for the dead letter queue.'
35
+ opt '--kms_key_arn ARN', 'KMS key ARN to use to encrypt environment_variables.'
36
+ opt '--tracing_mode MODE', 'Tracing mode', default: 'PassThrough', enum: %w(Active PassThrough), note: 'Needs xray:PutTraceSegments xray:PutTelemetryRecords on the role'
37
+ opt '--layers LAYERS', 'Function layer arns', type: :array
38
+ opt '--function_tags TAGS', 'List of tags to add to the function', type: :array, format: /[\w\-]+=.+/, note: 'Can be encrypted for added security'
39
+ opt '--publish', 'Create a new version of the code instead of replacing the existing one.'
40
+ opt '--zip PATH', 'Path to a packaged Lambda, a directory to package, or a single file to package', default: '.'
41
+ opt '--dot_match', 'Include hidden .* files to the zipped archive'
42
+
43
+ msgs login: 'Using Access Key: %{access_key_id}',
44
+ create_function: 'Creating function %{function_name}.',
45
+ update_config: 'Updating existing function %{function_name}.',
46
+ update_tags: 'Updating tags.',
47
+ update_code: 'Updating code.',
48
+ description: 'Deploy build %{build_number} to AWS Lambda via Travis CI'
49
+
50
+ def login
51
+ info :login
52
+ end
53
+
54
+ def deploy
55
+ exists? ? update : create
56
+ rescue Aws::Errors::ServiceError => e
57
+ error e.message
58
+ end
59
+
60
+ private
61
+
62
+ def exists?
63
+ !!client.get_function(function_name: function_name)
64
+ rescue ::Aws::Lambda::Errors::ResourceNotFoundException
65
+ false
66
+ end
67
+
68
+ def create
69
+ info :create_function
70
+ config = function_config
71
+ config = config.merge(code: { zip_file: function_zip })
72
+ config = config.merge(tags: function_tags) if function_tags?
73
+ client.create_function(config)
74
+ end
75
+
76
+ def update
77
+ arn = update_config
78
+ update_tags(arn) if function_tags?
79
+ update_code
80
+ end
81
+
82
+ def update_config
83
+ info :update_config
84
+ response = client.update_function_configuration(function_config)
85
+ response.function_arn
86
+ end
87
+
88
+ def update_tags(arn)
89
+ info :update_tags
90
+ client.tag_resource(tag_resource(arn))
91
+ end
92
+
93
+ def update_code
94
+ info :update_code
95
+ client.update_function_code(function_code)
96
+ end
97
+
98
+ def function_config
99
+ compact(
100
+ function_name: function_name,
101
+ role: role,
102
+ handler: handler,
103
+ description: description,
104
+ timeout: timeout,
105
+ memory_size: memory_size,
106
+ vpc_config: vpc_config,
107
+ environment: environment,
108
+ runtime: runtime,
109
+ dead_letter_config: dead_letter_arn,
110
+ kms_key_arn: kms_key_arn,
111
+ tracing_config: tracing_config,
112
+ layers: layers
113
+ )
114
+ end
115
+
116
+ def tag_resource(arn)
117
+ {
118
+ resource: arn,
119
+ tags: function_tags
120
+ }
121
+ end
122
+
123
+ def function_code
124
+ {
125
+ function_name: function_name,
126
+ zip_file: function_zip,
127
+ publish: publish?
128
+ }
129
+ end
130
+
131
+ def handler
132
+ Handler.new(runtime, module_name, handler_name).to_s if handler_name?
133
+ end
134
+
135
+ def function_zip
136
+ Zip.new(zip, tmp_filename, opts).zip
137
+ end
138
+
139
+ def vpc_config
140
+ compact(subnet_ids: subnet_ids, security_group_ids: security_group_ids)
141
+ end
142
+
143
+ def environment
144
+ { variables: split_vars(super) } if environment?
145
+ end
146
+
147
+ def dead_letter_arn
148
+ { target_arn: super } if dead_letter_arn?
149
+ end
150
+
151
+ def tracing_config
152
+ { mode: tracing_mode } if tracing_mode?
153
+ end
154
+
155
+ def function_tags
156
+ split_vars(super) if function_tags?
157
+ end
158
+
159
+ def description
160
+ super || interpolate(msg(:description))
161
+ end
162
+
163
+ def client
164
+ @client ||= Aws::Lambda::Client.new(region: region, credentials: credentials)
165
+ end
166
+
167
+ def credentials
168
+ Aws::Credentials.new(access_key_id, secret_access_key)
169
+ end
170
+
171
+ def split_vars(vars)
172
+ vars.map { |var| var.split('=', 2) }.to_h
173
+ end
174
+
175
+ def tmp_filename
176
+ @tmp_filename ||= "#{tmp_dir}/#{repo_name}.zip"
177
+ end
178
+
179
+ class Handler < Struct.new(:runtime, :module_name, :handler_name)
180
+ SEP = {
181
+ default: '.',
182
+ java: '::',
183
+ dotnet: '::',
184
+ go: ''
185
+ }
186
+
187
+ def to_s
188
+ [go? ? nil : module_name, sep, handler_name].compact.join
189
+ end
190
+
191
+ def sep
192
+ key = SEP.keys.detect { |key| runtime.start_with?(key.to_s) }
193
+ SEP[key || :default]
194
+ end
195
+
196
+ def go?
197
+ runtime.start_with?('go')
198
+ end
199
+ end
200
+ end
201
+ end
202
+ end
@@ -0,0 +1,74 @@
1
+ module Dpl
2
+ module Providers
3
+ class Launchpad < Provider
4
+ status :alpha
5
+
6
+ description sq(<<-str)
7
+ tbd
8
+ str
9
+
10
+ opt '--slug SLUG', 'Launchpad project slug', format: /^~[^\/]+\/[^\/]+\/[^\/]+$/, example: '~user-name/project-name/branch-name'
11
+ opt '--oauth_token TOKEN', 'Launchpad OAuth token', secret: true
12
+ opt '--oauth_token_secret SECRET', 'Launchpad OAuth token secret', secret: true
13
+
14
+ msgs invalid_credentials: 'Invalid credentials (%s)',
15
+ unknown_error: 'Error: %s (%s)'
16
+
17
+ def deploy
18
+ handle_response(post)
19
+ end
20
+
21
+ private
22
+
23
+ def post
24
+ req = Net::HTTP::Post.new(path)
25
+ req['Authorization'] = authorization
26
+ req.set_form_data(data)
27
+ http.request(req)
28
+ end
29
+
30
+ def handle_response(res)
31
+ error :invalid_credentials, res.code if res.code == '401'
32
+ error :unknown_error, res.body, res.code unless res.kind_of?(Net::HTTPSuccess)
33
+ end
34
+
35
+ def http
36
+ http = Net::HTTP.new('api.launchpad.net', 443)
37
+ http.use_ssl = true
38
+ http
39
+ end
40
+
41
+ def path
42
+ "/1.0/#{slug}/+code-import"
43
+ end
44
+
45
+ def data
46
+ { 'ws.op' => 'requestImport' }
47
+ end
48
+
49
+ def authorization
50
+ squish(<<-auth)
51
+ OAuth oauth_consumer_key="Travis%20Deploy",
52
+ oauth_nonce="#{nonce}",
53
+ oauth_signature="%26#{oauth_token_secret}",
54
+ oauth_signature_method="PLAINTEXT",
55
+ oauth_timestamp="#{now}",
56
+ oauth_token="#{oauth_token}",
57
+ oauth_version="1.0"
58
+ auth
59
+ end
60
+
61
+ def nonce
62
+ rand(36 ** 32).to_s(36)
63
+ end
64
+
65
+ def now
66
+ Time::now().to_i
67
+ end
68
+
69
+ def squish(str)
70
+ str.strip.gsub(/\s+/, ' ')
71
+ end
72
+ end
73
+ end
74
+ end