is_it_done_yet 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1778acaba096d60e74ad95e7fae02e11a0a8cec0
4
- data.tar.gz: 1fa88b4da2deae3f11f31765d86c7478ef2a6108
3
+ metadata.gz: acd12c54ad56816b78a4dce97b4959ca75f13392
4
+ data.tar.gz: 61d989bd6096d96b479d17b0823d360d8e374824
5
5
  SHA512:
6
- metadata.gz: 0a14bcf35ad70e435d7a817a7a6f8f05b2292f82f5fc385135ac69778a0509940175222f9880f1fc403541b077bd13757edca2db19ae94860726e31dd71b58bb
7
- data.tar.gz: 1ef23febcd56156d6c72ec677f661da926102d6e9043e9f1ae3912ef53ce1a19deeb16b98af72648530e0954706a273f76efedd064b89e62356032e468793274
6
+ metadata.gz: 5e90bcdbe755b2430d43f1e3f9e4579e5ed262beeeb7eb0179aa0dad1531c6683a8ecbfc6cf8d56fdb286e2d451e176e7759cca98910a933147ccd41c82d8cb1
7
+ data.tar.gz: a13eb75011f38fe0492df830e8f7a7a5a3d0c8cbc9816c08c7bfb548acb35a79a847454c1bd7acc68a4a755bf3c5817799dce0225af87a78151d0e75dbc41ba3
data/.gitignore CHANGED
@@ -11,3 +11,4 @@
11
11
  # rspec failure tracking
12
12
  .rspec_status
13
13
  *.gem
14
+ .byebug_history
data/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ # 0.3.0
2
+
3
+ Features:
4
+
5
+ * Clear state for a build using `DELETE /builds/:build_id`. Useful when a CI build is restarted.
6
+
7
+ Bug fixes:
8
+
9
+ * Posting now adheres to standard REST conventions; returns 201 with no body if successful and 409 if the node already exists.
10
+
11
+
1
12
  # 0.2.0
2
13
 
3
14
  Features:
data/Rakefile CHANGED
@@ -1,10 +1,9 @@
1
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
3
  require 'knapsack'
4
4
 
5
-
6
5
  RSpec::Core::RakeTask.new(:spec)
7
6
 
8
- task :default => :spec
7
+ task default: :spec
9
8
 
10
9
  Knapsack.load_tasks if defined?(Knapsack)
data/bin/console CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require "bundler/setup"
4
- require "is_it_done_yet"
3
+ require 'bundler/setup'
4
+ require 'is_it_done_yet'
5
5
 
6
6
  # You can add fixtures and/or initialization code here to make experimenting
7
7
  # with your gem easier. You can also use a different console, if you like.
@@ -10,5 +10,5 @@ require "is_it_done_yet"
10
10
  # require "pry"
11
11
  # Pry.start
12
12
 
13
- require "irb"
13
+ require 'irb'
14
14
  IRB.start(__FILE__)
data/examples/ci-clear ADDED
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Script that clears build status of
4
+ # travis nodes from synchronising service
5
+
6
+ require 'net/http'
7
+ require 'uri'
8
+ require 'json'
9
+
10
+ SLEEP_TIME_SECONDS = 30
11
+
12
+ env_ok = ENV['CI_NODE_INDEX'] &&
13
+ ENV['CI_NODE_TOTAL'] &&
14
+ ENV['IIDY_ENDPOINT'] &&
15
+ ENV['TRAVIS_BUILD_NUMBER'] &&
16
+ ENV['TRAVIS_JOB_NUMBER'] &&
17
+ ENV['IIDY_TOKEN']
18
+
19
+ abort 'Bad env' unless env_ok
20
+
21
+ main_node = ENV['CI_NODE_INDEX'] == '0'
22
+ auth_token = "Token token=\"#{ENV['IIDY_TOKEN']}\""
23
+
24
+ if main_node
25
+ build_id = "is_it_done_yet--#{ENV['TRAVIS_BUILD_NUMBER']}"
26
+
27
+ url = ENV['IIDY_ENDPOINT'] + "/builds/#{build_id}"
28
+
29
+ puts "URL: #{url}"
30
+
31
+ uri = URI(url)
32
+
33
+ request = Net::HTTP::Delete.new(uri)
34
+ request['Authorization'] = auth_token
35
+
36
+ response = Net::HTTP.start(
37
+ uri.hostname,
38
+ uri.port,
39
+ use_ssl: uri.scheme == 'https'
40
+ ) { |http| http.request(request) }
41
+
42
+ abort 'Failed to clear results' unless response.code == '204'
43
+ puts 'Successfully cleared results!'
44
+ else
45
+ puts 'Not main node!'
46
+ end
data/examples/ci-post CHANGED
@@ -46,5 +46,5 @@ else
46
46
  use_ssl: uri.scheme == 'https'
