vx-router 0.2.0.pre28

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 (45) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +7 -0
  3. data/.rspec +3 -0
  4. data/Gemfile +9 -0
  5. data/LICENSE.txt +276 -0
  6. data/Rakefile +46 -0
  7. data/bin/vx-router +5 -0
  8. data/fixtures/jobs_publisher +13 -0
  9. data/fixtures/travis.yml +5 -0
  10. data/lib/vx/router.rb +158 -0
  11. data/lib/vx/router/build.rb +80 -0
  12. data/lib/vx/router/cli.rb +53 -0
  13. data/lib/vx/router/configuration.rb +27 -0
  14. data/lib/vx/router/consumers/build_logs_consumer.rb +13 -0
  15. data/lib/vx/router/consumers/build_status_consumer.rb +13 -0
  16. data/lib/vx/router/consumers/builds_consumer.rb +27 -0
  17. data/lib/vx/router/consumers/job_status_consumer.rb +13 -0
  18. data/lib/vx/router/consumers/jobs_consumer.rb +13 -0
  19. data/lib/vx/router/ext/array.rb +5 -0
  20. data/lib/vx/router/ext/string.rb +9 -0
  21. data/lib/vx/router/helper/config.rb +11 -0
  22. data/lib/vx/router/helper/logger.rb +11 -0
  23. data/lib/vx/router/helper/trace_sh_command.rb +12 -0
  24. data/lib/vx/router/initializers/amqp.rb +3 -0
  25. data/lib/vx/router/script_builder.rb +98 -0
  26. data/lib/vx/router/script_builder/databases.rb +28 -0
  27. data/lib/vx/router/script_builder/env.rb +21 -0
  28. data/lib/vx/router/script_builder/prepare.rb +58 -0
  29. data/lib/vx/router/script_builder/ruby.rb +68 -0
  30. data/lib/vx/router/script_builder/script.rb +22 -0
  31. data/lib/vx/router/script_builder/webdav_cache.rb +80 -0
  32. data/lib/vx/router/version.rb +5 -0
  33. data/spec/lib/build_spec.rb +123 -0
  34. data/spec/lib/configuration_spec.rb +23 -0
  35. data/spec/lib/router_spec.rb +80 -0
  36. data/spec/lib/script_builder/prepare_spec.rb +44 -0
  37. data/spec/lib/script_builder/webdav_cache_spec.rb +80 -0
  38. data/spec/lib/script_builder_spec.rb +36 -0
  39. data/spec/spec_helper.rb +17 -0
  40. data/spec/support/create.rb +40 -0
  41. data/spec/support/fixture.rb +7 -0
  42. data/spec/support/last_build_log_message.rb +3 -0
  43. data/spec/support/shared_examples/update_build_status_message.rb +5 -0
  44. data/vx-router.gemspec +32 -0
  45. metadata +225 -0
