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.
- checksums.yaml +5 -5
- data/CHANGELOG.md +74 -0
- data/CONTRIBUTING.md +392 -0
- data/Gemfile +17 -3
- data/Gemfile.lock +373 -0
- data/LICENSE +16 -19
- data/NOTES.md +275 -0
- data/README.md +1977 -707
- data/Rakefile +2 -2
- data/bin/dpl +7 -3
- data/lib/dpl.rb +20 -0
- data/lib/dpl/assets/atlas/install +19 -0
- data/lib/dpl/assets/dpl/README.erb.md +133 -0
- data/lib/dpl/assets/dpl/git_ssh +2 -0
- data/lib/dpl/assets/git/detect_private_key +8 -0
- data/lib/dpl/assets/hephy/filter_log +3 -0
- data/lib/dpl/assets/pypi/install +4 -0
- data/lib/dpl/assets/scalingo/install +6 -0
- data/lib/dpl/cli.rb +36 -48
- data/lib/dpl/ctx.rb +2 -0
- data/lib/dpl/ctx/bash.rb +543 -0
- data/lib/dpl/ctx/test.rb +242 -0
- data/lib/dpl/helper/assets.rb +36 -0
- data/lib/dpl/helper/cmd.rb +167 -0
- data/lib/dpl/helper/config_file.rb +47 -0
- data/lib/dpl/helper/env.rb +39 -0
- data/lib/dpl/helper/interpolate.rb +126 -0
- data/lib/dpl/helper/memoize.rb +20 -0
- data/lib/dpl/helper/squiggle.rb +22 -0
- data/lib/dpl/helper/zip.rb +69 -0
- data/lib/dpl/provider.rb +562 -234
- data/lib/dpl/provider/dsl.rb +369 -0
- data/lib/dpl/provider/examples.rb +128 -0
- data/lib/dpl/provider/status.rb +59 -0
- data/lib/dpl/providers.rb +40 -0
- data/lib/dpl/providers/anynines.rb +65 -0
- data/lib/dpl/providers/atlas.rb +49 -0
- data/lib/dpl/providers/azure_web_apps.rb +59 -0
- data/lib/dpl/providers/bintray.rb +313 -0
- data/lib/dpl/providers/bluemixcloudfoundry.rb +92 -0
- data/lib/dpl/providers/boxfuse.rb +48 -0
- data/lib/dpl/providers/cargo.rb +19 -0
- data/lib/dpl/providers/chef_supermarket.rb +128 -0
- data/lib/dpl/providers/cloud66.rb +40 -0
- data/lib/dpl/providers/cloudfiles.rb +56 -0
- data/lib/dpl/providers/cloudfoundry.rb +81 -0
- data/lib/dpl/providers/codedeploy.rb +179 -0
- data/lib/dpl/providers/datica.rb +60 -0
- data/lib/dpl/providers/elasticbeanstalk.rb +195 -0
- data/lib/dpl/providers/engineyard.rb +107 -0
- data/lib/dpl/providers/firebase.rb +41 -0
- data/lib/dpl/providers/gae.rb +74 -0
- data/lib/dpl/providers/gcs.rb +105 -0
- data/lib/dpl/providers/hackage.rb +47 -0
- data/lib/dpl/providers/hephy.rb +101 -0
- data/lib/dpl/providers/heroku.rb +111 -0
- data/lib/dpl/providers/heroku/api.rb +119 -0
- data/lib/dpl/providers/heroku/git.rb +50 -0
- data/lib/dpl/providers/lambda.rb +202 -0
- data/lib/dpl/providers/launchpad.rb +74 -0
- data/lib/dpl/providers/netlify.rb +30 -0
- data/lib/dpl/providers/npm.rb +88 -0
- data/lib/dpl/providers/openshift.rb +46 -0
- data/lib/dpl/providers/opsworks.rb +142 -0
- data/lib/dpl/providers/packagecloud.rb +190 -0
- data/lib/dpl/providers/pages.rb +17 -0
- data/lib/dpl/providers/pages/api.rb +102 -0
- data/lib/dpl/providers/pages/git.rb +251 -0
- data/lib/dpl/providers/puppetforge.rb +44 -0
- data/lib/dpl/providers/pypi.rb +120 -0
- data/lib/dpl/providers/releases.rb +214 -0
- data/lib/dpl/providers/rubygems.rb +89 -0
- data/lib/dpl/providers/s3.rb +243 -0
- data/lib/dpl/providers/scalingo.rb +63 -0
- data/lib/dpl/providers/script.rb +28 -0
- data/lib/dpl/providers/snap.rb +59 -0
- data/lib/dpl/providers/surge.rb +55 -0
- data/lib/dpl/providers/testfairy.rb +93 -0
- data/lib/dpl/providers/transifex.rb +66 -0
- data/lib/dpl/support/aws_sdk_patch.rb +23 -0
- data/lib/dpl/support/gems.rb +69 -0
- data/lib/dpl/support/gstore_patch.rb +6 -0
- data/lib/dpl/support/version.rb +83 -0
- data/lib/dpl/version.rb +2 -2
- metadata +98 -169
- data/.coveralls.yml +0 -1
- data/.github/CONTRIBUTING.md +0 -173
- data/.github/stale.yml +0 -53
- data/.gitignore +0 -13
- data/.rspec +0 -2
- data/.travis.yml +0 -56
- data/dpl-anynines.gemspec +0 -3
- data/dpl-atlas.gemspec +0 -3
- data/dpl-azure_webapps.gemspec +0 -3
- data/dpl-bintray.gemspec +0 -3
- data/dpl-bitballoon.gemspec +0 -3
- data/dpl-bluemix_cloud_foundry.gemspec +0 -3
- data/dpl-boxfuse.gemspec +0 -3
- data/dpl-cargo.gemspec +0 -3
- data/dpl-catalyze.gemspec +0 -3
- data/dpl-chef_supermarket.gemspec +0 -20
- data/dpl-cloud66.gemspec +0 -3
- data/dpl-cloud_files.gemspec +0 -3
- data/dpl-cloud_foundry.gemspec +0 -3
- data/dpl-code_deploy.gemspec +0 -3
- data/dpl-deis.gemspec +0 -3
- data/dpl-elastic_beanstalk.gemspec +0 -3
- data/dpl-engine_yard.gemspec +0 -3
- data/dpl-firebase.gemspec +0 -3
- data/dpl-gae.gemspec +0 -3
- data/dpl-gcs.gemspec +0 -3
- data/dpl-hackage.gemspec +0 -3
- data/dpl-hephy.gemspec +0 -3
- data/dpl-heroku.gemspec +0 -3
- data/dpl-lambda.gemspec +0 -3
- data/dpl-launchpad.gemspec +0 -3
- data/dpl-npm.gemspec +0 -3
- data/dpl-openshift.gemspec +0 -3
- data/dpl-ops_works.gemspec +0 -3
- data/dpl-packagecloud.gemspec +0 -3
- data/dpl-pages.gemspec +0 -3
- data/dpl-puppet_forge.gemspec +0 -3
- data/dpl-pypi.gemspec +0 -3
- data/dpl-releases.gemspec +0 -8
- data/dpl-rubygems.gemspec +0 -3
- data/dpl-s3.gemspec +0 -3
- data/dpl-scalingo.gemspec +0 -3
- data/dpl-script.gemspec +0 -3
- data/dpl-snap.gemspec +0 -3
- data/dpl-surge.gemspec +0 -3
- data/dpl-testfairy.gemspec +0 -3
- data/dpl-transifex.gemspec +0 -3
- data/dpl.gemspec +0 -3
- data/gemspec_helper.rb +0 -51
- data/lib/dpl/error.rb +0 -3
- data/notes/engine_yard.md +0 -1
- data/notes/heroku.md +0 -3
- data/spec/cli_spec.rb +0 -36
- data/spec/provider_spec.rb +0 -191
- 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
|