kibo 0.3.5 → 0.4.0

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.
data/lib/kibo/config.rb CHANGED
@@ -1,134 +1,119 @@
1
1
  require "yaml"
2
+ require "mash"
2
3
 
3
- class Kibo::Configfile < Hash
4
- attr :path
4
+ class Kibo::Config < Mash
5
+ DEFAULTS = {
6
+ "heroku" => {
7
+ "mode" => "freemium"
8
+ },
9
+ "deployment" => {},
10
+ "collaborations" => {},
11
+ "source" => {},
12
+ "collaborators" => []
13
+ }
14
+
15
+ attr :environment, :kibofile
5
16
 
6
- def initialize(path)
7
- @path = path
17
+ def initialize(kibofile, environment)
18
+ @kibofile, @environment = kibofile, environment
19
+ @kibofile = File.expand_path @kibofile
8
20
 
9
- File.read(path).
10
- split("\n").
11
- each_with_index do |line, lineno|
12
- next if line =~ /^\s*#/
13
- next if line =~ /^\s*$/
14
- die(lineno, "Can't parse line: #{line.inspect}") unless line =~ /\s*([a-z]+):\s*(.*)$/
15
- key, value = $1, $2.gsub(/\s+$/, "")
16
-
17
- die(lineno, "Multiple entries for #{key.inspect}") if key?(key)
21
+ kibo = begin
22
+ YAML.load File.read(kibofile)
23
+ rescue Errno::ENOENT
24
+ E "No such file", File.expand_path(@kibofile)
25
+ end
18
26
 
19
- update key => value
20
- end
21
- rescue
22
- E "No such file", path
27
+ build_config(kibo)
28
+ verify_config
23
29
  end
24
-
25
- def die(lineno, msg)
26
- E "#{path}:#{lineno}", msg
30
+
31
+ def processes
32
+ return unless processes = super
33
+ processes.reject { |k,v| v.to_s.to_i <= 0 }
27
34
  end
28
- end
29
35
 
30
- class Kibo::Config
31
- attr :procfile
32
-
33
- DEFAULTS = {
34
- "procfile" => "Procfile"
35
- }
36
-
37
- def [](key)
38
- @data[key]
36
+ def freemium?
37
+ heroku.mode == "freemium"
39
38
  end
40
39
 
41
- def environment
42
- Kibo.environment
40
+ def namespace
41
+ heroku.namespace
43
42
  end
44
43
 
45
- def initialize(path)
46
- super()
47
-
48
- @data = DEFAULTS.dup
44
+ private
45
+
46
+ def build_config(kibo)
47
+ config = DEFAULTS.dup
49
48
 
50
- begin
51
- kibo = YAML.load File.read(path)
52
- @data.update(kibo)
53
- @data.update(kibo["defaults"] || {})
54
- @data.update(kibo[environment] || {})
55
- rescue Errno::ENOENT
56
- W "No such file", path
49
+ [ kibo, kibo["defaults"], kibo[environment] ].each do |hash|
50
+ next unless hash
51
+ config = config.deep_merge(hash)
57
52
  end
58
53
 
59
- verify_version!
60
-
61
- @procfile = Kibo::Configfile.new(self["procfile"])
54
+ self.update config
62
55
  end
63
56
 
64
- # processes are defined in the Procfile. The scaling, however, is defined in
65
- # the Kibofile.
66
- def processes
67
- @processes ||= procfile.keys.inject({}) do |hash, key|
68
- hash.update key => (self[key] || 1)
69
- end
57
+ def verify_config
58
+ Kibo::Config.verify_version!(self.version)
59
+
60
+ # verify required entries
61
+ E("#{@kibofile}: Please set the heroku namespace.") unless heroku.namespace?
62
+ E("#{@kibofile}: Please set the heroku account email") unless heroku.account?
63
+ E("#{@kibofile}: Missing 'processes' settings") unless self.processes.is_a?(Hash)
70
64
  end
65
+
66
+ def self.verify_version!(version)
67
+ return unless version
71
68
 
72
- def verify_version!
73
- return unless self["version"]
69
+ kibofile_version = version.split(".").map(&:to_i)
70
+ kibo_version = Kibo::VERSION.split(".").map(&:to_i)
74
71
 
