ree_spec 0.0.4 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 68eb3e82ab6595a8e4115ecfccea6c639c7d4de80a8c2daf4a33bb2fd68b2c3f
4
- data.tar.gz: 9b31bb1cb252ba420461afd259e108fa77e1388f8e18a50c1377d6f7e7e4d5c2
3
+ metadata.gz: 971f1556635ff273e2a921facab36b08918b9d3cddfa236146e054ee59114bbb
4
+ data.tar.gz: 44d05a565bd7cd4683274361594d90bae3cbdd0d443044b71276cd8a7f77bb38
5
5
  SHA512:
6
- metadata.gz: 53a62c797bc3d2419a5fb8c53a4905aac5660be16a8916f8309c44ad569b8fc407081808621aeb4713cecb3c999ae222d73b0b653794aeebefb87fa9621770ce
7
- data.tar.gz: 2e81850bedb0f88b5ddf72c779160f45b2627f6141b10b1ccbf6225150489dca3b5a4e88021fb380bd3b314e495881332b3fc3519893605dbed1a8b39fcd8388
6
+ metadata.gz: e366fe6c67b093aef3a47bf71edb74fb283a1d9d098c51f3cbab46f2b190bf644e17645cca216192eccac4d7e47a25982be14c4da3f85c9dfbb9826341fdd74b
7
+ data.tar.gz: b74d0c9e98c680445835ac9d366e6e4e6f8a6cbc76fa8526cd4001f6d20cf804f68394a053bd3a03f52f1a3b9eaec0f821dcb869987965f8986387d551ff8da4
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ree_spec (0.0.4)
4
+ ree_spec (0.0.6)
5
5
  commander (~> 5.0.0)
6
6
  ree (~> 1.0.47)
7
7
  ree_lib (~> 1.0.124)
@@ -9,10 +9,10 @@ class ReeSpecCli::RunCommand
9
9
  end
10
10
 
11
11
  def call
12
- action_proc = Proc.new do |package_names, spec_matcher, tag, files, run_all, project_path, process_count, specs_per_process|
12
+ action_proc = Proc.new do |package_names, spec_matcher, tag, files, run_all, only_failed, project_path, process_count|
13
13
  run_specs(
14
- package_names, spec_matcher, tag, files, run_all,
15
- project_path, process_count, specs_per_process
14
+ package_names, spec_matcher, tag, files, run_all, only_failed,
15
+ project_path, process_count
16
16
  )
17
17
  end
18
18
 
@@ -2,14 +2,12 @@ class ReeSpecCli::CommandBuilder
2
2
  include Commander::Methods
3
3
 
4
4
  DEFAULT_PROCESS_COUNT = 1
5
- DEFAULT_SPECS_PER_PROCESS_COUNT = 5
6
5
 
7
6
  def build(&action_proc)
8
7
  files = []
9
8
  package_names = []
10
9
  run_all = false
11
10
  process_count = DEFAULT_PROCESS_COUNT
12
- specs_per_process = DEFAULT_SPECS_PER_PROCESS_COUNT
13
11
 
14
12
  program :name, "Ree Spec"
15
13
  program :version, "1.0"
@@ -25,7 +23,8 @@ class ReeSpecCli::CommandBuilder
25
23
  c.example "ree spec --tag wip", "Run specs for packages which have \"wip\" tag"
26
24
  c.option "--project_path [ROOT_DIR]", String, "Root project dir path"
27
25
  c.option "--tag TAG_NAME", String, "Run specs for packages with specified tag"
28
- c.option "--parallel OPTS", String, "Run specs in parallel processes (e.g. --parallel 15:5, 15 processes, max 5 package spec files per process)"
26
+ c.option "--parallel PROCESS_COUNT", String, "Run specs in parallel processes (e.g. --parallel 15, 15 processes)"
27
+ c.option "--only-failed", "Run only failed specs from previous run"
29
28
 
30
29
  c.option "-f SPEC_FILE", "--fule SPEC_FILE", String, "List of spec files" do |f|
31
30
  files ||= []
@@ -39,11 +38,16 @@ class ReeSpecCli::CommandBuilder
39
38
  c.action do |args, options|
40
39
  package_name = args[0]&.to_sym
41
40
  spec_matcher = args[1]
42
- options_hash = options.__hash__
43
- options_hash.delete(:trace)
44
41
 
45
- if options_hash[:project_path]
46
- options_hash[:project_path] = File.expand_path(options_hash[:project_path])
42
+ if options.project_path
43
+ path = File.expand_path(options.project_path.to_s)
44
+
45
+ if !File.directory?(path)
46
+ puts("Project path not found: #{options.project_path}")
47
+ exit 1
48
+ end
49
+
50
+ options.project_path = File.expand_path(options.project_path.to_s)
47
51
  end
48
52
 
49
53
  if package_name
@@ -54,13 +58,8 @@ class ReeSpecCli::CommandBuilder
54
58
  run_all = true
55
59
  end