47
47
  ) { |http| http.request(request) }
48
48
 
49
- abort "Failed to post build status: #{response.code}" unless response.code == '200'
49
+ abort "Failed to post build status: #{response.code}" unless response.code == '201'
50
50
  end
data/examples/ci-sync CHANGED
@@ -8,7 +8,7 @@ require 'net/http'
8
8
  require 'uri'
9
9
  require 'json'
10
10
 
11
- OK_STATES = %w(OK GOOD).freeze
11
+ OK_STATES = %w[OK GOOD].freeze
12
12
  SLEEP_TIME_SECONDS = 30
13
13
 
14
14
  env_ok = ENV['CI_NODE_INDEX'] &&
@@ -52,13 +52,17 @@ if main_node
52
52
  use_ssl: uri.scheme == 'https'
53
53
  ) { |http| http.request(request) }
54
54
 
55
- next unless response.code == '200'
55
+ unless response.code == '200'
56
+ sleep SLEEP_TIME_SECONDS
57
+ next
58
+ end
59
+
56
60
  build_states = JSON.parse(response.body)['build_states']
57
61
 
58
62
  if build_states.size < expected_size
59
63
  puts "Some nodes have not reported in yet, \
60
- found #{build_states.size}, \
61
- expected #{expected_size}, waiting a bit"
64
+ found #{build_states.size}, \
65
+ expected #{expected_size}, waiting a bit"
62
66
  sleep SLEEP_TIME_SECONDS
63
67
  next
64
68
  end
data/examples/config.ru CHANGED
@@ -4,8 +4,14 @@ require 'rack/token_auth'
4
4
  require 'is_it_done_yet'
5
5
  Bundler.require
6
6
 
7
- use Rack::TokenAuth do |token, options, env|
7
+ # Shared secret authentication
8
+ use Rack::TokenAuth do |token, _options, _env|
8
9
  token == ENV['IIDY_TOKEN']
9
10
  end
10
11
 
12
+ # Heartbeat endpoint
13
+ map '/health_check' do
14
+ run ->(_env) { [200, { 'Content-Type' => 'text/plain' }, ['success']] }
15
+ end
16
+
11
17
  run IsItDoneYet.build_app
@@ -1,4 +1,5 @@
1
1
  # coding: utf-8
2
+
2
3
  lib = File.expand_path('../lib', __FILE__)
3
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
5
  require 'is_it_done_yet/version'
@@ -46,4 +47,5 @@ Gem::Specification.new do |spec|
46
47
  spec.add_development_dependency 'rspec', '~> 3.0'
47
48
  spec.add_development_dependency 'rack-test', '~> 0.6'
48
49
  spec.add_development_dependency 'knapsack', '~> 1.13'
50
+ spec.add_development_dependency 'byebug', '~> 9'
49
51
  end
@@ -1,96 +1,9 @@
1
1
  require 'is_it_done_yet/version'
2
- require 'sinatra'
3
- require 'concurrent'
4
- require 'json'
5
- require 'time'
2
+ require 'is_it_done_yet/web_app'
6
3
  require 'rack/contrib'
4
+ require 'rack'
7
5
 
8
6
  module IsItDoneYet