75
- files_version = self["version"].split(".").map(&:to_i)
76
- kibos_version = Kibo::VERSION.split(".").map(&:to_i)
72
+ return if kibo_version >= kibofile_version
77
73
 
78
- files_version.zip(kibos_version).each do |files, kibos|
79
- next if kibos == files
80
- if kibos > files
81
- W "The Kibofile requires kibo version #{self["version"]}. You have #{Kibo::VERSION}... this might work."
82
- return
83
- end
84
-
85
- E "The Kibofile requires kibo version #{self["version"]}. You have #{Kibo::VERSION}."
86
- end
74
+ E "The Kibofile requires kibo version #{version}. You have #{Kibo::VERSION}."
87
75
  end
76
+ end
88
77
 
89
- #
90
- # we need namespace-ENVIRONMENT-process<1>
78
+ class Kibo::Instance < String
79
+ attr :count, :role
91
80
 
92
- # returns the heroku configuration
93
- def heroku
94
- self["heroku"] || {}
95
- end
96
-
97
- # returns deployment specific configuration
98
- def deployment
99
- self["deployment"] || {}
81
+ def initialize(config, role, count)
82
+ @role, @count = role, count
83
+
84
+ super "#{config.namespace}-#{config.environment}-#{role}"
100
85
  end
101
86
 
102
- def collaborations
103
- self["collaborations"] || {}
87
+ def addons
88
+ []
104
89
  end
105
90
 
106
- # returns source specific configuration
107
- def source
108
- self["source"] || {}
109
- end
110
-
111
- # returns the heroku namespace
112
- def namespace
113
- heroku["namespace"] || E("Please set the heroku namespace in your Kibofile.")
91
+ class Freemium < self
92
+ def initialize(config, role, number)
93
+ super config, role, 1
94
+ @number = number
95
+
96
+ concat "#{@number}"
97
+ end
114
98
  end
99
+ end
115
100
 
116
- # returns the heroku account email. This is the account that
117
- # you should be logged in
118
- def account
119
- heroku["account"] || E("Please set the heroku account email in your Kibofile")
120
- end
101
+ class Kibo::Config
121
102
 
122
- def remotes_by_process
123
- remotes = Kibo.git("remote", :quiet).split("\n")
124
-
125
- @remotes_by_process ||= begin
126
- r = processes.map do |process, count|
127
- prefix = "#{namespace}-#{environment}-#{process}"
128
- remotes = 1.upto(count).map { |idx| "#{prefix}#{idx}" }
129
- [ process, remotes ]
103
+ # return an array of instances.
104
+ def instances
105
+ instances = if freemium?
106
+ processes.map do |process, count|
107
+ 1.upto(count).map { |idx|
108
+ Kibo::Instance::Freemium.new self, process, idx
109
+ }
110
+ end.flatten
111
+ else
112
+ processes.map do |process, count|
113
+ Kibo::Instance.new self, process, count
130
114
  end
131
- Hash[r]
132
115
  end
116
+
117
+ instances.sort_by(&:to_s)
133
118
  end
134
119
  end
@@ -0,0 +1,30 @@
1
+ class Array
2
+ def self.diff(one, other)
3
+ one.zip(other).each do |ones, others|
4
+ return 0 if ones.nil? && others.nil?
5
+
6
+ return -1 if ones.nil?
7
+ return 1 if others.nil?
8
+
9
+ return -1 if ones < others
10
+ return 1 if others < ones
11
+ end
12
+
13
+ return 0
14
+ end
15
+
16
+ def < (other); Array.diff(self, other) < 0; end
17
+ def > (other); Array.diff(self, other) > 0; end
18
+ def <= (other); Array.diff(self, other) <= 0; end
19
+ def >= (other); Array.diff(self, other) >= 0; end
20
+ end
21
+
22
+ class Hash
23
+ def deep_merge(other_hash)
24
+ self.merge(other_hash) do |key, oldval, newval|
25
+ oldval = oldval.to_hash if oldval.respond_to?(:to_hash)
26
+ newval = newval.to_hash if newval.respond_to?(:to_hash)
27
+ oldval.class.to_s == 'Hash' && newval.class.to_s == 'Hash' ? oldval.deep_merge(newval) : newval
28
+ end
29
+ end
30
+ end
@@ -1,3 +1,5 @@
1
+ module Kibo::Helpers; end
2
+
1
3
  class Kibo::Helpers::Info < Array
