buildbox 0.0.2 → 0.0.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 50ef87e918e385b0169d8bc601aa29f94c6a7dbf
4
- data.tar.gz: 8aeb7524a9a4df2b8f74fb80bcff2d6669d4b380
3
+ metadata.gz: eb5d520609a7709bb39f3101371b189843a1529f
4
+ data.tar.gz: 17c6f844295770f5db6e0ed00b8d96d9780ebbe6
5
5
  SHA512:
6
- metadata.gz: 6c46f041eeb2929692d1f4a90d8a931cc10f9de14dab779b116737e4a2553d9d2f4159e36d71d332253269ee46a4649f6919113529d42fcb750e389c7b9e4de0
7
- data.tar.gz: a3903b0189b3907b5ccea550ef619cb2f2ba7a40a27a5975c18c62b395c4f82493dc1ecb7cf372c60f11db344ca95cd13a79aaba01802675f57313533d1d4da2
6
+ metadata.gz: 71082a07bf307f1a53d1e294f2a84ebcbb0882a9194a289a35ee13b9ca1ebc69efd04f38428e63f5498008008346725e634b124a228b10f9602beae602814772
7
+ data.tar.gz: 0e2ad6bca3ac9228d49d3e09d5e012644839281bef5d4c18980e484156ce42aa73a8194f437e088cccffa8542d5dd71e15b853b7b489ce81610dd468cdbb91b9
@@ -0,0 +1,2 @@
1
+ [build]
2
+ commands = [ "bundle", "rspec" ]
data/README.md CHANGED
@@ -12,7 +12,7 @@ Then authenticate
12
12
 
13
13
  Then you can start monitoring for builds like so:
14
14
 
15
- $ buildbox monitor:start
15
+ $ buildbox monitor:start --daemon
16
16
 
17
17
  For more help with the command line interface
18
18
 
@@ -5,7 +5,7 @@ require "buildbox/build"
5
5
  require "buildbox/version"
6
6
  require "buildbox/client"
7
7
  require "buildbox/api"
8
- require "buildbox/worker"
8
+ require "buildbox/queue"
9
9
  require "buildbox/pid_file"
10
10
  require "buildbox/configuration"
11
11
  require "buildbox/auth"
@@ -6,6 +6,7 @@ module Buildbox
6
6
 
7
7
  def initialize(options)
8
8
  @options = options
9
+ @queue = ::Queue.new
9
10
  end
10
11
 
11
12
  def crash(exception, information = {})
@@ -20,27 +21,56 @@ module Buildbox
20
21
  payload[:meta][:build_uuid] = information[:build] if information[:build]
21
22
  payload[:meta][:client_version] = Buildbox::VERSION
22
23
 
23
- request(:post, "crashes", :crash => payload)
24
+ request(:post, "crashes", payload)
24
25
  end
25
26
 
26
27
  def register(payload)
27
- request(:post, "workers", :worker => payload)
28
+ request(:post, "workers", payload)
28
29
  end
29
30
 
30
31
  def login
31
32
  request(:get, "user")
32
33
  end
33
34
 
34
- def update(build, payload)
35
- request(:put, "workers/#{worker_uuid}/builds/#{build.uuid}", :build => payload)
36
- end
37
-
38
35
  def builds(options = {})
39
36
  request(:get, "workers/#{worker_uuid}/builds")
40
37
  end
41
38
 
39
+ def update_build_state_async(*args)
40
+ async :update_build_state, args
41
+ end
42
+
43
+ def update_build_state(build_uuid, state)
44
+ request(:put, "workers/#{worker_uuid}/builds/#{build_uuid}", :state => state)
45
+ end
46
+
47
+ def update_build_result_async(*args)
48
+ async :update_build_result, args
49
+ end
50
+
51
+ def update_build_result(build_uuid, result_uuid, attributes)
52
+ request(:put, "workers/#{worker_uuid}/builds/#{build_uuid}/results/#{result_uuid}", attributes)
53
+ end
54
+
42
55
  private
