rspec-tracer 1.1.2 → 1.2.0

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: 43ff2641751b61443860449bb5857cfeb2a4028881e05a7c58001f1bc6a7681d
4
- data.tar.gz: aabe43c08122caf4e0af52ba77ef5ec85443953803488aae5d5bba83af7cdf6e
3
+ metadata.gz: 4ca4bb6bc03d28906d2dd6456af80031a9bc60a9d05ce761d818f4ef01284f40
4
+ data.tar.gz: b2e975d043e9e34a92055312e65be52d41ec34c515fe520b7c063bbde8ddc1eb
5
5
  SHA512:
6
- metadata.gz: 90b4b9795ff2b78e8c8a167e90736d639a74a4b4b082e69813cbaf66f4001852e603ad81ad761bb03565d7d4a0319d52ee3d0d79857b7880a7de82c1932b8640
7
- data.tar.gz: 8784ef81e6fc6e076b64d22372215feeba7cfb7b5349b79b2b2e1618a745cced55c29e24ae768b941bda4f3a3058b28420ef4533a8b343f4e112d3bc9b47723f
6
+ metadata.gz: d33f2f0d87397499ce7b72ca197e8496c0f4ceea3ef791a61e74f10db81ed7655d6a0febb72366d24d7931779c305187202d281069fb83194440430112c54fd8
7
+ data.tar.gz: 2bd13872430988cdf0285f06a07db02492adb485c4273b1ac48526bb0419f3d27a56d73e64fa3cb111d436e25016c7cf2de75c0876286e16974971f541f08e98
data/CHANGELOG.md CHANGED
@@ -1,3 +1,57 @@
1
+ ## [1.2.0] - 2026-04-24
2
+
3
+ ### Added
4
+
5
+ - **`USE_TEST_SUITE_ID_CACHE` env flag** for per-suite remote-cache
6
+ validation. When set to the exact string `"true"`, the validator
7
+ accepts the current `TEST_SUITE_ID`'s cache independently of peer
8
+ suites' state — so an aborted suite on one CI run no longer forces
9
+ a cold run across every suite on the next. Default unset preserves
10
+ 1.1.x behaviour byte-for-byte. Ports
11
+ [upstream PR #70](https://github.com/avmnu-sng/rspec-tracer/pull/70)
12
+ (kirpalsangha), with credit to the interviewstreet fork
13
+ ([PR #1](https://github.com/interviewstreet/rspec-tracer/pull/1))
14
+ where the same fix was shipped to HackerRank's production CI in 2024.
15
+
16
+ ### Fixed
17
+
18
+ - **`SourceFile#file_path` silently dropped dependencies on external
19
+ absolute paths** (closes the issue behind upstream PRs
20
+ [#37](https://github.com/avmnu-sng/rspec-tracer/pull/37) and
21
+ [#67](https://github.com/avmnu-sng/rspec-tracer/pull/67)). When a
22
+ spec's `metadata[:file_path]` resolved to an absolute path **outside**
23
+ `RSpecTracer.root` — typical for shared examples from vendored gems
24
+ (`/opt/bundle/gems/rspec-rails-X/lib/shared_examples/...`) or for
25
+ monorepo spec files adjacent to the project tree — the method stripped
26
+ the leading `/` and expanded against `RSpecTracer.root`, producing a
27
+ non-existent path like `<root>/opt/bundle/...`. `File.file?` returned
28
+ false, `from_path` returned nil, and the tracer **silently skipped
29
+ dependency registration** for that file. Cache-staleness silent-
30
+ correctness bug: shared examples from external gems never appeared as
31
+ dependencies, so changes to them never invalidated the cache. The fix
32
+ returns the input unchanged only when it's an absolute path to an
33
+ existing file outside `RSpecTracer.root`; all other inputs (relative
34
+ paths, stripped-root forms, in-root absolute paths) continue through
35
+ the existing project-relative expansion, preserving byte-for-byte
36
+ behaviour for 1.1.x configurations.
37
+ - **`ValidationError` constant now defined.** `remote_cache/validator.rb`
38
+ previously referenced `ValidationError` in its XOR-guard `raise` but
39
+ the constant was never declared anywhere. Tripping the guard
40
+ (setting exactly one of `TEST_SUITE_ID` / `TEST_SUITES`) raised
41
+ `NameError: uninitialized constant` instead of the intended
42
+ error class. Added `class ValidationError < StandardError` inside
43
+ `Validator`, mirroring `Aws::AwsError`.
44
+ - **Typo in the XOR-guard error message** — `"enviornment"` →
45
+ `"environment"`.
46
+ - **Single-suite `@cached_files_regex` now anchored** — `$` appended
47
+ so the pattern no longer matches extraneous-extension files like
48
+ `/ref/hash/foo.json.backup`. Multi-suite regex was already anchored
49
+ in 1.1.x.
50
+ - **`remote_cache/aws.rb#upload_dir` error message** — reported
51
+ `"Failed to download files from …"` when the upload failed. Closes
52
+ upstream [PR #64](https://github.com/avmnu-sng/rspec-tracer/pull/64)
53
+ (C3).
54
+
1
55
  ## [1.1.2] - 2026-04-24
2
56
 
3
57
  ### Fixed
data/README.md CHANGED
@@ -149,6 +149,22 @@ uses cache for specific test suites and not merge them.
149
149
  TEST_SUITE_ID=2 bundle exec rspec spec/helpers
150
150
  ```
151
151
 
152
+ - **`USE_TEST_SUITE_ID_CACHE`** (optional, default unset) changes how the remote
153
+ cache validator treats per-suite caches. When set to the exact string `"true"`,
154
+ the validator accepts the current `TEST_SUITE_ID`'s cache independently of the
155
+ other suites' state — so if one suite aborts mid-CI, the remaining suites can
156
+ still reuse their own cached results on the next run. When unset (the default),
157
+ 1.1.x behaviour is preserved byte-for-byte: the validator requires every
158
+ `TEST_SUITES` slot to be present before accepting any cache.
159
+ ```sh
160
+ export TEST_SUITES=3
161
+ export TEST_SUITE_ID=1
162
+ export USE_TEST_SUITE_ID_CACHE=true
163
+ bundle exec rspec spec/models
164
+ ```
165
+ Only the literal string `"true"` activates the flag; `"1"`, `"yes"`, or any
166
+ other truthy value keeps the default behaviour.
167
+
152
168
  ## Advanced Configuration
153
169
 
154
170
  Configuration settings must be defined in **`.rspec-tracer`** file:
@@ -8,6 +8,8 @@ module RSpecTracer
8
8
  def initialize
9
9
  @s3_bucket, @s3_path = setup_s3
10
10
  @aws_cli = RSpecTracer.use_local_aws ? 'awslocal' : 'aws'
11
+ @use_test_suite_id_cache = ENV.fetch('USE_TEST_SUITE_ID_CACHE', nil) == 'true'
12
+ @test_suite_id = ENV.fetch('TEST_SUITE_ID', nil) if @use_test_suite_id_cache
11
13
  end
12
14
 
13
15
  def branch_refs?(branch_name)
@@ -60,7 +62,11 @@ module RSpecTracer
60
62
  end
61
63
 
62
64
  def cache_files_list(ref)
63
- prefix = "s3://#{@s3_bucket}/#{@s3_path}/#{ref}/"
65
+ prefix = if @use_test_suite_id_cache && !@test_suite_id.nil?
66
+ "s3://#{@s3_bucket}/#{@s3_path}/#{ref}/#{@test_suite_id}/"
67
+ else
68
+ "s3://#{@s3_bucket}/#{@s3_path}/#{ref}/"
69
+ end
64
70
 
65
71
  `#{@aws_cli} s3 ls #{prefix} --recursive`.chomp.split("\n")
66
72
  end
@@ -125,7 +131,7 @@ module RSpecTracer
125
131
  remote_dir = s3_dir(ref, run_id)
126
132
  local_dir = File.join(RSpecTracer.cache_path, run_id)
127
133
 
128
- raise AwsError, "Failed to download files from #{local_dir}" unless system(
134
+ raise AwsError, "Failed to upload files from #{local_dir}" unless system(
129
135
  @aws_cli,
130
136
  's3',
131
137
  'cp',
@@ -3,16 +3,19 @@
3
3
  module RSpecTracer
4
4
  module RemoteCache
5
5
  class Validator
6
+ class ValidationError < StandardError; end
7
+
6
8
  CACHE_FILES_PER_TEST_SUITE = 11
7
9
 
8
10
  def initialize
9
11
  @test_suite_id = ENV.fetch('TEST_SUITE_ID', nil)
10
12
  @test_suites = ENV.fetch('TEST_SUITES', nil)
13
+ @use_test_suite_id_cache = ENV.fetch('USE_TEST_SUITE_ID_CACHE', nil) == 'true'
11
14
 
12
15
  if @test_suite_id.nil? ^ @test_suites.nil?
13
16
  raise(
14
17
  ValidationError,
15
- 'Both the enviornment variables TEST_SUITE_ID and TEST_SUITES are not set'
18
+ 'Both the environment variables TEST_SUITE_ID and TEST_SUITES are not set'
16
19
  )
17
20
  end
18
21
 
@@ -20,13 +23,11 @@ module RSpecTracer
20
23
  end
21
24
 
22
25
  def valid?(ref, cache_files)
23
- last_run_regex = Regexp.new(format(@last_run_files_regex, ref: ref))
24
-
25
- return false if cache_files.count { |file| file.match?(last_run_regex) } != @last_run_files_count
26
-
27
- cache_regex = Regexp.new(format(@cached_files_regex, ref: ref))
28
-
29
- cache_files.count { |file| file.match?(cache_regex) } == @cached_files_count
26
+ if @use_test_suite_id_cache
27
+ test_suite_id_specific_validation?(ref, cache_files)
28
+ else
29
+ general_validation?(ref, cache_files)
30
+ end
30
31
  end
31
32
 
32
33
  private
@@ -36,7 +37,7 @@ module RSpecTracer
36
37
  @last_run_files_count = 1
37
38
  @last_run_files_regex = '/%<ref>s/last_run.json$'
38
39
  @cached_files_count = CACHE_FILES_PER_TEST_SUITE
39
- @cached_files_regex = '/%<ref>s/[0-9a-f]{32}/.+.json'
40
+ @cached_files_regex = '/%<ref>s/[0-9a-f]{32}/.+.json$'
40
41
  else
41
42
  @test_suites = @test_suites.to_i
42
43
  @test_suites_regex = (1..@test_suites).to_a.join('|')
@@ -47,6 +48,25 @@ module RSpecTracer
47
48
  @cached_files_regex = "/%<ref>s/(#{@test_suites_regex})/[0-9a-f]{32}/.+.json$"
48
49
  end
49
50
  end
51
+
52
+ def general_validation?(ref, cache_files)
53
+ last_run_regex = Regexp.new(format(@last_run_files_regex, ref: ref))
54
+
55
+ return false if cache_files.count { |file| file.match?(last_run_regex) } != @last_run_files_count
56
+
57
+ cache_regex = Regexp.new(format(@cached_files_regex, ref: ref))
58
+
59
+ cache_files.count { |file| file.match?(cache_regex) } == @cached_files_count
60
+ end
61
+
62
+ def test_suite_id_specific_validation?(ref, cache_files)
63
+ last_run_regex = Regexp.new("/#{ref}/#{@test_suite_id}/last_run.json$")
64
+ cache_regex = Regexp.new("/#{ref}/#{@test_suite_id}/[0-9a-f]{32}/.+.json$")
65
+
66
+ return false unless cache_files.any? { |file| file.match?(last_run_regex) }
67
+
68
+ cache_files.any? { |file| file.match?(cache_regex) }
69
+ end
50
70
  end
51
71
  end
52
72
  end
@@ -25,7 +25,15 @@ module RSpecTracer
25
25
  end
26
26
 
27
27
  def file_path(file_name)
28
+ return file_name if absolute_external_file?(file_name)
29
+
28
30
  File.expand_path(file_name.sub(%r{^/}, ''), RSpecTracer.root)
29
31
  end
32
+
33
+ def absolute_external_file?(file_name)
34
+ file_name.start_with?('/') &&
35
+ !file_name.start_with?(RSpecTracer.root) &&
36
+ File.file?(file_name)
37
+ end
30
38
  end
31
39
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RSpecTracer
4
- VERSION = '1.1.2'
4
+ VERSION = '1.2.0'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspec-tracer
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.2
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Abhimanyu Singh
@@ -111,7 +111,7 @@ licenses:
111
111
  - MIT
112
112
  metadata:
113
113
  homepage_uri: https://github.com/avmnu-sng/rspec-tracer
114
- source_code_uri: https://github.com/avmnu-sng/rspec-tracer/tree/v1.1.2
114
+ source_code_uri: https://github.com/avmnu-sng/rspec-tracer/tree/v1.2.0
115
115
  changelog_uri: https://github.com/avmnu-sng/rspec-tracer/blob/main/CHANGELOG.md
116
116
  bug_tracker_uri: https://github.com/avmnu-sng/rspec-tracer/issues
117
117
  rdoc_options: []