9
- class WebApp < ::Sinatra::Base
10
- UNKNOWN_NODE = { errors: ['Unknown Node'] }.to_json
11
- UNKNOWN_BUILD = { errors: ['Unknown Build'] }.to_json
12
- NO_BUILD_STATE = { errors: ['You forgot build state'] }.to_json
13
- TTL_SECONDS = 24 * 60 * 60
14
-
15
- configure do
16
- set :state, ::Concurrent::Map.new
17
- end
18
-
19
- helpers do
20
- private
21
-
22
- def key(build_id, node_id)
23
- [build_id, node_id].freeze
24
- end
25
-
26
- def house_keeping
27
- expired_keys =
28
- settings.state.each_pair.with_object([]) do |(key, (_b, time)), acc|
29
- acc << key if time < Time.now - TTL_SECONDS
30
- end
31
-
32
- expired_keys.each { |key| settings.state.delete(key) }
33
- end
34
-
35
- def store(key, value)
36
- settings.state[key] = [value, Time.now]
37
- end
38
-
39
- def retrieve(key)
40
- build_state, _t = settings.state[key]
41
- build_state
42
- end
43
-
44
- def retrieve_all(build_id)
45
- settings.state
46
- .each_pair
47
- .select { |((b, _n), _v)| build_id == b }
48
- .map { |((_b, node_id), (build_state, _t))| [node_id, build_state] }
49
- .to_h
50
- end
51
- end
52
-
53
- before do
54
- house_keeping
55
-
56
- content_type :json
57
- end
58
-
59
- get '/builds/:build_id/nodes/:node_id' do
60
- build_id, node_id = params.values_at('build_id', 'node_id')
61
- k = key(build_id, node_id)
62
-
63
- build_state = retrieve(k)
64
-
65
- halt 404, UNKNOWN_NODE unless build_state
66
-
67
- content_type :json
68
- { build_state: build_state }.to_json
69
- end
70
-
71
- get '/builds/:build_id' do
72
- build_id = params['build_id']
73
-
74
- build_states = retrieve_all(build_id)
75
-
76
- halt 404, UNKNOWN_BUILD if build_states.to_a.empty?
77
-
78
- content_type :json
79
- { build_states: build_states }.to_json
80
- end
81
-
82
- post '/builds/:build_id/nodes/:node_id' do
83
- build_state = params['build_state']
84
- halt 400, NO_BUILD_STATE unless build_state
85
-
86
- build_id, node_id = params.values_at('build_id', 'node_id')
87
- k = key(build_id, node_id)
88
- store(k, build_state)
89
-
90
- 200
91
- end
92
- end
93
-
94
7
  def self.build_app
95
8
  Rack::Builder.app do
96
9
  use Rack::PostBodyContentTypeParser
@@ -1,3 +1,3 @@
1
1
  module IsItDoneYet
2
- VERSION = "0.2.0"
2
+ VERSION = '0.3.0'.freeze
3
3
  end
