evrone-ci-router 0.2.0.pre0

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.
Files changed (55) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +7 -0
  3. data/.rspec +3 -0
  4. data/Gemfile +7 -0
  5. data/README.md +1 -0
  6. data/Rakefile +22 -0
  7. data/bin/cli +3 -0
  8. data/bin/git_ssh +3 -0
  9. data/bin/jobs_publisher +12 -0
  10. data/bin/workers +13 -0
  11. data/evrone-ci-router.gemspec +30 -0
  12. data/fixtures/travis.yml +5 -0
  13. data/lib/evrone/ci/router.rb +100 -0
  14. data/lib/evrone/ci/router/build.rb +60 -0
  15. data/lib/evrone/ci/router/build_matrix.rb +89 -0
  16. data/lib/evrone/ci/router/configuration.rb +27 -0
  17. data/lib/evrone/ci/router/consumers/build_logs_consumer.rb +15 -0
  18. data/lib/evrone/ci/router/consumers/build_status_consumer.rb +15 -0
  19. data/lib/evrone/ci/router/consumers/builds_consumer.rb +28 -0
  20. data/lib/evrone/ci/router/consumers/jobs_consumer.rb +15 -0
  21. data/lib/evrone/ci/router/ext/array.rb +5 -0
  22. data/lib/evrone/ci/router/ext/string.rb +9 -0
  23. data/lib/evrone/ci/router/helper/config.rb +13 -0
  24. data/lib/evrone/ci/router/helper/logger.rb +13 -0
  25. data/lib/evrone/ci/router/helper/trace_sh_command.rb +14 -0
  26. data/lib/evrone/ci/router/initializers/amqp.rb +63 -0
  27. data/lib/evrone/ci/router/middleware/create_build_matrix.rb +54 -0
  28. data/lib/evrone/ci/router/middleware/create_dirs.rb +25 -0
  29. data/lib/evrone/ci/router/middleware/fetch_commit_info.rb +22 -0
  30. data/lib/evrone/ci/router/middleware/fetch_source.rb +36 -0
  31. data/lib/evrone/ci/router/middleware/log_build.rb +24 -0
  32. data/lib/evrone/ci/router/middleware/travis/env.rb +21 -0
  33. data/lib/evrone/ci/router/middleware/travis/ruby.rb +55 -0
  34. data/lib/evrone/ci/router/middleware/travis/script.rb +25 -0
  35. data/lib/evrone/ci/router/middleware/update_build_status.rb +75 -0
  36. data/lib/evrone/ci/router/queue.rb +58 -0
  37. data/lib/evrone/ci/router/travis.rb +104 -0
  38. data/lib/evrone/ci/router/travis/serializable.rb +45 -0
  39. data/lib/evrone/ci/router/version.rb +7 -0
  40. data/spec/lib/build_matrix_spec.rb +145 -0
  41. data/spec/lib/build_spec.rb +75 -0
  42. data/spec/lib/configuration_spec.rb +22 -0
  43. data/spec/lib/middleware/create_build_matrix_spec.rb +73 -0
  44. data/spec/lib/middleware/create_dirs_spec.rb +26 -0
  45. data/spec/lib/middleware/fetch_commit_info_spec.rb +23 -0
  46. data/spec/lib/middleware/fetch_source_spec.rb +27 -0
  47. data/spec/lib/middleware/log_build_spec.rb +14 -0
  48. data/spec/lib/middleware/update_build_status_spec.rb +70 -0
  49. data/spec/lib/queue_spec.rb +55 -0
  50. data/spec/lib/travis_spec.rb +182 -0
  51. data/spec/spec_helper.rb +17 -0
  52. data/spec/support/create.rb +47 -0
  53. data/spec/support/fixture.rb +7 -0
  54. data/spec/support/shared_examples/update_build_status_message.rb +5 -0
  55. metadata +228 -0
