ree_spec 0.0.5 → 0.0.7

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: 31fc4911be2ef72173d82b4d81ed810cf02db09bd91efd8c5181537745aaf9a5
4
- data.tar.gz: 13f654e48d93ea78b7beae3d6fc499d2d2c35bf36f099e482ca44b957114894c
3
+ metadata.gz: 581f953006377bf8cf85c1c26ab5abb8d3281bdacdd45bc8fde3dab18568488d
4
+ data.tar.gz: b1d39de7abf2f2093803345f1eed1d95bb12c74b748ef4539437532e8d204e95
5
5
  SHA512:
6
- metadata.gz: ff794e13034853d5edf9518a3ba7548348710030ece9327cbdd5f56f89b662f6d67db60511b78aca397c42daaaa6694d028f272ec71c7f5e8e458cc7f00dd20b
7
- data.tar.gz: 988f45cf4d197284bfae26c42e255a226952bc150a5cf448cf062863137cc968b6d425aaaa775f139828b490f24c75c66fb8003a7a6824f27ef3ffab4610c45d
6
+ metadata.gz: 503bccf95820a786517b6b2ec51ee37b8ed787c04e41fc614b111b9f9fcb81492419416f575d58f8f487ab878f445531ae5ddc7d84ea20a42c6f31fd42613bca
7
+ data.tar.gz: d2c720d253548193328d1d0912cfc8313d4d84c6ea7d19e7017b317a92e27e6335e3b35aaff69c7324679c834b0212436e051ca314a813f09fb17dc7f35d4414
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ree_spec (0.0.5)
4
+ ree_spec (0.0.7)
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)
@@ -60,7 +88,7 @@ class ReeSpecCli::RunSpecs
60
88
 
61
89
  ['INT', 'TERM'].each do |signal|
62
90
  trap(signal) do
63
- shutdown(processes)
91
+ shutdown(result)
64
92
  exit
65
93
  end
66
94
  end
@@ -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)
@@ -119,23 +147,53 @@ class ReeSpecCli::RunSpecs
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 = 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.5"
4
+ VERSION = "0.0.7"
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.5
4
+ version: 0.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ruslan Gatiyatov