ree_spec 0.0.5 → 0.0.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 31fc4911be2ef72173d82b4d81ed810cf02db09bd91efd8c5181537745aaf9a5
4
- data.tar.gz: 13f654e48d93ea78b7beae3d6fc499d2d2c35bf36f099e482ca44b957114894c
3
+ metadata.gz: 971f1556635ff273e2a921facab36b08918b9d3cddfa236146e054ee59114bbb
4
+ data.tar.gz: 44d05a565bd7cd4683274361594d90bae3cbdd0d443044b71276cd8a7f77bb38
5
5
  SHA512:
6
- metadata.gz: ff794e13034853d5edf9518a3ba7548348710030ece9327cbdd5f56f89b662f6d67db60511b78aca397c42daaaa6694d028f272ec71c7f5e8e458cc7f00dd20b
7
- data.tar.gz: 988f45cf4d197284bfae26c42e255a226952bc150a5cf448cf062863137cc968b6d425aaaa775f139828b490f24c75c66fb8003a7a6824f27ef3ffab4610c45d
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.5)
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)
@@ -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.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.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.5
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ruslan Gatiyatov