buildmeister 0.8.6 → 1.0.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/Rakefile CHANGED
@@ -4,14 +4,20 @@ require 'rubygems'
4
4
  require 'hoe'
5
5
  require './lib/buildmeister.rb'
6
6
 
7
- Hoe.new('buildmeister', Buildmeister::VERSION) do |p|
8
- p.rubyforge_name = 'buildmeister' # if different than lowercase project name
9
- p.developer('Leigh Caplan', 'lcaplan@onehub.com')
10
- end
11
-
12
- task :cultivate do
13
- system "touch Manifest.txt; rake check_manifest | grep -v \"(in \" | patch"
14
- system "rake debug_gem | grep -v \"(in \" > `basename \\`pwd\\``.gemspec"
7
+ begin
8
+ require 'jeweler'
9
+ Jeweler::Tasks.new do |s|
10
+ s.name = "buildmeister"
11
+ s.executables = ["buildmeister", "git_cleanup"]
12
+ s.summary = "Dead simple tools for managing Lighthouse and Git deployment workflow"
13
+ s.email = "lcaplan@onehub.com"
14
+ s.homepage = "http://github.com/onehub/buildmeister"
15
+ s.description = "Dead simple tools for managing Lighthouse and Git deployment workflow"
16
+ s.authors = ["Leigh Caplan"]
17
+ s.files = FileList["[A-Z]*", "{bin,generators,lib,spec}/**/*"]
18
+ end
19
+ rescue LoadError
20
+ puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
15
21
  end
16
22
 
17
23
  # vim: syntax=Ruby
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0
data/bin/buildmeister CHANGED
@@ -3,12 +3,16 @@
3
3
  require File.expand_path(File.dirname(__FILE__) + "/../lib/buildmeister")
4
4
 
5
5
  begin
6
- Buildmeister.new.send ARGV.shift
6
+ command = ARGV.shift
7
+ args = ARGV.dup
8
+ ARGV.clear
9
+
10
+ Buildmeister::Base.new(*args).send command
7
11
  rescue Interrupt => i
8
- Buildmeister.post_notification("Buildmeister Shut Down", "Goodbye!")
12
+ Buildmeister::Notifier.post("Buildmeister Shut Down", "Goodbye!")
9
13
  puts "\rThank you for using Buildmeister!"
10
14
  rescue Exception => e
11
- Buildmeister.post_notification("Buildmeister Error: #{e.class}", e.message)
15
+ Buildmeister::Notifier.post("Buildmeister Error: #{e.class}", e.message)
12
16
  puts "Quitting Buildmeister due to error: #{e.message}"
13
17
  puts e.backtrace
14
18
  end
data/lib/buildmeister.rb CHANGED
@@ -1,303 +1,13 @@
1
1
  require 'rubygems'
2
2
  require 'lighthouse'
3
3
  require 'activesupport'
4
- require 'optparse'
5
4
 
6
- class Buildmeister
7
- attr_accessor :project, :project_name, :bin_groups, :notification_interval
8
-
9
- RETRY_COUNT = 5
10
-
11
- def initialize
12
- @options = {}
13
- OptionParser.new do |opts|
14
- opts.banner = "Usage: buildmeister notify"
5
+ $: << File.dirname(__FILE__)
15
6
 
