bundler-dependencies 0.5.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c16e60328617e09d591746dda98147960439c09872d72f19c190cfd9db7dc507
4
- data.tar.gz: f47346858b2f17ce75367442716e57d954a858bd7bb5e41d7021b1086b4e6ea6
3
+ metadata.gz: 14ac3a29d55de090dd738670f145af12e8777c7e764e195593cb33355fb61e74
4
+ data.tar.gz: 31364e1126f8b6a35054dcece7c7bd7b0dbc2ed9c181ad5a836e2c0c7a91e961
5
5
  SHA512:
6
- metadata.gz: '09d8abbe0cf1bc3bec621640976db86f8ce8a9b7cb1e15cfa6ea8b28721249e66f5145de0c09438cd2a556ffe232fc038cb5d9dbe79748c97a79c9ac36efc990'
7
- data.tar.gz: 01bb7b0342df912eb034bb583e5abac4c487ed60a98ea94b491ad22e8bb4c950f4a23d7768ec7b6b7139f578b6b028011423b2328cf2430f0fc8443864c075fa
6
+ metadata.gz: bbaa127be7d0396701f9bfc257129493c01b9c1b2953a0120e88ce34b13b044bcbd9f161ff6756fbf9e605df9679b80c830f63fbe446d1e3f9ac3d9f7d8a3836
7
+ data.tar.gz: d98b0b92b3cc44cf1c550d1f4c5ce5f2bd9fc1fadb1232a2c5890e2e291a73757ca05fa8aa21de2c90252355f9cb2b7ce4938420b640be3b1615727867b2d515
@@ -0,0 +1,34 @@
1
+ # This workflow uses actions that are not certified by GitHub.
2
+ # They are provided by a third-party and are governed by
3
+ # separate terms of service, privacy policy, and support
4
+ # documentation.
5
+ # This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
6
+ # For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
7
+
8
+ name: Lint
9
+
10
+ on:
11
+ push:
12
+ branches: [ "master" ]
13
+ pull_request:
14
+ branches: [ "master" ]
15
+
16
+ concurrency:
17
+ group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
18
+ cancel-in-progress: true
19
+
20
+ permissions:
21
+ contents: read
22
+
23
+ jobs:
24
+ rubocop:
25
+ name: Run Rubocop
26
+ runs-on: ubuntu-latest
27
+ steps:
28
+ - uses: actions/checkout@v4
29
+ - uses: ruby/setup-ruby@v1
30
+ with:
31
+ ruby-version: ruby # Latest stable CRuby version
32
+ bundler-cache: true
33
+ - name: rubocop
34
+ run: bundle exec rubocop
@@ -0,0 +1,39 @@
1
+ # This workflow uses actions that are not certified by GitHub.
2
+ # They are provided by a third-party and are governed by
3
+ # separate terms of service, privacy policy, and support
4
+ # documentation.
5
+ # This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
6
+ # For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
7
+
8
+ name: Test
9
+
10
+ on:
11
+ push:
12
+ branches: [ "master", "v1.0" ]
13
+ pull_request:
14
+ branches: [ "master", "v1.0" ]
15
+
16
+ concurrency:
17
+ group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
18
+ cancel-in-progress: true
19
+
20
+ permissions:
21
+ contents: read
22
+
23
+ jobs:
24
+ test:
25
+
26
+ runs-on: ubuntu-latest
27
+ strategy:
28
+ matrix:
29
+ ruby-version: ['2.7', '3.0', '3.1', '3.2', '3.3', '3.4', 'head']
30
+
31
+ steps:
32
+ - uses: actions/checkout@v4
33
+ - name: Set up Ruby
34
+ uses: ruby/setup-ruby@v1
35
+ with:
36
+ ruby-version: ${{ matrix.ruby-version }}
37
+ bundler-cache: true # runs 'bundle install' and caches installed gems automatically
38
+ - name: Run tests
39
+ run: bundle exec rspec
data/.rubocop.yml CHANGED
@@ -1,5 +1,9 @@
1
- inherit_gem:
2
- rubocop_defaults: .rubocop.yml
1
+ inherit_from: .rubocop_todo.yml
2
+
3
+ require:
4
+ - rubocop/cop/internal_affairs
5
+ - rubocop-performance
6
+ - rubocop-rspec
3
7
 
4
8
  inherit_mode:
5
9
  merge:
@@ -7,18 +11,43 @@ inherit_mode:
7
11
  - IgnoredMethods
8
12
 
9
13
  AllCops:
10
- TargetRubyVersion: 2.6
14
+ NewCops: enable
15
+ TargetRubyVersion: 3.0
16
+ SuggestExtensions:
17
+ rubocop-rake: false
11
18
  Exclude:
12
19
  - .pryrc
13
20
 
