evrone-ci-router 0.2.0.pre0

Sign up to get free protection for your applications and to get access to all the features.
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,22 @@
1
+ require 'spec_helper'
2
+
3
+ describe Evrone::CI::Router::Configuration do
4
+ let(:config) { Evrone::CI::Router.config }
5
+ subject { config }
6
+
7
+ before { Evrone::CI::Router.reset_config! }
8
+
9
+ its(:timeout) { should eq 1800 }
10
+ its(:amqp_url) { should be_nil }
11
+
12
+ context ".configure" do
13
+ subject {
14
+ Evrone::CI::Router.configure do |c|
15
+ c.timeout = 1
16
+ c.amqp_url = "2"
17
+ end
18
+ }
19
+ its(:timeout) { should eq 1 }
20
+ its(:amqp_url) { should eq "2" }
21
+ end
22
+ end
@@ -0,0 +1,73 @@
1
+ require 'spec_helper'
2
+ require 'pathname'
3
+
4
+ describe Evrone::CI::Router::Middleware::CreateBuildMatrix do
5
+ let(:app) { ->(_) { 0 } }
6
+ let(:build) { create :build }
7
+ let(:env) { OpenStruct.new build: build, repo_dir: repo_dir }
8
+ let(:repo_dir) { Pathname.new fixture_path("repo") }
9
+ let(:matrix) { described_class.new app }
10
+
11
+ it { should be }
12
+
13
+ context "call" do
14
+ let(:travis) { create :travis, attributes: { rvm: %w{ 1.9.3 2.0.0 } } }
15
+ subject { matrix.call env }
16
+
17
+ context "successfuly" do
18
+ before do
19
+ mock(matrix).load_travis(repo_dir) { travis }
20
+ end
21
+
22
+ it { should eq 0 }
23
+
24
+ it "should create and delivery jobs " do
25
+ expect{ subject }.to change{
26
+ Evrone::CI::Router::JobsConsumer.messages.count
27
+ }.by(2)
28
+ end
29
+
30
+ context "first delivered job" do
31
+ let(:m) { Evrone::CI::Router::JobsConsumer.messages.first }
32
+ subject { m }
33
+ before { matrix.call env }
34
+
35
+ its("job_id") { should eq 1 }
36
+ end
37
+
38
+ context "last delivered job" do
39
+ let(:m) { Evrone::CI::Router::JobsConsumer.messages.last }
40
+ subject { m }
41
+ before { matrix.call env }
42
+
43
+ its("job_id") { should eq 2 }
44
+ end
45
+
46
+ context "update build" do
47
+ it "should assign jobs_count" do
48
+ expect{ subject }.to change(build, :jobs_count).from(nil).to(2)
49
+ end
50
+
51
+ it "should assign matrix" do
52
+ expect{ subject }.to change(build, :matrix).from(nil).to(%w{rvm})
53
+ end
54
+ end
55
+ end
56
+
57
+ context "when travis.yml not found" do
58
+
59
+ before do
60
+ mock(Evrone::CI::Router::Travis).from_file(anything){ nil }
61
+ end
62
+
63
+ it "should return -1" do
64
+ expect(subject).to eq(-1)
65
+ end
66
+
67
+ it "cannot delivery any job" do
68
+ expect{ subject }.to_not change(Evrone::CI::Router::JobsConsumer.messages, :size)
69
+ end
70
+
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+ require 'pathname'
3
+ require 'fileutils'
4
+
5
+ describe Evrone::CI::Router::Middleware::CreateDirs do
6
+ let(:build) { create :build }
7
+ let(:path_prefix) { Pathname.new '/tmp/.test' }
8
+ let(:app) { ->(_) { 0 } }
9
+ let(:env) { OpenStruct.new build: build, path_prefix: path_prefix }
10
+
11
+ subject { described_class.new app }
12
+
13
+ before { FileUtils.rm_rf path_prefix }
14
+ after { FileUtils.rm_rf path_prefix }
15
+
16
+ context "call" do
17
+ subject{ described_class.new(app).call env }
18
+ it { should eq 0 }
19
+
20
+ it "should create and assign to env repo_dir" do
21
+ subject
22
+ expect(env.repo_dir.to_s).to eq '/tmp/.test/repo'
23
+ expect(File.directory? env.repo_dir).to be
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe Evrone::CI::Router::Middleware::FetchCommitInfo do
4
+ let(:build) { create :build }
5
+ let(:env) { OpenStruct.new build: build, scm: scm }
6
+ let(:app) { ->(_) { 0 } }
7
+ let(:commit_info) { 'commit_info' }
8
+ let(:scm) { 'scm' }
9
+ subject { described_class.new(app).call env }
10
+
11
+ before do
12
+ mock(scm).commit_info { commit_info }
13
+ end
14
+
15
+ it { should eq 0 }
16
+
17
+ it "should assign commit info to build" do
18
+ subject
19
+ expect(build.commit_info).to eq commit_info
20
+ end
21
+
22
+ end
23
+
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+ require 'pathname'
3
+ require 'fileutils'
4
+
5
+ describe Evrone::CI::Router::Middleware::FetchSource do
6
+ let(:path_prefix) { '/tmp/.test' }
7
+ let(:build) { create :build, options }
8
+ let(:options) { {} }
9
+ let(:repo_dir) { Pathname.new '/tmp/.test' }
10
+ let(:app) { ->(_) { 0 } }
11
+ let(:env) { OpenStruct.new build: build, repo_dir: repo_dir }
12
+ subject { described_class.new(app).call env }
13
+
14
+ before { FileUtils.rm_rf(repo_dir) }
15
+ after { FileUtils.rm_rf(repo_dir) }
16
+
17
+ it "should checkout repo" do
18
+ expect(subject).to eq 0
19
+ expect(File.directory? "/tmp/.test/.git").to be
20
+ end
21
+
22
+ context "when failed" do
23
+ let(:options) { { src: "/not-exists.git" } }
24
+ it { should eq(-1) }
25
+ end
26
+ end
27
+
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+
3
+ describe Evrone::CI::Router::Middleware::LogBuild do
4
+ let(:build) { create :build }
5
+ let(:app) { ->(_) { 0 } }
6
+ let(:env) { OpenStruct.new build: build }
7
+
8
+ subject { described_class.new app }
9
+
10
+ context "call" do
11
+ subject{ described_class.new(app).call env }
12
+ it { should eq 0 }
13
+ end
14
+ end
@@ -0,0 +1,70 @@
1
+ require 'spec_helper'
2
+
3
+ describe Evrone::CI::Router::Middleware::UpdateBuildStatus do
4
+ let(:exit_code) { 0 }
5
+ let(:app) { ->(_) { exit_code } }
6
+ let(:build) { create :build }
7
+ let(:env) { OpenStruct.new build: build }
8
+ let(:mid) { described_class.new app }
9
+ let(:messages) { Evrone::CI::Router::BuildStatusConsumer.messages }
10
+
11
+ subject { mid.call env }
12
+
13
+ it "should delivery 2 messages" do
14
+ expect {
15
+ subject
16
+ }.to change(messages, :size).by(2)
17
+ end
18
+
19
+ { 0 => 3, 1 => 4, -1 => 5 }.each do |code, status|
20
+ context "when exit code is #{code}" do
21
+ let(:exit_code) { code }
22
+ it { should eq code }
23
+
24
+ context "messages" do
25
+ before { mid.call env }
26
+
27
+ context "first" do
28
+ subject { messages.first }
29
+ it_should_behave_like "UpdateBuildStatus message" do
30
+ its(:status) { should eq 2 }
31
+ end
32
+ end
33
+
34
+ context "last" do
35
+ subject { messages.last }
36
+ it_should_behave_like "UpdateBuildStatus message" do
37
+ its(:status) { should eq status }
38
+ end
39
+ end
40
+
41
+ end
42
+ end
43
+ end
44
+
45
+ context "when raise exception" do
46
+ let(:app) { ->(_) { raise "Ignore Me" } }
47
+ it { should eq(-1) }
48
+
49
+ context "messages" do
50
+ before { mid.call env }
51
+
52
+ context "first" do
53
+ subject { messages.first }
54
+ it_should_behave_like "UpdateBuildStatus message" do
55
+ its(:status) { should eq 2 }
56
+ end
57
+ end
58
+
59
+ context "last" do
60
+ subject { messages.last }
61
+ it_should_behave_like "UpdateBuildStatus message" do
62
+ its(:status) { should eq 5 }
63
+ end
64
+ end
65
+
66
+ end
67
+ end
68
+
69
+ end
70
+
@@ -0,0 +1,55 @@
1
+ require 'spec_helper'
2
+
3
+ describe Evrone::CI::Router::Queue do
4
+ let(:travis) { create :travis }
5
+ let(:queue) { described_class.new travis }
6
+ let(:expected_before_script) {
7
+ s = ["set -e"]
8
+ s << "export LC_ALL=en_US.UTF8"
9
+ s << "eval \"$(rbenv init -)\" || true"
10
+ s << %{
11
+ rbenv shell
12
+ $(rbenv versions |
13
+ sed -e 's/^*/ /' |
14
+ awk '{print $1}' |
15
+ grep -v 'system' |
16
+ grep '2.0.0' |
17
+ tail -n1)
18
+ }.compact
19
+ s << 'export BUNDLE_GEMFILE=${PWD}/Gemfile'
20
+ s << "export GEM_HOME=/tmp/.rubygems"
21
+ trace s, "env"
22
+ s << "gem query -q -in '^bundler$' > /dev/null || gem install bundler -q --no-rdoc --no-ri"
23
+ trace s, "ruby --version"
24
+ trace s, "gem --version"
25
+ trace s, "bundle --version"
26
+ trace s, "bundle install"
27
+ trace s, "echo before_script"
28
+ s.join("\n")
29
+ }
30
+ let(:expected_script) {
31
+ s = ["set -e"]
32
+ trace s, "RAILS_ENV=test ls -1 && echo DONE!"
33
+ s.join("\n")
34
+ }
35
+ subject { queue }
36
+
37
+ its(:travis) { should eq travis }
38
+
39
+ context "to_before_script" do
40
+ subject { queue.to_before_script }
41
+
42
+ it { should eq expected_before_script }
43
+ end
44
+
45
+ context "to_script" do
46
+ subject { queue.to_script }
47
+
48
+ it { should eq expected_script }
49
+ end
50
+
51
+ def trace(s, cmd)
52
+ s << "echo #{Shellwords.escape "$ " + cmd}"
53
+ s << cmd
54
+ end
55
+ end
@@ -0,0 +1,182 @@
1
+ require 'spec_helper'
2
+
3
+ describe Evrone::CI::Router::Travis do
4
+ let(:content) { YAML.load fixture('travis.yml') }
5
+ let(:travis) { described_class.from_attributes content }
6
+ subject { travis }
7
+
8
+ its(:attributes) { should be }
9
+ its(:rvm) { should eq %w{ 2.0.0 } }
10
+ its(:before_script) { should eq ["echo before_script"] }
11
+ its(:script) { should eq ["RAILS_ENV=test ls -1 && echo DONE!"] }
12
+
13
+ context "merge" do
14
+ let(:new_attrs) { { rvm: "replaced" } }
15
+ subject{ travis.merge new_attrs }
16
+
17
+ it "should build a new travis instance" do
18
+ expect(subject).to be_an_instance_of(described_class)
19
+ end
20
+
21
+ it "should replace attributes" do
22
+ expect(subject.attributes["rvm"]).to eq %w{ replaced }
23
+ end
24
+ end
25
+
26
+ context "(serialization)" do
27
+
28
+ context "build new instance" do
29
+ let(:expected) { {
30
+ "rvm" => ["2.0.0"],
31
+ "before_script" => ["echo before_script"],
32
+ "script" => ["RAILS_ENV=test ls -1 && echo DONE!"],
33
+ "env" => {
34
+ "matrix" => [],
35
+ "global" => []
36
+ }
37
+ } }
38
+
39
+ context "from_yaml" do
40
+ subject { described_class.from_yaml(fixture('travis.yml')).attributes }
41
+ it { should eq expected }
42
+ end
43
+
44
+ context "form_file" do
45
+ subject { described_class.from_file('fixtures/travis.yml').attributes }
46
+ it { should eq expected }
47
+ end
48
+
49
+ context "from_attributes" do
50
+ let(:attrs) {{
51
+ rvm: "2.0.0",
52
+ before_script: "echo before_script",
53
+ script: "RAILS_ENV=test ls -1 && echo DONE!"
54
+ }}
55
+ subject { described_class.from_attributes(attrs).attributes }
56
+ it { should eq expected }
57
+ end
58
+ end
59
+
60
+ context ".to_yaml" do
61
+ subject { travis.to_yaml }
62
+ it { should eq travis.attributes.to_yaml }
63
+ end
64
+ end
65
+
66
+ context "to_queue" do
67
+ subject { travis.to_queue }
68
+ it { should be }
69
+ end
70
+
71
+ context "to_matrix_s" do
72
+ subject { travis.to_matrix_s }
73
+ it { should eq 'rvm:2.0.0' }
74
+
75
+ context "when many items" do
76
+ before do
77
+ mock(travis).rvm { %w{ 1.9.3 2.0.0 } }
78
+ mock(travis).scala { %w{ 2.10.1 } }
79
+ end
80
+ it { should eq "rvm:1.9.3, rvm:2.0.0, scala:2.10.1" }
81
+ end
82
+ end
83
+
84
+ context "matrix_keys" do
85
+ subject { travis.matrix_keys }
86
+ it { should eq %w{ rvm:2.0.0 } }
87
+
88
+ context "when many items" do
89
+ before do
90
+ mock(travis).rvm { %w{ 1.9.3 2.0.0 } }
91
+ mock(travis).scala { %w{ 2.10.1 } }
92
+ end
93
+ it { should eq %w{ rvm:1.9.3 rvm:2.0.0 scala:2.10.1 }}
94
+ end
95
+ end
96
+
97
+
98
+ it "empty attributes must be empty Array" do
99
+ expect(travis.scala).to eq([])
100
+ end
101
+
102
+ context "normalize_attributes" do
103
+ described_class::AS_ARRAY.each do |m|
104
+ context "convert #{m} attribute to Array" do
105
+ let(:content) { { m => m } }
106
+ subject { travis.__send__(m) }
107
+ it { should eq([m]) }
108
+ end
109
+ end
110
+
111
+ context "convert hash keys to strings" do
112
+ let(:content) { { rvm: "rvm" } }
113
+ subject { travis.attributes }
114
+ it { should include("rvm" => %w{rvm}) }
115
+ end
116
+
117
+ context "build env hash" do
118
+ subject { travis.attributes["env"] }
119
+
120
+ context "from String" do
121
+ let(:content) { { env: "FOO" } }
122
+ it { should eq( "global" => [], "matrix" => %w{ FOO } ) }
123
+ end
124
+
125
+ context "from Array" do
126
+ let(:content) { { env: %w{ FOO BAR } } }
127
+ it { should eq( 'global' => [], 'matrix' => %w{ FOO BAR } ) }
128
+ end
129
+
130
+ context "from empty Hash" do
131
+ let(:content) { { env: {} } }
132
+ it { should eq( 'global' => [], 'matrix' => [] ) }
133
+ end
134
+
135
+ context "from Hash" do
136
+ let(:content) { { env: { "global" => "1", 'matrix' => '2' } } }
137
+ it { should eq( 'global' => %w{1}, 'matrix' => %w{2} ) }
138
+ end
139
+ end
140
+ end
141
+
142
+ context "env" do
143
+ let(:content) { { env: env } }
144
+ subject { travis.env }
145
+
146
+ context "when attributes[env] is Array" do
147
+ let(:env) { %w{ FOO=1 BAR=2 } }
148
+ it { should eq %w{ FOO=1 BAR=2 } }
149
+ end
150
+
151
+ context "when attributes[env] is Hash" do
152
+ let(:env) { { "matrix" => %w{ BAZ=1 } } }
153
+ it { should eq %w{ BAZ=1 } }
154
+ end
155
+
156
+ context "when attributes[env] is empty" do
157
+ let(:env) { {} }
158
+ it { should eq([]) }
159
+ end
160
+ end
161
+
162
+ context "global_env" do
163
+ let(:content) { { env: env } }
164
+ subject { travis.global_env }
165
+
166
+ context "when attributes[env] is Array" do
167
+ let(:env) { %w{ FOO=1 } }
168
+ it { should eq([]) }
169
+ end
170
+
171
+ context "when attributes[env] is Hash" do
172
+ let(:env) { { "global" => %w{ FOO=1 } } }
173
+ it { should eq %w{ FOO=1 } }
174
+ end
175
+
176
+ context "when attributes[env] is empty" do
177
+ let(:env) { {} }
178
+ it { should eq([]) }
179
+ end
180
+ end
181
+
182
+ end