kensa 1.2.0rc7 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,64 +1,17 @@
1
1
  require 'restclient'
2
2
  require 'term/ansicolor'
3
3
  require 'launchy'
4
+ require 'optparse'
4
5
 
5
6
  module Heroku
6
- class Git
7
- class << self
8
- def verify_create(app_name, template)
9
- raise CommandInvalid.new("template #{clone_url(template)} does not exist") unless template_exists?(template)
10
- raise CommandInvalid.new("Need git to clone repository") unless git_installed?
11
- end
12
-
13
- def template_exists?(template)
14
- true
15
- end
16
-
17
- def git_installed?
18
- `git` rescue false
19
- end
20
-
21
- def clone(app_name, template)
22
- verify_create(app_name, template)
23
- cmd = "git clone #{clone_url(template)} #{app_name}"
24
- puts cmd
25
- `#{cmd}`
26
- raise Exception.new("couldn't clone the repository from #{clone_url(template)}") unless File.directory?("#{app_name}")
27
- puts "Created #{app_name} from #{template} template"
28
- end
29
-
30
- def clone_url(name)
31
- prefix = ENV['REPO_PREFIX'] || "heroku"
32
- if name.include? "://" #its a full url
33
- return name
34
- elsif name.include? "/" #its a non-heroku repo
35
- name = "#{prefix}/#{name}"
36
- else #its one of ours
37
- name = "#{prefix}/kensa-create-#{name}"
38
- end
39
-
40
- "git://github.com/#{name}"
41
- end
42
- end
43
- end
44
-
45
7
  module Kensa
46
- class UserError < RuntimeError; end
47
-
48
8
  class Client
49
- def initialize(args, options)
9
+ def initialize(args, options = {})
50
10
  @args = args
51
- @options = options
11
+ @options = OptParser.parse(args).merge(options)
52
12
  end
53
13
 
54
- def filename
55
- @options[:filename]
56
- end
57
-
58
- #you fucked up
59
14
  class CommandInvalid < Exception; end
60
- #we fucked up
61
- class CommandFailed < Exception; end
62
15
 
63
16
  def run!
64
17
  command = @args.shift || @options[:command]
@@ -67,63 +20,44 @@ module Heroku
67
20
  end
68
21
 
69
22
  def init
70
- Manifest.new(filename, @options).write
71
- Screen.new.message "Initialized new addon manifest in #{filename}\n"
23
+ Manifest.new(@options).write
24
+ screen.message "Initialized new addon manifest in #{filename}\n"
25
+ if @options[:foreman]
26
+ screen.message "Initialized new .env file for foreman\n"
27
+ end
72
28
  end
73
29
 
74
30
  def create
75
31
  app_name = @args.shift
76
32
  template = @options[:template]
77
- raise CommandInvalid.new("Need git to supply a template") unless template
78
- raise CommandInvalid.new("Need git to supply an application name") unless app_name
79
-
33
+ raise CommandInvalid.new("Need to supply an application name") unless app_name
34
+ raise CommandInvalid.new("Need to supply a template") unless template
80
35
  begin
81
- Git.clone(app_name, template)
36
+ Git.clone(app_name, template) and screen.message "Created #{app_name} from #{template} template\n"
37
+ Dir.chdir(app_name)
38
+ @options[:foreman] = true
39
+ init
82
40
  rescue Exception => e
83
- raise CommandFailed.new("error cloning #{Git.clone_url(template)} into #{app_name}")
41
+ raise CommandInvalid.new("error cloning #{Git.clone_url(template)} into #{app_name}")
84
42
  end
85
-
86
- Dir.chdir("./#{app_name}")
87
- `./after_clone #{app_name}` if File.exist?('./after_clone')
88
43
  end
89
44
 
90
-
91
45
  def test
92
46
  case check = @args.shift
93
47
  when "manifest"
94
- require "#{File.dirname(__FILE__)}/../../../test/manifest_test"
95
- require 'test/unit/ui/console/testrunner'
96
- $manifest = Yajl::Parser.parse(resolve_manifest)
97
- Test::Unit.run = true
98
- Test::Unit::UI::Console::TestRunner.new(ManifestTest.suite).start
48
+ run_check ManifestCheck
99
49
  when "provision"
100
- require "#{File.dirname(__FILE__)}/../../../test/provision_test"
101
- require 'test/unit/ui/console/testrunner'
102
- $manifest = Yajl::Parser.parse(resolve_manifest)
103
- Test::Unit.run = true
104
- Test::Unit::UI::Console::TestRunner.new(ProvisionTest.suite).start
50
+ run_check ManifestCheck, ProvisionCheck
105
51
  when "deprovision"
