Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add RuboCop Performance #5586

Merged
merged 27 commits into from
Sep 5, 2022
Merged

Add RuboCop Performance #5586

merged 27 commits into from
Sep 5, 2022

Conversation

mattt
Copy link
Contributor

@mattt mattt commented Aug 25, 2022

Related to #5588

RuboCop Performance is a RuboCop extension that adds linters for Ruby (anti-)patterns that have an outsized performance impact.

This PR adds rubocop-performance as a development dependency to dependabot-common and updates the shared .rubocop.yml file to enable Performance cops.

@mattt
Copy link
Contributor Author

mattt commented Aug 25, 2022

Disabled Performance/ChainArrayAllocation for now because it was generating an unreasonable number of warnings.

@mattt
Copy link
Contributor Author

mattt commented Aug 25, 2022

With the current slate of cops, we get:

732 files inspected, 311 offenses detected, 211 offenses correctable

Of the remaining after autocorrection:

Rakefile:133:18: C: Performance/SelectMap: Use filter_map instead of select.map.
                 select { |gs| gs.include?("/") }. ...
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
bin/bump-version.rb:12:8: W: Lint/LiteralAsCondition: Literal which gh appeared as a condition.
unless `which gh` && $CHILD_STATUS.success?
       ^^^^^^^^^^