14
- Layout/IndentFirstArrayElement:
21
+ Layout/FirstArrayElementIndentation:
15
22
  EnforcedStyle: consistent
16
23
 
24
+ Layout/ArgumentAlignment:
25
+ EnforcedStyle: with_fixed_indentation
26
+
27
+ Layout/EndAlignment:
28
+ EnforcedStyleAlignWith: variable
29
+
30
+ Naming/FileName:
31
+ Exclude:
32
+ - lib/bundler-dependencies.rb
33
+
17
34
  RSpec/ExampleLength:
18
35
  Max: 10
19
36
  Exclude:
20
37
  - spec/bundler/dependencies/cli_spec.rb
21
38
 
39
+ RSpec/ContextWording:
40
+ Enabled: false
41
+
42
+ RSpec/NamedSubject:
43
+ Enabled: false
44
+
45
+ RSpec/NestedGroups:
46
+ Max: 5
47
+
48
+ RSpec/NotToNot:
49
+ EnforcedStyle: to_not
50
+
22
51
  Style/FormatStringToken:
23
52
  Enabled: false
24
53
 
@@ -26,5 +55,6 @@ Style/NumericPredicate:
26
55
  Enabled: false
27
56
 
28
57
  Style/MethodCallWithArgsParentheses:
29
- IgnoredMethods:
58
+ AllowedMethods:
59
+ - and
30
60
  - method_option
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,33 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2025-01-24 18:08:13 UTC using RuboCop version 1.71.0.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 1
10
+ # Configuration parameters: Severity, Include.
11
+ # Include: **/*.gemspec
12
+ Gemspec/RequiredRubyVersion:
13
+ Exclude:
14
+ - 'bundler-dependencies.gemspec'
15
+
16
+ # Offense count: 14
17
+ # Configuration parameters: AllowedConstants.
18
+ Style/Documentation:
19
+ Exclude:
20
+ - 'lib/bundler/dependencies.rb'
21
+ - 'lib/bundler/dependencies/cli.rb'
22
+ - 'lib/bundler/dependencies/cli/command.rb'
23
+ - 'lib/bundler/dependencies/cli/count.rb'
24
+ - 'lib/bundler/dependencies/cli/find.rb'
25
+ - 'lib/bundler/dependencies/cli/graph.rb'
26
+ - 'lib/bundler/dependencies/cli/with_gem.rb'
27
+ - 'lib/bundler/dependencies/command.rb'
28
+ - 'lib/bundler/dependencies/graph.rb'
29
+ - 'lib/bundler/dependencies/scanner.rb'
30
+ - 'lib/bundler/dependencies/spec.rb'
31
+ - 'lib/bundler/dependencies/visitor.rb'
32
+ - 'lib/bundler/dependencies/visitors/paths.rb'
33
+ - 'lib/bundler/dependencies/visitors/shell_tree.rb'
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.6.2
1
+ 3.4.1
data/CHANGES.md CHANGED
@@ -1,9 +1,35 @@
1
1
  # CHANGELOG
2
2
 
3
- ## 0.5.1 (2019-11-18)
4
- * Fix crash when called without a path argument
5
- * Fix gemspec not setting up executables properly
3
+ ## 1.0.0 (2025-01-24)
6
4
 