106
52
  id = @args.shift || abort("! no id specified; see usage")
107
- require "#{File.dirname(__FILE__)}/../../../test/deprovision_test"
108
- require 'test/unit/ui/console/testrunner'
109
- $manifest = Yajl::Parser.parse(resolve_manifest).merge("user_id" => id)
110
- Test::Unit.run = true
111
- Test::Unit::UI::Console::TestRunner.new(DeprovisionTest.suite).start
53
+ run_check ManifestCheck, DeprovisionCheck, :id => id
112
54
  when "planchange"
113
55
  id = @args.shift || abort("! no id specified; see usage")
114
56
  plan = @args.shift || abort("! no plan specified; see usage")
115
- require "#{File.dirname(__FILE__)}/../../../test/plan_change_test"
116
- require 'test/unit/ui/console/testrunner'
117
- $manifest = Yajl::Parser.parse(resolve_manifest).merge("user_id" => id)
118
- Test::Unit.run = true
119
- Test::Unit::UI::Console::TestRunner.new(PlanChangeTest.suite).start
57
+ run_check ManifestCheck, PlanChangeCheck, :id => id, :plan => plan
120
58
  when "sso"
121
59
  id = @args.shift || abort("! no id specified; see usage")
122
- require "#{File.dirname(__FILE__)}/../../../test/sso_test"
123
- require 'test/unit/ui/console/testrunner'
124
- $manifest = Yajl::Parser.parse(resolve_manifest).merge("user_id" => id)
125
- Test::Unit.run = true
126
- Test::Unit::UI::Console::TestRunner.new(SsoTest.suite).start
60
+ run_check ManifestCheck, SsoCheck, :id => id
127
61
  else
128
62
  abort "! Unknown test '#{check}'; see usage"
129
63
  end
@@ -177,12 +111,20 @@ module Heroku
177
111
  end
178
112
 
179
113
  def version
180
- puts "Kensa #{Kensa::VERSION}"
114
+ puts "Kensa #{VERSION}"
181
115
  end
182
116
 
183
117
  private
118
+ def filename
119
+ @options[:filename]
120
+ end
121
+
122
+ def screen
123
+ @screen ||= @options[:silent] ? NilScreen.new : Screen.new
124
+ end
125
+
184
126
  def headers
185
- { :accept => :json, "X-Kensa-Version" => "1", "User-Agent" => "kensa/#{Kensa::VERSION}" }
127
+ { :accept => :json, "X-Kensa-Version" => "1", "User-Agent" => "kensa/#{VERSION}" }
186
128
  end
187
129
 
188
130
  def heroku_host
@@ -206,7 +148,6 @@ module Heroku
206
148
  options = args.pop if args.last.is_a?(Hash)
207
149
 
208
150
  args.each do |klass|
209
- screen = Screen.new
210
151
  data = Yajl::Parser.parse(resolve_manifest)
211
152
  check = klass.new(data.merge(@options.merge(options)), screen)
212
153
  result = check.call
@@ -298,6 +239,43 @@ module Heroku
298
239
  $stdout.puts "done."
299
240
  end
300
241
  end
242
+
243
+
244
+ class OptParser
245
+ def self.defaults
246
+ {
247
+ :filename => 'addon-manifest.json',
248
+ :env => "test",
249
+ :async => false,
250
+ }
251
+ end
252
+
253
+ def self.parse(args)
254
+ self.defaults.tap do |options|
255
+ OptionParser.new do |o|
256
+ o.on("-f file", "--file") { |filename| options[:filename] = filename }
257
+ o.on("--async") { options[:async] = true }
258
+ o.on("--production") { options[:env] = "production" }
259
+ o.on("--without-sso") { options[:sso] = false }
260
+ o.on("-h", "--help") { command = "help" }
261
+ o.on("-p plan", "--plan") { |plan| options[:plan] = plan }
262
+ o.on("-v", "--version") { options[:command] = "version" }
263
+ o.on("-s sso", "--sso") { |method| options[:method] = method }
264
+ o.on("--foreman") { options[:foreman] = true }
265
+ o.on("-t name", "--template") do |template|
266
+ options[:template] = template
267
+ end
268
+
269
+ begin
270
+ o.parse!(args)
271
+ rescue OptionParser::InvalidOption
272
+ #skip over invalid options
273
+ retry
274
+ end
275
+ end
276
+ end
277
+ end
278
+ end
301
279
  end