bin/bump-version.rb:17:8: W: Lint/LiteralAsCondition: Literal gh auth status -h github.com > /dev/null 2>&1 appeared as a condition.
unless `gh auth status -h github.com > /dev/null 2>&1` && $CHILD_STATUS.success?
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
bundler/helpers/v1/lib/functions/file_parser.rb:17:13: C: Performance/MethodObjectAsBlock: Use block explicitly instead of block-passing a method object.
        map(&method(:serialize_bundler_dependency))
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
bundler/helpers/v1/lib/functions/file_parser.rb:23:13: C: Performance/MethodObjectAsBlock: Use block explicitly instead of block-passing a method object.
        map(&method(:serialize_bundler_dependency))
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
bundler/helpers/v1/lib/functions/file_parser.rb:79:9: C: Performance/CollectionLiteralInLoop: Avoid immutable Array literals in loops. It is better to extract it into a local variable or a constant.
        [ ...
        ^
bundler/helpers/v1/monkey_patches/fileutils_keyword_splat_patch.rb:14:20: C: Performance/CollectionLiteralInLoop: Avoid immutable Array literals in loops. It is better to extract it into a local variable or a constant.
      reject { |n| [".", ".."].include?(n) }.
                   ^^^^^^^^^^^
bundler/helpers/v2/lib/functions/file_parser.rb:17:13: C: Performance/MethodObjectAsBlock: Use block explicitly instead of block-passing a method object.
        map(&method(:serialize_bundler_dependency))
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
bundler/helpers/v2/lib/functions/file_parser.rb:23:13: C: Performance/MethodObjectAsBlock: Use block explicitly instead of block-passing a method object.
        map(&method(:serialize_bundler_dependency))
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
bundler/helpers/v2/lib/functions/file_parser.rb:80:9: C: Performance/CollectionLiteralInLoop: Avoid immutable Array literals in loops. It is better to extract it into a local variable or a constant.
        [ ...
        ^
bundler/helpers/v2/spec/functions_spec.rb:41:45: C: Performance/CollectionLiteralInLoop: Avoid immutable Array literals in loops. It is better to extract it into a local variable or a constant.
        expect(uri.scheme).to(satisfy { |s| %w(http https).include?(s) })
                                            ^^^^^^^^^^^^^^
bundler/lib/dependabot/bundler/file_fetcher.rb:80:15: C: Performance/SelectMap: Use filter_map instead of select.map.
              select { |f| f.name.end_with?(".gemspec") }. ...
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
bundler/lib/dependabot/bundler/file_fetcher.rb:158:11: C: Performance/SelectMap: Use filter_map instead of select.map.
          select { |f| f.name.end_with?(".gemspec", ".specification") }. ...
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
bundler/lib/dependabot/bundler/file_fetcher.rb:168:13: C: Performance/SelectMap: Use filter_map instead of select.map.
            select { |s| s.source.instance_of?(::Bundler::Source::Path) }. ...
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
bundler/lib/dependabot/bundler/file_updater/gemfile_updater.rb:71:24: C: Performance/CollectionLiteralInLoop: Avoid immutable Array literals in loops. It is better to extract it into a local variable or a constant.
            find { |f| %w(Gemfile gems.rb).include?(f[:file]) }
                       ^^^^^^^^^^^^^^^^^^^
bundler/lib/dependabot/bundler/file_updater/gemfile_updater.rb:77:24: C: Performance/CollectionLiteralInLoop: Avoid immutable Array literals in loops. It is better to extract it into a local variable or a constant.
            find { |f| %w(Gemfile gems.rb).include?(f[:file]) }
                       ^^^^^^^^^^^^^^^^^^^
bundler/lib/dependabot/bundler/file_updater/gemfile_updater.rb:85:24: C: Performance/CollectionLiteralInLoop: Avoid immutable Array literals in loops. It is better to extract it into a local variable or a constant.
            find { |f| %w(Gemfile gems.rb).include?(f[:file]) }
                       ^^^^^^^^^^^^^^^^^^^
bundler/lib/dependabot/bundler/update_checker/file_preparer.rb:228:15: C: Performance/SelectMap: Use filter_map instead of select.map.
              select { |req_string| req_string.match?(VERSION_REGEX) }. ...
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
bundler/lib/dependabot/bundler/update_checker/shared_bundler_helpers.rb:184:33: C: Performance/CollectionLiteralInLoop: Avoid immutable Array literals in loops. It is better to extract it into a local variable or a constant.
              next false unless %w(http https).include?(uri.scheme)
                                ^^^^^^^^^^^^^^
bundler/spec/dependabot/bundler/file_parser_spec.rb:562:31: C: Performance/Count: Use count instead of reject...count.
          expect(dependencies.reject(&:top_level?).count).to eq(23)
                              ^^^^^^^^^^^^^^^^^^^^^^^^^^
cargo/lib/dependabot/cargo/file_fetcher.rb:268:11: C: Performance/SelectMap: Use filter_map instead of select.map.
          select { |file| file.type == "dir" }. ...
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
common/lib/dependabot/clients/github_with_retries.rb:39:11: C: Performance/SelectMap: Use filter_map instead of select.map.
          select { |cred| cred["password"] }. ...
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
common/lib/dependabot/clients/github_with_retries.rb:53:11: C: Performance/SelectMap: Use filter_map instead of select.map.
          select { |cred| cred["password"] }. ...
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
common/lib/dependabot/config/update_config.rb:20:11: C: Performance/SelectMap: Use filter_map instead of select.map.
          select { |ic| self.class.wildcard_match?(normalizer.call(ic.dependency_name), dep_name) }. ...
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
common/lib/dependabot/file_fetchers/base.rb:237:19: C: Performance/CollectionLiteralInLoop: Avoid immutable Array literals in loops. It is better to extract it into a local variable or a constant.
          next if [".", ".."].include?(name)
                  ^^^^^^^^^^^
common/lib/dependabot/file_fetchers/base.rb:248:22: C: Performance/OpenStruct: Consider using Struct over OpenStruct to optimize the performance.
          OpenStruct.new(
                     ^^^
common/lib/dependabot/file_fetchers/base.rb:281:20: C: Performance/OpenStruct: Consider using Struct over OpenStruct to optimize the performance.
        OpenStruct.new(
                   ^^^
common/lib/dependabot/file_fetchers/base.rb:302:24: C: Performance/OpenStruct: Consider using Struct over OpenStruct to optimize the performance.
            OpenStruct.new(
                       ^^^
common/lib/dependabot/file_fetchers/base.rb:321:22: C: Performance/OpenStruct: Consider using Struct over OpenStruct to optimize the performance.
          OpenStruct.new(
                     ^^^
common/lib/dependabot/file_fetchers/base.rb:344:22: C: Performance/OpenStruct: Consider using Struct over OpenStruct to optimize the performance.
          OpenStruct.new(
                     ^^^
common/lib/dependabot/file_fetchers/base.rb:361:22: C: Performance/OpenStruct: Consider using Struct over OpenStruct to optimize the performance.
          OpenStruct.new(
                     ^^^
common/lib/dependabot/git_commit_checker.rb:96:9: C: Performance/SelectMap: Use filter_map instead of select.map.
        select { |t| t.commit_sha == max_tag.commit_sha }. ...
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
common/lib/dependabot/git_metadata_fetcher.rb:99:20: C: Performance/OpenStruct: Consider using Struct over OpenStruct to optimize the performance.
        OpenStruct.new(body: stdout, status: 200)
                   ^^^
common/lib/dependabot/git_metadata_fetcher.rb:101:20: C: Performance/OpenStruct: Consider using Struct over OpenStruct to optimize the performance.
        OpenStruct.new(body: stderr, status: 500)
                   ^^^
common/lib/dependabot/git_metadata_fetcher.rb:107:9: C: Performance/SelectMap: Use filter_map instead of select.map.
        select { |ref| ref.ref_type == :tag }. ...
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
common/lib/dependabot/git_metadata_fetcher.rb:109:22: C: Performance/OpenStruct: Consider using Struct over OpenStruct to optimize the performance.
          OpenStruct.new(
                     ^^^
common/lib/dependabot/git_metadata_fetcher.rb:133:36: C: Performance/OpenStruct: Consider using Struct over OpenStruct to optimize the performance.
        res[ref_name] = OpenStruct.new(
                                   ^^^
common/lib/dependabot/metadata_finders/base/changelog_finder.rb:242:25: C: Performance/CollectionLiteralInLoop: Avoid immutable Array literals in loops. It is better to extract it into a local variable or a constant.
            next unless %w(doc docs).include?(f.name) && f.type == "dir"
                        ^^^^^^^^^^^^
common/lib/dependabot/metadata_finders/base/changelog_finder.rb:261:24: C: Performance/OpenStruct: Consider using Struct over OpenStruct to optimize the performance.
            OpenStruct.new(
                       ^^^
common/lib/dependabot/metadata_finders/base/changelog_finder.rb:283:24: C: Performance/OpenStruct: Consider using Struct over OpenStruct to optimize the performance.
            OpenStruct.new(
                       ^^^
common/lib/dependabot/metadata_finders/base/release_finder.rb:117:27: C: Performance/SelectMap: Use filter_map instead of select.map.
                          select { |nm| nm.chars.count(".") == dot_count }. ...
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
common/lib/dependabot/metadata_finders/base/release_finder.rb:139:27: C: Performance/SelectMap: Use filter_map instead of select.map.
                          select { |nm| nm.chars.count(".") == dot_count }. ...
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
common/lib/dependabot/metadata_finders/base/release_finder.rb:235:24: C: Performance/OpenStruct: Consider using Struct over OpenStruct to optimize the performance.
            OpenStruct.new(
                       ^^^
common/spec/dependabot/git_metadata_fetcher_spec.rb:120:24: C: Performance/OpenStruct: Consider using Struct over OpenStruct to optimize the performance.
            OpenStruct.new(
                       ^^^
composer/lib/dependabot/composer/file_fetcher.rb:87:17: C: Performance/SelectMap: Use filter_map instead of select.map.
                select { |details| details["type"] == "path" }. ...
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
composer/lib/dependabot/composer/file_fetcher.rb:113:23: C: Performance/SelectMap: Use filter_map instead of select.map.
                      select { |file| file.type == "dir" }. ...
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
composer/lib/dependabot/composer/file_fetcher.rb:119:28: C: Performance/SelectMap: Use filter_map instead of select.map.
                           select { |file| file.type == "dir" }. ...
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
composer/lib/dependabot/composer/file_fetcher.rb:138:13: C: Performance/SelectMap: Use filter_map instead of select.map.
            select { |details| details.dig("dist", "type") == "path" }. ...
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
composer/lib/dependabot/composer/file_updater/lockfile_updater.rb:457:13: C: Performance/SelectMap: Use filter_map instead of select.map.
            select { |c| c.fetch("type") == "php_environment_variable" }. ...
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
composer/lib/dependabot/composer/update_checker/latest_version_finder.rb:93:13: C: Performance/SelectMap: Use filter_map instead of select.map.
            select { |version| version_class.correct?(version.gsub(/^v/, "")) }. ...
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
composer/lib/dependabot/composer/update_checker/version_resolver.rb:211:17: C: Performance/SelectMap: Use filter_map instead of select.map.
                select { |req_string| req_string.match?(VERSION_REGEX) }. ...
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
docker/lib/dependabot/docker/file_fetcher.rb:60:11: C: Performance/SelectMap: Use filter_map instead of select.map.
          select { |f| f.type == "file" && f.name.match?(DOCKER_REGEXP) }. ...
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
docker/lib/dependabot/docker/file_fetcher.rb:75:11: C: Performance/SelectMap: Use filter_map instead of select.map.
          select { |f| f.type == "file" && f.name.match?(YAML_REGEXP) }. ...
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
docker/lib/dependabot/docker/file_updater.rb:138:11: C: Performance/SelectMap: Use filter_map instead of select.map.
          select { |r| r[:file] == file.name }. ...
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
docker/lib/dependabot/docker/file_updater.rb:145:11: C: Performance/SelectMap: Use filter_map instead of select.map.
          select { |r| r[:file] == file.name }. ...
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
docker/lib/dependabot/docker/file_updater.rb:189:11: C: Performance/SelectMap: Use filter_map instead of select.map.
          select { |r| r[:file] == file.name }.map do |r| ...
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
elm/lib/dependabot/elm/update_checker/elm_19_version_resolver.rb:162:13: C: Performance/CollectionLiteralInLoop: Avoid immutable Array literals in loops. It is better to extract it into a local variable or a constant.
            %w(direct indirect).each do |category|
            ^^^^^^^^^^^^^^^^^^^
github_actions/lib/dependabot/github_actions/file_fetcher.rb:52:11: C: Performance/SelectMap: Use filter_map instead of select.map.
          select { |f| f.type == "file" && f.name.match?(/\.ya?ml$/) }. ...
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
go_modules/lib/dependabot/go_modules/replace_stubber.rb:21:11: C: Performance/SelectMap: Use filter_map instead of select.map.
          select { |p| stub_replace_path?(p, directory) }. ...
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
go_modules/lib/dependabot/go_modules/update_checker/latest_version_finder.rb:98:31: C: Performance/SelectMap: Use filter_map instead of select.map.
              version_strings.select { |v| version_class.correct?(v) }. ...
                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
gradle/lib/dependabot/gradle/file_fetcher.rb:77:11: C: Performance/SelectMap: Use filter_map instead of select.map.
          select { |filename| filename.include?("dependencies") }. ...
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
gradle/lib/dependabot/gradle/update_checker/version_finder.rb:63:17: C: Performance/SelectMap: Use filter_map instead of select.map.
                select { |node| version_class.correct?(node.content) }. ...
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
gradle/lib/dependabot/gradle/update_checker/version_finder.rb:156:13: C: Performance/SelectMap: Use filter_map instead of select.map.
            select { |v| version_class.correct?(v) }. ...
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
gradle/lib/dependabot/gradle/update_checker/version_finder.rb:217:13: C: Performance/SelectMap: Use filter_map instead of select.map.
            select { |cred| cred["type"] == "maven_repository" }. ...
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
gradle/spec/dependabot/gradle/file_updater_spec.rb:67:11: C: Performance/CollectionLiteralInLoop: Avoid immutable Array literals in loops. It is better to extract it into a local variable or a constant.
          %w(build.gradle build.gradle.kts).include?(f.name)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
hex/lib/dependabot/hex/file_fetcher.rb:54:11: C: Performance/SelectMap: Use filter_map instead of select.map.
          select { |f| f.type == "dir" }. ...
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
hex/lib/dependabot/hex/file_updater/mixfile_sanitizer.rb:28:24: C: Performance/MethodObjectAsBlock: Use block explicitly instead of block-passing a method object.
            yield_self(&method(:prevent_version_file_loading)).
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
hex/lib/dependabot/hex/file_updater/mixfile_sanitizer.rb:29:24: C: Performance/MethodObjectAsBlock: Use block explicitly instead of block-passing a method object.
            yield_self(&method(:prevent_config_path_loading))
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
hex/lib/dependabot/hex/update_checker.rb:215:15: C: Performance/SelectMap: Use filter_map instead of select.map.
              select { |release| version_class.correct?(release["version"]) }. ...
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
hex/lib/dependabot/hex/update_checker/file_preparer.rb:104:15: C: Performance/SelectMap: Use filter_map instead of select.map.
              select { |req_string| req_string.match?(version_regex) }. ...
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
maven/lib/dependabot/maven/file_parser/repositories_finder.rb:44:13: C: Performance/SelectMap: Use filter_map instead of select.map.
            select { |url| url.start_with?("http") }. ...
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
maven/lib/dependabot/maven/update_checker/version_finder.rb:62:17: C: Performance/SelectMap: Use filter_map instead of select.map.
                select { |node| version_class.correct?(node.content) }. ...
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
maven/lib/dependabot/maven/update_checker/version_finder.rb:214:13: C: Performance/SelectMap: Use filter_map instead of select.map.
            select { |cred| cred["type"] == "maven_repository" }. ...
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
npm_and_yarn/lib/dependabot/npm_and_yarn/file_fetcher.rb:212:11: C: Performance/SelectMap: Use filter_map instead of select.map.
          select { |_, v| v.is_a?(String) && v.start_with?(*path_starts) }. ...
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
npm_and_yarn/lib/dependabot/npm_and_yarn/file_fetcher.rb:228:11: C: Performance/SelectMap: Use filter_map instead of select.map.
          select { |_, v| v.fetch("version", "").start_with?(*path_starts) }. ...
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
npm_and_yarn/lib/dependabot/npm_and_yarn/file_fetcher.rb:328:11: C: Performance/SelectMap: Use filter_map instead of select.map.
          select { |file| file.type == "dir" }. ...
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
npm_and_yarn/lib/dependabot/npm_and_yarn/update_checker/version_resolver.rb:386:13: C: Performance/SelectMap: Use filter_map instead of select.map.
            select do |version, details| ...
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
npm_and_yarn/lib/dependabot/npm_and_yarn/update_checker/version_resolver.rb:586:13: C: Performance/SelectMap: Use filter_map instead of select.map.
            select { |req_string| req_string.match?(version_regex) }. ...
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
npm_and_yarn/lib/dependabot/npm_and_yarn/update_checker/version_resolver.rb:588:13: C: Performance/SelectMap: Use filter_map instead of select.map.
            select { |version| version_class.correct?(version.to_s) }. ...
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
nuget/lib/dependabot/nuget/file_fetcher.rb:91:23: C: Performance/SelectMap: Use filter_map instead of select.map.
                      select { |f| f.name.end_with?(".sln") }.map(&:dup).
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
nuget/lib/dependabot/nuget/update_checker/repository_finder.rb:140:13: C: Performance/SelectMap: Use filter_map instead of select.map.
            select { |cred| cred["type"] == "nuget_feed" }. ...
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
python/lib/dependabot/python/file_parser/poetry_files_parser.rb:85:21: C: Performance/CollectionLiteralInLoop: Avoid immutable Array literals in loops. It is better to extract it into a local variable or a constant.
            next if %w(directory git url).include?(details.dig("source", "type"))
                    ^^^^^^^^^^^^^^^^^^^^^
python/lib/dependabot/python/file_updater/pip_compile_file_updater.rb:442:13: C: Performance/SelectMap: Use filter_map instead of select.map.
            select { |cred| cred["type"] == "python_index" }. ...
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
python/lib/dependabot/python/file_updater/pipfile_file_updater.rb:148:13: C: Performance/CollectionLiteralInLoop: Avoid immutable Array literals in loops. It is better to extract it into a local variable or a constant.
            %w(packages dev-packages).each do |type|
            ^^^^^^^^^^^^^^^^^^^^^^^^^
python/lib/dependabot/python/file_updater/pipfile_preparer.rb:118:13: C: Performance/SelectMap: Use filter_map instead of select.map.
            select { |cred| cred["type"] == "python_index" }. ...
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
python/lib/dependabot/python/file_updater/pyproject_preparer.rb:65:23: C: Performance/CollectionLiteralInLoop: Avoid immutable Array literals in loops. It is better to extract it into a local variable or a constant.
              next if %w(directory file url).include?(locked_details&.dig("source", "type"))
                      ^^^^^^^^^^^^^^^^^^^^^^
python/lib/dependabot/python/metadata_finder.rb:159:11: C: Performance/SelectMap: Use filter_map instead of select.map.
          select { |cred| cred["type"] == "python_index" }. ...
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
python/lib/dependabot/python/update_checker.rb:241:11: C: Performance/SelectMap: Use filter_map instead of select.map.
          select { |req_string| req_string.match?(VERSION_REGEX) }. ...
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
python/lib/dependabot/python/update_checker/latest_version_finder.rb:149:18: C: Performance/CollectionLiteralInLoop: Avoid immutable Array literals in loops. It is better to extract it into a local variable or a constant.
              if [401, 403].include?(index_response.status) &&
                 ^^^^^^^^^^
python/lib/dependabot/python/update_checker/latest_version_finder.rb:150:18: C: Performance/CollectionLiteralInLoop: Avoid immutable Array literals in loops. It is better to extract it into a local variable or a constant.
                 [401, 403].include?(registry_index_response(index_url).status)
                 ^^^^^^^^^^
python/lib/dependabot/python/update_checker/pip_compile_version_resolver.rb:237:13: C: Performance/SelectMap: Use filter_map instead of select.map.
            select { |cred| cred["type"] == "python_index" }. ...
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
python/spec/dependabot/python/file_updater_spec.rb:307:34: C: Performance/OpenStruct: Consider using Struct over OpenStruct to optimize the performance.
          and_return([OpenStruct.new(name: "updated files")])
                                 ^^^
python/spec/dependabot/python/file_updater_spec.rb:309:29: C: Performance/OpenStruct: Consider using Struct over OpenStruct to optimize the performance.
          to eq([OpenStruct.new(name: "updated files")])
                            ^^^
python/spec/dependabot/python/file_updater_spec.rb:337:36: C: Performance/OpenStruct: Consider using Struct over OpenStruct to optimize the performance.
            and_return([OpenStruct.new(name: "updated files")])
                                   ^^^
python/spec/dependabot/python/file_updater_spec.rb:339:31: C: Performance/OpenStruct: Consider using Struct over OpenStruct to optimize the performance.
            to eq([OpenStruct.new(name: "updated files")])
                              ^^^
terraform/lib/dependabot/terraform/file_fetcher.rb:43:11: C: Performance/SelectMap: Use filter_map instead of select.map.
          select { |f| f.type == "file" && f.name.end_with?(".tf") }. ...
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
terraform/lib/dependabot/terraform/file_fetcher.rb:50:11: C: Performance/SelectMap: Use filter_map instead of select.map.
          select { |f| f.type == "file" && terragrunt_file?(f.name) }. ...
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
terraform/lib/dependabot/terraform/file_fetcher.rb:62:15: C: Performance/SelectMap: Use filter_map instead of select.map.
              select { |f| f.type == "file" && f.name.end_with?(".tf") }. ...
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

732 files inspected, 98 offenses detected

If we exclude Performance/SelectMap, the total goes down to 44.

If these seem reasonable, we can go through and address them one-by-one.

@deivid-rodriguez
Copy link
Contributor

deivid-rodriguez commented Aug 25, 2022

The suggested cops seem fine, also they lead to more readable code in my opinion, so not only performance gains! I wonder why Lint/LiteralsAsCondition appeared here though, and the offenses seem like false positives to me 🤔.

Copy link
Member

@jeffwidman jeffwidman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 for the idea. I've been wanting to do this for a while. Not approving just because still in draft/significant code changes still inbound.

@mattt mattt marked this pull request as ready for review September 2, 2022 13:56
@mattt mattt requested a review from a team as a code owner September 2, 2022 13:56
@mattt
Copy link
Contributor Author

mattt commented Sep 2, 2022

TIL:

/o causes any #{…} substitutions in a particular regex literal to be performed just once, the first time it is evaluated. Otherwise, the substitutions will be performed every time the literal generates a Regexp object.

@mattt mattt force-pushed the mattt/rubocop-performance branch 7 times, most recently from ae78e5d to 554cb3e Compare September 2, 2022 19:07
Copy link
Contributor

@deivid-rodriguez deivid-rodriguez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really love these, I should use RuboCop more 😄.

Only cop I'm "meh" about is Performance/CaseCmp, because while I think the other cops make the code better (not only faster), this one I don't love it, because it leaks implementation details about the comparison into our code (although I admit well known for most: zero means equality).

As a tiny note, a9aa5e8 mentions "Disable Performance/ArraySemiInfiniteRangeSlice", but I don't see that cop anywhere?

Anyways, thanks for doing this!

next 0 unless all_parts.all? { |part| part.to_i.to_s == part }
# rubocop:enable Performance/RedundantEqualityComparisonBlock
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sounds like an upstream false positive, right? I can report it if so.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's a false positive. It suggests an incorrect fix of all_parts.all?(part.to_i.to_s).

relative_dir = Pathname.new(base_directory).sub(%r{\A/}, "").join(vendor_dir)
# rubocop:enable Performance/DeletePrefix
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one may be skippable upstream too, and also Pathname#delete_prefix sounds like a nice feature request. I can take of requesting both if they make sense.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, there's its complement Performance/DeleteSuffix has a similar problem.

It would be great if RuboCop didn't generate a false positive for Pathname. In rubocop/rubocop-performance#245, they marked it as not safe, but I don't know of any other changes beyond that.

Conversely, it'd also be nice if Pathname responded to #delete_prefix and #delete_suffix. I was surprised those methods didn't exist already.

when *Octokit::RATE_LIMITED_ERRORS
# If we get a rate-limited error we let dependabot-api handle the
# retry by re-enqueing the update job after the reset
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is removing the above comment intentional?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! Those must've been lost in the shuffle when the splat was moved to the end.

@mattt
Copy link
Contributor Author

mattt commented Sep 5, 2022

I really love these, I should use RuboCop more 😄.

As a tiny note, a9aa5e8 mentions "Disable Performance/ArraySemiInfiniteRangeSlice", but I don't see that cop anywhere?

Nice call-out. I reverted that commit after reading the docs for Performance/ArraySemiInfiniteRangeSlice, but neglected to remove the reference after squashing:

This cop was created due to a mistake in microbenchmark and hence is disabled by default. Refer rubocop/rubocop-performance#175 (comment)

Only cop I'm "meh" about is Performance/CaseCmp, because while I think the other cops make the code better (not only faster), this one I don't love it, because it leaks implementation details about the comparison into our code (although I admit well known for most: zero means equality).

I'm not the biggest fan of casecmp's ergonomics, but it is equivalent to the behavior of, for example, the <=> comparator. It's also more correct and faster than an equality check on #downcase. Most ecosystems restrict package names to basic Latin, so this doesn't come up often, but case mapping is full of hidden gotchas (for example, normalization variants for composable characters like é, Turkish dotless i, Greek lowercase sigma, German ß, and others). And #casecmp handles those cases correctly.

Edit: Actually, fact-checking that last statement, I realized that #casecmp does not, in fact, provide that for all Unicode (although #casecmp? does). Still, I'm inclined to use casecmp if only to promote greater awareness of text programming best practices.


@deivid-rodriguez Thanks for your offer to upstream fixes for the false positives. I think that'd be a great thing to do. Please let me know how I can help. 😃

@deivid-rodriguez
Copy link
Contributor

@mattt Ok about Performance/CaseCmp.

Regarding false positives, my offer was to report them, not fix them 😅, but my experience when reporting this kind of issues upstream is that they usually fix them quickly, so we'll see :)

@mattt mattt merged commit c00613f into main Sep 5, 2022
@mattt mattt deleted the mattt/rubocop-performance branch September 5, 2022 14:31
@mctofu mctofu mentioned this pull request Sep 6, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants