forked from solidusio/solidus
-
Notifications
You must be signed in to change notification settings - Fork 0
/
build-ci.rb
executable file
·207 lines (174 loc) · 4.33 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
194
195
196
197
198
199
200
201
202
203
204
205
206
207
#!/usr/bin/env ruby
# frozen_string_literal: true
require 'pathname'
class Project
attr_reader :name, :title, :weight
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, test_type: :rspec, title: nil, weight:)
@name = name
@title = title || name
@test_type = test_type
@weight = weight
end
ALL = [
new('api', weight: 50),
new('backend', weight: 215),
new('backend', test_type: :teaspoon, title: "backend JS", weight: 15),
new('core', weight: 220),
new('frontend', weight: 95),
new('sample', weight: 22)
].freeze
# Install subproject
#
# @raise [RuntimeError]
# in case of failure
#
# @return [self]
# otherwise
def self.install
bundle_check || bundle_install || fail('Cannot finish gem installation')
end
# Check if current bundle is already usable
#
# @return [Boolean]
def self.bundle_check
system(*%W[bundle check --path=#{VENDOR_BUNDLE}])
end
private_class_method :bundle_check
# Install the current bundle
#
# @return [Boolean]
# the success of the installation
def self.bundle_install
system(*%W[
bundle
install
--path=#{VENDOR_BUNDLE}
--jobs=#{BUNDLER_JOBS}
--retry=#{BUNDLER_RETRIES}
])
end
private_class_method :bundle_check
# Test subproject for passing its tests
#
# @return [Boolean]
# the success of the build
def pass?
chdir do
run_tests
end
end
# 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
unallocated = ALL.sort_by(&:weight).reverse
nodes = Array.new(NODE_TOTAL) { [] }
while project = unallocated.shift
nodes.min_by { |projects| projects.sum(&:weight) } << project
end
nodes[NODE_INDEX]
end
private_class_method :current_projects
# Log a progress message to stderr
#
# @param [String] message
#
# @return [void]
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)
fail ArgumentError if arguments.length > 1
mode = arguments.fetch(0, DEFAULT_MODE)
case mode
when 'install'
install
true
when 'test'
test
else
fail "Unknown mode: #{mode.inspect}"
end
end
private
# Run tests for subproject
#
# @return [Boolean]
# the success of the tests
def run_tests
send(:"run_#{@test_type}")
end
def run_rspec
run_test_cmd(%w[bundle exec rspec] + rspec_arguments)
end
def run_teaspoon
run_test_cmd(%w[bundle exec teaspoon] + teaspoon_arguments)
end
def run_test_cmd(args)
puts "Run: #{args.join(' ')}"
result = system(*args)
puts(result ? "Success" : "Failed")
result
end
def teaspoon_arguments
if report_dir
%W[--format documentation,junit>#{report_dir}/rspec/#{name}_js.xml]
else
%w[--format documentation]
end
end
def rspec_arguments
args = []
args += %w[--format documentation --profile 10]
if report_dir
args += %W[-r rspec_junit_formatter --format RspecJunitFormatter -o #{report_dir}/rspec/#{name}.xml]
end
args
end
def report_dir
ENV['CIRCLE_TEST_REPORTS']
end
# Change to subproject directory and execute block
#
# @return [void]
def chdir(&block)
Dir.chdir(ROOT.join(name), &block)
end
end # Project
exit Project.run_cli(ARGV)