56
60
 
57
- if options_hash[:parallel]
58
- parallel = options_hash[:parallel].split(":")[0..1]
59
- process_count = Integer(parallel.first)
60
-
61
- if parallel.size > 1
62
- specs_per_process = Integer(parallel.last)
63
- end
61
+ if options.parallel
62
+ process_count = Integer(options.parallel)
64
63
  end
65
64
 
66
65
  if package_names.size > 1
@@ -68,9 +67,9 @@ class ReeSpecCli::CommandBuilder
68
67
  end
69
68
 
70
69
  action_proc.call(
71
- package_names, spec_matcher, options_hash[:tag], files,
72
- run_all, options_hash[:project_path] || File.expand_path(Dir.pwd),
73
- process_count, specs_per_process
70
+ package_names, spec_matcher, options.tag, files,
71
+ run_all, !!options.only_failed, options.project_path || File.expand_path(Dir.pwd),
72
+ process_count
74
73
  )
75
74
  end
76
75
  end
@@ -2,21 +2,23 @@ class ReeSpecCli::RunSpecs
2
2
  include Ree::FnDSL
3
3
 
4
4
  fn :run_specs do
5
- link :in_groups_of, from: :ree_array
6
5
  link :run_package_specs
6
+ link :from_json, from: :ree_json
7
+ link :symbolize_keys, from: :ree_hash
8
+ link :group_by, from: :ree_array
9
+ link :index_by, from: :ree_array
10
+ link :to_hash, from: :ree_object
11
+ link :to_json, from: :ree_json
7
12
  end
8
13
 
9
- MAX_SPECS_PER_PROCESS = 1000
14
+ SPEC_META_FILENAME = "ree_spec_meta.json"
10
15
 
11
- contract ArrayOf[Symbol], Nilor[String], Nilor[String], ArrayOf[String], Bool, String, Integer, Integer => nil
12
- def call(package_names, spec_matcher, tag, files, run_all, project_path,
13
- process_count, specs_per_process)
16
+ contract ArrayOf[Symbol], Nilor[String], Nilor[String], ArrayOf[String], Bool, Bool, String, Integer => nil
17
+ def call(package_names, spec_matcher, tag, files, run_all, only_failed, project_path, process_count)
14
18
  init_ree_project(project_path)
15
19
 
16
20
  packages = filter_packages_to_run(package_names, tag, run_all)
17
- specs_per_process = calculate_specs_per_process(process_count, specs_per_process)
18
- jobs = get_jobs(packages, specs_per_process, spec_matcher, files)
19
-
21
+ jobs, meta_index = get_jobs(packages, spec_matcher, files, only_failed)
20
22
  processes = build_processes(process_count)
21
23
  error_files = []
22
24
  success_files = []
@@ -29,9 +31,35 @@ class ReeSpecCli::RunSpecs
29
31
 
30
32
  processes[number] = Process.fork do
31
33
  print_start_message(job)
32
- result = run_package_specs(job.package, job.files, number)
33
34
 
34
- if result.status.exitstatus != 0
35
+ prev_meta = meta_index[job.abs_path]
36
+ start_time = Time.now
37
+
38
+ result = run_package_specs(job.package, [job.abs_path], number)
39
+
40
+ end_time = Time.now
41
+ exec_time = end_time - start_time
42
+ is_success = result.status.exitstatus == 0
43
+
44
+ duration = if is_success
45
+ exec_time
46
+ elsif prev_meta
47
+ prev_meta.duration
48
+ else
49
+ exec_time
50
+ end
51
+
52
+ update_scan_metadata(
53
+ SpecMeta.new(
54
+ package: job.package.name.to_s,
55
+ abs_path: job.abs_path,
56
+ duration: duration,
57
+ last_scan_at: Time.now,
58
+ success: is_success
59
+ )
60
+ )
61
+
62
+ if !is_success
35
63
  error_file.write(result.out)
36
64
  error_file.rewind
37
65
  puts(result.out)
@@ -83,7 +111,7 @@ class ReeSpecCli::RunSpecs
83
111
  end
84
112
 
85
113
  def print_start_message(job)
86
- puts("\n**** Running #{job.files.size} spec#{job.files.size == 1 ? "" : "s"} for #{job.package.name} ****\n")
114
+ puts("Running spec for :#{job.package.name}:\n#{job.abs_path}")
87
115
  end
88
116
 
89
117
  def print_messages(error_files, success_files)
@@ -114,28 +142,58 @@ class ReeSpecCli::RunSpecs
114
142
  end
115
143
 
116
144
  pid = Process.wait
117
- number = processes.find { |_, v| v == pid }
145
+ number = processes.find { |_, v| v == pid }.first
118
146
  processes[number] = nil
119
147
  number
120
148
  end
121
149
 
122
- class Job < Struct.new(:package, :dir, :files); end
150
+ class Job
151
+ include ReeDto::DSL
152
+
153
+ build_dto do
154
+ field :package, Ree::Package
155
+ field :abs_path, String
156
+ end
157
+ end
123
158
 