7
- ## 0.5.0 (2019-11-18)
5
+ ### New features
6
+ * Gem now works as a bundle plugin!
7
+
8
+ ### Bug fixes
9
+ * Fixed command name outputted when calling `bundle dependencies help`.
10
+
11
+ ### Changes
12
+ * Minimum supported Ruby version increased to 2.7.
13
+ * `thor` version restrictions were relaxed, now allows any `1.x.y` version.
14
+
15
+ ## 0.6.0 (2019-11-18)
16
+
17
+ ### New features
18
+ * Add `find` command to find all gems in the Gemfile which depend on a given gem.
19
+
20
+ ### Bug fixes
21
+ * Fix crash when calling `bundle dependencies graph` with a gem that isn't in the bundle.
22
+
23
+ ### Changes
24
+ * Handle invoking a command with help as the first argument (show the command's help).
25
+ * Add global `--no-color` switch to disable colorizing output.
26
+
27
+ ## 0.5.1
28
+
29
+ ### Bug fixes
30
+ * Fix crash when called without a path argument.
31
+ * Fix gemspec not setting up executables properly.
32
+
33
+ ## 0.5.0
8
34
 
9
35
  Initial version
data/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
2
4
 
3
5
  source 'https://rubygems.org'
@@ -5,4 +7,11 @@ source 'https://rubygems.org'
5
7
  # Specify your gem's dependencies in bundler-dependencies.gemspec
6
8
  gemspec
7
9
 
8
- gem 'rubocop_defaults', github: 'dvandersluis/rubocop_defaults'
10
+ gem 'pry'
11
+ gem 'rake'
12
+ gem 'rspec'
13
+ gem 'rubocop'
14
+ gem 'rubocop-performance'
15
+ gem 'rubocop-rspec'
16
+
17
+ plugin 'bundler-dependencies', path: '.' unless ENV['CI']
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright 2019 Daniel Vandersluis
1
+ Copyright 2019-2025 Daniel Vandersluis
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
4
 
data/README.md CHANGED
@@ -1,11 +1,55 @@
1
1
  # Bundler::Dependencies
2
2
 
3
- [![Build Status](https://travis-ci.org/dvandersluis/bundler-dependencies.svg?branch=master)](https://travis-ci.org/dvandersluis/bundler-dependencies)
3
+ ![Test](https://github.com/dvandersluis/bundler-dependencies/actions/workflows/test.yml/badge.svg)
4
+ ![Lint](https://github.com/dvandersluis/bundler-dependencies/actions/workflows/lint.yml/badge.svg)
5
+ [![Gem Version](https://badge.fury.io/rb/bundler-dependencies.svg)](https://badge.fury.io/rb/bundler-dependencies)
4
6
 
5
7
  Bundler plugin to inspect dependencies of gems used by your project.
6
8
 
9
+ A project's `Gemfile.lock` shows some basic information about what gems are directly depended on by other gems, but this extension takes it a step further and enumerates the entire dependency tree of each gem being depended on. For instance, `rails` has 12 direct dependencies, but altogether installs **40** gems.
10
+
11
+ Each dependency is a potential point of failure, vulnerability, maintenance and *complexity* for a project, so the goal of `bundle dependencies` is to shed some light on what's being installed by what. This shouldn't stop you from installing gems that are useful to your project, but to be able to make an educated decision if a gem with 25 dependencies is a worthy tradeoff, for example.
12
+
13
+ ## Installation
14
+
15
+ Add this line to your application's Gemfile:
16
+
17
+ ```sh
18
+ plugin 'bundler-graph'
19
+ ```
20
+
21
+ And then execute:
22
+
23
+ ```sh
24
+ $ bundle install
25
+ ```
26
+
27
+ Alternately, you can install the plugin directly:
28
+
29
+ ```sh
30
+ $ bundle plugin install bundle-dependencies
31
+ ```
32
+
33
+ ## Usage
34
+
35
+ ```sh
36
+ bundler dependencies [command]
37
+ [--path=PATH] # Path to Gemfile.lock to scan
38
+ [-W, --without=one two three] # Gems to ignore
39
+ [-R, --without-rails] # Ignore all Rails gems
40
+ ```
41
+
42
+ Requires a `Gemfile.lock` or `gems.locked` file to evaluate.
43
+
7
44
  ## Commands
8
45
 
46
+ **NOTE:** By default, `bundler dependencies` runs the `count` command.
47
+
48
+ ### Getting Help
49
+
50
+ * `bundle dependencies help` to get an overview of all commands.
51
+ * `bundle dependencies help COMMAND` to get help for a specific command.
52
+
9
53
  ### Count
10
54
 
11
55
  Check how many dependencies each gem in the Gemfile has (use the `--minimum N` switch to limit the output to gems with at least `N` dependencies):
@@ -14,6 +58,20 @@ Check how many dependencies each gem in the Gemfile has (use the `--minimum N` s
14
58
  bundle dependencies [count] [--minimum N]
15
59
  ```
16
60
 
61
+ ### Find
62
+
63
+ Find all the gems in the Gemfile that depend on a given gem (either directly or indirectly), as well as all the dependency paths for that gem:
64
+
65
+ ```sh
66
+ bundle dependencies find GEM
67
+ ```
68
+
69
+ Get just the number of dependent gems:
70
+
71
+ ```sh
72
+ bundle dependencies find GEM --quiet
73
+ ```
74
+
17
75
  ### Graph
18
76
 
19
77
  See a graph of all dependencies:
@@ -28,6 +86,8 @@ bundle dependencies graph GEMNAME
28
86
 
29
87
  ### Command Options
30
88
 
89
+ The following options can be used with any command:
90
+
31
91
  * `--path PATH`: User the Gemfile for the project at `PATH`, rather than the current project's Gemfile.
32
92
  * `--without foo bar baz`/`-W foo bar baz`: Exclude the listed gems from the scan. Any uses either directly in your Gemfile or as dependencies will be excluded, and not be counted.
33
93
  * `--without-rails`/`-R`: Quick option to exclude all 1st party Rails gems from the scan.
data/Rakefile CHANGED
@@ -1,6 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'bundler/gem_tasks'
2
4
  require 'rspec/core/rake_task'
5
+ require 'rubocop/rake_task'
3
6
 
4
7
  RSpec::Core::RakeTask.new(:spec)
5
8
 
6
- task :default => :spec
9
+ desc 'Run RuboCop'
10
+ RuboCop::RakeTask.new(:rubocop)
11
+
12
+ task default: %i[spec rubocop]
data/bin/console CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'bundler/setup'
4
5
  require 'bundler/dependencies'
@@ -7,8 +8,5 @@ require 'bundler/dependencies'
7
8
  # with your gem easier. You can also use a different console, if you like.
8
9
 
9
10
  # (If you use this, don't forget to add pry to your Gemfile!)
10
- # require "pry"
11
- # Pry.start
12
-
13
- require 'irb'
14
- IRB.start(__FILE__)
11
+ require 'pry'
12
+ Pry.start
@@ -1,29 +1,25 @@
1
- lib = File.expand_path('lib', __dir__)
2
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
- require 'bundler/dependencies/version'
1
+ # frozen_string_literal: true
4
2
 
5
- Gem::Specification.new do |spec|
6
- spec.name = 'bundler-dependencies'
7
- spec.version = Bundler::Dependencies::VERSION
8
- spec.authors = ['Daniel Vandersluis']
9
- spec.email = ['daniel.vandersluis@gmail.com']
10
- spec.licenses = ['MIT']
11
-
12
- spec.summary = 'Find gems in your Gemfile with too many dependencies'
13
- spec.homepage = 'https://github.com/dvandersluis/bundler-dependencies'
3
+ require_relative 'lib/bundler/dependencies/version'
14
4
 
15
- # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
16
- # 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'] = spec.homepage
22
- spec.metadata['changelog_uri'] = "#{spec.homepage}/CHANGES.md"
23
- else
24
- raise 'RubyGems 2.0 or newer is required to protect against ' \
25
- 'public gem pushes.'
26
- end
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'bundler-dependencies'
7
+ spec.version = Bundler::Dependencies::VERSION
8
+ spec.platform = Gem::Platform::RUBY
9
+ spec.required_ruby_version = '>= 2.7'
10
+ spec.authors = ['Daniel Vandersluis']
11
+ spec.email = ['daniel.vandersluis@gmail.com']
12
+ spec.licenses = ['MIT']
13
+
14
+ spec.summary = 'Find gems in your Gemfile with too many dependencies'
15
+ spec.homepage = 'https://github.com/dvandersluis/bundler-dependencies'
16
+
17
+ spec.metadata = {
18
+ 'source_code_uri' => spec.homepage,
19
+ 'changelog_uri' => "#{spec.homepage}/CHANGES.md",
20
+ 'bug_tracker_uri' => "#{spec.homepage}/issues",
21
+ 'rubygems_mfa_required' => 'true'
22
+ }
27
23
 
28
24
  # Specify which files should be added to the gem when it is released.
29
25
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
@@ -31,18 +27,7 @@ Gem::Specification.new do |spec|
31
27
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
32
28
  end
33
29
 
34
- glob = lambda { |patterns| spec.files & Dir[*patterns] }
35
- spec.executables = glob['bin/bundle*'].map { |path| File.basename(path) }
36
- spec.default_executable = spec.executables.first if Gem::VERSION < '1.7.'
37
-
38
30
  spec.require_paths = ['lib']
39
31
 
40
- spec.add_dependency 'bundler', '~> 2.0'
41
- spec.add_dependency 'thor', '~> 0.20.3'
42
-
43
- spec.add_development_dependency 'pry', '~> 0.12.2'
44
- spec.add_development_dependency 'rake', '~> 10.0'
45
- spec.add_development_dependency 'rspec', '~> 3.0'
46
- spec.add_development_dependency 'rubocop', '~> 0.76.0'
47
- spec.add_development_dependency 'rubocop-rspec', '~> 1.36.0'
32
+ spec.add_dependency 'thor', '>= 1', '< 2'
48
33
  end
@@ -1,14 +1,18 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bundler
2
4
  module Dependencies
3
5
  class CLI < ::Thor
4
6
  class Command < ::Thor
5
- RAILS_GEMS = %w(
7
+ RAILS_GEMS = %w[
6
8
  rails actioncable actionmailbox actionmailer actionpack actiontext actionview
7
9
  activejob activemodel activerecord activestorage activesupport railties
8
- ).freeze
10
+ ].freeze
9
11
 
10
12
  def initialize(options)
13
+ super()
11
14
  @options = options
15
+ self.shell = Thor::Shell::Basic.new unless options.color?
12
16
  end
13
17
 
14
18
  no_commands do
@@ -19,7 +23,7 @@ module Bundler
19
23
  end
20
24
  end
21
25
 
22
- private
26
+ private
23
27
 
24
28
  attr_reader :options
25
29
 
@@ -34,14 +38,21 @@ module Bundler
34
38
  def path
35
39
  return options.path if valid_gemfile?(options.path)
36
40
 
37
- SharedHelpers.chdir(File.dirname(options.path)) if options.path
41
+ dir = path_dir(options.path)
42
+ SharedHelpers.chdir(dir) if dir
38
43
  SharedHelpers.default_lockfile
39
44
  end
40
45
 
46
+ def path_dir(path)
47
+ return nil unless path
48
+
49
+ Dir.exist?(options.path) ? options.path : File.dirname(options.path)
50
+ end
51
+
41
52
  def valid_gemfile?(path)
42
53
  return false unless path && File.exist?(path)
43
54
 
44
- %w(Gemfile.lock gems.locked).include?(File.basename(path))
55
+ File.basename(path).end_with?('.lock', '.locked')
45
56
  end
46
57
 
47
58
  def without
@@ -50,12 +61,17 @@ module Bundler
50
61
  end
51
62
  end
52
63
 
64
+ def gems
65
+ @gems ||= graph.without(*without)
66
+ end
67
+
53
68
  def warn(message)
54
- say(message, %i(bold yellow))
69
+ say(message, %i[bold yellow])
55
70
  end
56
71
 
57
72
  def error(message)
58
- say(message, %i(bold red))
73
+ message = shell.send(:prepare_message, message, :red, :bold)
74
+ super
59
75
  end
60
76
  end
61
77
  end
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bundler
2
4
  module Dependencies
3
5
  class CLI < ::Thor
4
6
  class Count < Command
5
- private
7
+ private
6
8
 
7
9
  def to_s
8
10
  say(scanner.to_s, :bold)
@@ -11,7 +13,7 @@ module Bundler
11
13
  end
12
14
 
13
15
  def counts
14
- @counts ||= graph.without(*without).counts(min: options.minimum)
16
+ @counts ||= gems.counts(min: options.minimum)
15
17
  end
16
18
 
17
19
  def warnings
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bundler
4
+ module Dependencies
5
+ class CLI < ::Thor
6
+ class Find < Command
7
+ include WithGem
8
+
9
+ private
10
+
11
+ def to_s
12
+ if dependents.empty?
13
+ error("No gems in the bundle depend on #{gem}.")
14
+ exit(1)
15
+ end
16
+
17
+ banner
18
+ paths unless options.quiet
19
+ end
20
+
21
+ def dependents
22
+ Bundler::Dependencies::Visitors::Paths.new.walk(gems, gem).each_with_object({}) do |path, acc|
23
+ acc[path.first] ||= []
24
+ acc[path.first] << path.join(' → ')
25
+ end
26
+ end
27
+
28
+ def paths
29
+ dependents.each do |gem, paths|
30
+ puts
31
+ say(gem, %i[bold])
32
+ paths.each { |p| say " * #{p}" }
33
+ end
34
+ end
35
+
36
+ def banner
37
+ if options.quiet?
38
+ puts dependents.count
39
+ else
40
+ say("#{dependents.count} gems depend on #{gem}:", :bold)
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -1,22 +1,24 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bundler
2
4
  module Dependencies
3
5
  class CLI < ::Thor
4
6
  class Graph < Command
5
- def initialize(gem, options)
6
- @gem = gem
7
- super(options)
8
- end
7
+ include CLI::WithGem
9
8
 
10
- private
11
-
12
- attr_reader :gem
9
+ private
13
10
 
14
11
  def to_s
15
- Visitors::ShellTree.new.walk(graph.without(*without), shell)
12
+ if gems.empty?
13
+ error("#{gem} is not present in your bundle.")
14
+ exit(1)
15
+ end
16
+
17
+ Visitors::ShellTree.new.walk(gems, shell)
16
18
  end
17
19
 
18
20
  def graph
19
- gem ? Bundler::Dependencies::Graph.new(specs: [Spec.find(gem)]) : super
21
+ gem ? Bundler::Dependencies::Graph.new(specs: [super.find(gem)]) : super
20
22
  end
21
23
  end
22
24
  end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bundler
4
+ module Dependencies
5
+ class CLI < ::Thor
6
+ module WithGem
7
+ def initialize(gem, options)
8
+ @gem = gem
9
+ super(options)
10
+ end
11
+
12
+ private
13
+
14
+ attr_reader :gem
15
+ end
16
+ end
17
+ end
18
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'thor'
2
4
  require 'bundler'
3
5
  require 'bundler/vendored_thor'
@@ -7,33 +9,65 @@ require 'bundler/dependencies'
7
9
  module Bundler
8
10
  module Dependencies
9
11
  class CLI < ::Thor
12
+ package_name 'bundler-dependencies'
13
+
10
14
  def self.shared_options
11
15
  method_option :path, type: :string, desc: 'Path to Gemfile.lock to scan'
12
16
  method_option :without, type: :array, desc: 'Gems to ignore', aliases: ['-W']
13
17
  method_option :without_rails, type: :boolean, default: false, desc: 'Ignore all Rails gems', aliases: ['-R']
18
+ method_option :color, type: :boolean, default: true, desc: 'Colorize output'
19
+ end
20
+
21
+ def self.exit_on_failure?
22
+ true
23
+ end
24
+
25
+ def self.basename
26
+ 'bundle dependencies'
14
27
  end
15
28
 
16
29
  default_task :count
17
30
  map '--version' => :version
31
+ map '--help' => :help
32
+ map '-h' => :help
33
+ map '-?' => :help
18
34
 
19
- desc 'count', 'Checks for gems that install too many dependencies'
35
+ desc 'version', 'Prints the bundler-dependencies version'
36
+ def version
37
+ puts "#{File.basename($PROGRAM_NAME)} #{VERSION}"
38
+ end
39
+
40
+ desc 'count', 'Count the number of dependencies each gem in the bundle relies on, recursively'
20
41
  shared_options
21
- method_option :minimum, type: :numeric, desc: 'Report only gems with a minimum N dependencies', aliases: ['-m'], default: 0
42
+ method_option :minimum, type: :numeric, desc: <<~DESC, aliases: ['-m'], default: 0
43
+ Report only gems with a minimum N dependencies
44
+ DESC
45
+
46
+ def count(*args)
47
+ return help(:count) if args.first == 'help'
22
48
 
23
- def count
24
49
  Count.new(options).output
25
50
  end
26
51
 
27
- desc 'graph [GEM]', 'Outputs a dependency graph'
52
+ desc 'graph [GEM]', 'Output a graph of dependencies, for all gems in the bundle or a specific gem'
28
53
  shared_options
29
54
 
30
55
  def graph(gem = nil)
56
+ return help(:graph) if gem == 'help'
57
+
31
58
  Graph.new(gem, options).output
32
59
  end
33
60
 
34
- desc 'version', 'Prints the bundler-dependencies version'
35
- def version
36
- puts "#{File.basename($PROGRAM_NAME)} #{VERSION}"
61
+ desc 'find [GEM]', 'Output gems in the bundle that depend on GEM'
62
+ shared_options
63
+ method_option :quiet, type: :boolean, default: false, desc: <<~DESC, aliases: ['-q']
64
+ Show only the number of gems and no other output
65
+ DESC
66
+
67
+ def find(gem = nil)
68
+ return help(:find) if gem.nil? || gem == 'help'
69
+
70
+ Find.new(gem, options).output
37
71
  end
38
72
  end
39
73
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bundler
4
+ module Dependencies
5
+ class Command
6
+ Bundler::Plugin::API.command('dependencies', self)
7
+
8
+ def exec(_command_name, args)
9
+ Bundler::Dependencies::CLI.start(args)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bundler
2
4
  module Dependencies
3
5
  class Graph
@@ -9,7 +11,7 @@ module Bundler
9
11
  if lockfile
10
12
  load_lockfile
11
13
  else
12
- @specs = specs
14
+ @specs = specs.compact
13
15
  end
14
16
  end
15
17
 
@@ -26,13 +28,17 @@ module Bundler
26
28
  gems.each(&block)
27
29
  end
28
30
 
31
+ def find(gem)
32
+ include_dependency?(gem) ? Spec.find(gem) : nil
33
+ end
34
+
29
35
  def counts(min: 0)
30
- @counts ||= map do |gem|
36
+ @counts ||= filter_map do |gem|
31
37
  count = gem.dependency_count
32
38
  next if count < min
33
39
 
34
40
  [gem.name, gem.dependency_count]
35
- end.compact.sort_by(&:last).reverse.to_h
41
+ end.sort_by(&:last).reverse.to_h
36
42
  end
37
43
 
38
44
  def delete(*specs)
@@ -49,7 +55,7 @@ module Bundler
49
55
 
50
56
  def include_dependency?(gem)
51
57
  gem = Spec.new(gem) unless gem.is_a?(Spec)
52
- include?(gem) || any? { |spec| spec.dependencies.include_dependency?(gem) }
58
+ include?(gem) || any? { |spec| spec.include_dependency?(gem) }
53
59
  end
54
60
 
55
61
  def without(*gems)
@@ -63,7 +69,7 @@ module Bundler
63
69
  self
64
70
  end
65
71
 
66
- private
72
+ private
67
73
 
68
74
  attr_reader :lockfile, :specs
69
75
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bundler
2
4
  module Dependencies
3
5
  class Scanner
@@ -20,7 +22,7 @@ module Bundler
20
22
  "#{gem_count} gems scanned; #{spec_count} dependencies found"
21
23
  end
22
24
 
23
- private
25
+ private
24
26
 
25
27
  attr_reader :lockfile
26
28
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bundler
2
4
  module Dependencies
3
5
  class Spec
@@ -23,6 +25,10 @@ module Bundler
23
25
  SPECS[name] = self
24
26
  end
25
27
 
28
+ def include_dependency?(gem)
29
+ dependencies.include_dependency?(gem)
30
+ end
31
+
26
32
  def flatten
27
33
  dependencies.inject([]) do |arr, dependency|
28
34
  arr << dependency
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bundler
2
4
  module Dependencies
3
- VERSION = '0.5.1'.freeze
5
+ VERSION = '1.0.0'
4
6
  end
5
7
  end
@@ -1,9 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bundler
2
4
  module Dependencies
3
5
  class Visitor
4
6
  def self.walk(graph, depth = 0, &block)
5
7
  graph.each do |gem|
6
- block.call(gem, depth)
8
+ yield(gem, depth)
7
9
  walk(gem.dependencies, depth + 1, &block) if gem.dependencies
8
10
  end
9
11
  end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bundler
4
+ module Dependencies
5
+ module Visitors
6
+ class Paths
7
+ def walk(graph, name, acc = [], key = [])
8
+ graph.each do |gem|
9
+ next unless gem.include_dependency?(name)
10
+
11
+ new_key = key.dup.push(gem.name)
12
+ walk(gem.dependencies, name, acc, new_key)
13
+ acc << (new_key << name) if gem.dependencies.include?(name)
14
+ end
15
+
16
+ acc
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bundler
2
4
  module Dependencies
3
5
  module Visitors
@@ -15,7 +17,7 @@ module Bundler
15
17
  nil
16
18
  end
17
19
 
18
- private
20
+ private
19
21
 
20
22
  def say(shell, message, opts)
21
23
  if shell
@@ -1,18 +1,24 @@
1
- require 'bundler/dependencies/version'
1
+ # frozen_string_literal: true
2
2
 
3
3
  require 'bundler'
4
4
 
5
- require 'bundler/dependencies/cli'
6
- require 'bundler/dependencies/graph'
7
- require 'bundler/dependencies/scanner'
8
- require 'bundler/dependencies/spec'
9
- require 'bundler/dependencies/visitor'
5
+ require_relative 'dependencies/version'
10
6
 
11
- require 'bundler/dependencies/cli/command'
12
- require 'bundler/dependencies/cli/count'
13
- require 'bundler/dependencies/cli/graph'
7
+ require_relative 'dependencies/cli'
8
+ require_relative 'dependencies/command'
9
+ require_relative 'dependencies/graph'
10
+ require_relative 'dependencies/scanner'
11
+ require_relative 'dependencies/spec'
12
+ require_relative 'dependencies/visitor'
14
13
 
15
- require 'bundler/dependencies/visitors/shell_tree'
14
+ require_relative 'dependencies/cli/command'
15
+ require_relative 'dependencies/cli/with_gem'
16
+ require_relative 'dependencies/cli/count'
17
+ require_relative 'dependencies/cli/find'
18
+ require_relative 'dependencies/cli/graph'
19
+
20
+ require_relative 'dependencies/visitors/shell_tree'
21
+ require_relative 'dependencies/visitors/paths'
16
22
 
17
23
  module Bundler
18
24
  module Dependencies
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'bundler/dependencies'
data/plugins.rb ADDED
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/bundler-dependencies'
metadata CHANGED
@@ -1,157 +1,80 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bundler-dependencies
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Vandersluis
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2019-11-18 00:00:00.000000000 Z
10
+ date: 2025-01-24 00:00:00.000000000 Z
12
11
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: bundler
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '2.0'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '2.0'
27
12
  - !ruby/object:Gem::Dependency
28
13
  name: thor
29
14
  requirement: !ruby/object:Gem::Requirement
30
15
  requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: 0.20.3
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: 0.20.3
41
- - !ruby/object:Gem::Dependency
42
- name: pry
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: 0.12.2
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: 0.12.2
55
- - !ruby/object:Gem::Dependency
56
- name: rake
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
16
+ - - ">="
60
17
  - !ruby/object:Gem::Version
61
- version: '10.0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
18
+ version: '1'
19
+ - - "<"
67
20
  - !ruby/object:Gem::Version
68
- version: '10.0'
69
- - !ruby/object:Gem::Dependency
70
- name: rspec
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - "~>"
74
- - !ruby/object:Gem::Version
75
- version: '3.0'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - "~>"
81
- - !ruby/object:Gem::Version
82
- version: '3.0'
83
- - !ruby/object:Gem::Dependency
84
- name: rubocop
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - "~>"
88
- - !ruby/object:Gem::Version
89
- version: 0.76.0
90
- type: :development
21
+ version: '2'
22
+ type: :runtime
91
23
  prerelease: false
92
24
  version_requirements: !ruby/object:Gem::Requirement
93
25
  requirements:
94
- - - "~>"
95
- - !ruby/object:Gem::Version
96
- version: 0.76.0
97
- - !ruby/object:Gem::Dependency
98
- name: rubocop-rspec
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - "~>"
26
+ - - ">="
102
27
  - !ruby/object:Gem::Version
103
- version: 1.36.0
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - "~>"
28
+ version: '1'
29
+ - - "<"
109
30
  - !ruby/object:Gem::Version
110
- version: 1.36.0
111
- description:
31
+ version: '2'
112
32
  email:
113
33
  - daniel.vandersluis@gmail.com
114
- executables:
115
- - bundle-dependencies
116
- - bundler-dependencies
34
+ executables: []
117
35
  extensions: []
118
36
  extra_rdoc_files: []
119
37
  files:
38
+ - ".github/workflows/lint.yml"
39
+ - ".github/workflows/test.yml"
120
40
  - ".gitignore"
121
41
  - ".rspec"
122
42
  - ".rubocop.yml"
43
+ - ".rubocop_todo.yml"
123
44
  - ".ruby-version"
124
- - ".travis.yml"
125
45
  - CHANGES.md
126
46
  - Gemfile
127
47
  - LICENSE
128
48
  - README.md
129
49
  - Rakefile
130
- - bin/bundle-dependencies
131
- - bin/bundler-dependencies
132
50
  - bin/console
133
51
  - bin/setup
134
52
  - bundler-dependencies.gemspec
53
+ - lib/bundler-dependencies.rb
135
54
  - lib/bundler/dependencies.rb
136
55
  - lib/bundler/dependencies/cli.rb
137
56
  - lib/bundler/dependencies/cli/command.rb
138
57
  - lib/bundler/dependencies/cli/count.rb
58
+ - lib/bundler/dependencies/cli/find.rb
139
59
  - lib/bundler/dependencies/cli/graph.rb
60
+ - lib/bundler/dependencies/cli/with_gem.rb
61
+ - lib/bundler/dependencies/command.rb
140
62
  - lib/bundler/dependencies/graph.rb
141
63
  - lib/bundler/dependencies/scanner.rb
142
64
  - lib/bundler/dependencies/spec.rb
143
65
  - lib/bundler/dependencies/version.rb
144
66
  - lib/bundler/dependencies/visitor.rb
67
+ - lib/bundler/dependencies/visitors/paths.rb
145
68
  - lib/bundler/dependencies/visitors/shell_tree.rb
69
+ - plugins.rb
146
70
  homepage: https://github.com/dvandersluis/bundler-dependencies
147
71
  licenses:
148
72
  - MIT
149
73
  metadata:
150
- allowed_push_host: https://rubygems.org
151
- homepage_uri: https://github.com/dvandersluis/bundler-dependencies
152
74
  source_code_uri: https://github.com/dvandersluis/bundler-dependencies
153
75
  changelog_uri: https://github.com/dvandersluis/bundler-dependencies/CHANGES.md
154
- post_install_message:
76
+ bug_tracker_uri: https://github.com/dvandersluis/bundler-dependencies/issues
77
+ rubygems_mfa_required: 'true'
155
78
  rdoc_options: []
156
79
  require_paths:
157
80
  - lib
@@ -159,15 +82,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
159
82
  requirements:
160
83
  - - ">="
161
84
  - !ruby/object:Gem::Version
162
- version: '0'
85
+ version: '2.7'
163
86
  required_rubygems_version: !ruby/object:Gem::Requirement
164
87
  requirements:
165
88
  - - ">="
166
89
  - !ruby/object:Gem::Version
167
90
  version: '0'
168
91
  requirements: []
169
- rubygems_version: 3.0.3
170
- signing_key:
92
+ rubygems_version: 3.6.2
171
93
  specification_version: 4
172
94
  summary: Find gems in your Gemfile with too many dependencies
173
95
  test_files: []
data/.travis.yml DELETED
@@ -1,22 +0,0 @@
1
- ---
2
- os: linux
3
- language: ruby
4
- cache: bundler
5
- rvm:
6
- - 2.6.5
7
- - 2.5.7
8
- - 2.4.9
9
- - 2.7.0-preview2
10
- before_install: gem install bundler -v 2.0.1
11
-
12
- jobs:
13
- include:
14
- - stage: lint
15
- rvm: 2.6.5
16
- script: bundle exec rubocop
17
- allow_failures:
18
- - rvm: 2.7.0.preview2
19
-
20
- stages:
21
- - lint
22
- - test
@@ -1,10 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'rubygems'
4
-
5
- lib_dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
6
- $LOAD_PATH << lib_dir unless $LOAD_PATH.include?(lib_dir)
7
-
8
- require 'bundler/dependencies/cli'
9
-
10
- Bundler::Dependencies::CLI.start
@@ -1,3 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- load File.expand_path('bundle-dependencies', __dir__)