2
4
  def self.print(out = STDOUT, &block)
3
5
  out.puts build(&block).to_s
@@ -12,9 +12,11 @@
12
12
  # The heroku gem is licensed under the terms of the MIT license,
13
13
  # see the file License.MIT.
14
14
  #
15
- # The heroku has been created by Adam Wiggins, and is currently maintained
15
+ # The heroku gem has been created by Adam Wiggins, and is currently maintained
16
16
  # by Wesley Beary.
17
- module Kibo::Helpers::Heroku
17
+ module Kibo::Heroku
18
+ extend self
19
+
18
20
  require "netrc"
19
21
 
20
22
  def whoami
@@ -72,4 +74,16 @@ module Kibo::Helpers::Heroku
72
74
  end
73
75
  end
74
76
  end
77
+
78
+ # --- helpers for kibo ----------------------------------------------
79
+
80
+ public
81
+
82
+ # returns names of all apps for the current user on heroku
83
+ def apps
84
+ @apps ||= Kibo::System.heroku("apps").
85
+ split(/\n/).
86
+ reject { |line| line.empty? || line =~ /=== / }.
87
+ map { |line| line.split(" ").first }
88
+ end
75
89
  end
data/lib/kibo/log.rb CHANGED
@@ -13,12 +13,14 @@ def D(*args)
13
13
  end
14
14
 
15
15
  def W(*args)
16
- UI.warn log_message(*args)
16
+ UI.warn log_message(*args).to_s
17
+ end
18
+
19
+ class FatalError < RuntimeError
17
20
  end
18
21
 
19
22
  def E(*args)
20
- UI.error log_message(*args)
21
- exit 1
23
+ raise FatalError, log_message(*args)
22
24
  end
23
25
 
24
26
  def B(*args, &block)
data/lib/kibo/system.rb CHANGED
@@ -10,9 +10,11 @@ module Kibo::System
10
10
  end
11
11
 
12
12
  def sys(*args)
13
- cmd = build_command(*args)
13
+ quiet = args.pop if args.last == :quiet
14
+
15
+ cmd = build_command(quiet, *args)
14
16
  result = Kernel.send "`", "bash -c \"#{cmd}\""
15
- if command_succeeded?(cmd)
17
+ if command_succeeded?(quiet, cmd)
16
18
  result.chomp
17
19
  end
18
20
  end
@@ -21,30 +23,19 @@ module Kibo::System
21
23
  sys(*args) || exit(1)
22
24
  end
23
25
 
24
- def sh(*args)
25
- cmd = build_command(*args)
26
- system(cmd)
27
- command_succeeded?(cmd)
28
- end
29
-
30
- def sh!(*args)
31
- sh(*args) || exit(1)
32
- end
33
-
34
26
  private
35
-
36
- def build_command(*args)
37
- quiet = args.pop if args.last == :quiet
27
+
28
+ def build_command(quiet, *args)
38
29
  args[0].sub!(/^kibo\b/, $0)
39
30
  cmd = args.map(&:to_s).join(" ")
40
31
  W cmd unless quiet
41
32
  cmd
42
33
  end
43
34
 
44
- def command_succeeded?(cmd)
35
+ def command_succeeded?(quiet, cmd)
45
36
  return true if $?.exitstatus == 0
46
37
 
47
- UI.error("Command failed: #{cmd}")
38
+ UI.error("Command failed: #{cmd}") unless quiet
48
39
  false
49
40
  end
50
41
  end
data/lib/kibo/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Kibo
2
- VERSION = "0.3.5"
2
+ VERSION = "0.4.0"
3
3
  end
data/lib/kibo.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  module Kibo
2
2
  end
3
3
 
4
+ require_relative "kibo/ext/ruby_ext.rb"
4
5
  require_relative "kibo/version"
5
6
  require_relative "kibo/log"
6
7
  require_relative "kibo/system"
@@ -12,22 +13,25 @@ module Kibo
12
13
  extend self
13
14
 
14
15
  def config
15
- @config ||= Config.new(kibofile)
16
+ @config ||= Config.new(CommandLine.config, CommandLine.environment)
16
17
  end
17
18
 
18
19
  def environment
19
- CommandLine.environment
20
+ Kibo.config.environment
21
+ end
22
+
23
+ def namespace
24
+ Kibo.config.heroku.namespace
20
25
  end
21
26
 
22
27
  def run
23
28
  Commands.send CommandLine.subcommand
29
+ rescue RuntimeError
30
+ UI.error $!.to_s
31
+ exit 1
24
32
  end
25
-
26
- def command_line
27
- CommandLine
28
- end
29
-
30
- def kibofile
31
- command_line.kibofile
33
+
34
+ def binary
35
+ File.join(File.dirname(__FILE__), "..", "bin", "kibo")
32
36
  end
33
37
  end
data/man/kibo.1 CHANGED
@@ -1,7 +1,7 @@
1
1
  .\" generated with Ronn/v0.7.3
2
2
  .\" http://github.com/rtomayko/ronn/tree/0.7.3
3
3
  .
4
- .TH "KIBO" "1" "September 2012" "Kibo 0.3.5" "Kibo Manual"
4
+ .TH "KIBO" "1" "October 2012" "Kibo 0.4.0" "Kibo Manual"
5
5
  .
6
6
  .SH "NAME"
7
7
  \fBkibo\fR \- manage heroku applications
data/man/kibo.1.html CHANGED
@@ -172,8 +172,8 @@ kibo -e production spindown
172
172
 
173
173
 
174
174
  <ol class='man-decor man-foot man foot'>
175
- <li class='tl'>Kibo 0.3.5</li>
176
- <li class='tc'>September 2012</li>
175
+ <li class='tl'>Kibo 0.4.0</li>
176
+ <li class='tc'>October 2012</li>
177
177
  <li class='tr'>kibo(1)</li>
178
178
  </ol>
179
179
 
data/test/Kibofile ADDED
@@ -0,0 +1,33 @@
1
+ # This is an example Kibofile. Use with kibo(1) to configure
2
+ # remote instances.
3
+ heroku:
4
+ # The email of the heroku account to create app instances on heroku.
5
+ account: kibo@kibo.local
6
+
7
+ # Namespace to use when generating names for git remotes and heroku app
8
+ # instances. With a "kibo" namespace our instances will be called
9
+ # 'kibo-staging-clerk1', 'kibo-production-twirl1', etc.
10
+ namespace: kibo
11
+
12
+ # How many instances to spin up?
13
+ defaults:
14
+ processes:
15
+ stats: 0
16
+ clerk: 1
17
+ twirl: 1
18
+
19
+ # Live mode will have 1 clerk and 3 twirls.
20
+ live:
21
+ heroku:
22
+ mode: pro
23
+ processes:
24
+ clerk: 1
25
+ twirl: 3
26
+
27
+ source:
28
+ pre:
29
+ - rake bountybase:release
30
+ success:
31
+ - git tag $ENVIRONMENT-$(date "+%Y.%m.%d-%H.%M")
32
+
33
+ #arena:
data/test/kibo_test.rb ADDED
@@ -0,0 +1,59 @@
1
+ require_relative 'test_helper'
2
+
3
+
4
+ module Kibo::CommandLine
5
+ extend self
6
+
7
+ def parse
8
+ raise "CommandLine::parse"
9
+ end
10
+ end
11
+
12
+ class KiboTest < Test::Unit::TestCase
13
+ def config(environment = "staging")
14
+ Kibo::Config.new(File.dirname(__FILE__) + "/Kibofile", environment)
15
+ end
16
+
17
+ def test_missing_config
18
+ assert_raise(FatalError) {
19
+ Kibo::Config.new(File.dirname(__FILE__) + "/Kibofile.missing", "environment")
20
+ }
21
+ end
22
+
23
+ def test_verify_version
24
+ assert(Kibo::VERSION =~ /^0\.4/)
25
+
26
+ assert_raise(FatalError) {
27
+ Kibo::Config.verify_version!("1.0")
28
+ }
29
+
30
+ assert_raise(FatalError) {
31
+ Kibo::Config.verify_version!("0.5")
32
+ }
33
+
34
+ assert_nothing_raised(FatalError) {
35
+ Kibo::Config.verify_version!(Kibo::VERSION)
36
+ Kibo::Config.verify_version!("0.1")
37
+ }
38
+ end
39
+
40
+ def test_config
41
+ config = self.config
42
+
43
+ assert_equal({"clerk"=>1, "twirl"=>1}, config.processes)
44
+
45
+ assert_equal config.namespace, "kibo"
46
+ assert config.freemium?
47
+ assert_equal ["kibo-staging-clerk1", "kibo-staging-twirl1"], config.instances
48
+ end
49
+
50
+ def test_live_config
51
+ config = self.config("live")
52
+
53
+ assert_equal({"clerk"=>1, "twirl"=>3}, config.processes)
54
+
55
+ assert_equal config.namespace, "kibo"
56
+ assert !config.freemium?
57
+ assert_equal ["kibo-live-clerk", "kibo-live-twirl"], config.instances
58
+ end
59
+ end
@@ -0,0 +1,25 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ ENV["RACK_ENV"] ||= "test"
5
+
6
+ require 'ruby-debug'
7
+ require 'simplecov'
8
+ require 'test/unit'
9
+ require 'test/unit/ui/console/testrunner'
10
+
11
+ class Test::Unit::UI::Console::TestRunner
12
+ def guess_color_availability; true; end
13
+ end
14
+
15
+ require 'mocha'
16
+ require 'awesome_print'
17
+
18
+ SimpleCov.start do
19
+ add_filter "test/*.rb"
20
+ end
21
+
22
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
23
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
24
+ require 'kibo'
25
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kibo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.5
4
+ version: 0.4.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-10-05 00:00:00.000000000 Z
12
+ date: 2012-10-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: trollop
@@ -75,6 +75,54 @@ dependencies:
75
75
  - - ! '>='