302
280
  end
303
281
  end
@@ -0,0 +1,39 @@
1
+ module Heroku
2
+ module Kensa
3
+ class Git
4
+ class << self
5
+ def verify_create(app_name, template)
6
+ raise CommandInvalid.new("Need git to clone repository") unless git_installed?
7
+ end
8
+
9
+ def git_installed?
10
+ `git` rescue false
11
+ end
12
+
13
+ def clone(app_name, template)
14
+ verify_create(app_name, template)
15
+ run("git clone #{clone_url(template)} #{app_name}")
16
+ end
17
+
18
+ def run(cmd)
19
+ puts cmd
20
+ system(cmd)
21
+ end
22
+
23
+ def heroku_prefix
24
+ ENV["REPO_PREFIX"] || "heroku/kensa-create-"
25
+ end
26
+
27
+ def clone_url(name)
28
+ if name.include? "://" #its a full url not on github
29
+ return name
30
+ elsif !name.include? "/" #its one of ours
31
+ name = heroku_prefix + name
32
+ end
33
+
34
+ "git://github.com/#{name}"
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -2,28 +2,59 @@ module Heroku
2
2
  module Kensa
3
3
  class Manifest
4
4
 
5
- def initialize(filename = 'addon-manifest.json', options = {})
6
- @filename, @options = filename, options
5
+ def initialize(options = {})
6
+ @method = options.fetch(:method, 'post').to_sym
7
+ @filename = options.fetch(:filename, 'addon-manifest.json')
8
+ @options = options
7
9
  end
8
10
 
9
11
  def skeleton_json
12
+ @password = generate_password(16)
13
+ @port = @options[:foreman] ? 5000 : 4567
14
+ (@method == :get) ? get_skeleton : post_skeleton
15
+ end
16
+
17
+ def get_skeleton
18
+ <<-JSON
19
+ {
20
+ "id": "myaddon",
21
+ "api": {
22
+ "config_vars": [ "MYADDON_URL" ],
23
+ "password": "#{@password}",#{ sso_key }
24
+ "production": "https://yourapp.com/",
25
+ "test": "http://localhost:#{@port}/"
26
+ }
27
+ }
28
+ JSON
29
+ end
30
+
31
+ def post_skeleton
10
32
  <<-JSON
11
33
  {
12
34
  "id": "myaddon",
13
35
  "api": {
14
- "config_vars": [ "MYADDON_USER", "MYADDON_URL" ],
15
- "password": "#{generate_password(16)}",#{ sso_key }
36
+ "config_vars": [ "MYADDON_URL" ],
37
+ "password": "#{@password}",#{ sso_key }
16
38
  "production": {
17
39
  "base_url": "https://yourapp.com/heroku/resources",
18
40
  "sso_url": "https://yourapp.com/sso/login"
19
41
  },
20
42
  "test": {
21
- "base_url": "http://localhost:4567/heroku/resources",
22
- "sso_url": "http://localhost:4567/sso/login"
43
+ "base_url": "http://localhost:#{@port}/heroku/resources",
44
+ "sso_url": "http://localhost:#{@port}/sso/login"
23
45
  }
24
46
  }
25
47
  }
26
48
  JSON
49
+
50
+ end
51
+
52
+ def foreman
53
+ <<-ENV
54
+ SSO_SALT=#{@sso_salt}
55
+ HEROKU_USERNAME=myaddon
56
+ HEROKU_PASSWORD=#{@password}
57
+ ENV
27
58
  end
28
59
 
29
60
  def skeleton
@@ -31,14 +62,16 @@ JSON
31
62
  end
32
63
 
33
64
  def write
34
- open(@filename, 'w') { |f| f << skeleton_json }
65
+ File.open(@filename, 'w') { |f| f << skeleton_json }
66
+ File.open('.env', 'w') { |f| f << foreman } if @options[:foreman]
35
67
  end
36
68
 
37
69
  private
38
70
 
39
71
  def sso_key
72
+ @sso_salt = generate_password(16)
40
73
  unless @options[:sso] === false