@@ -0,0 +1,75 @@
1
+ module Evrone
2
+ module CI
3
+ class Router
4
+ module Middleware
5
+
6
+ UpdateBuildStatus = Struct.new(:app) do
7
+
8
+ include Helper::Logger
9
+
10
+ STARTED = 2
11
+ FINISHED = 3
12
+ BROKEN = 4
13
+ FAILED = 5
14
+
15
+ def call(env)
16
+
17
+ update_status env.build, STARTED
18
+ rs = -1
19
+ begin
20
+ rs = app.call env
21
+ rescue Exception => e
22
+ logger.error("ERROR: #{e.inspect}\n BACKTRACE:\n#{e.backtrace.map{|i| " #{i}" }.join("\n")}")
23
+ end
24
+
25
+ case
26
+ when rs == 0
27
+ update_status env.build, FINISHED
28
+ when rs > 0
29
+ update_status env.build, BROKEN
30
+ when rs < 0
31
+ update_status env.build, FAILED
32
+ end
33
+
34
+ rs
35
+ end
36
+
37
+ private
38
+
39
+ def update_status(build, status)
40
+ publish_status create_message(build, status), status
41
+ end
42
+
43
+ def create_message(build, status)
44
+ tm = Time.now
45
+ attributes = {
46
+ build_id: build.message.id,
47
+ status: status,
48
+ tm: tm.to_i,
49
+ tm_usec: tm.usec,
50
+ matrix: build.matrix || [],
51
+ jobs_count: build.jobs_count || 0,
52
+ }
53
+
54
+ if build.commit_info
55
+ attributes.merge!(
56
+ commit_author: build.commit_info.author,
57
+ commit_author_email: build.commit_info.email,
58
+ commit_sha: build.commit_info.sha,
59
+ commit_message: build.commit_info.message
60
+ )
61
+ end
62
+ Message::BuildStatus.new attributes
63
+ end
64
+
65
+ def publish_status(message, status)
66
+ logger.info "delivered build status #{message.inspect}"
67
+ BuildStatusConsumer.publish message
68
+ end
69
+
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+
@@ -0,0 +1,58 @@
1
+ require 'shellwords'
2
+ require 'evrone/ci/common'
3
+
4
+ module Evrone
5
+ module CI
6
+ class Router
7
+ class Queue
8
+
9
+ include Common::Helper::Middlewares
10
+
11
+ middlewares do
12
+ use Middleware::Travis::Env
13
+ use Middleware::Travis::Ruby
14
+ use Middleware::Travis::Script
15
+ end
16
+
17
+ attr_reader :travis
18
+
19
+ def initialize(travis)
20
+ @travis = travis
21
+ end
22
+
23
+ def to_before_script
24
+ a = ["set -e"]
25
+ a += env.init
26
+ a += env.before_install
27
+ a += env.install
28
+ a += env.before_script
29
+ a.join("\n")
30
+ end
31
+
32
+ def to_script
33
+ a = ["set -e"]
34
+ a << env.script
35
+ a.join("\n")
36
+ end
37
+
38
+ private
39
+
40
+ def env
41
+ @env ||= run_middlewares(default_env) {|_| _ }
42
+ end
43
+
44
+ def default_env
45
+ OpenStruct.new(
46
+ init: [],
47
+ before_install: [],
48
+ install: [],
49
+ before_script: [],
50
+ script: [],
51
+ travis: travis
52
+ )
53
+ end
54
+
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,104 @@
1
+ require File.expand_path("../travis/serializable", __FILE__)
2
+
3
+ module Evrone
4
+ module CI
5
+ class Router
6
+ class Travis
7
+
8
+ include Travis::Serializable
9
+
10
+ LANGS = %w{ rvm scala java go }.freeze
11
+ KEYS = %w{ before_script script }.freeze
12
+ AS_ARRAY = (KEYS + LANGS).freeze
13
+
14
+ attr_reader :attributes
15
+ alias_method :to_hash, :attributes
16
+
17
+ def initialize(attrs = {})
18
+ @attributes = normalize_attributes attrs
19
+ end
20
+
21
+ def [](val)
22
+ public_send(val)
23
+ end
24
+
25
+ def matrix_keys
26
+ @matrix_keys ||=
27
+ BuildMatrix::KEYS.inject([]) do |a,k|
28
+ val = send(k)
29
+ unless val.empty?
30
+ a << val.map{|v| "#{k}:#{v}" }
31
+ end
32
+ a
33
+ end.flatten.sort
34
+ end
35
+
36
+ def to_matrix_s
37
+ @to_matrix_s ||= matrix_keys.join(", ")
38
+ end
39
+
40
+ def to_queue
41
+ Queue.new(self)
42
+ end
43
+
44
+ def env
45
+ attributes["env"]["matrix"]
46
+ end
47
+
48
+ def global_env
49
+ attributes["env"]["global"]
50
+ end
51
+
52
+ AS_ARRAY.each do |m|
53
+ define_method m do
54
+ @attributes[m] || []
55
+ end
56
+ end
57
+
58
+ def merge(attrs = {})
59
+ self.class.from_attributes self.attributes.merge(attrs)
60
+ end
61
+
62
+ private
63
+
64
+ def normalize_attributes(attributes)
65
+ attributes = attributes.inject({}) do |a,row|
66
+ k,v = row
67
+ if AS_ARRAY.include?(k.to_s)
68
+ v = Array(v)
69
+ end
70
+ a[k.to_s] = v
71
+ a
72
+ end
73
+ normalize_env_attribute attributes
74
+ end
75
+
76
+ def normalize_env_attribute(attributes)
77
+ env = (attributes['env'] || {}) .dup
78
+ case env
79
+ when Hash
80
+ attributes["env"] = {
81
+ "matrix" => Array(env['matrix']),
82
+ "global" => Array(env['global'])
83
+ }
84
+ else
85
+ attributes['env'] = {
86
+ "matrix" => Array(env).map(&:to_s),
87
+ "global" => []
88
+ }
89
+ end
90
+ freeze_normalized_attributes attributes
91
+ end
92
+
93
+ def freeze_normalized_attributes(attributes)
94
+ attributes.freeze
95
+ attributes['env'].freeze
96
+ attributes['env']['global'].freeze
97
+ attributes['env']['matrix'].freeze
98
+ attributes
99
+ end
100
+
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,45 @@
1
+ require 'yaml'
2
+ require 'json'
3
+
4
+ module Evrone
5
+ module CI
6
+ class Router
7
+ class Travis
8
+
9
+ module Serializable
10
+
11
+ def self.included(base)
12
+ base.extend ClassMethods
13
+ end
14
+
15
+ def to_yaml
16
+ YAML.dump(attributes)
17
+ end
18
+
19
+ def to_hash
20
+ attributes
21
+ end
22
+
23
+ module ClassMethods
24
+
25
+ def from_file(file)
26
+ if File.readable? file
27
+ from_yaml File.read(file)
28
+ end
29
+ end
30
+
31
+ def from_yaml(yaml)
32
+ from_attributes YAML.load(yaml)
33
+ end
34
+
35
+ def from_attributes(attrs)
36
+ Travis.new attrs
37
+ end
38
+
39
+ end
40
+
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,7 @@
1
+ module Evrone
2
+ module CI
3
+ class Router
4
+ VERSION = "0.2.0.pre0"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,145 @@
1
+ require 'spec_helper'
2
+ require 'yaml'
3
+
4
+ describe Evrone::CI::Router::BuildMatrix do
5
+ let(:attributes) { {
6
+ env: %w{ FOO=1 BAR=2 },
7
+ rvm: %w{ 1.8.7 1.9.3 2.0.0 },
8
+ scala: %w{ 2.9.2 2.10.1 }
9
+ } }
10
+ let(:travis) { create :travis, attributes: attributes }
11
+ let(:matrix) { described_class.new travis }
12
+
13
+ subject { matrix }
14
+
15
+ context "just created" do
16
+ its(:travis) { should eq travis }
17
+ end
18
+
19
+ context "keys" do
20
+ subject { matrix.keys }
21
+ it { should eq %w{ env rvm scala } }
22
+ context "without matrix" do
23
+ let(:attributes) { {} }
24
+
25
+ it { should eq [] }
26
+ end
27
+ end
28
+
29
+ context 'travises' do
30
+ context "values" do
31
+ subject { matrix.travises }
32
+
33
+ it { should have(12).items }
34
+
35
+ context "attributes" do
36
+ subject { matrix.travises.map(&:to_matrix_s) }
37
+
38
+ it do
39
+ should eq [
40
+ "env:BAR=2, rvm:1.8.7, scala:2.10.1",
41
+ "env:FOO=1, rvm:1.8.7, scala:2.10.1",
42
+ "env:BAR=2, rvm:1.8.7, scala:2.9.2",
43
+ "env:FOO=1, rvm:1.8.7, scala:2.9.2",
44
+ "env:BAR=2, rvm:1.9.3, scala:2.10.1",
45
+ "env:FOO=1, rvm:1.9.3, scala:2.10.1",
46
+ "env:BAR=2, rvm:1.9.3, scala:2.9.2",
47
+ "env:FOO=1, rvm:1.9.3, scala:2.9.2",
48
+ "env:BAR=2, rvm:2.0.0, scala:2.10.1",
49
+ "env:FOO=1, rvm:2.0.0, scala:2.10.1",
50
+ "env:BAR=2, rvm:2.0.0, scala:2.9.2",
51
+ "env:FOO=1, rvm:2.0.0, scala:2.9.2"
52
+ ]
53
+ end
54
+
55
+ context "without matrix" do
56
+ let(:attributes) { {
57
+ rvm: %w{ 2.0.0 },
58
+ } }
59
+
60
+ it { should eq ['rvm:2.0.0'] }
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ context 'attributes_for_new_travises' do
67
+ subject { matrix.attributes_for_new_travises }
68
+
69
+ it { should have(12).items }
70
+
71
+ its(:first) { should eq("rvm" => "1.8.7",
72
+ "scala" => "2.10.1",
73
+ "env" => "BAR=2") }
74
+ its(:last) { should eq("rvm" => "2.0.0",
75
+ "scala" => "2.9.2",
76
+ "env" => "FOO=1") }
77
+ end
78
+
79
+ context 'extract_pair_of_key_and_values' do
80
+ subject { matrix.extract_pair_of_key_and_values }
81
+ it {
82
+ should eq [
83
+ ["rvm", %w{ 1.8.7 1.9.3 2.0.0 }],
84
+ ["scala", %w{ 2.9.2 2.10.1 }],
85
+ ["env", %w{ FOO=1 BAR=2 }]
86
+ ]
87
+ }
88
+ end
89
+
90
+ context "permutate_and_build_values" do
91
+ subject { format_values matrix.permutate_and_build_values }
92
+ let(:expected) { [
93
+ %w{env:BAR=2 rvm:1.8.7 scala:2.10.1},
94
+ %w{env:BAR=2 rvm:1.8.7 scala:2.9.2},
95
+ %w{env:BAR=2 rvm:1.9.3 scala:2.10.1},
96
+ %w{env:BAR=2 rvm:1.9.3 scala:2.9.2},
97
+ %w{env:BAR=2 rvm:2.0.0 scala:2.10.1},
98
+ %w{env:BAR=2 rvm:2.0.0 scala:2.9.2},
99
+ %w{env:FOO=1 rvm:1.8.7 scala:2.10.1},
100
+ %w{env:FOO=1 rvm:1.8.7 scala:2.9.2},
101
+ %w{env:FOO=1 rvm:1.9.3 scala:2.10.1},
102
+ %w{env:FOO=1 rvm:1.9.3 scala:2.9.2},
103
+ %w{env:FOO=1 rvm:2.0.0 scala:2.10.1},
104
+ %w{env:FOO=1 rvm:2.0.0 scala:2.9.2},
105
+ ] }
106
+
107
+ it { should eq expected }
108
+
109
+ context "with empty keys" do
110
+ let(:attributes) { {
111
+ env: %w{ FOO=1 BAR=2 },
112
+ rvm: %w{ 1.8.7 1.9.3 2.0.0 },
113
+ scala: %w{ 2.9.2 2.10.1 },
114
+ java: [],
115
+ go: nil
116
+ } }
117
+ it { should eq expected }
118
+ end
119
+
120
+ context "with one key" do
121
+ let(:attributes) { {
122
+ rvm: %w{ 1.9.3 2.0.0 },
123
+ } }
124
+ let(:expected) {[
125
+ %w{ rvm:1.9.3 },
126
+ %w{ rvm:2.0.0 }
127
+ ]}
128
+ it { should eq expected }
129
+ end
130
+
131
+ context "without matrix" do
132
+ let(:attributes) { {
133
+ rvm: %w{ 2.0.0 },
134
+ } }
135
+ let(:expected) {[
136
+ %w{ rvm:2.0.0 }
137
+ ]}
138
+ it { should eq expected }
139
+ end
140
+
141
+ def format_values(values)
142
+ values.map{|i| i.map(&:to_s).sort }.sort
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,75 @@
1
+ require 'spec_helper'
2
+
3
+ describe Evrone::CI::Router::Build do
4
+ let(:msg) { create :message, 'PerformBuild' }
5
+ let(:build) { described_class.new msg }
6
+
7
+ subject { build }
8
+
9
+ context "just created" do
10
+ its(:message) { should eq msg }
11
+ its(:output) { should eq '' }
12
+ end
13
+
14
+ context "create_build_log_message" do
15
+ let(:tm) { Time.new(2012, 12, 10, 15, 45) }
16
+ let(:data) { 'log' }
17
+ subject { build.create_build_log_message data }
18
+
19
+ before do
20
+ mock(Time).now { tm }
21
+ end
22
+
23
+ it { should be_an_instance_of(Evrone::CI::Message::BuildLog) }
24
+ its(:build_id) { should eq build.message.id }
25
+ its(:tm) { should eq tm.to_i }
26
+ its(:log) { should eq data }
27
+ end
28
+
29
+ context "add_to_output" do
30
+ let(:data) { 'data' }
31
+ let(:messages) { Evrone::CI::Router::BuildLogsConsumer.messages }
32
+ subject { build.add_to_output(data) ; build }
33
+
34
+ its(:output) { should eq data }
35
+ it "should delivery message" do
36
+ expect {
37
+ subject
38
+ }.to change(messages, :size).by(1)
39
+ end
40
+ end
41
+
42
+ context "add_command_to_output" do
43
+ let(:data) { 'data' }
44
+ let(:messages) { Evrone::CI::Router::BuildLogsConsumer.messages }
45
+ subject { build.add_command_to_output(data) ; build }
46
+
47
+ its(:output) { should eq "$ #{data}\n" }
48
+ it "should delivery message" do
49
+ expect {
50
+ subject
51
+ }.to change(messages, :size).by(1)
52
+ end
53
+ end
54
+
55
+ context ".to_perform_job_message" do
56
+ let(:travis) { create :travis }
57
+ let(:job_id) { 2 }
58
+ subject { build.to_perform_job_message travis, job_id }
59
+
60
+ it { should be_an_instance_of Evrone::CI::Message::PerformJob }
61
+
62
+ context "created message" do
63
+ its(:id) { should eq build.message.id }
64
+ its(:name) { should eq build.message.name }
65
+ its(:src) { should eq build.message.src }
66
+ its(:sha) { should eq build.message.sha }
67
+ its(:deploy_key) { should eq build.message.deploy_key }
68
+
69
+ its(:job_id) { should eq job_id }
70
+ its(:before_script) { should be }
71
+ its(:script) { should be }
72
+ its(:matrix_keys) { should eq ['rvm:2.0.0'] }
73
+ end
74
+ end
75
+ end