43
56
 
57
+ def async(method, args)
58
+ @queue << [ method, args ]
59
+
60
+ if !@thread || !@thread.alive?
61
+ @thread = Thread.new do
62
+ loop do
63
+ async_call = @queue.pop
64
+ Thread.exit if async_call.nil?
65
+
66
+ self.send(async_call[0], *async_call[1])
67
+ end
68
+ end
69
+
70
+ @thread.abort_on_exception = true
71
+ end
72
+ end
73
+
44
74
  def http(uri)
45
75
  Net::HTTP.new(uri.host, uri.port).tap do |http|
46
76
  http.use_ssl = uri.scheme == "https"
@@ -57,15 +87,14 @@ module Buildbox
57
87
  end
58
88
 
59
89
  uri = URI.parse(endpoint(path))
60
- request = klass.new(uri.request_uri)
90
+ request = klass.new(uri.request_uri, 'Content-Type' => 'application/json',
91
+ 'Accept' => 'application/json')
61
92
 
62
93
  if payload.nil?
63
94
  Buildbox.logger.debug "#{method.to_s.upcase} #{uri}"
64
95
  else
65
- normalized_payload = normalize_payload(payload)
66
- request.set_form_data normalized_payload
67
-
68
- Buildbox.logger.debug "#{method.to_s.upcase} #{uri} #{normalized_payload.inspect}"
96
+ request.body = JSON.dump(payload)
97
+ Buildbox.logger.debug "#{method.to_s.upcase} #{uri} #{payload.inspect}"
69
98
  end
70
99
 
71
100
  Response.new http(uri).request(request)
@@ -79,37 +108,5 @@ module Buildbox
79
108
  (Buildbox.configuration.use_ssl ? "https://" : "http://") +
80
109
  "#{Buildbox.configuration.endpoint}/v#{Buildbox.configuration.api_version}/#{path}"
81
110
  end
82
-
83
- # { :foo => { :bar => { :bang => "yolo" } } } => { "foo[bar][bang]" => "yolo" }
84
- def normalize_payload(params, key=nil)
85
- params = flatten_keys(params) if params.is_a?(Hash)
86
- result = {}
87
- params.each do |k,v|
88
- case v
89
- when Hash
90
- result[k.to_s] = normalize_params(v)
91
- when Array
92
- v.each_with_index do |val,i|
93
- result["#{k.to_s}[#{i}]"] = val.to_s
94
- end
95
- else
96
- result[k.to_s] = v.to_s
97
- end
98
- end
99
- result
100
- end
101
-
102
- def flatten_keys(hash, newhash={}, keys=nil)
103
- hash.each do |k, v|
104
- k = k.to_s
105
- keys2 = keys ? keys+"[#{k}]" : k
106
- if v.is_a?(Hash)
107
- flatten_keys(v, newhash, keys2)
108
- else
109
- newhash[keys2] = v
110
- end
111
- end
112
- newhash
113
- end
114
111
  end
115
112
  end
@@ -6,44 +6,61 @@ module Buildbox
6
6
  @uuid = options[:uuid]
7
7
  @repository = options[:repository]
8
8
  @commit = options[:commit]
9
- @command = options[:command] || "bundle && rspec"
9
+ @config = options[:config]
10
10
  end
11
11
 
12
12
  def start(&block)
13
- checkout
14
- update
13
+ @block = block
15
14
 
16
- @result = command.run(@command) do |chunk|
17
- yield(chunk) if block_given?
15
+ unless build_path.exist?
16
+ setup_build_path
17
+ clone_repository
18
18
  end
19
+
20
+ fetch_and_checkout
21
+ build
22
+
23
+ true
19
24
  end
20
25
 
21
26
  private
22
27
 
23
- def checkout
24
- unless build_path.exist?
25
- build_path.mkpath
28
+ def setup_build_path
29
+ run %{mkdir -p "#{build_path}"}
30
+ end
26
31
 
