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.
- checksums.yaml +7 -0
- data/.gitignore +7 -0
- data/.rspec +3 -0
- data/Gemfile +9 -0
- data/LICENSE.txt +276 -0
- data/Rakefile +46 -0
- data/bin/vx-router +5 -0
- data/fixtures/jobs_publisher +13 -0
- data/fixtures/travis.yml +5 -0
- data/lib/vx/router.rb +158 -0
- data/lib/vx/router/build.rb +80 -0
- data/lib/vx/router/cli.rb +53 -0
- data/lib/vx/router/configuration.rb +27 -0
- data/lib/vx/router/consumers/build_logs_consumer.rb +13 -0
- data/lib/vx/router/consumers/build_status_consumer.rb +13 -0
- data/lib/vx/router/consumers/builds_consumer.rb +27 -0
- data/lib/vx/router/consumers/job_status_consumer.rb +13 -0
- data/lib/vx/router/consumers/jobs_consumer.rb +13 -0
- data/lib/vx/router/ext/array.rb +5 -0
- data/lib/vx/router/ext/string.rb +9 -0
- data/lib/vx/router/helper/config.rb +11 -0
- data/lib/vx/router/helper/logger.rb +11 -0
- data/lib/vx/router/helper/trace_sh_command.rb +12 -0
- data/lib/vx/router/initializers/amqp.rb +3 -0
- data/lib/vx/router/script_builder.rb +98 -0
- data/lib/vx/router/script_builder/databases.rb +28 -0
- data/lib/vx/router/script_builder/env.rb +21 -0
- data/lib/vx/router/script_builder/prepare.rb +58 -0
- data/lib/vx/router/script_builder/ruby.rb +68 -0
- data/lib/vx/router/script_builder/script.rb +22 -0
- data/lib/vx/router/script_builder/webdav_cache.rb +80 -0
- data/lib/vx/router/version.rb +5 -0
- data/spec/lib/build_spec.rb +123 -0
- data/spec/lib/configuration_spec.rb +23 -0
- data/spec/lib/router_spec.rb +80 -0
- data/spec/lib/script_builder/prepare_spec.rb +44 -0
- data/spec/lib/script_builder/webdav_cache_spec.rb +80 -0
- data/spec/lib/script_builder_spec.rb +36 -0
- data/spec/spec_helper.rb +17 -0
- data/spec/support/create.rb +40 -0
- data/spec/support/fixture.rb +7 -0
- data/spec/support/last_build_log_message.rb +3 -0
- data/spec/support/shared_examples/update_build_status_message.rb +5 -0
- data/vx-router.gemspec +32 -0
- 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,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
|