76
76
  - !ruby/object:Gem::Version
77
77
  version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: mash
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :runtime
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: foreman
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :runtime
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ - !ruby/object:Gem::Dependency
111
+ name: heroku
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
78
126
  description: Manage heroku instances with ease
79
127
  email:
80
128
  - eno@radiospiel.org
@@ -88,6 +136,7 @@ files:
88
136
  - Gemfile.lock
89
137
  - README.md
90
138
  - Rakefile
139
+ - YUILICENSE.md
91
140
  - bin/kibo
92
141
  - kibo.gemspec
93
142
  - lib/kibo.rb
@@ -95,16 +144,17 @@ files:
95
144
  - lib/kibo/commandline.rb
96
145
  - lib/kibo/commands.rb
97
146
  - lib/kibo/commands/compress.rb
98
- - lib/kibo/commands/create.rb
99
147
  - lib/kibo/commands/deploy.rb
100
148
  - lib/kibo/commands/generate.rb
149
+ - lib/kibo/commands/helpers.rb
101
150
  - lib/kibo/commands/info.rb
102
- - lib/kibo/commands/reconfigure.rb
151
+ - lib/kibo/commands/logs.rb
152
+ - lib/kibo/commands/setup.rb
103
153
  - lib/kibo/commands/spin.rb
104
154
  - lib/kibo/config.rb
105
- - lib/kibo/helpers.rb
106
- - lib/kibo/helpers/heroku.rb
155
+ - lib/kibo/ext/ruby_ext.rb
107
156
  - lib/kibo/helpers/info.rb
157
+ - lib/kibo/heroku.rb
108
158
  - lib/kibo/log.rb
109
159
  - lib/kibo/system.rb
110
160
  - lib/kibo/version.rb
@@ -113,6 +163,9 @@ files:
113
163
  - man/kibo.1.markdown
114
164
  - man/kibo.1.ronn
115
165
  - tasks/doc.rake
166
+ - test/Kibofile
167
+ - test/kibo_test.rb
168
+ - test/test_helper.rb
116
169
  homepage: http://github.com/radiospiel/kibo
117
170
  licenses: []
118
171
  post_install_message:
@@ -127,7 +180,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
127
180
  version: '0'
128
181
  segments:
129
182
  - 0
130
- hash: 173262939670169996
183
+ hash: -3844677239198829294
131
184
  required_rubygems_version: !ruby/object:Gem::Requirement
132
185
  none: false
133
186
  requirements:
@@ -140,4 +193,7 @@ rubygems_version: 1.8.24
140
193
  signing_key:
141
194
  specification_version: 3
142
195
  summary: Manage heroku instances with ease
143
- test_files: []
196
+ test_files:
197
+ - test/Kibofile
198
+ - test/kibo_test.rb
199
+ - test/test_helper.rb