124
- def get_jobs(package_names, specs_per_process, spec_matcher, files)
159
+ def get_jobs(package_names, spec_matcher, files, only_failed)
160
+ prev_scan_meta = read_prev_scan_metadata
125
161
  result = []
126
162
  packages = package_names.map { packages_facade.get_package(_1) }
163
+ scan_index = index_by(prev_scan_meta) { _1.abs_path }
127
164
 
128
165
  packages.each do |package|
129
- dir = Ree::PathHelper.abs_package_module_dir(package)
130
-
131
166
  spec_files = get_spec_files(package, spec_matcher, files)
132
167
 
133
- in_groups_of(spec_files, specs_per_process).each do |specs_group|
134
- result << Job.new(package, dir, specs_group)
168
+ spec_files.each do |abs_path|
169
+ result << Job.new(package:, abs_path:)
135
170
  end
136
171
  end
137
172
 
138
- result
173
+ if only_failed
174
+ result = result.select do |item|
175
+ if scan_index[item.abs_path]
176
+ !scan_index[item.abs_path].success
177
+ else
178
+ false
179
+ end
180
+ end
181
+ end
182
+
183
+ cur_min_duration = prev_scan_meta.min { _1.duration }&.duration || 0
184
+
185
+ result.sort_by do |item|
186
+ dur = if el = scan_index[item.abs_path]
187
+ el.duration
188
+ else
189
+ cur_min_duration -= 1
190
+ cur_min_duration
191
+ end
192
+
193
+ -dur
194
+ end
195
+
196
+ [result, scan_index]
139
197
  end
140
198
 
141
199
  def get_spec_files(package, spec_matcher, files)
@@ -172,21 +230,11 @@ class ReeSpecCli::RunSpecs
172
230
  result
173
231
  end
174
232
  end
175
- elsif files && files.size > 0
176
- files
177
233
  else
178
234
  all_specs
179
235
  end
180
236
  end
181
237
 
182
- def calculate_specs_per_process(process_count, specs_per_process)
183
- if process_count > 1
184
- specs_per_process
185
- else
186
- MAX_SPECS_PER_PROCESS
187
- end
188
- end
189
-
190
238
  def filter_packages_to_run(package_names, tag, run_all)
191
239
  packages_to_run = []
192
240
 
@@ -238,4 +286,60 @@ class ReeSpecCli::RunSpecs
238
286
  package.tags.include?(tag)
239
287
  end
240
288
  end
289
+
290
+ def spec_meta_file_name
291
+ dir = Dir.pwd
292
+ File.join(dir, SPEC_META_FILENAME)
293
+ end
294
+
295
+ def read_prev_scan_metadata
296
+ path = spec_meta_file_name
297
+
298
+ if File.exist?(path)
299
+ result = begin
300
+ from_json(File.read(path))
301
+ rescue
302
+ []
303
+ end
304
+
305
+ build_metadata(result)
306
+ else
307
+ build_metadata([])
308
+ end
309
+ end
310
+
311
+ def update_scan_metadata(spec_meta)
312
+ meta = read_prev_scan_metadata
313
+ prev_spec = meta.find { _1.abs_path == spec_meta.abs_path }
314
+ meta.delete(prev_spec) if prev_spec
315
+ meta << spec_meta
316
+
317
+ result = to_json(meta.map { to_hash(_1) })
318
+
319
+ File.open(spec_meta_file_name, "w") do |f|
320
+ f.flock(File::LOCK_EX)
321
+ f.write(result)
322
+ f.flock(File::LOCK_UN)
323
+ end
324
+ end
325
+
326
+ class SpecMeta
327
+ include ReeDto::DSL
328
+
329
+ build_dto do
330
+ field :package, String
331
+ field :abs_path, String
332
+ field :duration, Float
333
+ field :last_scan_at, Time
334
+ field :success, Bool
335
+ end
336
+ end
337
+
338
+ def build_metadata(data)
339
+ data.map do |d|
340
+ SpecMeta.new(symbolize_keys(d))
341
+ end.compact
342
+ rescue
343
+ []
344
+ end
241
345
  end
@@ -3,5 +3,9 @@ module ReeSpecCli
3
3
 
4
4
  package do
5
5
  depends_on :ree_array
6
+ depends_on :ree_json
7
+ depends_on :ree_dto
8
+ depends_on :ree_hash
9
+ depends_on :ree_object
6
10
  end
7
11
  end
@@ -13,6 +13,8 @@ RSpec.describe :run_command do
13
13
  ARGV << "accounts"
14
14
  ARGV << "--project_path"
15
15
  ARGV << project_path
16
+ ARGV << "--parallel"
17
+ ARGV << "2"
16
18
 
17
19
  run_command()
18
20
  }
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ReeSpec
4
- VERSION = "0.0.4"
4
+ VERSION = "0.0.6"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ree_spec
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ruslan Gatiyatov