apperol 0.0.1

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: db158e412b26ecb904f357742bd9e6560d573627
4
+ data.tar.gz: 9d9939c3ec0104b2a3c1b860268b9a6cee9c22ae
5
+ SHA512:
6
+ metadata.gz: d15027aed70b6c7850587104b070477df35d4eecca06a640c4ab5a1c583b61a88682aa4cbf7a50881cd1ef2a33dff2eba09e124cb170b923d6201b8c3b5b366d
7
+ data.tar.gz: 059e5e660c1b8c106ec44492df8d5505e128fe04f264f7ff78c065778ee15a41a8f2849cb5985d3ca7a1d885825daf453b6b1a1a1aedc2fbe686325f1c71ceda
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in apperol.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Yannick
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,48 @@
1
+ # Apperol
2
+
3
+ Create apps from heroku repositories on GitHub.
4
+ Use app.json to customize options.
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem 'apperol'
12
+ ```
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+ Or install it yourself as:
19
+
20
+ $ gem install apperol
21
+
22
+ ## Usage
23
+
24
+ ```
25
+ Usage: apperol [options] [app_extension]
26
+ -p, --personal Force app in personal apps instead of orgs
27
+ -s, --stack stack Stack for app on heroku
28
+ -b, --branch branch Branch to setup app from
29
+ -r, --repo repo GitHub repository source
30
+ -o, --org org GitHub org where the current repo is located
31
+ -u, --user user GitHub user where the current repo is located
32
+ -h, --help Displays Help
33
+
34
+ ```
35
+
36
+ ## Information
37
+
38
+ - App will be named [current_dir]-[app_extension] e.g.: direwolf-staging
39
+ - Apperol CLI will have many options based on `env` part of the `app.json`
40
+ - Apperol CLI uses heroku org by default, use `-r user/repo` to specify yours.
41
+
42
+ ## Contributing
43
+
44
+ 1. Fork it ( https://github.com/[my-github-username]/apperol/fork )
45
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
46
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
47
+ 4. Push to the branch (`git push origin my-new-feature`)
48
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
data/apperol.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'apperol/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "apperol"
8
+ spec.version = Apperol::VERSION
9
+ spec.authors = ["Yannick"]
10
+ spec.email = ["yannick@heroku.com"]
11
+ spec.summary = %q{Create heroku app from heroku repository}
12
+ spec.description = %q{Create heroku app from heroku repository with app.json}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.7"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+
24
+ spec.add_dependency "netrc", "~> 0.8.0"
25
+ spec.add_dependency "spinning_cursor", "~> 0.3.0"
26
+ end
data/bin/apperol ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'apperol'
4
+ puts Apperol::CLI.new(ARGV).call
5
+
@@ -0,0 +1,244 @@
1
+ require "bundler"
2
+ require "net/http"
3
+ require "openssl"
4
+ require "json"
5
+ require "optparse"
6
+ require "netrc"
7
+ require "spinning_cursor"
8
+
9
+ module Apperol
10
+ class CLI
11
+ EX_USAGE = 64
12
+
13
+ def initialize(args = [])
14
+ @options = {}
15
+
16
+ parser = OptionParser.new do|opts|
17
+ opts.banner = "Usage: apperol [options] [app_extension]"
18
+ app_json["env"].each do |key, definition|
19
+ option_key_name = key.downcase.gsub("_", "-")
20
+ option_key_key = key.downcase.to_sym
21
+ # Set default
22
+ @options[option_key_key] = definition["value"]
23
+ opts.on("--#{option_key_name} value", "#{definition["description"]} (Default: '#{definition["value"]}')") do |value|
24
+ @options[option_key_key] = value
25
+ end
26
+ end
27
+ opts.on("-p", "--personal", "Force app in personal apps instead of orgs") do
28
+ @options[:personal] = true
29
+ end
30
+ opts.on("-r", "--repo repo", "GitHub repository used for the deploy") do |repo|
31
+ @options[:repo] = repo
32
+ end
33
+ opts.on("-o", "--org org", "GitHub org where current repo is located") do |org|
34
+ @options[:org] = org
35
+ end
36
+ opts.on("-u", "--user user", "GitHub user where current repo is located") do |user|
37
+ @options[:org] = user
38
+ end
39
+ opts.on("-s", "--stack stack", "Stack for app on heroku") do |stack|
40
+ @options[:stack] = stack
41
+ end
42
+ opts.on("-b", "--branch branch", "Branch to setup app from") do |branch|
43
+ @options[:branch] = branch
44
+ end
45
+ opts.on('-h', '--help', 'Displays Help') do
46
+ puts opts
47
+ exit EX_USAGE
48
+ end
49
+ end
50
+ parser.parse!(args)
51
+
52
+ @app_extension = args.shift
53
+
54
+ unless @app_extension
55
+ $stderr.puts("usage: apperol [options] [app_extension]")
56
+ exit EX_USAGE
57
+ end
58
+ end
59
+
60
+ def call
61
+ heroku_app_setup
62
+ end
63
+
64
+ def heroku_app_setup
65
+ req = Net::HTTP::Post.new(app_setup_url, initheader = heroku_headers)
66
+ req.basic_auth *heroku_creds
67
+ req.body = app_setup_payload
68
+ $stdout.puts("Setting up heroku app #{heroku_app_name}-#{@app_extension}")
69
+ res = heroku_http.request(req)
70
+ if res.code != "202"
71
+ $stderr.puts JSON.parse(res.body)["message"]
72
+ exit 1
73
+ else
74
+ poll_app_status(JSON.parse(res.body))
75
+ end
76
+ end
77
+
78
+ def poll_app_status(response)
79
+ req = Net::HTTP::Get.new(app_setup_url(response["id"]), initheader = heroku_headers)
80
+ req.basic_auth *heroku_creds
81
+ res = {}
82
+ spin_wait("Setting up your app", "App setup done") do
83
+ loop do
84
+ res = JSON.parse(heroku_http.request(req).body)
85
+ break unless res["status"] == "pending"
86
+ end
87
+ end
88
+ if res["status"] == "succeeded"
89
+ unless res["postdeploy"].empty?
90
+ $stdout.puts(res["postdeploy"]["output"])
91
+ end
92
+ $stdout.puts("Application #{res["app"]["name"]}.herokuapp.com has been successfully created.")
93
+ exit 0
94
+ else
95
+ $stderr.puts("error: #{res["failure_message"]}")
96
+ unless res["manifest_errors"].empty?
97
+ $stderr.puts(" #{res["manifest_errors"]}")
98
+ end
99
+ unless res["postdeploy"].empty?
100
+ $stderr.puts(res["postdeploy"]["output"])
101
+ end
102
+ exit 1
103
+ end
104
+ end
105
+
106
+ def spin_wait(banner_txt, message_txt)
107
+ SpinningCursor.run do
108
+ banner banner_txt
109
+ type :dots
110
+ message message_txt
111
+ end
112
+
113
+ yield
114
+
115
+ SpinningCursor.stop
116
+ end
117
+
118
+ def app_setup_url(id = nil)
119
+ URI("https://api.heroku.com/app-setups/#{id}")
120
+ end
121
+
122
+ def heroku_headers
123
+ {
124
+ "Content-Type" => "application/json",
125
+ "Accept" => "application/vnd.heroku+json; version=3"
126
+ }
127
+ end
128
+
129
+ def heroku_http
130
+ @heroku_http ||= Net::HTTP.new(app_setup_url.hostname, app_setup_url.port).tap do |http|
131
+ http.use_ssl = true
132
+ end
133
+ end
134
+
135
+ def app_setup_payload
136
+ payload = {
137
+ app: {
138
+ name: "#{heroku_app_name}-#{@app_extension}",
139
+ stack: stack
140
+ },
141
+ source_blob: { url: github_tarball_location },
142
+ overrides: { env: {}}
143
+ }
144
+ required_not_filled = []
145
+ app_json["env"].each do |key, definition|
146
+ value = @options[key.downcase.to_sym]
147
+ if definition["required"] && value.strip.empty?
148
+ required_not_filled << key
149
+ end
150
+ payload[:overrides][:env][key] = value
151
+ end
152
+ unless required_not_filled.empty?
153
+ $stderr.puts("error: Required fields not filled. Please specify them. #{required_not_filled}")
154
+ exit 1
155
+ end
156
+ payload[:app][:organization] = "heroku" unless personal_app?
157
+ payload.to_json
158
+ end
159
+
160
+ def github_tarball_location
161
+ $stdout.puts("Getting tarball location for empirical branch #{github_branch}")
162
+ req = Net::HTTP::Get.new(github_url)
163
+ req.basic_auth *github_creds
164
+ res = github_http.request(req)
165
+ if res["Location"]
166
+ res["Location"]
167
+ else
168
+ $stderr.puts("error: No tarball found for #{github_url} : #{JSON.parse(res.body)["message"]}")
169
+ exit 1
170
+ end
171
+ end
172
+
173
+ def github_http
174
+ @github_http ||= Net::HTTP.new(github_url.hostname, github_url.port).tap do |http|
175
+ http.use_ssl = true
176
+ end
177
+ end
178
+
179
+ def personal_app?
180
+ @options.fetch(:personal, false)
181
+ end
182
+
183
+ def repo
184
+ @options.fetch(:repo, default_repo)
185
+ end
186
+
187
+ def default_repo
188
+ "#{org}/#{heroku_app_name}"
189
+ end
190
+
191
+ def org
192
+ @options.fetch(:org, "heroku")
193
+ end
194
+
195
+ def rollbar_token
196
+ @options.fetch(:rollbar_token) {
197
+ $stdout.puts("Missing rollbar_token option, its not required but you won't have exception tracking")
198
+ ""
199
+ }
200
+ end
201
+
202
+ def github_branch
203
+ @options.fetch(:branch, "master")
204
+ end
205
+
206
+ def stack
207
+ @options.fetch(:stack, "cedar-14")
208
+ end
209
+
210
+ def rack_env
211
+ @options.fetch(:rack_env) {
212
+ @app_extension == "production" ? "production" : "staging"
213
+ }
214
+ end
215
+
216
+ def github_url
217
+ @github_url ||= URI("https://api.github.com/repos/#{repo}/tarball/#{github_branch}")
218
+ end
219
+
220
+ def github_creds
221
+ netrc["api.github.com"]
222
+ end
223
+
224
+ def heroku_creds
225
+ netrc["api.heroku.com"]
226
+ end
227
+
228
+ def netrc
229
+ @netrc ||= Netrc.read
230
+ end
231
+
232
+ def heroku_app_name
233
+ Dir.pwd.split("/").last
234
+ end
235
+
236
+ def app_json
237
+ unless File.exists?("app.json")
238
+ $stderr.puts("No app.json file here")
239
+ exit 1
240
+ end
241
+ @app_json ||= JSON.parse(File.read("app.json"))
242
+ end
243
+ end
244
+ end
@@ -0,0 +1,3 @@
1
+ module Apperol
2
+ VERSION = "0.0.1"
3
+ end
data/lib/apperol.rb ADDED
@@ -0,0 +1,5 @@
1
+ require "apperol/version"
2
+ require "apperol/cli"
3
+
4
+ module Apperol
5
+ end
metadata ADDED
@@ -0,0 +1,111 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: apperol
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Yannick
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-10-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: netrc
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.8.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.8.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: spinning_cursor
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.3.0
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.3.0
69
+ description: Create heroku app from heroku repository with app.json
70
+ email:
71
+ - yannick@heroku.com
72
+ executables:
73
+ - apperol
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - ".gitignore"
78
+ - Gemfile
79
+ - LICENSE.txt
80
+ - README.md
81
+ - Rakefile
82
+ - apperol.gemspec
83
+ - bin/apperol
84
+ - lib/apperol.rb
85
+ - lib/apperol/cli.rb
86
+ - lib/apperol/version.rb
87
+ homepage: ''
88
+ licenses:
89
+ - MIT
90
+ metadata: {}
91
+ post_install_message:
92
+ rdoc_options: []
93
+ require_paths:
94
+ - lib
95
+ required_ruby_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ required_rubygems_version: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ requirements: []
106
+ rubyforge_project:
107
+ rubygems_version: 2.2.2
108
+ signing_key:
109
+ specification_version: 4
110
+ summary: Create heroku app from heroku repository
111
+ test_files: []