test_file_finder 0.2.1 → 0.3.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: 753b9d59524b70621af97db8e7167594fb4fa58e50cd0e48883791ad99f41ddf
4
- data.tar.gz: 2ae423a1fd377e425372eed3a362c234f715ef6626c5a67e475021a149a08809
3
+ metadata.gz: 42ce8ef84263c84c281c4e0002f011ce595841daeca4d5da6689a7a34edca1d7
4
+ data.tar.gz: 755701aacdd1fd4af7810366daf3e3c8a10d75a6bea3b749e9f2c1d375b78f76
5
5
  SHA512:
6
- metadata.gz: 3b668ecff7ea38f8dae220e69b3b45e7a35287cd93662e2f77c98342a118c41dacad758f48c450950c7a346f0bd6b3f0e71af261faa132dc0e2d2714840be9bc
7
- data.tar.gz: 27e0652756e2c9b59f31a1bda9f8a630ee986aa099f8a84697df65400e2fc4f3308d079e7941ad75380f2fb4d2bb0bfecb331b21ce3d9355858e0eb1c10391bc
6
+ metadata.gz: 600e982684b54d6b4c35fbdd613df7c6cb595dac85acddc3dc8cef300b882ee100565fa2eac362dfde1cc8cdca645a6c2dd5347f97411f7d06bb749e0520a946
7
+ data.tar.gz: 510046d569019470b0fbcf6ec24e007de694b3d6611a78fe58ff979db81208c66e7fe68ae0dfe071f78334a57f3ea68756c337f726bedd59722bb038000bc6b0
data/.gitlab-ci.yml CHANGED
@@ -6,9 +6,10 @@ stages:
6
6
  variables:
7
7
  BUNDLE_FROZEN: "true"
8
8
 
9
- rspec:
9
+ .default-test-job:
10
+ image: "ruby:${RUBY_VERSION}"
10
11
  stage: test
11
- image: "ruby:$RUBY_VERSION"
12
+ needs: []
12
13
  cache:
13
14
  paths:
14
15
  - vendor/ruby
@@ -17,18 +18,25 @@ rspec:
17
18
  - gem install bundler -v 2.4.13
18
19
  - bundle config set --local path "vendor/ruby/$RUBY_VERSION"
19
20
  - bundle install
20
- script:
21
- - bundle exec rspec
22
- - bundle exec rspec feature
23
21
  parallel:
24
22
  matrix:
25
23
  - RUBY_VERSION:
26
- - "2.7"
27
24
  - "3.0"
28
25
  - "3.1"
29
26
  - "3.2"
30
27
 
28
+ rspec:
29
+ extends: .default-test-job
30
+ script:
31
+ - bundle exec rspec
32
+ - bundle exec rspec feature
33
+
34
+ rubocop:
35
+ extends: .default-test-job
36
+ script:
37
+ - bundle exec rubocop --extra-details .
38
+
31
39
  include:
32
40
  - template: 'Workflows/MergeRequest-Pipelines.gitlab-ci.yml'
33
- - project: 'gitlab-org/quality/pipeline-common'
34
- file: '/ci/gem-release.yml'
41
+ - component: gitlab.com/gitlab-org/components/gem-release/gem-release@~latest
42
+ - component: gitlab.com/gitlab-org/components/danger-review/danger-review@~latest
data/.rubocop.yml ADDED
@@ -0,0 +1,21 @@
1
+ inherit_gem:
2
+ gitlab-styles:
3
+ - rubocop-default.yml
4
+
5
+ require:
6
+ - rubocop-rake
7
+
8
+ AllCops:
9
+ TargetRubyVersion: 3.0
10
+ NewCops: disable
11
+
12
+ # Disables Rails cops.
13
+ Rails:
14
+ Enabled: false
15
+
16
+ # Disables Rails-related cops
17
+ CodeReuse/ActiveRecord:
18
+ Enabled: false
19
+
20
+ RSpec/MultipleMemoizedHelpers:
21
+ Max: 20
data/Dangerfile ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'gitlab-dangerfiles'
4
+
5
+ Gitlab::Dangerfiles.for_project(self, &:import_defaults)
data/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source 'https://rubygems.org'
2
4
 
3
5
  # Specify your gem's dependencies in test_file_finder.gemspec
data/Gemfile.lock CHANGED
@@ -1,25 +1,114 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- test_file_finder (0.2.1)
4
+ test_file_finder (0.3.0)
5
5
  faraday (>= 1.0, < 3.0, != 2.0.0)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
+ activesupport (7.1.3.2)
11
+ base64
12
+ bigdecimal
13
+ concurrent-ruby (~> 1.0, >= 1.0.2)
14
+ connection_pool (>= 2.2.5)
15
+ drb
16
+ i18n (>= 1.6, < 2)
17
+ minitest (>= 5.1)
18
+ mutex_m
19
+ tzinfo (~> 2.0)
10
20
  addressable (2.8.4)
11
21
  public_suffix (>= 2.0.2, < 6.0)
22
+ ast (2.4.2)
23
+ base64 (0.2.0)
24
+ bigdecimal (3.1.7)
12
25
  byebug (11.1.3)
26
+ claide (1.1.0)
27
+ claide-plugins (0.9.2)
28
+ cork
29
+ nap
30
+ open4 (~> 1.3)
31
+ colored2 (3.1.2)
32
+ concurrent-ruby (1.2.3)
33
+ connection_pool (2.4.1)
34
+ cork (0.3.0)
35
+ colored2 (~> 3.1)
13
36
  crack (0.4.5)
14
37
  rexml