27
- command.run! %{git clone "#{@repository}" .}
28
- end
32
+ def clone_repository
33
+ run %{git clone "#{@repository}" . -q}
29
34
  end
30
35
 
31
- def update
32
- command.run! %{git clean -fd}
33
- command.run! %{git fetch}
34
- command.run! %{git checkout -qf "#{@commit}"}
36
+ def fetch_and_checkout
37
+ run %{git clean -fd}
38
+ run %{git fetch}
39
+ run %{git checkout -qf "#{@commit}"}
35
40
  end
36
41
 
37
- def build_path
38
- Buildbox.root_path.join folder_name
42
+ def build
43
+ @config[:build][:commands].each { |command| run command }
39
44
  end
40
45
 
41
46
  def folder_name
42
47
  @repository.gsub(/[^a-zA-Z0-9]/, '-')
43
48
  end
44
49
 
45
- def command
46
- Buildbox::Command.new(build_path)
50
+ def build_path
51
+ Buildbox.root_path.join folder_name
52
+ end
53
+
54
+ def run(command)
55
+ path = build_path if build_path.exist?
56
+
57
+ result = Buildbox::Command.new(path).run(command) do |result, chunk|
58
+ @block.call(result)
59
+ end
60
+
61
+ @block.call(result)
62
+
63
+ result
47
64
  end
48
65
  end
49
66
  end
@@ -18,11 +18,14 @@ module Buildbox
18
18
 
19
19
  loop do
20
20
  reload_configuration
21
- process_build_queue
21
+ Buildbox::Queue.new.process
22
22
  wait_for_interval
23
23
  end
24
24
  rescue => e
25
- api.crash(e, :build => @build)
25
+ Buildbox.logger.error "#{e.class.name}: #{e.message}"
26
+ e.backtrace.each { |line| Buildbox.logger.error line }
27
+
28
+ api.crash(e)
26
29
  ensure
27
30
  pid_file.delete
28
31
  end
@@ -51,18 +54,6 @@ module Buildbox
51
54
  Buildbox.configuration.update :worker_uuid, response.payload[:uuid]
52
55
  end
53
56
 
54
- def process_build_queue
55
- scheduled = api.builds.payload.first
56
-
57
- if scheduled
58
- # store build in an instance variable so we can report on it in
59
- # the event of a crash
60
- @build = Build.new(scheduled)
61
- Buildbox::Worker.new(@build, api).run
62
- @build = nil
63
- end
64
- end
65
-
66
57
  def reload_configuration
67
58
  Buildbox.configuration.reload
68
59
  end
@@ -81,6 +72,9 @@ module Buildbox
81
72
  end
82
73
  end
83
74
 
75
+ def worker
76
+ end
77
+
84
78
  def api
85
79
  @api ||= Buildbox::API.new(:api_key => Buildbox.configuration.api_key)
86
80
  end
@@ -12,8 +12,8 @@ module Buildbox
12
12
  def run(command)
13
13
  Buildbox.logger.debug(command)
14
14
 
15
- output = ""
16
15
  read_io, write_io, pid = nil
16
+ result = Buildbox::Result.new(command)
17
17
 
18
18
  begin
19
19
  dir = File.expand_path(@path)
@@ -33,9 +33,9 @@ module Buildbox
33
33
  begin
34
34
  chunk = read_io.read_nonblock(10240)
35
35
  if block_given?
36
- yield chunk
36
+ yield result, chunk
37
37
  end
38
- output += chunk
38
+ result.output += chunk
39
39
  rescue Errno::EAGAIN, Errno::EWOULDBLOCK
40
40
  # do select again
41
41
  rescue EOFError, Errno::EIO # EOFError from OSX, EIO is raised by ubuntu
@@ -49,9 +49,10 @@ module Buildbox
49
49
  Process.waitpid(pid)
50
50
 
51
51
  # output may be invalid UTF-8, as it is produced by the build command.
