bob-the-builder 0.1 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,52 +1,24 @@
1
1
  = Bob the Builder
2
2
 
3
- Given a Buildable object with the following public API:
4
-
5
- * <tt>buildable.kind</tt>
6
-
7
- Should return a Symbol with whatever kind of repository the buildable's code is
8
- in (:git, :svn, etc).
9
-
10
- * <tt>buildable.uri</tt>
11
-
12
- Returns a string like "git://github.com/integrity/bob.git", pointing to the code
13
- repository.
14
-
15
- * <tt>buildable.branch</tt>
16
-
17
- What branch of the repository should we build?
18
-
19
- * <tt>buildable.build_script</tt>
20
-
21
- Returns a string containing the build script to be run when "building".
22
-
23
- * <tt>buildable.start_building(commit_id)</tt>
24
-
25
- `commit_id` is a String that contains whatever is appropriate for the repo type,
26
- so it would be a SHA1 hash for git repos, or a numeric id for svn, etc. This is a
27
- callback so the buildable can determine how long it takes to build. It doesn't
28
- need to return anything.
29
-
30
- * <tt>buildable.finish_building(commit_id, build_status, build_output)</tt>
31
-
32
- Callback for when the build finishes. It doesn't need to return anything. It will
33
- receive a string with the commit identifier, a boolean for the build exit status
34
- (true for successful builds, false fore failed ones) and a string with the build
35
- output (both STDOUT and STDERR).
3
+ Given a Buildable object with a determined API (described in it's documentation),
4
+ Bob will, when called like:
36
5
 
37
- A successful build is one where the build script returns a zero status code.
6
+ Bob.build(buildable, commit_id) # or Bob.build(buildable, [commit_id, commit_id, ...])
38
7
 
39
- Bob will, when called like:
8
+ or from your buildable (if you are using the Bob::Buildable mixin provided) as:
40
9
 
41
- Bob.build(buildable, commit_id)
10
+ buildable.build(commit_id) # or buildable.build([commit_id, commit_id, ...])
42
11
 
43
12
  1. Checkout the buildable on the specified commit
44
- 2. Call <tt>buildable.start_building</tt>
45
- 3. Run the script provided in <tt>build_script</tt> in the buildable.
46
- 4. When the build process finishes, it will call <tt>finish_building</tt> with
13
+ 2. Call <tt>Buildable#start_building</tt>
14
+ 3. Run the script provided in <tt>Buildable#build_script</tt> in the buildable.
15
+ 4. When the build process finishes, it will call <tt>Buildable#finish_building</tt> with
47
16
  the commit_id, the build status (true if the script returns a status code
48
17
  of 0, false otherwise), and a string with the build output (both STDOUT and STDERR).
49
18
 
19
+ If you pass an array of commits, the steps 1-4 will be repeated for each commit provided,
20
+ in order.
21
+
50
22
  == Do I need this?
51
23
 
52
24
  Probably not. Check out integrity[http://integrityapp.com] for a full fledged
data/Rakefile CHANGED
@@ -7,7 +7,7 @@ rescue LoadError
7
7
  end
8
8
 
9
9
  begin
10
- require "metric_fu"
10
+ require "metric_fu" if RUBY_VERSION < "1.9"
11
11
  rescue LoadError
12
12
  end
13
13
 
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "bob-the-builder"
3
- s.version = "0.1"
4
- s.date = "2009-05-05"
3
+ s.version = "0.1.1"
4
+ s.date = "2009-05-08"
5
5
 
6
6
  s.description = "Bob the Builder will build your code. Simple."
7
7
  s.summary = "Bob builds!"
@@ -33,14 +33,22 @@ bob-the-builder.gemspec
33
33
  lib/bob.rb
34
34
  lib/bob/background_engines.rb
35
35
  lib/bob/background_engines/foreground.rb
36
+ lib/bob/background_engines/threaded.rb
36
37
  lib/bob/builder.rb
38
+ lib/bob/buildable.rb
37
39
  lib/bob/scm.rb
38
40
  lib/bob/scm/abstract.rb
39
41
  lib/bob/scm/git.rb
42
+ lib/bob/scm/svn.rb
40
43
  lib/core_ext/object.rb
44
+ test/background_engine/threaded_test.rb
41
45
  test/bob_test.rb
42
46
  test/helper.rb
43
- test/helper/git_helper.rb
47
+ test/helper/abstract_scm_helper.rb
44
48
  test/helper/buildable_stub.rb
49
+ test/helper/git_helper.rb
50
+ test/helper/svn_helper.rb
51
+ test/scm/git_test.rb
52
+ test/scm/svn_test.rb
45
53
  ]
46
54
  end
data/lib/bob.rb CHANGED
@@ -4,6 +4,7 @@ require "logger"
4
4
  require "time"
5
5
  require "addressable/uri"
6
6
 
7
+ require "bob/buildable"
7
8
  require "bob/builder"
8
9
  require "bob/scm"
9
10
  require "bob/background_engines"
@@ -0,0 +1,108 @@
1
+ require "thread"
2
+
3
+ module Bob
4
+ module BackgroundEngines
5
+ class Threaded
6
+
7
+ def initialize(pool_size = 2)
8
+ @pool = ThreadPool.new(pool_size)
9
+ end
10
+
11
+ def call(job)
12
+ @pool << job
13
+ end
14
+
15
+ def njobs
16
+ @pool.njobs
17
+ end
18
+
19
+ def wait!
20
+ Thread.pass until @pool.njobs == 0
21
+ end
22
+
23
+ class ThreadPool
24
+ class Incrementor
25
+ def initialize(v = 0)
26
+ @m = Mutex.new
27
+ @v = v
28
+ end
29
+
30
+ def inc(v = 1)
31
+ sync { @v += v }
32
+ end
33
+
34
+ def dec(v = 1)
35
+ sync { @v -= v }
36
+ end
37
+
38
+ def inspect
39
+ @v.inspect
40
+ end
41
+
42
+ def to_i
43
+ @v
44
+ end
45
+
46
+ private
47
+
48
+ def sync(&b)
49
+ @m.synchronize &b
50
+ end
51
+ end
52
+
53
+ attr_reader :size, :jobs
54
+
55
+ def size=(other)
56
+ @size = other
57
+
58
+ if @workers.size > @size
59
+ (@workers.size - @size).times do
60
+ @workers.shift[:run] = false
61
+ end
62
+ else
63
+ (@size - @workers.size).times do
64
+ @workers << spawn
65
+ end
66
+ end
67
+ end
68
+
69
+ def initialize(size = nil)
70
+ size ||= 2
71
+ @jobs = Queue.new
72
+ @njobs = Incrementor.new
73
+ @workers = Array.new(size) { spawn }
74
+ end
75
+
76
+ def add(*jobs, &blk)
77
+ jobs = jobs + Array(blk)
78
+
79
+ jobs.each do |job|
80
+ @jobs << job
81
+ @njobs.inc
82
+ end
83
+ end
84
+
85
+ alias_method :push, :add
86
+ alias_method :<<, :add
87
+
88
+ def njobs
89
+ @njobs.to_i
90
+ end
91
+
92
+ private
93
+
94
+ def spawn
95
+ Thread.new do
96
+ c = Thread.current
97
+ c[:run] = true
98
+
99
+ while c[:run]
100
+ @jobs.pop.call
101
+ @njobs.dec
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,70 @@
1
+ module Bob
2
+ # Mixin to add to your classes.
3
+ module Buildable
4
+ # Builds the list of commits you pass. You must provide an
5
+ # enumerable with commit identifiers appropriate to the
6
+ # repository the code is in (SHAs if git, rev numbers if svn,
7
+ # etc), or a single string with a commit id.
8
+ def build(commits)
9
+ Bob.build(self, commits)
10
+ end
11
+
12
+ # What kind of repository this buildable represents. Must
13
+ # return a Symbol (:git, :svn, etc.)
14
+ #
15
+ # <b>You must implement this in the classes where you mixin this module</b>
16
+ def kind
17
+ raise NotImplementedError
18
+ end
19
+
20
+ # Full URI to the repository to clone/checkout.
21
+ #
22
+ # <b>You must implement this in the classes where you mixin this module</b>
23
+ def uri
24
+ raise NotImplementedError
25
+ end
26
+
27
+ # Branch of the code you want to watch in order to build.
28
+ #
29
+ # <b>You must implement this in the classes where you mixin this module</b>
30
+ def branch
31
+ raise NotImplementedError
32
+ end
33
+
34
+ # Script that will be run in the buildable's checked out code,
35
+ # if it returns a status code of 0 it will be considered a
36
+ # successfull build. Else it will be considered a failed build.
37
+ #
38
+ # <b>You must implement this in the classes where you mixin this module</b>
39
+ def build_script
40
+ raise NotImplementedError
41
+ end
42
+
43
+ # Callback sent when a build starts. The first argument is a
44
+ # string with whatever identifier is appropriate for a repository
45
+ # of this kind. The second is a hash with information about the
46
+ # commit.
47
+ #
48
+ # <tt>:author</tt>:: A string with the name/email of the committer
49
+ # <tt>:message</tt>:: The commit message
50
+ # <tt>:committed_at</tt>:: A Time object with the timestamp of the
51
+ # commit
52
+ #
53
+ # <b>You must implement this in the classes where you mixin this module</b>
54
+ def start_building(commit_id, commit_info)
55
+ raise NotImplementedError
56
+ end
57
+
58
+ # Callback sent after a build finishes. The first argument is a
59
+ # string with whatever identifier is appropriate for a respository
60
+ # of this kind. The second is a boolean which is true if the build
61
+ # was successful or false if it failed. And the last one is a string
62
+ # with the full output returned by the build process (STDOUT and
63
+ # STDERR interleaved)
64
+ #
65
+ # <b>You must implement this in the classes where you mixin this module</b>
66
+ def finish_building(commit_id, build_status, build_output)
67
+ raise NotImplementedError
68
+ end
69
+ end
70
+ end
@@ -35,8 +35,8 @@ module Bob
35
35
 
36
36
  protected
37
37
 
38
- def run(command)
39
- command = "(cd #{working_dir} && #{command} &>/dev/null)"
38
+ def run(command, cd_into_working_dir=true)
39
+ command = "(#{cd_into_working_dir ? "cd #{working_dir} && " : ""}#{command} &>/dev/null)"
40
40
  Bob.logger.debug command
41
41
  system(command) || raise(CantRunCommand, "Couldn't run SCM command `#{command}`")
42
42
  end
@@ -29,10 +29,8 @@ module Bob
29
29
  end
30
30
 
31
31
  def clone
32
- git "clone #{uri} #{working_dir}"
33
- rescue CantRunCommand
34
32
  FileUtils.rm_r working_dir
35
- retry
33
+ run "git clone #{uri} #{working_dir}", false
36
34
  end
37
35
 
38
36
  def fetch
@@ -45,10 +43,6 @@ module Bob
45
43
  git "reset --hard #{commit_id}"
46
44
  end
47
45
 
48
- def reset(commit_id)
49
- git "reset --hard #{commit_id}"
50
- end
51
-
52
46
  def git(command)
53
47
  run "git #{command}"
54
48
  end
@@ -0,0 +1,46 @@
1
+ require "bob/scm/abstract"
2
+
3
+ module Bob
4
+ module SCM
5
+ class Svn < Abstract
6
+ def info(revision)
7
+ dump = %x[svn log --non-interactive --revision #{revision} #{uri}].split("\n")
8
+ meta = dump[1].split(" | ")
9
+
10
+ { :message => dump[3],
11
+ :author => meta[1],
12
+ :committed_at => Time.parse(meta[2]) }
13
+ end
14
+
15
+ def with_commit(commit_id)
16
+ update_code
17
+ checkout(commit_id)
18
+ yield
19
+ end
20
+
21
+ protected
22
+
23
+ def path_from_uri
24
+ "svn-#{uri.path[1..-1]}"
25
+ end
26
+
27
+ private
28
+
29
+ def update_code
30
+ initial_checkout unless checked_out?
31
+ end
32
+
33
+ def checkout(revision)
34
+ run("svn up -q -r#{revision}")
35
+ end
36
+
37
+ def initial_checkout(revision=nil)
38
+ run("svn co -q #{uri} #{working_dir}")
39
+ end
40
+
41
+ def checked_out?
42
+ File.directory?(working_dir + "/.svn")
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,36 @@
1
+ require File.dirname(__FILE__) + "/../helper"
2
+
3
+ class ThreadedBobTest < Test::Unit::TestCase
4
+ def setup
5
+ super
6
+
7
+ @repo = GitRepo.new(:test_repo)
8
+ @repo.create
9
+
10
+ @buildable = GitBuildableStub.new(@repo)
11
+ end
12
+
13
+ test "with a successful threaded build" do
14
+ old_engine = Bob.engine
15
+
16
+ repo.add_successful_commit
17
+ commit_id = repo.commits.first[:identifier]
18
+
19
+ begin
20
+ Thread.abort_on_exception = true
21
+ Bob.engine = Bob::BackgroundEngines::Threaded.new(5)
22
+ Bob.build(buildable, commit_id)
23
+ Bob.engine.wait!
24
+
25
+ status, output = buildable.builds[commit_id]
26
+ assert_equal :successful, status
27
+ assert_equal "Running tests...\n", output
28
+
29
+ commit = buildable.metadata[commit_id]
30
+ assert_equal "This commit will work", commit[:message]
31
+ assert_equal Time.now.min, commit[:committed_at].min
32
+ ensure
33
+ Bob.engine = old_engine
34
+ end
35
+ end
36
+ end
@@ -16,9 +16,6 @@ require "git_helper"
16
16
  require "svn_helper"
17
17
  require "buildable_stub"
18
18
 
19
- Bob.logger = Logger.new("/dev/null")
20
- Bob.engine = Bob::BackgroundEngines::Foreground
21
- Bob.directory = File.expand_path(File.dirname(__FILE__) + "/../tmp")
22
19
 
23
20
  class Test::Unit::TestCase
24
21
  include Bob
@@ -27,6 +24,10 @@ class Test::Unit::TestCase
27
24
  attr_reader :repo, :buildable
28
25
 
29
26
  def setup
30
- FileUtils.rm_rf(Bob.directory)
27
+ Bob.logger = Logger.new("/dev/null")
28
+ Bob.engine = Bob::BackgroundEngines::Foreground
29
+ Bob.directory = File.expand_path(File.dirname(__FILE__) + "/../tmp")
30
+
31
+ FileUtils.rm_rf(Bob.directory) if File.directory?(Bob.directory)
31
32
  end
32
33
  end
@@ -0,0 +1,50 @@
1
+ module TestHelper
2
+ class AbstractSCMRepo
3
+ attr_reader :path, :name
4
+
5
+ def initialize(name, base_dir=Bob.directory)
6
+ @name = name
7
+ @path = File.join(base_dir, @name.to_s)
8
+ end
9
+
10
+ def add_commit(message, &action)
11
+ Dir.chdir(@path) do
12
+ yield action
13
+ commit(message)
14
+ end
15
+ end
16
+
17
+ def add_failing_commit
18
+ add_commit "This commit will fail" do
19
+ system "echo '#{build_script(false)}' > test"
20
+ system "chmod +x test"
21
+ add "test &>/dev/null"
22
+ end
23
+ end
24
+
25
+ def add_successful_commit
26
+ add_commit "This commit will work" do
27
+ system "echo '#{build_script(true)}' > test"
28
+ system "chmod +x test"
29
+ add "test"
30
+ end
31
+ end
32
+
33
+ protected
34
+ def add(file)
35
+ raise NotImplementedError
36
+ end
37
+
38
+ def commit(message)
39
+ raise NotImplementedError
40
+ end
41
+
42
+ def build_script(successful=true)
43
+ <<-script
44
+ #!/bin/sh
45
+ echo "Running tests..."
46
+ exit #{successful ? 0 : 1}
47
+ script
48
+ end
49
+ end
50
+ end
@@ -1,5 +1,7 @@
1
1
  module TestHelper
2
2
  module BuildableStub
3
+ include Bob::Buildable
4
+
3
5
  attr_reader :repo, :builds, :metadata
4
6
 
5
7
  def initialize(repo)
@@ -17,7 +17,7 @@ module TestHelper
17
17
 
18
18
  def commits
19
19
  Dir.chdir(@path) do
20
- commits = `git log --pretty=oneline`.collect { |l| l.split(" ").first }
20
+ commits = `git log --pretty=oneline`.each_line.collect { |l| l.split(" ").first }
21
21
  commits.inject([]) do |commits, sha1|
22
22
  format = "---%n:message: >-%n %s%n:timestamp: %ci%n" +
23
23
  ":identifier: %H%n:author: %n :name: %an%n :email: %ae%n"
@@ -0,0 +1,68 @@
1
+ require File.dirname(__FILE__) + "/abstract_scm_helper"
2
+
3
+ module TestHelper
4
+ class SvnRepo < AbstractSCMRepo
5
+ def self.server_root
6
+ @root ||= File.join(Bob.directory, "svn")
7
+ end
8
+
9
+ attr_reader :remote
10
+
11
+ def initialize(name, base_dir=Bob.directory)
12
+ super
13
+
14
+ @path = File.join(base_dir, "svn-#{name}")
15
+ @remote = File.join(SvnRepo.server_root, name.to_s)
16
+ end
17
+
18
+ def create
19
+ create_remote
20
+
21
+ system "svn checkout file://#{remote} #{path} &>/dev/null"
22
+
23
+ add_commit("First commit") do
24
+ system "echo 'just a test repo' >> README"
25
+ add "README"
26
+ end
27
+ end
28
+
29
+ def commits
30
+ Dir.chdir(path) do
31
+ doc = Hpricot::XML(`svn log --xml`)
32
+
33
+ (doc/:log/:logentry).inject([]) { |commits, commit|
34
+ commits << { :identifier => commit["revision"],
35
+ :message => commit.at("msg").inner_html,
36
+ :committed_at => Time.parse(commit.at("date").inner_html) }
37
+ }
38
+ end
39
+ end
40
+
41
+ def head
42
+ commits.first[:identifier]
43
+ end
44
+
45
+ protected
46
+ def add(file)
47
+ system "svn add #{file} &>/dev/null"
48
+ end
49
+
50
+ def commit(message)
51
+ system %Q{svn commit -m "#{message}" &>/dev/null}
52
+ system "svn up &>/dev/null"
53
+ end
54
+
55
+ private
56
+ def create_remote
57
+ FileUtils.mkdir_p(SvnRepo.server_root)
58
+
59
+ system "svnadmin create #{remote} &>/dev/null"
60
+
61
+ File.open(File.join(remote, "conf", "svnserve.conf"), "w") { |f|
62
+ f.puts "[general]"
63
+ f.puts "anon-access = write"
64
+ f.puts "auth-access = write"
65
+ }
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,59 @@
1
+ require File.dirname(__FILE__) + "/../helper"
2
+
3
+ class BobGitTest < Test::Unit::TestCase
4
+ def setup
5
+ super
6
+
7
+ @repo = GitRepo.new(:test_repo)
8
+ @repo.create
9
+
10
+ @buildable = GitBuildableStub.new(@repo)
11
+ end
12
+
13
+ test "with a successful build" do
14
+ repo.add_successful_commit
15
+
16
+ commit_id = repo.commits.first[:identifier]
17
+
18
+ buildable.build(commit_id)
19
+
20
+ status, output = buildable.builds[commit_id]
21
+ assert_equal :successful, status
22
+ assert_equal "Running tests...\n", output
23
+
24
+ assert_equal 1, buildable.metadata.length
25
+
26
+ commit = buildable.metadata[commit_id]
27
+ assert_equal "This commit will work", commit[:message]
28
+ assert commit[:committed_at].is_a?(Time)
29
+ end
30
+
31
+ test "with a failed build" do
32
+ repo.add_failing_commit
33
+
34
+ commit_id = repo.commits.first[:identifier]
35
+
36
+ buildable.build(commit_id)
37
+
38
+ status, output = buildable.builds[commit_id]
39
+ assert_equal :failed, status
40
+ assert_equal "Running tests...\n", output
41
+
42
+ assert_equal 1, buildable.metadata.length
43
+
44
+ commit = buildable.metadata[commit_id]
45
+ assert_equal "This commit will fail", commit[:message]
46
+ assert commit[:committed_at].is_a?(Time)
47
+ end
48
+
49
+ test "with multiple commits" do
50
+ 2.times { repo.add_failing_commit }
51
+ commits = repo.commits.collect { |c| c[:identifier] }
52
+
53
+ buildable.build(commits)
54
+
55
+ assert_equal 2, commits.length
56
+ assert_equal 2, buildable.metadata.length
57
+ assert_equal 2, buildable.builds.length
58
+ end
59
+ end
@@ -0,0 +1,57 @@
1
+ require File.dirname(__FILE__) + "/../helper"
2
+
3
+ class BobSvnTest < Test::Unit::TestCase
4
+ def setup
5
+ super
6
+
7
+ @repo = SvnRepo.new(:test_repo)
8
+ @repo.create
9
+
10
+ @buildable = SvnBuildableStub.new(@repo)
11
+ end
12
+
13
+ test "with a successful build" do
14
+ repo.add_successful_commit
15
+
16
+ buildable.build("2")
17
+
18
+ assert_equal 1, buildable.metadata.length
19
+
20
+ status, output = buildable.builds["2"]
21
+ assert_equal :successful, status
22
+ assert_equal "Running tests...\n", output
23
+
24
+ assert_equal 1, buildable.metadata.length
25
+
26
+ commit = buildable.metadata["2"]
27
+ assert commit[:committed_at].is_a?(Time)
28
+ assert_equal "This commit will work", commit[:message]
29
+ end
30
+
31
+ test "with a failed build" do
32
+ repo.add_failing_commit
33
+ commit_id = repo.commits.first[:identifier]
34
+
35
+ buildable.build(commit_id)
36
+
37
+ status, output = buildable.builds[commit_id]
38
+ assert_equal :failed, status
39
+ assert_equal "Running tests...\n", output
40
+
41
+ assert_equal 1, buildable.metadata.length
42
+
43
+ commit = buildable.metadata[commit_id]
44
+ assert commit[:committed_at].is_a?(Time)
45
+ assert_equal "This commit will fail", commit[:message]
46
+ end
47
+
48
+ test "with multiple commits" do
49
+ repo.add_successful_commit
50
+ 2.times { repo.add_failing_commit }
51
+
52
+ buildable.build(repo.commits.collect { |c| c[:identifier] })
53
+
54
+ assert_equal 3, buildable.metadata.length
55
+ assert_equal 3, buildable.builds.length
56
+ end
57
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bob-the-builder
3
3
  version: !ruby/object:Gem::Version
4
- version: "0.1"
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - "Nicol\xC3\xA1s Sanguinetti"
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2009-05-05 00:00:00 -03:00
13
+ date: 2009-05-08 00:00:00 -03:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -80,17 +80,27 @@ files:
80
80
  - lib/bob.rb
81
81
  - lib/bob/background_engines.rb
82
82
  - lib/bob/background_engines/foreground.rb
83
+ - lib/bob/background_engines/threaded.rb
83
84
  - lib/bob/builder.rb
85
+ - lib/bob/buildable.rb
84
86
  - lib/bob/scm.rb
85
87
  - lib/bob/scm/abstract.rb
86
88
  - lib/bob/scm/git.rb
89
+ - lib/bob/scm/svn.rb
87
90
  - lib/core_ext/object.rb
91
+ - test/background_engine/threaded_test.rb
88
92
  - test/bob_test.rb
89
93
  - test/helper.rb
90
- - test/helper/git_helper.rb
94
+ - test/helper/abstract_scm_helper.rb
91
95
  - test/helper/buildable_stub.rb
96
+ - test/helper/git_helper.rb
97
+ - test/helper/svn_helper.rb
98
+ - test/scm/git_test.rb
99
+ - test/scm/svn_test.rb
92
100
  has_rdoc: true
93
101
  homepage: http://integrityapp.com
102
+ licenses: []
103
+
94
104
  post_install_message:
95
105
  rdoc_options: []
96
106
 
@@ -111,9 +121,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
111
121
  requirements: []
112
122
 
113
123
  rubyforge_project: bob-the-builder
114
- rubygems_version: 1.3.1
124
+ rubygems_version: 1.3.3
115
125
  signing_key:
116
- specification_version: 2
126
+ specification_version: 3
117
127
  summary: Bob builds!
118
128
  test_files: []
119
129