buildbox 0.0.4 → 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,86 +0,0 @@
1
- module Buildbox
2
- class Client
3
- def initialize(options)
4
- @options = options
5
- @interval = 5
6
- end
7
-
8
- def start
9
- exit_if_already_running
10
-
11
- Buildbox.logger.info "Starting client..."
12
-
13
- register_client
14
-
15
- begin
16
- daemonize if @options[:daemon]
17
- pid_file.save
18
-
19
- loop do
20
- reload_configuration
21
- Buildbox::Worker.new.process
22
- wait_for_interval
23
- end
24
- rescue => e
25
- Buildbox.logger.error "#{e.class.name}: #{e.message}"
26
- e.backtrace.each { |line| Buildbox.logger.error line }
27
-
28
- api.crash(e)
29
- ensure
30
- pid_file.delete
31
- end
32
- end
33
-
34
- def stop
35
- Buildbox.logger.info "Stopping client..."
36
-
37
- Process.kill(:KILL, pid_file.delete)
38
- end
39
-
40
- private
41
-
42
- def daemonize
43
- if @options[:daemon]
44
- Process.daemon
45
-
46
- Buildbox.logger = Logger.new(Buildbox.root_path.join("buildbox.log"))
47
- end
48
- end
49
-
50
- def register_client
51
- worker_uuid = Buildbox.configuration.worker_uuid
52
- response = api.register(:uuid => worker_uuid, :hostname => `hostname`.chomp)
53
-
54
- Buildbox.configuration.update :worker_uuid, response.payload[:uuid]
55
- end
56
-
57
- def reload_configuration
58
- Buildbox.configuration.reload
59
- end
60
-
61
- def wait_for_interval
62
- Buildbox.logger.debug "Sleeping for #{@interval} seconds"
63
-
64
- sleep(@interval)
65
- end
66
-
67
- def exit_if_already_running
68
- if pid_file.exist?
69
- Buildbox.logger.error "Process (#{pid_file.pid} - #{pid_file.path}) is already running."
70
-
71
- exit 1
72
- end
73
- end
74
-
75
- def worker
76
- end
77
-
78
- def api
79
- @api ||= Buildbox::API.new(:api_key => Buildbox.configuration.api_key)
80
- end
81
-
82
- def pid_file
83
- @pid_file ||= Buildbox::PidFile.new
84
- end
85
- end
86
- end
@@ -1,59 +0,0 @@
1
- module Buildbox
2
- class Observer
3
- INTERVAL = 3 # feels like a good number
4
-
5
- def initialize(api, build_uuid)
6
- @api = api
7
- @build_uuid = build_uuid
8
-
9
- @queue = Queue.new
10
- @results = {}
11
- @threads = {}
12
- end
13
-
14
- def started(result)
15
- @results[result.uuid] = result
16
-
17
- update(result.uuid)
18
- end
19
-
20
- def chunk(result)
21
- update_on_interval(result.uuid)
22
- end
23
-
24
- def finished(result)
25
- # kill off the interval updater
26
- thread = @threads[result.uuid]
27
- thread.kill if thread && thread.alive?
28
-
29
- update(result.uuid)
30
- end
31
-
32
- private
33
-
34
- # every INTERVAL seconds, read from the result and update the server with the output.
35
- # if we don't do updates every INTERVAL like this, then we end up spamming the server
36
- # with every chunk we get from the command runner (which ends up being every line), and in the case
37
- # of a bundle install for example, it may have 100 lines, we end up doing 100 updates to the server.
38
- def update_on_interval(uuid)
39
- return if @threads[uuid]
40
-
41
- @threads[uuid] = Thread.new do
42
- loop do
43
- update(uuid)
44
- sleep INTERVAL
45
- end
46
- end
47
-
48
- @threads[uuid].abort_on_exception = true
49
- end
50
-
51
- def update(uuid)
52
- result = @results[uuid]
53
- json = result.as_json
54
- json[:state] = json.delete(:finished) ? 'finished' : 'started'
55
-
56
- @api.update_build_result_async(@build_uuid, json.delete(:uuid), json)
57
- end
58
- end
59
- end
@@ -1,25 +0,0 @@
1
- module Buildbox
2
- class PidFile
3
- def exist?
4
- File.exist?(path)
5
- end
6
-
7
- def path
8
- Buildbox.root_path.join("buildbox.pid")
9
- end
10
-
11
- def pid
12
- File.readlines(path).first.to_i
13
- end
14
-
15
- def save
16
- File.open(path, 'w+') { |file| file.write(Process.pid.to_s) }
17
- end
18
-
19
- def delete
20
- value = pid
21
- File.delete(path)
22
- value
23
- end
24
- end
25
- end
@@ -1,49 +0,0 @@
1
- module Buildbox
2
- class Response
3
- attr_reader :payload
4
-
5
- def initialize(response)
6
- @response = response
7
-
8
- unless success?
9
- raise "API Error: #{@response.code} #{@response.body}"
10
- end
11
-
12
- if json?
13
- json = JSON.parse(@response.body)
14
-
15
- if json.kind_of?(Array)
16
- @payload = json.map { |item| symbolize_keys(item) }
17
- else
18
- @payload = symbolize_keys(json)
19
- end
20
- end
21
- end
22
-
23
- def success?
24
- @response.code.to_i == 200
25
- end
26
-
27
- private
28
-
29
- def json?
30
- @response['content-type'] =~ /json/
31
- end
32
-
33
- def symbolize_keys(hash)
34
- hash.inject({}) do |result, item|
35
- key, value = item
36
- new_key = case key
37
- when String then key.to_sym
38
- else key
39
- end
40
- new_value = case value
41
- when Hash then symbolize_keys(value)
42
- else value
43
- end
44
- result[new_key] = new_value
45
- result
46
- end
47
- end
48
- end
49
- end
@@ -1,36 +0,0 @@
1
- module Buildbox
2
- class Result
3
- require 'securerandom'
4
-
5
- attr_reader :uuid, :command
6
- attr_accessor :output, :finished, :exit_status
7
-
8
- def initialize(command)
9
- @uuid = SecureRandom.uuid
10
- @output = ""
11
- @finished = false
12
- @command = command
13
- end
14
-
15
- def finished?
16
- finished
17
- end
18
-
19
- def success?
20
- exit_status == 0
21
- end
22
-
23
- def as_json
24
- { :uuid => @uuid,
25
- :command => @command,
26
- :output => clean_output,
27
- :exit_status => @exit_status }
28
- end
29
-
30
- private
31
-
32
- def clean_output
33
- Buildbox::UTF8.clean(@output).chomp
34
- end
35
- end
36
- end
@@ -1,66 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Buildbox::Build do
4
- let(:build) { Buildbox::Build.new(:uuid => '1234', :repository => "git@github.com:keithpitt/ci-ruby.git", :commit => "67b15b704e0", :command => "rspec") }
5
-
6
- describe "#start" do
7
- let(:build_path) { double }
8
- let(:root_path) { double(:join => build_path) }
9
- let(:command) { double(:run => true, :run! => true) }
10
-
11
- before do
12
- Buildbox.stub(:root_path => root_path)
13
- Buildbox::Command.stub(:new => command)
14
- end
15
-
16
- context "with a new checkout" do
17
- before do
18
- build_path.stub(:exist? => false, :mkpath => true)
19
- end
20
-
21
- it "creates a directory for the build" do
22
- build_path.should_receive(:mkpath)
23
-
24
- build.start
25
- end
26
-
27
- it "creates a folder for the build" do
28
- root_path.should_receive(:join).with('git-github-com-keithpitt-ci-ruby-git')
29
-
30
- build.start
31
- end
32
-
33
- it "clones the repo" do
34
- command.should_receive(:run!).with(%{git clone "git@github.com:keithpitt/ci-ruby.git" .}).once
35
-
36
- build.start
37
- end
38
- end
39
-
40
- context "with an existing checkout" do
41
- before do
42
- build_path.stub(:exist? => true)
43
- end
44
-
45
- it "doesn't checkout the repo again" do
46
- command.should_not_receive(:run!).with(%{git clone "git@github.com:keithpitt/ci-ruby.git" .})
47
-
48
- build.start
49
- end
50
-
51
- it "cleans, fetches and checks out the commit" do
52
- command.should_receive(:run!).with(%{git clean -fd}).ordered
53
- command.should_receive(:run!).with(%{git fetch}).ordered
54
- command.should_receive(:run!).with(%{git checkout -qf "67b15b704e0"}).ordered
55
-
56
- build.start
57
- end
58
-
59
- it "runs the command" do
60
- command.should_receive(:run).with(%{rspec})
61
-
62
- build.start
63
- end
64
- end
65
- end
66
- end
@@ -1,9 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Buildbox::Configuration do
4
- subject(:configuration) { Buildbox::Configuration.new }
5
-
6
- it "has a default endpoint" do
7
- configuration.endpoint.should =~ /buildbox/
8
- end
9
- end
@@ -1,4 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Buildbox do
4
- end
@@ -1,3 +0,0 @@
1
- require 'dotenv'
2
-
3
- Dotenv.load