41
- %{\n "sso_salt": #{ generate_password(16).inspect },}
74
+ %{\n "sso_salt": "#{@sso_salt}",}
42
75
  end
43
76
  end
44
77
 
@@ -0,0 +1,37 @@
1
+ module Heroku
2
+ module Kensa
3
+
4
+ class NilScreen
5
+ def test(msg)
6
+ end
7
+
8
+ def check(msg)
9
+ end
10
+
11
+ def error(msg)
12
+ end
13
+
14
+ def result(status)
15
+ end
16
+
17
+ def message(msg)
18
+ end
19
+ end
20
+
21
+ class IOScreen
22
+ attr_accessor :output
23
+
24
+ def initialize(io)
25
+ @output = io
26
+ end
27
+
28
+ def to_s
29
+ @output.closed_read? ? '' : @output.tap{|o| o.rewind }.read
30
+ end
31
+
32
+ [:test, :check, :error, :result, :message].each do |method|
33
+ eval %{ def #{method}(*args)\n @output.puts *args\n end }
34
+ end
35
+ end
36
+ end
37
+ end
@@ -1,43 +1,40 @@
1
1
  require 'restclient'
2
+ require 'uri'
2
3
 
3
4
  module Heroku
4
5
  module Kensa
5
6
  class Sso
6
- attr_accessor :id, :url, :proxy_port, :timestamp, :token, :sso_url
7
+ attr_accessor :id, :url, :proxy_port, :timestamp, :token
7
8
 
8
9
  def initialize(data)
9
10
  @id = data[:id]
10
11
  @salt = data['api']['sso_salt']
11
12
 
12
13
  env = data.fetch :env, 'test'
13
- if data["api"][env].is_a?(Hash)
14
- @url = data["api"][env]["base_url"].chomp('/')
15
- @sso_url = data["api"][env]["sso_url"].chomp('/')
16
- @use_post = true
14
+ if @url = data['api'][env]['sso_url']
15
+ @use_post = true
16
+ @proxy_port = find_available_port
17
17
  else
18
18
  @url = data["api"][env].chomp('/')
19
- @use_post = false
20
- end
21
- @proxy_port = find_available_port
19
+ end
22
20
  @timestamp = Time.now.to_i
23
21
  @token = make_token(@timestamp)
24
22
  end
25
23
 
26
24
  def path
27
- extra = self.post? ? '/sso' : ''
28
- if self.post?
29
- self.sso_url
25
+ if self.POST?
26
+ URI.parse(url).path
30
27
  else
31
28
  "/heroku/resources/#{id}"
32
29
  end
33
30
  end
34
31
 
35
- def post?
32
+ def POST?
36
33
  @use_post
37
34
  end
38
35
 
39
36
  def sso_url
40
- if self.post?
37
+ if self.POST?
41
38
  "http://localhost:#{@proxy_port}/"
42
39
  else
43
40
  full_url
@@ -50,13 +47,13 @@ module Heroku
50
47
  alias get_url full_url
51
48
 
52
49
  def post_url
53
- @sso_url
50
+ url
54
51
  end
55
52
 
56
53
  def timestamp=(other)
57
54
  @timestamp = other
58
55
  @token = make_token(@timestamp)
59
- end
56
+ end
60
57
 
61
58
  def make_token(t)
62
59
  Digest::SHA1.hexdigest([@id, @salt, t].join(':'))
@@ -64,7 +61,7 @@ module Heroku
64
61
 
65
62
  def querystring
66
63
  return '' unless @salt
67
- '?' + query_data
64
+ '?' + query_data
68
65
  end
69
66
 
70
67
  def query_data
@@ -72,10 +69,13 @@ module Heroku
72
69
  end
73
70
 
74
71
  def query_params
75
- { 'token' => @token,
72
+ { 'token' => @token,
76
73
  'timestamp' => @timestamp.to_s,
77
- 'nav-data' => sample_nav_data,
78
- 'user' => 'username@example.com' }
74
+ 'nav-data' => sample_nav_data,
75
+ 'email' => 'username@example.com'
76
+ }.tap do |params|
77
+ params.merge!('id' => @id) if self.POST?
78
+ end
79
79
  end
80
80
 
81
81
  def sample_nav_data
@@ -97,7 +97,7 @@ module Heroku
97
97
  end
98
98
 
99
99
  def message
100
- if self.post?
100
+ if self.POST?
101
101
  "POSTing #{query_data} to #{post_url} via proxy on port #{@proxy_port}"
102
102
  else
103
103
  "Opening #{full_url}"
@@ -117,13 +117,13 @@ module Heroku
117
117
  end
118
118
 
119
119
  def run_proxy
120
- return unless self.post?
120
+ return unless self.POST?
121
121
  server = PostProxy.new self
122
122
  @proxy = server
123
123
 
124
124
  trap("INT") { server.stop }
125
125
  pid = fork do
126
- server.start
126
+ server.start
127
127
  end
128
128
  at_exit { server.stop; Process.waitpid pid }
129
129
  end