Class: BPCI
- Inherits:
-
Object
- Object
- BPCI
- Defined in:
- lib/bpci.rb,
lib/bpci/irc.rb,
lib/bpci/build.rb,
lib/bpci/queue.rb,
lib/bpci/commit.rb,
lib/bpci/config.rb,
lib/bpci/server.rb,
lib/bpci/version.rb
Defined Under Namespace
Classes: Build, Commit, Config, IRCBot, Queue, Server
Constant Summary collapse
- Version =
VERSION = "0.0.1"
Instance Attribute Summary collapse
-
#current_build ⇒ Object
readonly
Returns the value of attribute current_build.
-
#last_build ⇒ Object
readonly
Returns the value of attribute last_build.
-
#project ⇒ Object
readonly
Returns the value of attribute project.
-
#url ⇒ Object
readonly
Returns the value of attribute url.
-
#user ⇒ Object
readonly
Returns the value of attribute user.
Instance Method Summary collapse
-
#build(branch = nil) ⇒ Object
run the build but make sure only one is running at a time (if new one comes in we will park it).
-
#build!(branch = nil) ⇒ Object
update git then run the build.
-
#build_failed(output, error) ⇒ Object
build callbacks.
- #build_successful(output) ⇒ Object
-
#building? ⇒ Boolean
is a build running?.
- #finish_build(status, output) ⇒ Object
- #git_branch ⇒ Object
- #git_sha ⇒ Object
- #git_update ⇒ Object
- #git_user_and_project ⇒ Object
-
#initialize(project_path) ⇒ BPCI
constructor
A new instance of BPCI.
- #open_pipe(cmd) {|read, pid| ... } ⇒ Object
- #path_in_project(path) ⇒ Object
-
#pid ⇒ Object
the pid of the running child process.
-
#read_build(name) ⇒ Object
load build info from file.
- #repo_config ⇒ Object
-
#restore ⇒ Object
restore current / last build state from disk.
-
#run_hook(hook) ⇒ Object
massage our repo.
-
#runner_command ⇒ Object
shellin’ out.
-
#stop ⇒ Object
kill the child and exit.
-
#write_build(name, build) ⇒ Object
write build info for build to file.
Constructor Details
#initialize(project_path) ⇒ BPCI
Returns a new instance of BPCI.
20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
# File 'lib/bpci.rb', line 20 def initialize(project_path) @project_path = File.(project_path) @user, @project = git_user_and_project @url = "http://github.com/#{@user}/#{@project}" @irc = BPCI::IRCBot.new(@project_path) @last_build = nil @current_build = nil @queue = Queue.new(!repo_config.buildqueue.to_s.empty?, true) trap("INT") { stop } end |
Instance Attribute Details
#current_build ⇒ Object (readonly)
Returns the value of attribute current_build.
18 19 20 |
# File 'lib/bpci.rb', line 18 def current_build @current_build end |
#last_build ⇒ Object (readonly)
Returns the value of attribute last_build.
18 19 20 |
# File 'lib/bpci.rb', line 18 def last_build @last_build end |
#project ⇒ Object (readonly)
Returns the value of attribute project.
18 19 20 |
# File 'lib/bpci.rb', line 18 def project @project end |
#url ⇒ Object (readonly)
Returns the value of attribute url.
18 19 20 |
# File 'lib/bpci.rb', line 18 def url @url end |
#user ⇒ Object (readonly)
Returns the value of attribute user.
18 19 20 |
# File 'lib/bpci.rb', line 18 def user @user end |
Instance Method Details
#build(branch = nil) ⇒ Object
run the build but make sure only one is running at a time (if new one comes in we will park it)
85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/bpci.rb', line 85 def build(branch=nil) if building? @queue.append_unless_already_exists(branch) @irc.broadcast "#{3.chr}8Queueing new build#{3.chr} of #{2.chr}#{@project}#{2.chr}" if @queue.enabled? # leave anyway because a current build runs return end @current_build = Build.new(@project_path, @user, @project) @irc.broadcast "#{3.chr}12Starting build#{3.chr} of #{2.chr}#{@project}#{2.chr} at: #{@current_build.started_at}" write_build 'current', @current_build Thread.new { build!(branch) } end |
#build!(branch = nil) ⇒ Object
update git then run the build
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/bpci.rb', line 113 def build!(branch=nil) @git_branch = branch build = @current_build output = '' git_update build.sha = git_sha build.branch = git_branch write_build 'current', build open_pipe("cd #{@project_path} && #{runner_command} 2>&1") do |pipe, pid| puts "#{Time.now.to_i}: Building #{build.branch} at #{build.short_sha}: pid=#{pid}" build.pid = pid write_build 'current', build output = pipe.read end Process.waitpid(build.pid, 1) status = $?.exitstatus.to_i @current_build = build puts "#{Time.now.to_i}: Built #{build.short_sha}: status=#{status}" status == 0 ? build_successful(output) : build_failed('', output) rescue Object => e puts "Exception building: #{e.} (#{e.class})" build_failed('', e.to_s) end |
#build_failed(output, error) ⇒ Object
build callbacks
52 53 54 55 56 |
# File 'lib/bpci.rb', line 52 def build_failed(output, error) finish_build :failed, "#{error}\n\n#{output}" @irc.broadcast "Build of #{2.chr}#{@project}#{2.chr} finished: #{3.chr}4FAILED#{3.chr} - took #{@last_build.duration} seconds." run_hook "build-failed" end |
#build_successful(output) ⇒ Object
58 59 60 61 62 |
# File 'lib/bpci.rb', line 58 def build_successful(output) finish_build :successful, output @irc.broadcast "Build of #{2.chr}#{@project}#{2.chr} finished: #{3.chr}9SUCCEEDED#{3.chr} - took #{@last_build.duration} seconds." run_hook "build-successful" end |
#building? ⇒ Boolean
is a build running?
36 37 38 |
# File 'lib/bpci.rb', line 36 def building? !!@current_build end |
#finish_build(status, output) ⇒ Object
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/bpci.rb', line 64 def finish_build(status, output) @current_build.finished_at = Time.now @current_build.status = status @current_build.output = output @last_build = @current_build @current_build = nil # Obtain the latest file ID by globbing and using some ugly hacks. old_builds = Dir.entries(path_in_project(".git/builds/")) newest_file_id = old_builds.keep_if {|z| z =~ /^\d/}.collect {|z| z.split('-')[0].to_i}.max || 0 write_build "#{newest_file_id + 1}-#{@last_build.sha[0,7]}", @last_build write_build 'current', @current_build write_build 'last', @last_build build(@queue.next_branch_to_build) if @queue.waiting? end |
#git_branch ⇒ Object
160 161 162 163 164 |
# File 'lib/bpci.rb', line 160 def git_branch return @git_branch if @git_branch branch = repo_config.branch.to_s @git_branch = branch == '' ? "master" : branch end |
#git_sha ⇒ Object
147 148 149 |
# File 'lib/bpci.rb', line 147 def git_sha `cd #{@project_path} && git rev-parse origin/#{git_branch}`.chomp end |
#git_update ⇒ Object
151 152 153 154 |
# File 'lib/bpci.rb', line 151 def git_update `cd #{@project_path} && git fetch origin && git reset --hard origin/#{git_branch}` run_hook "after-reset" end |
#git_user_and_project ⇒ Object
156 157 158 |
# File 'lib/bpci.rb', line 156 def git_user_and_project Config.remote(@project_path).origin.url.to_s.chomp('.git').split(':')[-1].split('/')[-2, 2] end |
#open_pipe(cmd) {|read, pid| ... } ⇒ Object
98 99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/bpci.rb', line 98 def open_pipe(cmd) read, write = IO.pipe pid = fork do read.close $stdout.reopen write exec cmd end write.close yield read, pid end |
#path_in_project(path) ⇒ Object
204 205 206 |
# File 'lib/bpci.rb', line 204 def path_in_project(path) File.join(@project_path, path) end |
#pid ⇒ Object
the pid of the running child process
41 42 43 |
# File 'lib/bpci.rb', line 41 def pid building? and current_build.pid end |
#read_build(name) ⇒ Object
load build info from file.
224 225 226 |
# File 'lib/bpci.rb', line 224 def read_build(name) Build.load(path_in_project(".git/builds/#{name}"), @project_path) end |
#repo_config ⇒ Object
219 220 221 |
# File 'lib/bpci.rb', line 219 def repo_config Config.bpci(@project_path) end |
#restore ⇒ Object
restore current / last build state from disk.
193 194 195 196 197 198 199 200 201 202 |
# File 'lib/bpci.rb', line 193 def restore @last_build = read_build('last') @current_build = read_build('current') Process.kill(0, @current_build.pid) if @current_build && @current_build.pid rescue Errno::ESRCH # build pid isn't running anymore. assume previous # server died and reset. @current_build = nil end |
#run_hook(hook) ⇒ Object
massage our repo
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
# File 'lib/bpci.rb', line 167 def run_hook(hook) if File.exists?(file=path_in_project(".git/hooks/#{hook}")) && File.executable?(file) data = if @last_build && @last_build.commit { "MESSAGE" => @last_build.commit., "AUTHOR" => @last_build.commit., "SHA" => @last_build.commit.sha, "OUTPUT" => @last_build.env_output } else {} end orig_ENV = ENV.to_hash ENV.clear data.each{ |k, v| ENV[k] = v } output = `cd #{@project_path} && sh #{file}` ENV.clear orig_ENV.to_hash.each{ |k, v| ENV[k] = v} output end end |
#runner_command ⇒ Object
shellin’ out
142 143 144 145 |
# File 'lib/bpci.rb', line 142 def runner_command runner = repo_config.runner.to_s runner == '' ? "rake -s test:units" : runner end |
#stop ⇒ Object
kill the child and exit
46 47 48 49 |
# File 'lib/bpci.rb', line 46 def stop Process.kill(9, pid) if pid exit! end |
#write_build(name, build) ⇒ Object
write build info for build to file.
209 210 211 212 213 214 215 216 217 |
# File 'lib/bpci.rb', line 209 def write_build(name, build) filename = path_in_project(".git/builds/#{name}") Dir.mkdir path_in_project('.git/builds') unless File.directory?(path_in_project('.git/builds')) if build build.dump filename elsif File.exist?(filename) File.unlink filename end end |