@@ -0,0 +1,108 @@
1
+ require 'is_it_done_yet/version'
2
+ require 'sinatra'
3
+ require 'concurrent'
4
+ require 'json'
5
+ require 'time'
6
+ require 'rack/contrib'
7
+
8
+ module IsItDoneYet
9
+ class WebApp < ::Sinatra::Base
10
+ UNKNOWN_NODE = { errors: ['Unknown Node'] }.to_json
11
+ ALREADY_EXISTS = { errors: ['Node already exists'] }.to_json
12
+ UNKNOWN_BUILD = { errors: ['Unknown Build'] }.to_json
13
+ NO_BUILD_STATE = { errors: ['You forgot build state'] }.to_json
14
+ TTL_SECONDS = 24 * 60 * 60
15
+
16
+ configure do
17
+ set :state, ::Concurrent::Map.new
18
+ end
19
+
20
+ helpers do
21
+ private
22
+
23
+ def key(build_id, node_id)
24
+ [build_id, node_id].freeze
25
+ end
26
+
27
+ def house_keeping
28
+ expired_keys =
29
+ settings.state.each_pair.with_object([]) do |(key, (_b, time)), acc|
30
+ acc << key if time < Time.now - TTL_SECONDS
31
+ end
32
+
33
+ expired_keys.each { |key| settings.state.delete(key) }
34
+ end
35
+
36
+ def store(key, value)
37
+ settings.state[key] = [value, Time.now]
38
+ end
39
+
40
+ def retrieve(key)
41
+ build_state, _t = settings.state[key]
42
+ build_state
43
+ end
44
+
45
+ def retrieve_all(build_id)
46
+ settings.state
47
+ .each_pair
48
+ .select { |((b, _n), _v)| build_id == b }
49
+ .map { |((_b, node_id), (build_state, _t))| [node_id, build_state] }
50
+ .to_h
51
+ end
52
+
53
+ def clear_nodes(build_id)
54
+ state = settings.state
55
+ keys_for_build = state.keys.select { |(b, _n)| b == build_id }
56
+ keys_for_build.each { |key| state.delete(key) }
57
+ end
58
+ end
59
+
60
+ before do
61
+ house_keeping
62
+
63
+ content_type :json
64
+ end
65
+
66
+ get '/builds/:build_id/nodes/:node_id' do
67
+ build_id, node_id = params.values_at('build_id', 'node_id')
68
+ k = key(build_id, node_id)
69
+
70
+ build_state = retrieve(k)
71
+
72
+ halt 404, UNKNOWN_NODE unless build_state
73
+
74
+ { build_state: build_state }.to_json
75
+ end
76
+
77
+ get '/builds/:build_id' do
78
+ build_id = params['build_id']
79
+
80
+ build_states = retrieve_all(build_id)
81
+
82
+ halt 404, UNKNOWN_BUILD if build_states.to_a.empty?
83
+
84
+ { build_states: build_states }.to_json
85
+ end
86
+
87
+ delete '/builds/:build_id' do
88
+ build_id = params['build_id']
89
+
90
+ clear_nodes(build_id)
91
+
92
+ 204
93
+ end
94
+
95
+ post '/builds/:build_id/nodes/:node_id' do
96
+ build_state = params['build_state']
97
+ halt 400, NO_BUILD_STATE unless build_state
98
+
99
+ build_id, node_id = params.values_at('build_id', 'node_id')
100
+ k = key(build_id, node_id)
101
+ halt 409, ALREADY_EXISTS if retrieve(k)
102
+
103
+ store(k, build_state)
104
+
105
+ 201
106
+ end
107
+ end
108
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: is_it_done_yet
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Erik Madsen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-04-23 00:00:00.000000000 Z
11
+ date: 2017-04-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -164,6 +164,20 @@ dependencies:
164
164
  - - "~>"
165
165
  - !ruby/object:Gem::Version
166
166
  version: '1.13'
167
+ - !ruby/object:Gem::Dependency
168
+ name: byebug
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - "~>"
172
+ - !ruby/object:Gem::Version
173
+ version: '9'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - "~>"
179
+ - !ruby/object:Gem::Version
180
+ version: '9'
167
181
  description: In case you need to carry out build steps in one of the nodes of your
168
182
  CI project after the other nodes finish, e.g. deploying, then you need a way of
169
183
  ascertaining the status of the other nodes. This is what is_it_done_yet is for.
@@ -183,6 +197,7 @@ files:
183
197
  - Rakefile
184
198
  - bin/console
185
199
  - bin/setup
200
+ - examples/ci-clear
186
201
  - examples/ci-deploy
187
202
  - examples/ci-post
188
203
  - examples/ci-sync
@@ -190,6 +205,7 @@ files:
190
205
  - is_it_done_yet.gemspec
191
206
  - lib/is_it_done_yet.rb
192
207
  - lib/is_it_done_yet/version.rb
208
+ - lib/is_it_done_yet/web_app.rb
193
209
  homepage: http://www.github.com/beatmadsen/is_it_done_yet
194
210
  licenses:
195
211
  - MIT