bob-the-builder 0.1 → 0.1.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.
@@ -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