forked from spree/spree
-
Notifications
You must be signed in to change notification settings - Fork 0
/
build-ci.rb
executable file
·193 lines (164 loc) · 3.93 KB
/
build-ci.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
#!/usr/bin/env ruby
require 'pathname'
class Project
attr_reader :name
NODE_TOTAL = Integer(ENV.fetch('CIRCLE_NODE_TOTAL', 1))
NODE_INDEX = Integer(ENV.fetch('CIRCLE_NODE_INDEX', 0))
ROOT = Pathname.pwd.freeze
VENDOR_BUNDLE = ROOT.join('vendor', 'bundle').freeze
BUNDLER_JOBS = 4
BUNDLER_RETRIES = 3
DEFAULT_MODE = 'test'.freeze
def initialize(name)
@name = name
end
ALL = %w[api backend core frontend sample].map(&method(:new)).freeze
# Install subproject
#
# @raise [RuntimeError]
# in case of failure
#
# @return [self]
# otherwise
def install
chdir do
bundle_check || bundle_install || raise('Cannot finish gem installation')
end
self
end
# Test subproject for passing its tests
#
# @return [Boolean]
# the success of the build
def pass?
chdir do
setup_test_app
run_tests
end
end
private
# Check if current bundle is already usable
#
# @return [Boolean]
def bundle_check
system(%W[bundle check --path=#{VENDOR_BUNDLE}])
end
# Install the current bundle
#
# @return [Boolean]
# the success of the installation
def bundle_install
system(%W[
bundle
install
--path=#{VENDOR_BUNDLE}
--jobs=#{BUNDLER_JOBS}
--retry=#{BUNDLER_RETRIES}
])
end
# Setup the test app
#
# @return [undefined]
def setup_test_app
system(%w[bundle exec rake test_app]) || raise('Failed to setup the test app')
end
# Run tests for subproject
#
# @return [Boolean]
# the success of the tests
def run_tests
system(%w[bundle exec rspec] + rspec_arguments)
end
def rspec_arguments
args = []
args += %w[--order random]
if report_dir = ENV['CIRCLE_TEST_REPORTS']
args += %W[-r rspec_junit_formatter --format RspecJunitFormatter -o #{report_dir}/rspec/#{name}.xml]
end
args
end
# Execute system command via execve
#
# No shell interpolation gets done this way. No escapes needed.
#
# @return [Boolean]
# the success of the system command
def system(arguments)
Kernel.system(*arguments)
end
# Change to subproject directory and execute block
#
# @return [undefined]
def chdir(&block)
Dir.chdir(ROOT.join(name), &block)
end
# Install subprojects
#
# @return [self]
def self.install
current_projects.each do |project|
log("Installing project: #{project.name}")
project.install
end
self
end
private_class_method :install
# Execute tests on subprojects
#
# @return [Boolean]
# the success of ALL subprojects
def self.test
projects = current_projects
suffix = "#{projects.length} projects(s) on node #{NODE_INDEX.succ} / #{NODE_TOTAL}"
log("Running #{suffix}")
projects.each do |project|
log("- #{project.name}")
end
builds = projects.map do |project|
log("Building: #{project.name}")
project.pass?
end
log("Finished running #{suffix}")
projects.zip(builds).each do |project, build|
log("- #{project.name} #{build ? 'SUCCESS' : 'FAILURE'}")
end
builds.all?
end
private_class_method :test
# Return the projects active on current node
#
# @return [Array<Project>]
def self.current_projects
NODE_INDEX.step(ALL.length - 1, NODE_TOTAL).map(&ALL.method(:fetch))
end
private_class_method :current_projects
# Log a progress message to stderr
#
# @param [String] message
#
# @return [undefined]
def self.log(message)
$stderr.puts(message)
end
private_class_method :log
# Process CLI arguments
#
# @param [Array<String>] arguments
#
# @return [Boolean]
# the success of the CLI run
def self.run_cli(arguments)
raise ArgumentError if arguments.length > 1
mode = arguments.fetch(0, DEFAULT_MODE)
case mode
when 'install'
install
true
when 'test'
test
else
raise "Unknown mode: #{mode.inspect}"
end
end
end # Project
exit Project.run_cli(ARGV)