16
- opts.on('-f', '--from-bin BIN_NAME', 'Move From Bin') do |f|
17
- @options[:move_from] = f
18
- end
19
-
20
- opts.on('-t', '--to-state STATE', 'Move to State') do |t|
21
- @options[:to_state] = t
22
- end
23
-
24
- opts.on('-v', '--verbose', 'Verbose') do |t|
25
- @options[:verbose] = true
26
- end
27
- end.parse!
28
-
29
- @config = Buildmeister.load_config
30
- Lighthouse.account = @config['account']
31
- Lighthouse.token = @config['token']
32
-
33
- self.project_name = @config['project_name']
34
- self.get_project
35
- self.bin_groups = []
36
-
37
- self.notification_interval = @config['notification_interval']
38
-
39
- @config['bin_groups'].each do |bin_group|
40
- self.bin_groups << {
41
- :name => bin_group.keys.first,
42
- :bin_names => bin_group.values.first.map
43
- }
44
- end
45
-
46
- self.bin_groups.each do |bin_group|
47
- bin_group[:bin_names].each do |bin_name|
48
- class << bin_name
49
- def normalize
50
- Buildmeister.normalize_bin_name(self)
51
- end
52
- end
53
-
54
- attr_accessor_init = <<-eos
55
- class << self
56
- attr_accessor :"#{bin_name.normalize}", :"last_#{bin_name.normalize}"
57
- end
58
- eos
59
-
60
- eval attr_accessor_init
61
- end
62
- end
63
-
64
- load_project
65
- end
66
-
67
- def normalize(bin_name)
68
- Buildmeister.normalize_bin_name(bin_name)
69
- end
70
-
71
- def new_hotfix
72
- generate_timed_branch('hotfix')
73
- end
74
-
75
- def new_experimental
76
- generate_timed_branch('experimental')
77
- end
78
-
79
- def generate_timed_branch(prefix)
80
- branches = local_branches
81
- now = Time.now
82
- count = 1
83
-
84
- loop do
85
- new_branch_name = "#{prefix}-#{now.year}-#{now.month.to_s.rjust 2, '0'}-#{now.day.to_s.rjust 2, '0'}-#{count.to_s.rjust 3, '0'}"
86
- unless branches.include? new_branch_name
87
- `git checkout -b #{new_branch_name}`
88
- puts "Created #{new_branch_name}"
89
- return true
90
- end
91
-
92
- count += 1
93
- end
94
- end
95
-
96
- def pull_bin(bin_name = ARGV.shift)
97
- bin_name = normalize(bin_name)
98
- existing_bin_names = bin_names.map { |b| b.normalize }
99
-
100
- raise ArgumentError, "#{bin_name} is not a valid bin! Must be in #{bin_names.join(', ')}" unless existing_bin_names.include?(bin_name)
101
-
102
- `git fetch origin`
103
-
104
- branches = remote_branches
105
- ticket_numbers = send(normalize(bin_name)).tickets.map { |tkt| tkt.id.to_s }
106
-
107
- branches_to_pull = branches.select do |branch_name|
108
- ticket_numbers.map { |tkt_number| branch_name =~ /#{tkt_number}/ }.any?
109
- end
110
-
111
- branches_to_pull.each do |branch|
112
- result = `git pull origin #{branch.gsub("origin/", "")}`
113
- puts result
114
- end
115
- end
116
-
117
- def local_branches
118
- `git branch`.split.reject { |name| name == "*" }
119
- end
120
-
121
- def remote_branches
122
- `git branch -r`.split.reject { |name| name == "*" }
123
- end
124
-
125
- def current_branch
126
- branches = `git branch`.split
127
- i = branches.index "*"
128
- branches[i + 1]
129
- end
130
-
131
- def move_all
132
- bin_name = normalize @options[:move_from]
133
- self.send(bin_name).tickets.each do |ticket|
134
- ticket.state = @options[:to_state]
135
- ticket.save
136
- end
137
-
138
- puts "All tickets from bin #{@options[:move_from]} have been moved to #{@options[:to_state]}"
139
- end
140
-
141
- def bin_group_report(bin_group_name = normalize(ARGV.shift))
142
- bin_group = bin_groups.find { |group| group[:name] == bin_group_name }
143
- bin_names = bin_group[:bin_names].map &:normalize
144
-
145
- ticket_numbers = bin_names.map do |bin_name|
146
- send(normalize(bin_name)).tickets.map &:id
147
- end.flatten
148
-
149
- # Pluck the relevant branch names using git...
150
- relevant_branches =
151
- remote_branches.select do |branch_name|
152
- ticket_numbers.map { |tkt_number| branch_name =~ /#{tkt_number}/ }.any?
153
- end.map { |b| b.gsub('origin/', '') }
154
-
155
- output = ""
156
- output << "#{current_branch}\n"
157
- relevant_branches.each do |branch|
158
- output << "\n#{branch}"
159
- end
160
-
161
- puts output
162
- end
163
-
164
- def resolve_verified
165
- self.verified.tickets.each do |ticket|
166
- ticket.state = 'resolved'
167
- ticket.save
168
- end
169
- end
170
-
171
- def stage_all
172
- self.ready.tickets.each do |ticket|
173
- ticket.state = 'staged'
174
- ticket.save
175
- end
176
- end
177
-
178
- def load_project
179
- bins = self.get_project.bins
180
-
181
- self.bin_groups.each do |bin_group|
182
- bin_group[:bin_names].each do |bin_name|
183
- self.send("#{bin_name.normalize}=", bins.find { |bin| bin.name == bin_name })
184
-
185
- class << self.send("#{bin_name.normalize}")
186
- attr_accessor :display_value
187
- end
188
- end
189
- end
190
- end
191
-
192
- def reload_info
193
- bin_names.each do |bin_name|
194
- send("last_#{bin_name.normalize}=", display_value(bin_name))
195
- end
196
-
197
- self.load_project
198
- end
199
-
200
- def bin_names
201
- bin_groups.map do |bin_group|
202
- bin_group[:bin_names].map do |bin_name|
203
- bin_name
204
- end
205
- end.flatten
206
- end
207
-
208
- def changed?
209
- bin_names.map { |bin_name| display_value(bin_name) } != bin_names.map { |bin_name| send("last_#{bin_name.normalize}") }
210
- end
211
-
212
- def get_project
213
- self.project ||= Lighthouse::Project.find(:all).find {|pr| pr.name == project_name}
214
- end
215
-
216
- def notify
217
- puts "Starting BuildMeister Notify..."
218
-
219
- retry_count = RETRY_COUNT
220
-
221
- loop do
222
- begin
223
- title = "BuildMeister: #{Time.now.strftime("%m/%d %I:%M %p")}"
224
-
225
- body = ''
226
-
227
- bin_groups.each do |bin_group|
228
- body += "#{bin_group[:name].titleize}\n"
229
- body += "---------\n"
230
-
231
- bin_group[:bin_names].each do |bin_name|
232
- body += "#{bin_name}: #{display_value(bin_name)}\n"
233
- end
234
-
235
- body += "\n"
236
- end
237
-
238
- puts "Updated notification at #{Time.now.strftime("%m/%d %I:%M %p")}"
239
-
240
- if changed?
241
- Buildmeister.post_notification(title, body)
242
- end
243
-
244
- sleep notification_interval.minutes.to_i
245
-
246
- reload_info
247
-
248
- # Reset the retry count, since we successfully completed this iteration
249
- retry_count = RETRY_COUNT
250
-
251
- rescue StandardError => e
252
- if retry_count < 1
253
- puts "Retried #{RETRY_COUNT} times... I give up!"
254
- raise e
255
- else
256
- # Exponential falloff...
257
- sleep_time = (50.0 * (1 / (retry_count / 2.0))).to_i
258
-
259
- puts "Caught error: #{e.class.name}: #{e.message}"
260
- puts "#{retry_count} more tries... sleeping #{sleep_time} seconds..."
261
-
262
- sleep sleep_time
263
-
264
- retry_count -= 1
265
-
266
- retry
267
- end
268
- end
269
- end
270
- end
271
-
272
- def display_value(bin_name)
273
- # We're memoizing the display value on the bin objects
274
- # so that when it comes time to reload, the previous value
275
- # is kept.
276
- send(bin_name.normalize).display_value ||=
277
- if @options[:verbose]
278
- send(bin_name.normalize).tickets.map(&:id).join(", ")
279
- else
280
- send(bin_name.normalize).tickets_count
281
- end
282
- end
283
-
284
- def git_cleanup
285
-
286
- end
287
-
288
- # -----------------------------------------
289
- # Class Methods
290
- # -----------------------------------------
291
-
292
- def self.post_notification(title, body)
293
- `growlnotify -H localhost -s -n "Buildmeister" -d "Buildmeister" -t #{title} -m "#{body}"`
294
- end
295
-
296
- def self.normalize_bin_name(bin_name)
297
- bin_name.squeeze(' ').gsub(' ', '_').gsub(/\W/, '').downcase
298
- end
299
-
300
- def self.load_config
301
- YAML.load_file(File.expand_path('~/.buildmeister_config.yml'))
302
- end
303
- end
7
+ require 'buildmeister/string_utils'
8
+ require 'buildmeister/git_utils'
9
+ require 'buildmeister/finder'
10
+ require 'buildmeister/base'
11
+ require 'buildmeister/notifier'
12
+ require 'buildmeister/project'
13
+ require 'buildmeister/bin'
@@ -0,0 +1,146 @@
1
+ require 'optparse'
2
+
3
+ module Buildmeister
4
+ class Base
5
+ include StringUtils
6
+ include GitUtils
7
+
8
+ RETRY_COUNT = 5
9
+
10
+ attr_accessor :projects, :notification_interval
11
+
12
+ def initialize(*args)
13
+ @options = {:mode => :verbose}
14
+
15
+ OptionParser.new do |opts|
16
+ opts.banner = "Usage: buildmeister notify"
17
+
18
+ opts.on('-q', '--quiet', 'Quiet') do
19
+ @options[:mode] = :quiet
20
+ end
21
+
22
+ opts.on('-f', '--from-bin BIN_NAME', 'Move From Bin') do |f|
23
+ @options[:move_from] = f
24
+ end
25
+
26
+ opts.on('-t', '--to-state STATE', 'Move to State') do |t|
27
+ @options[:to_state] = t
28
+ end
29
+
30
+ opts.on('-p', '--project PROJECT', 'Use Project') do |p|
31
+ @options[:project] = p
32
+ end
33
+ end.parse!(args)
34
+
35
+ # Lighthouse setup
36
+ @config = Buildmeister::Base.load_config
37
+
38
+ Lighthouse.account = @config['account']
39
+ Lighthouse.token = @config['token']
40
+
41
+ self.projects = []
42
+
43
+ projects.extend Finder
44
+
45
+ if @options[:project]
46
+ @config['projects'] = @config['projects'].select { |p| p['name'] == @options[:project] }
47
+ raise "#{@options[:project]} did not match any projects in the config file" if @config['projects'].blank?
48
+ end
49
+
50
+ @config['projects'].each do |project|
51
+ self.projects << Buildmeister::Project.new(project, @options)
52
+ end
53
+
54
+ self.notification_interval = @config['notification_interval']
55
+ end
56
+
57
+ def changed?
58
+ projects.any? &:changed?
59
+ end
60
+
61
+ def title
62
+ "Buildmeister: #{Time.now.strftime("%m/%d %I:%M %p")}"
63
+ end
64
+
65
+ def notify
66
+ puts "Starting Buildmeister Notify..."
67
+
68
+ retry_count = RETRY_COUNT
69
+
70
+ loop do
71
+ begin
72
+ body = ''
73
+
74
+ body << projects.map do |project|
75
+ "#{project.display}\n"
76
+ end.join("\n")
77
+
78
+ puts "Updated notification at #{Time.now.strftime("%m/%d %I:%M %p")}"
79
+
80
+ if changed?
81
+ Buildmeister::Notifier.post(title, body)
82
+ end
83
+
84
+ sleep notification_interval.minutes.to_i
85
+
86
+ refresh!
87
+
88
+ # Reset the retry count, since we successfully completed this iteration
89
+ retry_count = RETRY_COUNT
90
+
91
+ rescue StandardError => e
92
+ if retry_count < 1
93
+ puts "Retried #{RETRY_COUNT} times... I give up!"
94
+ raise e
95
+ else
96
+ # Exponential falloff...
97
+ sleep_time = (50.0 * (1 / (retry_count / 2.0))).to_i
98
+
99
+ puts "Caught error: #{e.class.name}: #{e.message}"
100
+ puts "#{retry_count} more tries... sleeping #{sleep_time} seconds..."
101
+
102
+ sleep sleep_time
103
+
104
+ retry_count -= 1
105
+
106
+ retry
107
+ end
108
+ end
109
+ end
110
+ end
111
+
112
+ def move_all
113
+ bin_name = @options[:move_from]
114
+
115
+ if projects.size > 1
116
+ puts "Two projects are loaded (#{projects.map(&:name).join(', ')})"
117
+ puts "Do you really want to move tickets in all projects? [y/n]"
118
+
119
+ choice = gets
120
+
121
+ if choice.downcase.strip == 'n'
122
+ puts "aborting..."
123
+ return
124
+ end
125
+ end
126
+
127
+ projects.each do |project|
128
+ project.bins.named(bin_name).tickets.each do |ticket|
129
+ puts "processing #{project.name}: #{ticket.id}"
130
+ ticket.state = @options[:to_state]
131
+ ticket.save
132
+ end
133
+ end
134
+
135
+ puts "All tickets from bin #{@options[:move_from]} have been moved to #{@options[:to_state]}"
136
+ end
137
+
138
+ def refresh!
139
+ projects.each &:refresh!
140
+ end
141
+
142
+ def self.load_config
143
+ YAML.load_file(File.expand_path('~/.buildmeister_config.yml'))
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,35 @@
1
+ # Wraps Lighthouse::Bin and keeps track of state
2
+
3
+ module Buildmeister
4
+ class Bin
5
+ attr_accessor :bin, :mode, :value, :last_value
6
+
7
+ delegate :name, :tickets, :to => :bin
8
+
9
+ def initialize(lighthouse_bin, mode = :verbose)
10
+ self.bin = lighthouse_bin
11
+ self.mode = mode
12
+
13
+ refresh!
14
+ end
15
+
16
+ def refresh!
17
+ self.last_value = value
18
+
19
+ case mode
20
+ when :verbose
21
+ self.value = bin.tickets.map(&:id).join(', ')
22
+ when :quiet
23
+ self.value = bin.tickets_count
24
+ end
25
+ end
26
+
27
+ def display
28
+ "#{name}: #{value}"
29
+ end
30
+
31
+ def changed?
32
+ value != last_value
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,7 @@
1
+ module Buildmeister
2
+ module Finder
3
+ def named(name)
4
+ find { |e| e.name == name}
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,65 @@
1
+ module Buildmeister
2
+ module GitUtils
3
+ def new_hotfix
4
+ generate_timed_branch('hotfix')
5
+ end
6
+
7
+ def new_experimental
8
+ generate_timed_branch('experimental')
9
+ end
10
+
11
+ def generate_timed_branch(prefix)
12
+ branches = local_branches
13
+ now = Time.now
14
+ count = 1
15
+
16
+ loop do
17
+ new_branch_name = "#{prefix}-#{now.year}-#{now.month.to_s.rjust 2, '0'}-#{now.day.to_s.rjust 2, '0'}-#{count.to_s.rjust 3, '0'}"
18
+ unless branches.include? new_branch_name
19
+ `git checkout -b #{new_branch_name}`
20
+ puts "Created #{new_branch_name}"
21
+ return true
22
+ end
23
+
24
+ count += 1
25
+ end
26
+ end
27
+
28
+ def pull_bin(bin_name = ARGV.shift)
29
+ raise "Multiple projects are loaded. Please use the -p flag to select one project." if projects.size > 1
30
+
31
+ project = projects.first
32
+ bin = project.bins.named(bin_name)
33
+
34
+ raise ArgumentError, "#{bin_name} is not a valid bin! Must be in #{project.bins.map(&:name).join(', ')}" unless bin
35
+
36
+ `git fetch origin`
37
+
38
+ branches = remote_branches
39
+ ticket_numbers = bin.tickets.map { |tkt| tkt.id.to_s }
40
+
41
+ branches_to_pull = branches.select do |branch_name|
42
+ ticket_numbers.map { |tkt_number| branch_name =~ /#{tkt_number}/ }.any?
43
+ end
44
+
45
+ branches_to_pull.each do |branch|
46
+ result = `git pull origin #{branch.gsub("origin/", "")}`
47
+ puts result
48
+ end
49
+ end
50
+
51
+ def local_branches
52
+ `git branch`.split.reject { |name| name == "*" }
53
+ end
54
+
55
+ def remote_branches
56
+ `git branch -r`.split.reject { |name| name == "*" }
57
+ end
58
+
59
+ def current_branch
60
+ branches = `git branch`.split
61
+ i = branches.index "*"
62
+ branches[i + 1]
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,7 @@
1
+ module Buildmeister
2
+ class Notifier
3
+ def self.post(title, body)
4
+ `growlnotify -H localhost -s -n "Buildmeister" -d "Buildmeister" -t #{title} -m "#{body}"`
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,45 @@
1
+ module Buildmeister
2
+ class Project
3
+ include StringUtils
4
+
5
+ attr_accessor :project, :name, :bins
6
+
7
+ def initialize(config, options = {})
8
+ self.name = config['name']
9
+ self.bins = []
10
+
11
+ bins.extend Finder
12
+
13
+ self.project = Lighthouse::Project.find(:all).find { |p| p.name == self.name }
14
+
15
+ project_bins = project.bins
16
+
17
+ config['bins'].each do |bin_name|
18
+ bin = project_bins.find { |b| b.name == bin_name }
19
+ raise "No bin named #{bin_name}" unless bin
20
+
21
+ bins << Buildmeister::Bin.new(bin, options[:mode])
22
+ end
23
+ end
24
+
25
+ def display
26
+ out = ''
27
+ out << name + "\n"
28
+ out << "#{divider}\n"
29
+
30
+ bins.each do |bin|
31
+ out << bin.display + "\n"
32
+ end
33
+
34
+ out
35
+ end
36
+
37
+ def refresh!
38
+ bins.each &:refresh!
39
+ end
40
+
41
+ def changed?
42
+ bins.any? &:changed?
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,7 @@
1
+ module Buildmeister
2
+ module StringUtils
3
+ def divider(char = '-', size = 10)
4
+ char * size
5
+ end
6
+ end
7
+ end
data/lib/git_cleanup.rb CHANGED
@@ -7,7 +7,7 @@ require File.expand_path(File.dirname(__FILE__) + "/../lib/buildmeister")
7
7
  class GitCleanup
8
8
 
9
9
  def initialize
10
- @config = Buildmeister.load_config
10
+ @config = Buildmeister::Base.load_config
11
11
  Lighthouse.token = @config['token']
12
12
  Lighthouse.account = @config['account']
13
13
 
@@ -0,0 +1,119 @@
1
+ require 'spec_helper'
2
+
3
+ describe Buildmeister::Base do
4
+ before(:each) do
5
+ Buildmeister::Base.stubs(:load_config).returns(load_test_config)
6
+ @project_stub = stub(:name => 'Project', :bins => [stub(), stub()])
7
+ Buildmeister::Project.stubs(:new).returns(@project_stub)
8
+ end
9
+
10
+ describe '#new' do
11
+ it "should create a new instance" do
12
+ b = Buildmeister::Base.new
13
+ b.should be_an_instance_of(Buildmeister::Base)
14
+ end
15
+
16
+ it "should set quiet mode if passed -q" do
17
+ b = Buildmeister::Base.new('-q')
18
+ b.instance_variable_get(:@options)[:mode].should == :quiet
19
+ end
20
+
21
+ it "should set move_from if passed -f" do
22
+ b = Buildmeister::Base.new('-f', 'Cool Bin')
23
+ b.instance_variable_get(:@options)[:move_from].should == 'Cool Bin'
24
+ end
25
+
26
+ it "should set to_state if passed -t" do
27
+ b = Buildmeister::Base.new('-t', 'staged')
28
+ b.instance_variable_get(:@options)[:to_state].should == 'staged'
29
+ end
30
+
31
+ context "passed the -p flag" do
32
+ before(:each) do
33
+ @b = Buildmeister::Base.new('-p', 'Macchiato')
34
+ end
35
+
36
+ it "should set the project" do
37
+ @b.instance_variable_get(:@options)[:project].should == 'Macchiato'
38
+ end
39
+
40
+ it "should only load the specified project" do
41
+ @b.projects.size.should == 1
42
+ end
43
+ end
44
+
45
+
46
+ it "should set the Lighthouse account from config" do
47
+ config = load_test_config
48
+ b = Buildmeister::Base.new
49
+ Lighthouse.account.should == config['account']
50
+ end
51
+
52
+ it "should set the Lighthouse token from config" do
53
+ config = load_test_config
54
+ b = Buildmeister::Base.new
55
+ Lighthouse.token.should == config['token']
56
+ end
57
+
58
+ it "should set up the projects" do
59
+ b = Buildmeister::Base.new
60
+ b.projects.should == [@project_stub, @project_stub]
61
+ end
62
+
63
+ it "should set the notification interval" do
64
+ b = Buildmeister::Base.new
65
+ b.notification_interval.should == 3
66
+ end
67
+ end
68
+
69
+ describe "#changed?" do
70
+ context "with changed bins" do
71
+ before(:each) do
72
+ @project_stub = stub(:changed? => true)
73
+ Buildmeister::Project.stubs(:new).returns(@project_stub)
74
+ end
75
+
76
+ it "should be true" do
77
+ b = Buildmeister::Base.new
78
+ b.changed?.should be_true
79
+ end
80
+ end
81
+ end
82
+
83
+ describe "#projects" do
84
+ before(:each) do
85
+ @project_stub = stub(:name => 'Project', :bins => [stub(), stub()])
86
+ Buildmeister::Project.stubs(:new).returns(@project_stub)
87
+ end
88
+
89
+ it "should search using named" do
90
+ b = Buildmeister::Base.new
91
+ b.projects.named('Project').should == @project_stub
92
+ end
93
+ end
94
+
95
+ describe "title" do
96
+ it "should look like this" do
97
+ Timecop.freeze(Time.parse('1/1/2010 9am')) do
98
+ b = Buildmeister::Base.new
99
+ b.title.should == 'Buildmeister: 01/01 09:00 AM'
100
+ end
101
+ end
102
+ end
103
+
104
+ describe "#divider" do
105
+ before(:each) do
106
+ @b = Buildmeister::Base.new
107
+ end
108
+
109
+ it "looks like this by default" do
110
+ @b.divider.should == "----------"
111
+ end
112
+
113
+ it "accepts character and size arguments" do
114
+ @b.divider("=", 5).should == '====='
115
+ end
116
+ end
117
+
118
+
119
+ end
@@ -0,0 +1,105 @@
1
+ require 'spec_helper'
2
+
3
+ describe Buildmeister::Bin do
4
+ def ticket_stubs
5
+ [stub('ticket_1', :id => 1), stub('ticket_2', :id => 2)]
6
+ end
7
+
8
+ before(:each) do
9
+ Lighthouse::Bin.any_instance.stubs(:tickets).returns(ticket_stubs)
10
+ end
11
+
12
+ describe "#new" do
13
+ it "should create a new instance" do
14
+ b = Buildmeister::Bin.new(Lighthouse::Bin.new)
15
+ end
16
+
17
+ it "should default to verbose mode" do
18
+ b = Buildmeister::Bin.new(Lighthouse::Bin.new)
19
+ b.mode.should == :verbose
20
+ end
21
+
22
+ it "should refresh" do
23
+ Buildmeister::Bin.any_instance.expects(:refresh!).once
24
+ b = Buildmeister::Bin.new(Lighthouse::Bin.new)
25
+ end
26
+ end
27
+
28
+ describe "#refresh!" do
29
+ before(:each) do
30
+ @b = Buildmeister::Bin.new(Lighthouse::Bin.new)
31
+ end
32
+
33
+ context "in verbose mode" do
34
+ it "should call tickets" do
35
+ @b.bin.expects(:tickets).once.returns(ticket_stubs)
36
+ @b.refresh!
37
+ end
38
+
39
+ it "should set value" do
40
+ @b.refresh!
41
+ @b.value.should == '1, 2'
42
+ end
43
+
44
+ context "after the first refresh" do
45
+ before(:each) do
46
+ @b.value = '1, 2'
47
+ end
48
+
49
+ it "should set the last value" do
50
+ @b.refresh!
51
+ @b.last_value.should == '1, 2'
52
+ end
53
+ end
54
+ end
55
+
56
+ context "in quiet mode" do
57
+ before(:each) do
58
+ @b.mode = :quiet
59
+ end
60
+
61
+ it "should call tickets_count" do
62
+ @b.bin.expects(:tickets_count).once.returns(2)
63
+ @b.refresh!
64
+ end
65
+ end
66
+ end
67
+
68
+ describe "#changed?" do
69
+ before(:each) do
70
+ @b = Buildmeister::Bin.new(Lighthouse::Bin.new)
71
+ end
72
+
73
+ context "with identical values" do
74
+ before(:each) do
75
+ @b.value = '1, 2'
76
+ @b.last_value = '1, 2'
77
+ end
78
+
79
+ it "should be false" do
80
+ @b.changed?.should be_false
81
+ end
82
+ end
83
+
84
+ context "with differing values" do
85
+ before(:each) do
86
+ @b.value = '1'
87
+ @b.last_value = '1, 2'
88
+ end
89
+
90
+ it "should be true" do
91
+ @b.changed?.should be_true
92
+ end
93
+ end
94
+ end
95
+
96
+ describe "#display" do
97
+ before(:each) do
98
+ @b = Buildmeister::Bin.new(stub(:name => 'The Bin', :tickets => ticket_stubs))
99
+ end
100
+
101
+ it "displays the ticket" do
102
+ @b.display.should == 'The Bin: 1, 2'
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,84 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Buildmeister::Project' do
4
+ def valid_config
5
+ @valid_config ||= load_test_config['projects'].first
6
+ end
7
+
8
+ def project_stub
9
+ stub(:name => valid_config['name'], :bins => valid_config['bins'].map { |b| stub({:name => b}) })
10
+ end
11
+
12
+ before(:each) do
13
+ Lighthouse::Project.stubs(:find).returns([project_stub])
14
+ @p = Buildmeister::Project.new(valid_config)
15
+ end
16
+
17
+ describe "#new" do
18
+ it "should create new given a valid config" do
19
+ @p.should be_an_instance_of(Buildmeister::Project)
20
+ end
21
+
22
+ it "should set the name" do
23
+ @p.name.should == valid_config['name']
24
+ end
25
+
26
+ it "should set the project" do
27
+ @p.project
28
+ end
29
+
30
+ it "should set up the appropriate number of bins" do
31
+ @p.should have(valid_config['bins'].size).bins
32
+ end
33
+
34
+ it "should set up Buildmeister::Bin objects" do
35
+ @p.bins.all? { |b| b.is_a?(Buildmeister::Bin) }.should be_true
36
+ end
37
+
38
+ it "should keep bins in order" do
39
+ @p.bins.map(&:name).should == ['Ready', 'Staged', 'Verified', 'Ready (Experimental)', 'Staged (Experimental)']
40
+ end
41
+ end
42
+
43
+ describe "#changed?" do
44
+ context "with changed bins" do
45
+ before(:each) do
46
+ @p.bins.each { |b| b.stubs(:changed?).returns(true) }
47
+ end
48
+
49
+ it "should be true" do
50
+ @p.changed?.should be_true
51
+ end
52
+ end
53
+
54
+ context "with no changed bins" do
55
+ before(:each) do
56
+ @p.bins.each { |b| b.stubs(:changed?).returns(false) }
57
+ end
58
+
59
+ it "should be false" do
60
+ @p.changed?.should be_false
61
+ end
62
+ end
63
+ end
64
+
65
+ describe "#bins" do
66
+ it "should search using named" do
67
+ @p.bins.named('Ready').should be_an_instance_of(Buildmeister::Bin)
68
+ end
69
+ end
70
+
71
+ describe "#display" do
72
+ it "should display the bins" do
73
+ @p.display.should == <<-STRING_CHEESE
74
+ Macchiato
75
+ ----------
76
+ Ready:
77
+ Staged:
78
+ Verified:
79
+ Ready (Experimental):
80
+ Staged (Experimental):
81
+ STRING_CHEESE
82
+ end
83
+ end
84
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1,4 @@
1
+ --colour
2
+ --format progress
3
+ --loadby mtime
4
+ --reverse
@@ -0,0 +1,14 @@
1
+ require 'spec/autorun'
2
+ require 'buildmeister'
3
+ require 'fakeweb'
4
+ require 'timecop'
5
+
6
+ FakeWeb.allow_net_connect = false
7
+
8
+ Spec::Runner.configure do |config|
9
+ config.mock_with :mocha
10
+ end
11
+
12
+ def load_test_config
13
+ @test_config ||= YAML.load_file(File.dirname(__FILE__) + '/../config/buildmeister_config.sample.yml')
14
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: buildmeister
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.6
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Leigh Caplan
@@ -9,70 +9,47 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-03-11 00:00:00 -07:00
13
- default_executable: buildmeister
14
- dependencies:
15
- - !ruby/object:Gem::Dependency
16
- name: activesupport
17
- type: :runtime
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
20
- requirements:
21
- - - ">="
22
- - !ruby/object:Gem::Version
23
- version: 2.0.0
24
- version:
25
- - !ruby/object:Gem::Dependency
26
- name: texel-lighthouse-api
27
- type: :runtime
28
- version_requirement:
29
- version_requirements: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: 1.0.1
34
- version:
35
- - !ruby/object:Gem::Dependency
36
- name: hoe
37
- type: :development
38
- version_requirement:
39
- version_requirements: !ruby/object:Gem::Requirement
40
- requirements:
41
- - - ">="
42
- - !ruby/object:Gem::Version
43
- version: 1.8.3
44
- version:
45
- description: FIX (describe your package)
46
- email:
47
- - lcaplan@onehub.com
12
+ date: 2009-12-10 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: Dead simple tools for managing Lighthouse and Git deployment workflow
17
+ email: lcaplan@onehub.com
48
18
  executables:
49
19
  - buildmeister
50
20
  - git_cleanup
51
21
  extensions: []
52
22
 
53
23
  extra_rdoc_files:
54
- - History.txt
55
- - Manifest.txt
56
24
  - README.rdoc
57
25
  files:
58
26
  - History.txt
59
- - Manifest.txt
60
27
  - README.rdoc
61
28
  - Rakefile
29
+ - VERSION
62
30
  - bin/buildmeister
63
31
  - bin/git_cleanup
64
- - config/buildmeister_config.sample.yml
65
32
  - lib/buildmeister.rb
33
+ - lib/buildmeister/base.rb
34
+ - lib/buildmeister/bin.rb
35
+ - lib/buildmeister/finder.rb
36
+ - lib/buildmeister/git_utils.rb
37
+ - lib/buildmeister/notifier.rb
38
+ - lib/buildmeister/project.rb
39
+ - lib/buildmeister/string_utils.rb
66
40
  - lib/git_cleanup.rb
67
- - test/test_buildmeister.rb
41
+ - spec/buildmeister/base_spec.rb
42
+ - spec/buildmeister/bin_spec.rb
43
+ - spec/buildmeister/project_spec.rb
44
+ - spec/spec.opts
45
+ - spec/spec_helper.rb
68
46
  has_rdoc: true
69
- homepage: http://github.com/texel/buildmeister
47
+ homepage: http://github.com/onehub/buildmeister
70
48
  licenses: []
71
49
 
72
50
  post_install_message:
73
51
  rdoc_options:
74
- - --main
75
- - README.txt
52
+ - --charset=UTF-8
76
53
  require_paths:
77
54
  - lib
78
55
  required_ruby_version: !ruby/object:Gem::Requirement
@@ -89,10 +66,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
89
66
  version:
90
67
  requirements: []
91
68
 
92
- rubyforge_project: buildmeister
69
+ rubyforge_project:
93
70
  rubygems_version: 1.3.5
94
71
  signing_key:
95
- specification_version: 2
96
- summary: FIX (describe your package)
72
+ specification_version: 3
73
+ summary: Dead simple tools for managing Lighthouse and Git deployment workflow
97
74
  test_files:
98
- - test/test_buildmeister.rb
75
+ - spec/buildmeister/base_spec.rb
76
+ - spec/buildmeister/bin_spec.rb
77
+ - spec/buildmeister/project_spec.rb
78
+ - spec/spec_helper.rb
data/Manifest.txt DELETED
@@ -1,10 +0,0 @@
1
- History.txt
2
- Manifest.txt
3
- README.rdoc
4
- Rakefile
5
- bin/buildmeister
6
- bin/git_cleanup
7
- config/buildmeister_config.sample.yml
8
- lib/buildmeister.rb
9
- lib/git_cleanup.rb
10
- test/test_buildmeister.rb
@@ -1,16 +0,0 @@
1
- token: Your Lighthouse token
2
- account: Your Lighthouse account name
3
- project_name: Your Lighthouse project name
4
-
5
- bin_groups:
6
- - staging:
7
- - Ready
8
- - Staged
9
- - Verified
10
-
11
- - master:
12
- - Ready (Experimental)
13
- - Staged (Experimental)
14
- - Verified (Experimental)
15
-
16
- notification_interval: 5
File without changes