buildbox 0.0.4 → 0.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,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