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,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