38
+ danger (9.4.1)
39
+ claide (~> 1.0)
40
+ claide-plugins (>= 0.9.2)
41
+ colored2 (~> 3.1)
42
+ cork (~> 0.1)
43
+ faraday (>= 0.9.0, < 3.0)
44
+ faraday-http-cache (~> 2.0)
45
+ git (~> 1.13)
46
+ kramdown (~> 2.3)
47
+ kramdown-parser-gfm (~> 1.0)
48
+ no_proxy_fix
49
+ octokit (>= 6.0)
50
+ terminal-table (>= 1, < 4)
51
+ danger-gitlab (8.0.0)
52
+ danger
53
+ gitlab (~> 4.2, >= 4.2.0)
15
54
  diff-lcs (1.5.0)
55
+ drb (2.2.1)
16
56
  faraday (2.7.10)
17
57
  faraday-net_http (>= 2.0, < 3.1)
18
58
  ruby2_keywords (>= 0.0.4)
59
+ faraday-http-cache (2.5.0)
60
+ faraday (>= 0.8)
19
61
  faraday-net_http (3.0.2)
62
+ git (1.18.0)
63
+ addressable (~> 2.8)
64
+ rchardet (~> 1.8)
65
+ gitlab (4.19.0)
66
+ httparty (~> 0.20)
67
+ terminal-table (>= 1.5.1)
68
+ gitlab-dangerfiles (4.6.0)
69
+ danger (>= 9.3.0)
70
+ danger-gitlab (>= 8.0.0)
71
+ rake (~> 13.0)
72
+ gitlab-styles (11.0.0)
73
+ rubocop (~> 1.57.1)
74
+ rubocop-graphql (~> 0.18)
75
+ rubocop-performance (~> 1.15)
76
+ rubocop-rails (~> 2.17)
77
+ rubocop-rspec (~> 2.22)
20
78
  hashdiff (1.0.1)
79
+ httparty (0.21.0)
80
+ mini_mime (>= 1.0.0)
81
+ multi_xml (>= 0.5.2)
82
+ i18n (1.14.4)
83
+ concurrent-ruby (~> 1.0)
84
+ json (2.7.1)
85
+ kramdown (2.4.0)
86
+ rexml
87
+ kramdown-parser-gfm (1.1.0)
88
+ kramdown (~> 2.0)
89
+ language_server-protocol (3.17.0.3)
90
+ lefthook (1.6.5)
91
+ mini_mime (1.1.5)
92
+ minitest (5.22.3)
93
+ multi_xml (0.6.0)
94
+ mutex_m (0.2.0)
95
+ nap (1.1.0)
96
+ no_proxy_fix (0.1.2)
97
+ octokit (8.0.0)
98
+ faraday (>= 1, < 3)
99
+ sawyer (~> 0.9)
100
+ open4 (1.3.4)
101
+ parallel (1.24.0)
102
+ parser (3.3.0.5)
103
+ ast (~> 2.4.1)
104
+ racc
21
105
  public_suffix (5.0.1)
22
- rake (10.5.0)
106
+ racc (1.7.3)
107
+ rack (3.0.8)
108
+ rainbow (3.1.1)
109
+ rake (13.1.0)
110
+ rchardet (1.8.0)
111
+ regexp_parser (2.9.0)
23
112
  rexml (3.2.5)
24
113
  rspec (3.12.0)
25
114
  rspec-core (~> 3.12.0)
@@ -34,7 +123,48 @@ GEM
34
123
  diff-lcs (>= 1.2.0, < 2.0)
35
124
  rspec-support (~> 3.12.0)
36
125
  rspec-support (3.12.0)
126
+ rubocop (1.57.2)
127
+ json (~> 2.3)
128
+ language_server-protocol (>= 3.17.0)
129
+ parallel (~> 1.10)
130
+ parser (>= 3.2.2.4)
131
+ rainbow (>= 2.2.2, < 4.0)
132
+ regexp_parser (>= 1.8, < 3.0)
133
+ rexml (>= 3.2.5, < 4.0)
134
+ rubocop-ast (>= 1.28.1, < 2.0)
135
+ ruby-progressbar (~> 1.7)
136
+ unicode-display_width (>= 2.4.0, < 3.0)
137
+ rubocop-ast (1.31.2)
138
+ parser (>= 3.3.0.4)
139
+ rubocop-capybara (2.20.0)
140
+ rubocop (~> 1.41)
141
+ rubocop-factory_bot (2.25.1)
142
+ rubocop (~> 1.41)
143
+ rubocop-graphql (0.19.0)
144
+ rubocop (>= 0.87, < 2)
145
+ rubocop-performance (1.19.1)
146
+ rubocop (>= 1.7.0, < 2.0)
147
+ rubocop-ast (>= 0.4.0)
148
+ rubocop-rails (2.22.1)
149
+ activesupport (>= 4.2.0)
150
+ rack (>= 1.1)
151
+ rubocop (>= 1.33.0, < 2.0)
152
+ rubocop-rake (0.6.0)
153
+ rubocop (~> 1.0)
154
+ rubocop-rspec (2.27.1)
155
+ rubocop (~> 1.40)
156
+ rubocop-capybara (~> 2.17)
157
+ rubocop-factory_bot (~> 2.22)
158
+ ruby-progressbar (1.13.0)
37
159
  ruby2_keywords (0.0.5)
160
+ sawyer (0.9.2)
161
+ addressable (>= 2.3.5)
162
+ faraday (>= 0.17.3, < 3)
163
+ terminal-table (3.0.2)
164
+ unicode-display_width (>= 1.1.1, < 3)
165
+ tzinfo (2.0.6)
166
+ concurrent-ruby (~> 1.0)
167
+ unicode-display_width (2.5.0)
38
168
  webmock (3.18.1)