52
- output = Buildbox::UTF8.clean(output)
52
+ result.finished = true
53
+ result.exit_status = $?.exitstatus
53
54
 
54
- Buildbox::Result.new(output.chomp, $?.exitstatus)
55
+ result
55
56
  end
56
57
 
57
58
  def run!(command)
@@ -13,7 +13,7 @@ module Buildbox
13
13
  attr_accessor :api_version
14
14
 
15
15
  def initialize
16
- @use_ssl = false
16
+ @use_ssl = true
17
17
  @endpoint = 'api.buildbox.io'
18
18
  @api_version = 1
19
19
  end
@@ -0,0 +1,28 @@
1
+ module Buildbox
2
+ class Queue
3
+ def process
4
+ if scheduled = api.builds.payload.first
5
+ start Build.new(scheduled)
6
+ end
7
+ end
8
+
9
+ private
10
+
11
+ def start(build)
12
+ api.update_build_state(build.uuid, 'started')
13
+
14
+ build.start do |result|
15
+ json = result.as_json
16
+ json[:state] = json.delete(:finished) ? 'finished' : 'started'
17
+
18
+ api.update_build_result_async(build.uuid, json.delete(:uuid), json)
19
+ end
20
+
21
+ api.update_build_state_async(build.uuid, 'finished')
22
+ end
23
+
24
+ def api
25
+ @api ||= Buildbox::API.new(:api_key => Buildbox.configuration.api_key)
26
+ end
27
+ end
28
+ end
@@ -1,7 +1,36 @@
1
1
  module Buildbox
2
- class Result < Struct.new(:output, :exit_status)
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
+
3
19
  def success?
4
20
  exit_status == 0
5
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
6
35
  end
7
36
  end
@@ -46,5 +46,22 @@ module Buildbox
46
46
  end
47
47
  raise CannotFindEncoding, 'Cannot find an intermediate encoding for conversion to UTF-8'
48
48
  end
49
+
50
+ def self.clean_utf8_iconv
51
+ unless @iconv_loaded
52
+ begin
53
+ require 'iconv'
54
+ rescue LoadError
55
+ @iconv = nil
56
+ else
57
+ @iconv = Iconv.new('utf-8//translit//ignore', 'utf-8')
58
+ # On some systems (Linux appears to be vulnerable, FreeBSD not)
59
+ # iconv chokes on invalid utf-8 with //translit//ignore.
60
+ @iconv_fallback = Iconv.new('utf-8//ignore', 'utf-8')
61
+ end
62
+ @iconv_loaded = true
63
+ end
64
+ [@iconv, @iconv_fallback]
65
+ end
49
66
  end
50
67
  end
@@ -1,3 +1,3 @@
1
1
  module Buildbox
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Buildbox::Build do
4
- let(:build) { Buildbox::Build.new(:uuid => '1234', :repo => "git@github.com:keithpitt/ci-ruby.git", :commit => "67b15b704e0", :command => "rspec") }
4
+ let(:build) { Buildbox::Build.new(:uuid => '1234', :repository => "git@github.com:keithpitt/ci-ruby.git", :commit => "67b15b704e0", :command => "rspec") }
5
5
 
6
6
  describe "#start" do
7
7
  let(:build_path) { double }
@@ -39,7 +39,7 @@ describe Buildbox::Command do
39
39
 
40
40
  it "can collect output in chunks" do
41
41
  chunked_output = ''
42
- result = command.run('echo hello world') do |chunk|
42
+ result = command.run('echo hello world') do |result, chunk|
43
43
  chunked_output += chunk
44
44
  end
45
45
 
@@ -52,7 +52,7 @@ describe Buildbox::Command do
52
52
  command = Buildbox::Command.new(nil, 0.1)
53
53
 
54
54
  chunked_output = ''
55
- result = command.run('sleep 0.5; echo hello world') do |chunk|
55
+ result = command.run('sleep 0.5; echo hello world') do |result, chunk|
56
56
  chunked_output += chunk