@@ -0,0 +1,58 @@
1
+ require 'vx/common'
2
+
3
+ module Vx
4
+ class Router
5
+ class ScriptBuilder
6
+
7
+ Prepare = Struct.new(:app) do
8
+
9
+ include Helper::TraceShCommand
10
+ include Common::Helper::UploadShCommand
11
+
12
+ def call(env)
13
+ name = env.build.message.name
14
+ deploy_key = env.build.message.deploy_key
15
+
16
+ repo_path = "code/#{name}"
17
+ data_path = "data/#{name}"
18
+ key_file = "#{data_path}/key"
19
+ git_ssh_file = "#{data_path}/git_ssh"
20
+
21
+ sha = env.build.message.sha
22
+ scm = build_scm(env, sha, repo_path)
23
+ git_ssh = scm.git_ssh.class.template(deploy_key && "$PWD/#{key_file}")
24
+
25
+ env.init.tap do |i|
26
+ i << "mkdir -p #{data_path}"
27
+ i << "mkdir -p #{repo_path}"
28
+
29
+ if deploy_key
30
+ i << "echo instaling keys"
31
+ i << upload_sh_command(key_file, deploy_key)
32
+ i << "chmod 0600 #{key_file}"
33
+ end
34
+
35
+ i << upload_sh_command(git_ssh_file, git_ssh)
36
+ i << "chmod 0750 #{git_ssh_file}"
37
+
38
+ i << "export GIT_SSH=$PWD/#{git_ssh_file}"
39
+ i << scm.make_fetch_command
40
+ i << "unset GIT_SSH"
41
+ end
42
+
43
+ app.call env
44
+ end
45
+
46
+ private
47
+
48
+ def build_scm(env, sha, path)
49
+ SCM::Git.new(env.build.message.src,
50
+ sha,
51
+ "$PWD/#{path}",
52
+ branch: env.build.message.branch)
53
+ end
54
+
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,68 @@
1
+ module Vx
2
+ class Router
3
+ class ScriptBuilder
4
+
5
+ Ruby = Struct.new(:app) do
6
+
7
+ ALIASES = {
8
+ '1.8.7' => "system"
9
+ }
10
+
11
+ include Helper::TraceShCommand
12
+
13
+ def call(env)
14
+ if rvm env
15
+ env.cache_key << "rvm-#{rvm env}"
16
+
17
+ env.before_install.tap do |i|
18
+ i << 'eval "$(rbenv init -)" || true'
19
+ i << "rbenv shell #{make_rbenv_version_command env}"
20
+ i << 'export BUNDLE_GEMFILE=${PWD}/Gemfile'
21
+ i << 'export GEM_HOME=$HOME/cached/rubygems'
22
+ end
23
+
24
+ env.announce.tap do |a|
25
+ a << trace_sh_command("ruby --version")
26
+ a << trace_sh_command("gem --version")
27
+ a << trace_sh_command("bundle --version")
28
+ end
29
+
30
+ env.install.tap do |i|
31
+ i << trace_sh_command("bundle install")
32
+ i << trace_sh_command("bundle clean --force")
33
+ end
34
+ end
35
+
36
+ app.call(env)
37
+ end
38
+
39
+ private
40
+
41
+ def rvm(env)
42
+ env.configuration.rvm.first
43
+ end
44
+
45
+ def make_rbenv_version_command(env)
46
+ select_rbenv_version_by_aliases(env) ||
47
+ select_rbenv_version(env)
48
+ end
49
+
50
+ def select_rbenv_version_by_aliases(env)
51
+ ALIASES[rvm(env)]
52
+ end
53
+
54
+ def select_rbenv_version(env)
55
+ %{
56
+ $(rbenv versions |
57
+ sed -e 's/^\*/ /' |
58
+ awk '{print $1}' |
59
+ grep -v 'system' |
60
+ grep '#{rvm env}' |
61
+ tail -n1)
62
+ }.compact
63
+ end
64
+
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,22 @@
1
+ module Vx
2
+ class Router
3
+ class ScriptBuilder
4
+
5
+ Script = Struct.new(:app) do
6
+
7
+ include Helper::TraceShCommand
8
+
9
+ def call(env)
10
+ env.configuration.before_script.each do |c|
11
+ env.before_script << trace_sh_command(c)
12
+ end
13
+ env.configuration.script.each do |c|
14
+ env.script << trace_sh_command(c)
15
+ end
16
+ app.call(env)
17
+ end
18
+
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,80 @@
1
+ module Vx
2
+ class Router
3
+ class ScriptBuilder
4
+
5
+ WebdavCache = Struct.new(:app) do
6
+
7
+ include Helper::Config
8
+ include Helper::Logger
9
+
10
+ CASHER_URL = "https://raw.github.com/travis-ci/casher/production/bin/casher"
11
+ CASHER_BIN = "$HOME/.casher/bin/casher"
12
+
13
+ def call(env)
14
+ rs = app.call env
15
+
16
+ if config.webdav_cache_url
17
+ assign_url_to_env(env)
18
+ prepare(env)
19
+ fetch(env)
20
+ add(env)
21
+ push(env)
22
+ end
23
+
24
+ rs
25
+ end
26
+
27
+ private
28
+
29
+ def assign_url_to_env(env)
30
+ urls = []
31
+ branch = env.build.message.branch
32
+ if branch != 'master'
33
+ urls << url_for(env, branch)
34
+ end
35
+ puts urls.inspect
36
+ urls << url_for(env, 'master')
37
+
38
+ env.webdav_fetch_url = urls
39
+ env.webdav_push_url = url_for(env, branch)
40
+ env
41
+ end
42
+
43
+ def url_for(env, branch)
44
+ name = env.build.message.name.dup + "/" + branch
45
+
46
+ key = env.cache_key.join("-").gsub(/[^a-z0-9_\-.]/, '-')
47
+ "#{config.webdav_cache_url}/#{name}/#{key}.tgz"
48
+ end
49
+
50
+ def prepare(env)
51
+ cmd = %{
52
+ export CASHER_DIR=$HOME/.casher &&
53
+ ( mkdir -p $CASHER_DIR/bin &&
54
+ curl #{CASHER_URL} -s -o #{CASHER_BIN} &&
55
+ chmod +x #{CASHER_BIN} ) ||
56
+ true
57
+ }.compact
58
+ env.init << cmd
59
+ end
60
+
61
+ def fetch(env)
62
+ urls = env.webdav_fetch_url.join(" ")
63
+ env.init << "#{CASHER_BIN} fetch #{urls} || true"
64
+ end
65
+
66
+ def add(env)
67
+ env.init << "#{CASHER_BIN} add $HOME/cached || true"
68
+ env.init << "unset CASHER_DIR"
69
+ end
70
+
71
+ def push(env)
72
+ if env.webdav_push_url
73
+ env.after_script << "#{CASHER_BIN} push #{env.webdav_push_url}"
74
+ end
75
+ end
76
+
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,5 @@
1
+ module Vx
2
+ class Router
3
+ VERSION = "0.2.0.pre28"
4
+ end
5
+ end
@@ -0,0 +1,123 @@
1
+ require 'spec_helper'
2
+ require 'vx/common'
3
+
4
+ describe Vx::Router::Build do
5
+ let(:msg) { create :message, 'PerformBuild' }
6
+ let(:build) { described_class.new msg }
7
+
8
+ subject { build }
9
+
10
+ context "just created" do
11
+ its(:message) { should eq msg }
12
+ its(:output) { should be_an_instance_of(Vx::Common::OutputBuffer)}
13
+ its(:output_counter) { should eq 0 }
14
+ end
15
+
16
+ context "publish_build_log_message" do
17
+ let(:data) { 'log' }
18
+ subject { build.publish_build_log_message data }
19
+
20
+ it { should be_an_instance_of(Vx::Message::BuildLog) }
21
+ its(:build_id) { should eq build.message.id }
22
+ its(:tm) { should eq 1 }
23
+ its(:log) { should eq data }
24
+
25
+ it "should increment counter" do
26
+ expect {
27
+ subject
28
+ }.to change(build, :output_counter).by(1)
29
+ end
30
+
31
+ it "should delivery message" do
32
+ expect {
33
+ subject
34
+ }.to change(Vx::Router::BuildLogsConsumer.messages, :count).by(1)
35
+ expect(last_build_log_message.log).to eq data
36
+ end
37
+ end
38
+
39
+ context "to_build_status_message" do
40
+ subject { build.to_build_status_message Vx::Router::Build::STARTED }
41
+
42
+ before do
43
+ build.jobs_count = 1
44
+ end
45
+
46
+ it { should be_an_instance_of(Vx::Message::BuildStatus) }
47
+ its(:build_id) { should eq build.message.id }
48
+ its(:status) { should eq 2 }
49
+ its(:tm) { should be }
50
+ its(:jobs_count) { should eq 1 }
51
+ end
52
+
53
+ context "add_to_output" do
54
+ let(:data) { 'data' }
55
+ let(:messages) { Vx::Router::BuildLogsConsumer.messages }
56
+ subject do
57
+ build.add_to_output(data)
58
+ build.output.flush
59
+ build
60
+ end
61
+
62
+ it "should delivery message" do
63
+ expect {
64
+ subject
65
+ }.to change(messages, :size).by(1)
66
+ expect(last_build_log_message.log).to eq data
67
+ end
68
+
69
+ it "should increment output_counter" do
70
+ expect {
71
+ subject
72
+ }.to change(build, :output_counter).by(1)
73
+ expect(last_build_log_message.tm).to eq 1
74
+ end
75
+ end
76
+
77
+ context "add_command_to_output" do
78
+ let(:data) { 'data' }
79
+ let(:messages) { Vx::Router::BuildLogsConsumer.messages }
80
+ subject do
81
+ build.add_command_to_output(data)
82
+ build.output.flush
83
+ build
84
+ end
85
+
86
+ it "should delivery message" do
87
+ expect {
88
+ subject
89
+ }.to change(messages, :size).by(1)
90
+ expect(last_build_log_message.log).to eq "$ #{data}\n"
91
+ end
92
+
93
+ it "should increment output_counter" do
94
+ expect {
95
+ subject
96
+ }.to change(build, :output_counter).by(1)
97
+ expect(last_build_log_message.tm).to eq 1
98
+ end
99
+ end
100
+
101
+ context ".to_perform_job_message" do
102
+ let(:config) { create :configuration }
103
+ let(:job_id) { 2 }
104
+ subject { build.to_perform_job_message config, job_id }
105
+
106
+ it { should be_an_instance_of Vx::Message::PerformJob }
107
+
108
+ context "created message" do
109
+ its(:id) { should eq build.message.id }
110
+ its(:name) { should eq build.message.name }
111
+ its(:job_id) { should eq job_id }
112
+ its(:before_script) { should be }
113
+ its(:script) { should be }
114
+ its(:after_script) { should be }
115
+ its(:matrix_keys) { should eq ['rvm:2.0.0'] }
116
+ end
117
+ end
118
+
119
+ context "scm_class" do
120
+ subject { build.scm_class }
121
+ it { should eq Vx::SCM::Git }
122
+ end
123
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe Vx::Router::Configuration do
4
+ let(:config) { Vx::Router.config }
5
+ subject { config }
6
+
7
+ before { Vx::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
+ Vx::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
+ its(:workers) { should eq 1 }
22
+ end
23
+ end
@@ -0,0 +1,80 @@
1
+ require 'spec_helper'
2
+ require 'fileutils'
3
+ require 'pathname'
4
+
5
+ describe Vx::Router do
6
+ let(:build) { create :build }
7
+ let(:router) { described_class.new build }
8
+ subject { router }
9
+
10
+ context "just created" do
11
+ its(:build) { should eq build }
12
+ end
13
+
14
+ context "#perform" do
15
+ subject { router.perform }
16
+ it { should be_true }
17
+ end
18
+
19
+ context "#update_build_status" do
20
+ let(:messages) { Vx::Router::BuildStatusConsumer.messages }
21
+ let(:first_message) { messages.first }
22
+ let(:last_message) { messages.last }
23
+
24
+ it "should delivery STARTED and FINISHED when success" do
25
+ router.update_build_status { true }
26
+ expect(messages).to have(2).items
27
+ expect(first_message.status).to eq Vx::Router::Build::STARTED
28
+ expect(last_message.status).to eq Vx::Router::Build::FINISHED
29
+ end
30
+
31
+ it "should delivery STARTED and FAILED when failed" do
32
+ router.update_build_status { false }
33
+ expect(messages).to have(2).items
34
+ expect(first_message.status).to eq Vx::Router::Build::STARTED
35
+ expect(last_message.status).to eq Vx::Router::Build::FAILED
36
+ end
37
+
38
+ it "should delivery STARTED and FAILED when exception raised" do
39
+ router.update_build_status { raise "Ignore Me" }
40
+ expect(messages).to have(2).items
41
+ expect(first_message.status).to eq Vx::Router::Build::STARTED
42
+ expect(last_message.status).to eq Vx::Router::Build::FAILED
43
+ end
44
+ end
45
+
46
+ context "#load_configuration" do
47
+ subject { router.load_configuration }
48
+
49
+ it "should build new BuildConfiguration instance from message" do
50
+ expect(subject).to be_true
51
+ expect(router.configuration).to be
52
+ end
53
+ end
54
+
55
+ context "#create_and_delivery_build_matrix" do
56
+ let(:messages) { Vx::Router::JobsConsumer.messages }
57
+ let(:message) { messages.first }
58
+ subject { router.create_and_delivery_build_matrix }
59
+ before do
60
+ stub(router).configuration { create :configuration }
61
+ end
62
+
63
+ it "should create build matrix from source configuration and delivery its to jobs" do
64
+ expect(subject).to be_true
65
+ expect(messages).to have(1).item
66
+ expect(message.job_id).to eq 1
67
+ end
68
+
69
+ it "should publish job_status message with status = INITIALIZED" do
70
+ expect {
71
+ subject
72
+ }.to change(Vx::Router::JobStatusConsumer.messages, :count).by(1)
73
+ message = Vx::Router::JobStatusConsumer.messages.last
74
+ expect(message.build_id).to eq build.message.id
75
+ expect(message.job_id).to eq 1
76
+ expect(message.status).to eq 0
77
+ end
78
+ end
79
+
80
+ end