39
169
  addressable (>= 2.8.0)
40
170
  crack (>= 0.3.2)
@@ -46,8 +176,12 @@ PLATFORMS
46
176
  DEPENDENCIES
47
177
  bundler (~> 2.1)
48
178
  byebug
49
- rake (~> 10.0)
179
+ gitlab-dangerfiles (~> 4.6.0)
180
+ gitlab-styles (~> 11.0)
181
+ lefthook (~> 1.6)
182
+ rake (~> 13.0)
50
183
  rspec (~> 3.0)
184
+ rubocop-rake (~> 0.6)
51
185
  test_file_finder!
52
186
  webmock (~> 3.18)
53
187
 
data/LICENSE.txt ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2011-2024 GitLab B.V.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ this software and associated documentation files (the “Software”), to deal in
5
+ the Software without restriction, including without limitation the rights to
6
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7
+ of the Software, and to permit persons to whom the Software is furnished to do
8
+ so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
data/README.md CHANGED
@@ -48,7 +48,9 @@ $ rspec $(tff $(git diff --name-only master..head))
48
48
 
49
49
  `TestFileFinder` can be used with an optional YAML mapping file to specify the mapping from a `source` file to a `test` file. Both, `source` and `test` can be lists to map multiple files.
50
50
 
51
- The mapping file is a yaml file containing to entries to match file patterns to its test files. The patterns may include capturing groups to be used to identify the test file. To refer to a captured value in the test file, use the `%s` placeholder. For example:
51
+ The mapping file is a yaml file containing to entries to match source file patterns to its test files.
52
+
53
+ The source file pattern may be an exact file path or a regular expression. The regular expression may include capturing groups to be used to identify the test file. To refer to a captured value in the test file, use the `%s` placeholder. For example:
52
54
 
53
55
  ```yaml
54
56
  mapping:
@@ -67,6 +69,32 @@ mapping:
67
69
  - 'ee/spec/%s%s_spec.rb'
68
70
  ```
69
71
 