57
57
  end
58
58
 
@@ -61,11 +61,13 @@ describe Buildbox::Command do
61
61
  chunked_output.should == "hello world\r\n"
62
62
  end
63
63
 
64
+ it 'passes a result object to the block'
65
+
64
66
  it "can collect chunks from within a thread" do
65
67
  chunked_output = ''
66
68
  result = nil
67
69
  worker_thread = Thread.new do
68
- result = command.run('echo before sleep; sleep 1; echo after sleep') do |chunk|
70
+ result = command.run('echo before sleep; sleep 1; echo after sleep') do |result, chunk|
69
71
  chunked_output += chunk
70
72
  end
71
73
  end
@@ -103,7 +105,7 @@ describe Buildbox::Command do
103
105
 
104
106
  it "captures color'd output" do
105
107
  chunked_output = ''
106
- result = command.run("rspec #{FIXTURES_PATH.join('rspec', 'test_spec.rb')} --color") do |chunk|
108
+ result = command.run("rspec #{FIXTURES_PATH.join('rspec', 'test_spec.rb')} --color") do |result, chunk|
107
109
  chunked_output += chunk
108
110
  end
109
111
 
@@ -4,6 +4,6 @@ describe Buildbox::Configuration do
4
4
  subject(:configuration) { Buildbox::Configuration.new }
5
5
 
6
6
  it "has a default endpoint" do
7
- configuration.endpoint.should =~ /buildboxci/
7
+ configuration.endpoint.should =~ /buildbox/
8
8
  end
9
9
  end
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
  describe 'running a build' do
4
4
  let(:commit) { "3e0c65433b241ff2c59220f80bcdcd2ebb7e4b96" }
5
5
  let(:command) { "rspec test_spec.rb" }
6
- let(:build) { Buildbox::Build.new(:project_id => 1, :build_id => 1, :repo => FIXTURES_PATH.join("repo.git").to_s, :commit => commit, :command => command) }
6
+ let(:build) { Buildbox::Build.new(:project_id => 1, :build_id => 1, :repository => FIXTURES_PATH.join("repo.git").to_s, :commit => commit, :command => command) }
7
7
 
8
8
  before do
9
9
  Buildbox.stub(:root_path).and_return(TEMP_PATH)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: buildbox
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Keith Pitt
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-06-11 00:00:00.000000000 Z
11
+ date: 2013-06-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -74,6 +74,7 @@ executables:
74
74
  extensions: []
75
75
  extra_rdoc_files: []
76
76
  files:
77
+ - .buildbox.toml
77
78
  - .gitignore
78
79
  - .rspec
79
80
  - Gemfile
@@ -90,11 +91,11 @@ files:
90
91
  - lib/buildbox/command.rb
91
92
  - lib/buildbox/configuration.rb
92
93
  - lib/buildbox/pid_file.rb
94
+ - lib/buildbox/queue.rb
93
95
  - lib/buildbox/response.rb
94
96
  - lib/buildbox/result.rb
95
97
  - lib/buildbox/utf8.rb
96
98
  - lib/buildbox/version.rb
97
- - lib/buildbox/worker.rb
98
99
  - spec/buildbox/buildbox/build_spec.rb
99
100
  - spec/buildbox/buildbox/command_spec.rb
100
101
  - spec/buildbox/buildbox/configuration_spec.rb
@@ -1,25 +0,0 @@
1
- module Buildbox
2
- class Worker
3
- def initialize(build, api)
4
- @build = build
5
- @api = api
6
- end
7
-
8
- def run
9
- update(:started_at => Time.now)
10
-
11
- chunks = ""
12
- result = @build.start do |chunk|
13
- update(:output => chunks += chunk)
14
- end
15
-
16
- update(:exit_status => result.exit_status, :output => result.output, :finished_at => Time.now)
17
- end
18
-
19
- private
20
-
21
- def update(data)
22
- @api.update(@build, data)
23
- end
24
- end
25
- end