is_it_done_yet 0.2.0 → 0.3.0
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 +4 -4
- data/.gitignore +1 -0
- data/CHANGELOG.md +11 -0
- data/Rakefile +3 -4
- data/bin/console +3 -3
- data/examples/ci-clear +46 -0
- data/examples/ci-post +1 -1
- data/examples/ci-sync +8 -4
- data/examples/config.ru +7 -1
- data/is_it_done_yet.gemspec +2 -0
- data/lib/is_it_done_yet.rb +2 -89
- data/lib/is_it_done_yet/version.rb +1 -1
- data/lib/is_it_done_yet/web_app.rb +108 -0
- metadata +18 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: acd12c54ad56816b78a4dce97b4959ca75f13392
|
4
|
+
data.tar.gz: 61d989bd6096d96b479d17b0823d360d8e374824
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5e90bcdbe755b2430d43f1e3f9e4579e5ed262beeeb7eb0179aa0dad1531c6683a8ecbfc6cf8d56fdb286e2d451e176e7759cca98910a933147ccd41c82d8cb1
|
7
|
+
data.tar.gz: a13eb75011f38fe0492df830e8f7a7a5a3d0c8cbc9816c08c7bfb548acb35a79a847454c1bd7acc68a4a755bf3c5817799dce0225af87a78151d0e75dbc41ba3
|
data/.gitignore
CHANGED
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
|
2
|
-
require
|
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 :
|
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
|
4
|
-
require
|
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
|
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
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
|
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
|
-
|
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
|
-
|
61
|
-
|
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
|
-
|
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
|
data/is_it_done_yet.gemspec
CHANGED
@@ -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
|
data/lib/is_it_done_yet.rb
CHANGED
@@ -1,96 +1,9 @@
|
|
1
1
|
require 'is_it_done_yet/version'
|
2
|
-
require '
|
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
|
@@ -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.
|
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-
|
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
|