72
+ The patterns may include named captures in test files and referenced by its
73
+ name in source files. For example:
74
+
75
+ ```yaml
76
+ mapping:
77
+ # maps `lib/api/issues.rb` to `spec/requests/api/issues/issues_spec.rb`
78
+ - source: 'lib/api/(?<name>.*)\.rb'
79
+ test: 'spec/requests/api/%{name}/%{name}_spec.rb'
80
+ ```
81
+
82
+ Numbered and named captures cannot be mixed in a single pattern.
83
+
84
+ A test file containing metacharacters like `*`, `{}`, `[]`, or `?` is
85
+ considered a file name pattern and [globbing is used to match](https://rubyapi.org/o/dir#method-c-glob)
86
+ the resulting test files.
87
+
88
+ For example:
89
+
90
+ ```yaml
91
+ mapping:
92
+ # maps `lib/api/issues.rb` to tests following this pattern
93
+ # `spec/requests/api/issues/*_spec.rb`
94
+ - source: 'lib/api/(.*)\.rb'
95
+ test: 'spec/requests/api/%s/*_spec.rb'
96
+ ```
97
+
70
98
  Command line example:
71
99
 
72
100
  ```bash
data/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'bundler/gem_tasks'
2
4
  require 'rspec/core/rake_task'
3
5
 
data/exe/tff CHANGED
@@ -1,17 +1,18 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
2
4
  require 'test_file_finder'
3
5
 
4
6
  options = TestFileFinder::OptionParser.parse!(ARGV)
5
7
 
6
8
  TestFileFinder::FileFinder.new(paths: ARGV).tap do |file_finder|
7
- if options.json
8
- file_finder.use TestFileFinder::MappingStrategies::DirectMatching.load_json(options.json)
9
- end
10
- if options.mapping_file
11
- file_finder.use TestFileFinder::MappingStrategies::PatternMatching.load(options.mapping_file)
12
- end
9
+ file_finder.use TestFileFinder::MappingStrategies::DirectMatching.load_json(options.json) if options.json
10
+
11
+ file_finder.use TestFileFinder::MappingStrategies::PatternMatching.load(options.mapping_file) if options.mapping_file
12
+
13
13
  if options.project_path && options.merge_request_iid
14
- file_finder.use TestFileFinder::MappingStrategies::GitlabMergeRequestRspecFailure.new(project_path: options.project_path, merge_request_iid: options.merge_request_iid)
14
+ file_finder.use TestFileFinder::MappingStrategies::GitlabMergeRequestRspecFailure.new(
15
+ project_path: options.project_path, merge_request_iid: options.merge_request_iid)
15
16
  end
16
17
 
17
18
  if file_finder.strategies.empty?
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  RSpec.describe 'tff exe' do
2
- subject { `ruby -Ilib ../exe/tff #{options} #{files}` }
4
+ subject(:output) { `ruby -Ilib ../exe/tff #{options} #{files}` }
3
5
 
4
6
  around do |example|
5
7
  Dir.chdir(File.join(__dir__, '../fixtures')) do
@@ -8,11 +10,11 @@ RSpec.describe 'tff exe' do
8
10
  end
9
11
 
10
12
  context 'without any mapping' do
11
- let(:options) {}
13
+ let(:options) { nil }
12
14
  let(:files) { 'app/models/test_file_finder_gem_executable_widget.rb' }
13
15
 
14
16
  it 'prints matching test files using default rails mapping' do
15
- expect(subject).to eq <<~OUTPUT
17
+ expect(output).to eq <<~OUTPUT
16
18
  spec/models/test_file_finder_gem_executable_widget_spec.rb
17
19
  OUTPUT
18
20
  end
@@ -23,11 +25,11 @@ RSpec.describe 'tff exe' do
23
25
 
24
26
  context 'with multiple sources' do
25
27
  ['db/schema.rb', 'db/migrate/001_init.rb'].each do |file|
26
- context "for file #{file}" do
28
+ context "with file #{file}" do
27
29
  let(:files) { file }
28
30
 
29
31
  it 'prints matching test files using given yaml mapping' do
30
- expect(subject).to eq <<~OUTPUT
32
+ expect(output).to eq <<~OUTPUT
31
33
  spec/db/schema_spec.rb
32
34
  OUTPUT
33
35
  end
@@ -39,7 +41,7 @@ RSpec.describe 'tff exe' do
39
41
  let(:files) { 'spec/models/project_spec.rb' }
40
42
 
41
43
  it 'prints matching test files using given yaml mapping' do
42
- expect(subject).to eq <<~OUTPUT
44
+ expect(output).to eq <<~OUTPUT
43
45
  spec/models/project_spec.rb
44
46
  spec/smoke_spec.rb
45
47
  OUTPUT
@@ -48,11 +50,11 @@ RSpec.describe 'tff exe' do
48
50
 
49
51
  context 'with multiple sources and tests' do
50
52
  ['views/main.html.haml', 'assets/application.css'].each do |file|
51
- context "for file #{file}" do
53
+ context "with file #{file}" do
52
54
  let(:files) { file }
53
55
 
54
56
  it 'prints matching test files using given yaml mapping' do
55
- expect(subject).to eq <<~OUTPUT
57
+ expect(output).to eq <<~OUTPUT
56
58
  spec/views/main_spec.rb
57
59
  features/smoke.feature
58
60
  OUTPUT
@@ -60,6 +62,16 @@ RSpec.describe 'tff exe' do
60
62
  end
61
63
  end
62
64
  end
65
+
66
+ context 'with named captures' do
67
+ let(:files) { 'lib/api/issues.rb' }
68
+
69
+ it 'prints matching test files using given yaml mapping' do
70
+ expect(output).to eq <<~OUTPUT
71
+ spec/requests/api/issues/issues_spec.rb
72
+ OUTPUT
73
+ end
74
+ end
63
75
  end
64
76
 
65
77
  context 'with a yaml mapping and json mapping' do
@@ -67,7 +79,7 @@ RSpec.describe 'tff exe' do
67
79
  let(:files) { 'db/schema.rb app/models/project.rb ' }
68
80
 
69
81
  it 'prints matching test files using both yaml and json mappings' do
70
- expect(subject).to eq <<~OUTPUT
82
+ expect(output).to eq <<~OUTPUT
71
83
  spec/models/project_spec.rb
72
84
  spec/controllers/projects_controller_spec.rb
73
85
  spec/db/schema_spec.rb
@@ -80,7 +92,7 @@ RSpec.describe 'tff exe' do
80
92
  let(:files) { 'app/models/test_file_finder_gem_executable_widget.rb app/models/project.rb' }
81
93
 
82
94
  it 'prints matching test files using json mapping' do
83
- expect(subject).to eq <<~OUTPUT
95
+ expect(output).to eq <<~OUTPUT
84
96
  spec/models/project_spec.rb
85
97
  spec/controllers/projects_controller_spec.rb
86
98
  OUTPUT
@@ -0,0 +1 @@
1
+ # frozen_string_literal: true
data/fixtures/mapping.yml CHANGED
@@ -7,7 +7,7 @@ mapping:
7
7
  - 'db/schema\.rb'
8
8
  - 'db/migrate/(.+)\.rb'
9
9
  test: 'spec/db/schema_spec.rb'
10
- - source: 'spec/(.+)_spec.rb'
10
+ - source: 'spec/(.+)_spec\.rb'
11
11
  test:
12
12
  - 'spec/%s_spec.rb'
13
13
  - 'spec/smoke_spec.rb'
@@ -17,3 +17,7 @@ mapping:
17
17
  test:
18
18
  - 'spec/views/main_spec.rb'
19
19
  - 'features/smoke.feature'
20
+ - source: '(?<ee>ee/)?lib/api/(?<name>.*)\.rb'
21
+ test:
22
+ - '%{ee}spec/requests/api/%{name}_spec.rb'
23
+ - '%{ee}spec/requests/api/%{name}/%{name}_spec.rb'
@@ -1 +1,3 @@
1
+ # frozen_string_literal: true
2
+
1
3
  test projects controller spec
@@ -1 +1,3 @@
1
+ # frozen_string_literal: true
2
+
1
3
  test schema spec
@@ -1 +1,3 @@
1
+ # frozen_string_literal: true
2
+
1
3
  test project spec
@@ -1 +1,3 @@
1
+ # frozen_string_literal: true
2
+
1
3
  existing specs
@@ -0,0 +1 @@
1
+ # frozen_string_literal: true
@@ -1 +1,3 @@
1
+ # frozen_string_literal: true
2
+
1
3
  smoke specs
@@ -1 +1,3 @@
1
+ # frozen_string_literal: true
2
+
1
3
  main page specs
data/lefthook.yml ADDED
@@ -0,0 +1,18 @@
1
+ # Lefthook configuration. For more information, see:
2
+ # https://github.com/evilmartians/lefthook/blob/master/docs/configuration.md
3
+
4
+ pre-push:
5
+ parallel: true
6
+ commands:
7
+ # Run all tests (warn if there are any missing tools required for tests).
8
+ # Run undercover, looking for missing test coverage
9
+ rspec:
10
+ files: git diff --name-only --diff-filter=d $(git merge-base origin/master HEAD)..HEAD
11
+ run: bundle exec rspec -f progress
12
+ glob: '*.rb'
13
+
14
+ # Run ruby linting
15
+ rubocop:
16
+ files: git diff --name-only --diff-filter=d $(git merge-base origin/master HEAD)..HEAD
17
+ glob: '*.{rb,rake}'
18
+ run: bundle exec rubocop --parallel --force-exclusion {files}
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'set'
2
4
 
3
5
  module TestFileFinder
@@ -22,7 +24,18 @@ module TestFileFinder
22
24
  attr_reader :paths
23
25
 
24
26
  def search
25
- file_path_guesses.select { |path| File.exist?(path) }
27
+ file_name_patterns, plain_guesses = file_path_guesses.partition(&file_name_pattern?)
28
+
29
+ file_name_patterns.flat_map { |pattern| Dir.glob(pattern) } +
30
+ plain_guesses.select { |path| File.exist?(path) }
31
+ end
32
+
33
+ # Returns true if a test file name contains metacharacter like *, {, [, ?
34
+ # which indicates a file name pattern.
35
+ #
36
+ # See https://rubyapi.org/o/dir#method-c-glob
37
+ def file_name_pattern?
38
+ proc { |guess| guess.match?(/[*{\[?]/) }
26
39
  end
27
40
 
28
41
  def file_path_guesses
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'set'
2
4
  require 'yaml'
3
5
  require 'test_file_finder/mapping_strategies'
@@ -1,31 +1,58 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'json'
2
4
 
3
5
  module TestFileFinder
4
6
  module MappingStrategies
5
7
  class DirectMatching
6
- JSON_ERROR_MESSAGE = 'json file should contain a json object, with array of test files as the values'.freeze
8
+ JSON_ERROR_MESSAGE = 'json file should contain a json object, with array of test files as the values'
9
+
10
+ attr_reader :map, :limit_percentage, :limit_min
7
11
 
8
- def self.load_json(json_file)
12
+ def self.load_json(json_file, **kwargs)
9
13
  map = JSON.parse(File.read(json_file))
10
14
 
11
- validate(map)
15
+ validate_map(map)
16
+ validate_params(**kwargs)
12
17
 
13
- new.tap do |strategy|
14
- strategy.map = map
15
- end
18
+ new(map, **kwargs)
16
19
  end
17
20
 
18
- def self.validate(map)
19
- return if map.is_a?(Hash) && map.values.all? { |value| value.is_a?(Array) }
21
+ def self.validate_map(map)
22
+ return if map.is_a?(Hash) && map.values.all?(Array)
20
23
 
21
24
  raise InvalidMappingFileError, JSON_ERROR_MESSAGE
22
25
  end
23
26
 
24
- attr_accessor :map
27
+ def self.validate_params(limit_percentage: nil, limit_min: nil)
28
+ return if limit_percentage.nil?
29
+
30
+ limit_percentage_valid = limit_percentage.is_a?(Integer) && (1..100).cover?(limit_percentage)
31
+ raise "Invalid value for limit_percentage: should be an integer between 1 and 100" unless limit_percentage_valid
32
+
33
+ limit_min_valid = limit_min.nil? || (limit_min.is_a?(Integer) && limit_min.positive?)
34
+ return if limit_min_valid
35
+
36
+ raise "Invalid value for limit_min: should be an integer strictly greater than zero"
37
+ end
38
+
39
+ def initialize(map, limit_percentage: nil, limit_min: nil)
40
+ @map = map
41
+ @limit_percentage = limit_percentage
42
+ @limit_min = limit_min
43
+ end
25
44
 
26
45
  def match(files)
27
46
  Array(files).inject(Set.new) do |result, file|
28
47
  test_files = @map.fetch(file, [])
48
+
49
+ if limit_percentage
50
+ sample_size = (limit_percentage * test_files.count).round
51
+ sample_size = limit_min if limit_min && sample_size <= limit_min
52
+
53
+ test_files = test_files.sample(sample_size)
54
+ end
55
+
29
56
  result.merge(test_files)
30
57
  end.to_a
31
58
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'faraday'
2
4
  require 'json'
3
5
  require 'set'
@@ -15,7 +17,7 @@ module TestFileFinder
15
17
  #
16
18
  # It returns file names of rspec failures in the pipeline.
17
19
  class GitlabMergeRequestRspecFailure
18
- TEST_REPORTS_URL_TEMPLATE = 'https://gitlab.com/%{project_path}/-/merge_requests/%{merge_request_iid}/test_reports.json'.freeze
20
+ TEST_REPORTS_URL_TEMPLATE = 'https://gitlab.com/%{project_path}/-/merge_requests/%{merge_request_iid}/test_reports.json'
19
21
 
20
22
  attr_reader :project_path, :merge_request_iid
21
23
 
@@ -53,21 +55,22 @@ module TestFileFinder
53
55
  def rspec_file(failure)
54
56
  file = failure['file'].sub('./', '')
55
57
 
56
- if file.end_with?('spec.rb')
57
- yield file
58
- end
58
+ yield(file) if file.end_with?('spec.rb')
59
59
  end
60
60
 
61
61
  def merge_request_test_reports
62
- test_reports_url = format(TEST_REPORTS_URL_TEMPLATE, { project_path: project_path, merge_request_iid: merge_request_iid })
62
+ test_reports_url = format(TEST_REPORTS_URL_TEMPLATE,
63
+ { project_path: project_path, merge_request_iid: merge_request_iid })
63
64
 
64
- response = Faraday.get(test_reports_url, {}, {'Accept' => 'application/json'})
65
+ response = Faraday.get(test_reports_url, {}, { 'Accept' => 'application/json' })
65
66
 
66
- if response.status == 204
67
- raise TestFileFinder::TestReportError, "Test report for merge request #{merge_request_iid} is not ready, please try again later."
68
- elsif response.status == 400
67
+ case response.status
68
+ when 204
69
+ raise TestFileFinder::TestReportError,
70
+ "Test report for merge request #{merge_request_iid} is not ready, please try again later."
71
+ when 400
69
72
  raise TestFileFinder::TestReportError, "The project #{project_path} does not have test reports configured."
70
- elsif response.status == 500
73
+ when 500
71
74
  raise TestFileFinder::TestReportError, 'Unable to retrieve test report, please try again later.'
72
75
  end
73
76
 
@@ -1,46 +1,53 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module TestFileFinder
2
4
  module MappingStrategies
3
5
  class PatternMatching
4
6
  attr_reader :pattern_matchers
5
7
 
6
8
  def self.load(mapping_file)
7
- content = File.read(mapping_file)
8
- maps = YAML.load(content)['mapping']
9
+ maps = YAML.safe_load_file(mapping_file)['mapping']
9
10
 
10
11
  validate(maps)
11
12
 
12
- new do |mapping|
13
- maps.each do |map|
14
- Array(map['source']).each do |source|
15
- Array(map['test']).each do |test|
16
- mapping.relate(source, test)
17
- end
18
- end
19
- end
20
- end
13
+ new(maps)
21
14
  end
22
15
 
23
- def self.validate(maps)
24
- raise InvalidMappingFileError, 'missing `mapping` in test mapping file' if maps.nil?
25
- raise InvalidMappingFileError, 'missing `source` or `test` in test mapping file' if maps.any? { |map| incomplete?(map) }
16
+ def self.default_rails_mapping
17
+ mapping = new
18
+ mapping.relate(%r{^app/(.+)\.rb$}, 'spec/%s_spec.rb')
19
+ mapping.relate(%r{^lib/(.+)\.rb$}, 'spec/lib/%s_spec.rb')
20
+ mapping.relate(%r{^spec/(.+)_spec\.rb$}, 'spec/%s_spec.rb')
21
+ mapping
26
22
  end
27
23
 
28
- def self.incomplete?(map)
29
- map['source'].nil? || map['test'].nil?
24
+ def self.validate(maps = nil)
25
+ raise InvalidMappingFileError, 'missing `mapping` in test mapping file' if maps.nil?
26
+
27
+ return if maps.all? { |map| complete?(map) }
28
+
29
+ raise InvalidMappingFileError, 'missing `source` or `test` in test mapping file'
30
30
  end
31
31
 
32
- def self.default_rails_mapping
33
- new do |mapping|
34
- mapping.relate(%r{^app/(.+)\.rb$}, 'spec/%s_spec.rb')
35
- mapping.relate(%r{^lib/(.+)\.rb$}, 'spec/lib/%s_spec.rb')
36
- mapping.relate(%r{^spec/(.+)_spec.rb$}, 'spec/%s_spec.rb')
37
- end
32
+ def self.complete?(map)
33
+ !map['source'].nil? && !map['test'].nil?
38
34
  end
39
35
 
40
- def initialize
36
+ def initialize(maps = nil)
41
37
  @pattern_matchers = []
42
38
 
43
- yield self if block_given?
39
+ # Useful for the .default_rails_mapping class method
40
+ #
41
+ # We don't have a file to use, but we still need an instance to be returned
42
+ return unless maps
43
+
44
+ maps.each do |map|
45
+ Array(map['source']).each do |source|
46
+ Array(map['test']).each do |test|
47
+ relate(source, test)
48
+ end
49
+ end
50
+ end
44
51
  end
45
52
 
46
53
  def relate(source, test)
@@ -57,13 +64,29 @@ module TestFileFinder
57
64
  private
58
65
 
59
66
  def pattern_matcher_for(source, test)
60
- regexp = %r{^#{source}$}
67
+ regexp = /^#{source}$/
68
+
69
+ if regexp.named_captures.any?
70
+ pattern_matcher_with_named_captures_for(regexp, test)
71
+ else
72
+ pattern_matcher_with_numbered_captures_for(regexp, test)
73
+ end
74
+ end
61
75
 
76
+ def pattern_matcher_with_named_captures_for(regexp, test)
62
77
  proc do |files|
63
78
  Array(files).flat_map do |file|
64
- if (match = regexp.match(file))
65
- test % match.captures
66
- end
79
+ match = regexp.match(file)
80
+ format(test, match.named_captures.transform_keys(&:to_sym)) if match
81
+ end.compact
82
+ end
83
+ end
84
+
85
+ def pattern_matcher_with_numbered_captures_for(regexp, test)
86
+ proc do |files|
87
+ Array(files).flat_map do |file|
88
+ match = regexp.match(file)
89
+ format(test, *match.captures) if match
67
90
  end.compact
68
91
  end
69
92
  end
@@ -1,9 +1,9 @@
1
- require 'test_file_finder/mapping_strategies/direct_matching'
2
- require 'test_file_finder/mapping_strategies/gitlab_merge_request_rspec_failure'
3
- require 'test_file_finder/mapping_strategies/pattern_matching'
1
+ # frozen_string_literal: true
4
2
 
5
3
  module TestFileFinder
6
4
  module MappingStrategies
7
-
5
+ autoload :DirectMatching, 'test_file_finder/mapping_strategies/direct_matching'
6
+ autoload :PatternMatching, 'test_file_finder/mapping_strategies/pattern_matching'
7
+ autoload :GitlabMergeRequestRspecFailure, 'test_file_finder/mapping_strategies/gitlab_merge_request_rspec_failure'
8
8
  end
9
9
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'optparse'
2
4
 
3
5
  module TestFileFinder
@@ -21,7 +23,8 @@ module TestFileFinder
21
23
  options.json = json
22
24
  end
23
25
 
24
- opts.on('--project-path PROJECT_PATH', String, 'Path of GitLab project, e.g `gitlab-org/gitlab`') do |project_path|
26
+ opts.on('--project-path PROJECT_PATH', String,
27
+ 'Path of GitLab project, e.g `gitlab-org/gitlab`') do |project_path|
25
28
  options.project_path = project_path
26
29
  end
27
30
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module TestFileFinder
2
- VERSION = '0.2.1'
4
+ VERSION = '0.3.0'
3
5
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_file_finder/file_finder'
2
4
  require 'test_file_finder/mapping'
3
5
  require 'test_file_finder/mapping_strategies'
@@ -5,7 +7,7 @@ require 'test_file_finder/option_parser'
5
7
  require 'test_file_finder/version'
6
8
 
7
9
  module TestFileFinder
8
- class Error < StandardError; end
10
+ Error = Class.new(StandardError)
9
11
 
10
12
  InvalidMappingFileError = Class.new(Error)
11
13
  TestReportError = Class.new(Error)
@@ -1,32 +1,34 @@
1
- lib = File.expand_path('../lib', __FILE__)
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
2
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
5
  require 'test_file_finder/version'
4
6
 
5
7
  Gem::Specification.new do |spec|
6
- spec.name = 'test_file_finder'
7
- spec.version = TestFileFinder::VERSION
8
- spec.authors = ['GitLab']
9
- spec.email = ['rubygems-committee@gitlab.com']
8
+ spec.name = 'test_file_finder'
9
+ spec.version = TestFileFinder::VERSION
10
+ spec.licenses = ['MIT']
11
+ spec.authors = ['GitLab']
12
+ spec.email = ['rubygems-committee@gitlab.com']
13
+ spec.required_ruby_version = '>= 3.0'
10
14
 
11
- spec.summary = %q{Guesses spec file paths given input file paths.}
12
- spec.description = %q{A command-line tool for guessing which spec files are relavant to a passed-in set of file paths.}
15
+ spec.summary = %q(Guesses spec file paths given input file paths.)
16
+ spec.description = %q(Command-line tool for guessing which spec files are relevant to a set of input file paths.)
13
17
  spec.homepage = 'https://gitlab.com/gitlab-org/ruby/gems/test_file_finder'
14
18
 
15
19
  # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
16
20
  # to allow pushing to a single host or delete this section to allow pushing to any host.
17
- if spec.respond_to?(:metadata)
18
- spec.metadata['allowed_push_host'] = 'https://rubygems.org'
19
-
20
- spec.metadata['homepage_uri'] = spec.homepage
21
- spec.metadata['source_code_uri'] = 'https://gitlab.com/gitlab-org/ruby/gems/test_file_finder'
22
- spec.metadata['changelog_uri'] = 'https://gitlab.com/gitlab-org/ruby/gems/test_file_finder/-/blob/master/CHANGELOG.md'
23
- else
24
- raise 'RubyGems 2.0 or newer is required to protect against public gem pushes.'
25
- end
21
+ raise 'RubyGems 2.0 or newer is required to protect against public gem pushes.' unless spec.respond_to?(:metadata)
22
+
23
+ spec.metadata['allowed_push_host'] = 'https://rubygems.org'
24
+
25
+ spec.metadata['homepage_uri'] = spec.homepage
26
+ spec.metadata['source_code_uri'] = 'https://gitlab.com/gitlab-org/ruby/gems/test_file_finder'
27
+ spec.metadata['changelog_uri'] = 'https://gitlab.com/gitlab-org/ruby/gems/test_file_finder/-/blob/master/CHANGELOG.md'
26
28
 
27
29
  # Specify which files should be added to the gem when it is released.
28
30
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
29
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
31
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
30
32
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
31
33
  end
32
34
  spec.bindir = 'exe'
@@ -37,7 +39,11 @@ Gem::Specification.new do |spec|
37
39
 
38
40
  spec.add_development_dependency 'bundler', '~> 2.1'
39
41
  spec.add_development_dependency 'byebug'
40
- spec.add_development_dependency 'rake', '~> 10.0'
42
+ spec.add_development_dependency 'gitlab-dangerfiles', '~> 4.6.0'
43
+ spec.add_development_dependency 'gitlab-styles', '~> 11.0'
44
+ spec.add_development_dependency 'lefthook', '~> 1.6'
45
+ spec.add_development_dependency 'rake', '~> 13.0'
41
46
  spec.add_development_dependency 'rspec', '~> 3.0'
47
+ spec.add_development_dependency 'rubocop-rake', '~> 0.6'
42
48
  spec.add_development_dependency 'webmock', '~> 3.18'
43
49
  end
data/tests.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  mapping:
2
- - source: lib/(.+).rb
2
+ - source: lib/(.+)\.rb
3
3
  test: spec/lib/%s_spec.rb
4
- - source: spec/spec_helper.rb
4
+ - source: spec/spec_helper\.rb
5
5
  test: spec
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: test_file_finder
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - GitLab
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-10-30 00:00:00.000000000 Z
11
+ date: 2024-03-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -64,20 +64,62 @@ dependencies:
64
64
  - - ">="
65
65
  - !ruby/object:Gem::Version
66
66
  version: '0'
67
+ - !ruby/object:Gem::Dependency
68
+ name: gitlab-dangerfiles
69
+ requirement: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - "~>"
72
+ - !ruby/object:Gem::Version
73
+ version: 4.6.0
74
+ type: :development
75
+ prerelease: false
76
+ version_requirements: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - "~>"
79
+ - !ruby/object:Gem::Version
80
+ version: 4.6.0
81
+ - !ruby/object:Gem::Dependency
82
+ name: gitlab-styles
83
+ requirement: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - "~>"
86
+ - !ruby/object:Gem::Version
87
+ version: '11.0'
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - "~>"
93
+ - !ruby/object:Gem::Version
94
+ version: '11.0'
95
+ - !ruby/object:Gem::Dependency
96
+ name: lefthook
97
+ requirement: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - "~>"
100
+ - !ruby/object:Gem::Version
101
+ version: '1.6'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - "~>"
107
+ - !ruby/object:Gem::Version
108
+ version: '1.6'
67
109
  - !ruby/object:Gem::Dependency
68
110
  name: rake
69
111
  requirement: !ruby/object:Gem::Requirement
70
112
  requirements:
71
113
  - - "~>"
72
114
  - !ruby/object:Gem::Version
73
- version: '10.0'
115
+ version: '13.0'
74
116
  type: :development
75
117
  prerelease: false
76
118
  version_requirements: !ruby/object:Gem::Requirement
77
119
  requirements:
78
120
  - - "~>"
79
121
  - !ruby/object:Gem::Version
80
- version: '10.0'
122
+ version: '13.0'
81
123
  - !ruby/object:Gem::Dependency
82
124
  name: rspec
83
125
  requirement: !ruby/object:Gem::Requirement
@@ -92,6 +134,20 @@ dependencies:
92
134
  - - "~>"
93
135
  - !ruby/object:Gem::Version
94
136
  version: '3.0'
137
+ - !ruby/object:Gem::Dependency
138
+ name: rubocop-rake
139
+ requirement: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - "~>"
142
+ - !ruby/object:Gem::Version
143
+ version: '0.6'
144
+ type: :development
145
+ prerelease: false
146
+ version_requirements: !ruby/object:Gem::Requirement
147
+ requirements:
148
+ - - "~>"
149
+ - !ruby/object:Gem::Version
150
+ version: '0.6'
95
151
  - !ruby/object:Gem::Dependency
96
152
  name: webmock
97
153
  requirement: !ruby/object:Gem::Requirement
@@ -106,8 +162,8 @@ dependencies:
106
162
  - - "~>"
107
163
  - !ruby/object:Gem::Version
108
164
  version: '3.18'
109
- description: A command-line tool for guessing which spec files are relavant to a passed-in
110
- set of file paths.
165
+ description: Command-line tool for guessing which spec files are relevant to a set
166
+ of input file paths.
111
167
  email:
112
168
  - rubygems-committee@gitlab.com
113
169
  executables:
@@ -119,8 +175,11 @@ files:
119
175
  - ".gitlab-ci.yml"
120
176
  - ".gitlab/merge_request_templates/Release.md"
121
177
  - ".rspec"
178
+ - ".rubocop.yml"
179
+ - Dangerfile
122
180
  - Gemfile
123
181
  - Gemfile.lock
182
+ - LICENSE.txt
124
183
  - README.md
125
184
  - Rakefile
126
185
  - bin/console
@@ -129,15 +188,18 @@ files:
129
188
  - exe/tff
130
189
  - feature/tff_exe_spec.rb
131
190
  - fixtures/features/smoke.feature
191
+ - fixtures/lib/api/issues.rb
132
192
  - fixtures/mapping.json
133
193
  - fixtures/mapping.yml
134
194
  - fixtures/spec/controllers/projects_controller_spec.rb
135
195
  - fixtures/spec/db/schema_spec.rb
136
196
  - fixtures/spec/models/project_spec.rb
137
197
  - fixtures/spec/models/test_file_finder_gem_executable_widget_spec.rb
198
+ - fixtures/spec/requests/api/issues/issues_spec.rb
138
199
  - fixtures/spec/smoke_spec.rb
139
200
  - fixtures/spec/views/main_spec.rb
140
201
  - fixtures/test_reports.json
202
+ - lefthook.yml
141
203
  - lib/test_file_finder.rb
142
204
  - lib/test_file_finder/file_finder.rb
143
205
  - lib/test_file_finder/mapping.rb
@@ -150,13 +212,14 @@ files:
150
212
  - test_file_finder.gemspec
151
213
  - tests.yml
152
214
  homepage: https://gitlab.com/gitlab-org/ruby/gems/test_file_finder
153
- licenses: []
215
+ licenses:
216
+ - MIT
154
217
  metadata:
155
218
  allowed_push_host: https://rubygems.org
156
219
  homepage_uri: https://gitlab.com/gitlab-org/ruby/gems/test_file_finder
157
220
  source_code_uri: https://gitlab.com/gitlab-org/ruby/gems/test_file_finder
158
221
  changelog_uri: https://gitlab.com/gitlab-org/ruby/gems/test_file_finder/-/blob/master/CHANGELOG.md
159
- post_install_message:
222
+ post_install_message:
160
223
  rdoc_options: []
161
224
  require_paths:
162
225
  - lib
@@ -164,15 +227,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
164
227
  requirements:
165
228
  - - ">="
166
229
  - !ruby/object:Gem::Version
167
- version: '0'
230
+ version: '3.0'
168
231
  required_rubygems_version: !ruby/object:Gem::Requirement
169
232
  requirements:
170
233
  - - ">="
171
234
  - !ruby/object:Gem::Version
172
235
  version: '0'
173
236
  requirements: []
174
- rubygems_version: 3.1.6
175
- signing_key:
237
+ rubygems_version: 3.3.26
238
+ signing_key:
176
239
  specification_version: 4
177
240
  summary: Guesses spec file paths given input file paths.
178
241
  test_files: []