bundler-resolutions 0.3.0 → 0.4.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: 7a6def9961c77861086b6b58177a934945938362e2125ba5dc49b8a6c06efdff
4
- data.tar.gz: ccef554f38761f9916843d675f70ef7189ef8a7070bdb3d9b2e466e2eed998de
3
+ metadata.gz: a4f090d8833033fef1949501d9b8876333cfbc8797c954306f4ee57d963981dc
4
+ data.tar.gz: 0400ae342a0e9b8c50f7644daf99b7642954fda1d2758e68b8b06041472244b6
5
5
  SHA512:
6
- metadata.gz: '01507905d1b9402c1efc92f9509b5aeef2b858d18c3b3e8555af937e1b479dc4b2711f87eed3ef87b8d64bfb7285bb299322a5925d43013e6dac6afa2128b5ba'
7
- data.tar.gz: c85660a42a9149ffcded4f649ef8b2d9413da63eb435d9c8231be3fcdf26dc6aebea0a6608bd1206298ac3caf47b01681a573cecc4e92b0dc3b6638a893b219d
6
+ metadata.gz: cc78cd3cfacb3b56a160fe9a59acffb848360f082a2e326a647f2c547ddd31a692198fdcb13faf1ac50a224b6595c00cf11aa725f98cbfc98a0cd5453f95d263
7
+ data.tar.gz: 77cdeadf7f8fda11a215e8ab50d9c1506e400991a087b07e5edceef0d796c2faad2681979a2bbd41324ae5d99820377e8c710467895b21932b91990396756721
data/README.md CHANGED
@@ -33,7 +33,7 @@ gems:
33
33
 
34
34
  `Gemfile`:
35
35
  ```ruby
36
- gem 'bundler-resolutions'
36
+ gem "bundler-resolutions", path: "../", install_if: -> { require Gem::Specification.find_by_name('bundler-resolutions').gem_dir + "/lib/bundler/resolutions"; true }
37
37
  gem "rails"
38
38
  ```
39
39
 
@@ -15,7 +15,7 @@ module Bundler
15
15
  YAML.safe_load_file(find_config(config))
16
16
  end
17
17
  gems = raw_hash.fetch("gems")
18
- gems.transform_values { |version| Gem::Requirement.new(version.split(",")) }
18
+ gems.transform_values { |reqs| Array(reqs).map { |req| Gem::Requirement.new(req) } }
19
19
  end
20
20
 
21
21
  private def find_config(config = nil)
@@ -25,8 +25,8 @@ module Bundler
25
25
  env_file = ENV["BUNDLER_RESOLUTIONS_CONFIG"]
26
26
  return env_file if env_file
27
27
 
28
- # Otherwise find it in the file tree
29
- dir = Dir.pwd
28
+ # Otherwise find it above where `BUNDLE_GEMFILE` is located, or pwd if not set
29
+ dir = ENV["BUNDLE_GEMFILE"] ? File.dirname(ENV["BUNDLE_GEMFILE"]) : Dir.pwd
30
30
  until File.exist?(File.join(dir, CONFIG_FILE_NAME))
31
31
  dir = File.dirname(dir)
32
32
  raise "Could not find #{CONFIG_FILE_NAME}" if dir == "/"
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "../resolutions"
4
-
5
3
  module Bundler
6
4
  class Resolutions
7
- VERSION = "0.3.0"
5
+ VERSION = "0.4.0"
8
6
  end
9
7
  end
8
+
9
+ require_relative "../resolutions"
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "yaml"
4
4
  require_relative "resolutions/config"
5
+ require_relative "resolutions/version"
5
6
 
6
7
  module Bundler
7
8
  class Resolutions
@@ -15,19 +16,24 @@ module Bundler
15
16
 
16
17
  class << self
17
18
  def instance
18
- @instance ||= new
19
+ @instance ||= new # rubocop:disable ThreadSafety/ClassInstanceVariable
20
+ end
21
+
22
+ # You can debug with BUNDLER_RESOLUTIONS_DEBUG=gem_name or BUNDLER_RESOLUTIONS_DEBUG=true
23
+ # to see all messages.
24
+ def log(message, gem = nil)
25
+ return if ENV["BUNDLER_RESOLUTIONS_DEBUG"].nil?
26
+ unless ENV["BUNDLER_RESOLUTIONS_DEBUG"] == "true" ||
27
+ ENV["BUNDLER_RESOLUTIONS_DEBUG"].split(",").include?(gem)
28
+ return
29
+ end
30
+
31
+ puts "bundler-resolutions: #{message}"
19
32
  end
20
33
  end
21
34
 
22
35
  # A module we prepend to Bundler::Resolutions::Resolver
23
- # :reek:ModuleInitialize
24
36
  module Resolver
25
- # Override the initializer in the resolver
26
- def initialize(*args)
27
- Bundler::Resolutions.instance.add_concrete_resolutions_for(args.first)
28
- super
29
- end
30
-
31
37
  # This overrides the default behaviour of the resolver to filter out versions that don't
32
38
  # satisfy the requirements specified in .bundler-resolutions.yml.
33
39
  def filtered_versions_for(package)
@@ -36,79 +42,66 @@ module Bundler
36
42
  end
37
43
 
38
44
  def constrain_versions_for(results, package)
45
+ log("Constraining versions for #{package} with results: #{results.map(&:to_s)}")
39
46
  results.select do |pkg|
40
- req = resolutions_for(package.name)
41
- if req
42
- log("making sure #{package} is satisfied by #{req}")
43
- req.satisfied_by?(pkg.version)
44
- else
47
+ reqs = resolutions_for(package.name)
48
+ if reqs.nil?
45
49
  true
46
- end
47
- end
48
- end
49
-
50
- def add_concrete_resolutions_for(base)
51
- base.requirements.each do |bundler_dependency|
52
- requirement_name = bundler_dependency.name
53
- resolutions = resolutions_for(requirement_name)
54
-
55
- if resolutions
56
- log(<<~MSG, requirement_name)
57
- has resolutions for concrete dependency '#{requirement_name}': #{resolutions}
58
- MSG
59
50
  else
60
- log("has no resolutions for concrete dependency '#{requirement_name}'", requirement_name)
61
- next
51
+ log("making sure #{package} / #{pkg} is satisfied by #{reqs.map(&:to_s)}")
52
+ reqs.all? { |req| req.satisfied_by?(pkg.version) }
62
53
  end
63
-
64
- bundler_resolutions_reqs = resolutions.requirements
65
- apply_resolutions_for_concrete_gem(bundler_dependency, bundler_resolutions_reqs)
66
54
  end
67
55
  end
68
56
 
69
- private def resolutions_for(package_name)
57
+ def resolutions_for(package_name)
70
58
  config[package_name]
71
59
  end
72
60
 
73
- # You can debug with BUNDLER_RESOLUTIONS_DEBUG=gem_name or BUNDLER_RESOLUTIONS_DEBUG=true
74
- # to see all messages.
75
- private def log(message, gem = nil)
76
- return unless ENV["BUNDLER_RESOLUTIONS_DEBUG"]
77
- return if gem && !ENV["BUNDLER_RESOLUTIONS_DEBUG"].split(",").include?(gem)
61
+ def log(message, gem = nil) = self.class.log(message, gem)
78
62
 
79
- puts "bundler-resolutions: #{message}"
80
- end
81
-
82
- private def apply_resolutions_for_concrete_gem(bundler_dependency, bundler_resolutions_reqs)
83
- requirement_name = bundler_dependency.name
84
- bundler_resolutions_reqs.each do |r|
85
- # If the concrete requirement is already in the Gemfile, skip it
86
- requirements = bundler_dependency.requirement.requirements
87
- if requirements.include?(r)
88
- # We don't want to double up / dupe the same requirements
89
- log(<<~MSG, requirement_name)
90
- Skipping adding requirements to gem concretely specified in Gemfile as it
91
- was already present: #{requirement_name}: #{bundler_dependency}
92
- MSG
93
- next
94
- end
95
-
96
- # Otherwise add the additional requirement
97
- before_req = bundler_dependency.to_s
98
- # If there were no requirements before, there is a default one for ">= 0". We need to
99
- # remove that so when we add the new one the implicit ">= 0" is not present, as it normally
100
- # isn't written out to lockfiles.
101
- requirements.clear if bundler_dependency.requirement == DEFAULT_GEM_REQUIREMENT
102
- # Add the new requirement
103
- requirements << r
104
- after_req = bundler_dependency.to_s
105
-
106
- log(<<~MSG, requirement_name)
107
- Adding concrete constraints for #{requirement_name}. Before: #{before_req}. After: #{after_req}.
108
- MSG
63
+ module Definition
64
+ def check_lockfile
65
+ super
66
+ invalids = @locked_specs.to_a.select { |lazy_specification|
67
+ reqs = Bundler::Resolutions.instance.resolutions_for(lazy_specification.name)
68
+ next if reqs.nil?
69
+
70
+ # rubocop:disable Layout/LineLength
71
+ if reqs.all? { |req| req.satisfied_by?(lazy_specification.version) }
72
+ Bundler::Resolutions.log "#{lazy_specification.name} (#{lazy_specification.version}) is satisfied by the current lockfile version."
73
+ nil
74
+ else
75
+ Bundler::Resolutions.log "#{lazy_specification.name} (#{lazy_specification.version}) is NOT satisfied by the current lockfile version."
76
+ lazy_specification
77
+ end
78
+ # rubocop:enable Layout/LineLength
79
+ }
80
+ @locked_specs.delete(invalids)
109
81
  end
110
82
  end
111
83
  end
112
84
  end
113
85
 
86
+ # Check if the methods exists before we prepend them, to avoid issues with Bundler versions
87
+ # that do not have this method.
88
+ {
89
+ Bundler::Resolver => :filtered_versions_for,
90
+ Bundler::Definition => :nothing_changed?,
91
+ }.each do |klass, method|
92
+ next if klass.instance_methods.include?(method) || klass.private_instance_methods.include?(method)
93
+
94
+ raise <<~ERR
95
+ Bundler version #{Bundler::VERSION} is not compatible with bundler-resolutions #{Bundler::Resolutions::VERSION}
96
+ The method '#{method}' is not defined in '#{klass}'. This is likely due to a refactoring of a new
97
+ Bundler version. Please check the bundler-resolutions changelog and the Bundler changelog
98
+ to see if this is a known issue, or submit a bug report to bundler-resolutions.
99
+ ERR
100
+ end
101
+
102
+ # This is needed so we can trigger a rebuild of the lock file if just the yaml has changed.
103
+ Bundler::Definition.prepend(Bundler::Resolutions::Definition)
104
+ # This removes the transitive dependency versions that do not satisfy the yaml config.
114
105
  Bundler::Resolver.prepend(Bundler::Resolutions::Resolver)
106
+
107
+ Bundler::Resolutions.log("bundler-resolutions #{Bundler::Resolutions::VERSION} loaded")
metadata CHANGED
@@ -1,13 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bundler-resolutions
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Harry Lascelles
8
+ autorequire:
8
9
  bindir: bin
9
10
  cert_chain: []
10
- date: 2025-05-03 00:00:00.000000000 Z
11
+ date: 2025-06-03 00:00:00.000000000 Z
11
12
  dependencies: []
12
13
  description: A bundler plugin to enforce resolutions without specifying a concrete
13
14
  dependency
@@ -32,6 +33,7 @@ metadata:
32
33
  source_code_uri: https://github.com/hlascelles/bundler-resolutions/
33
34
  bug_tracker_uri: https://github.com/hlascelles/bundler-resolutions/issues
34
35
  rubygems_mfa_required: 'true'
36
+ post_install_message:
35
37
  rdoc_options: []
36
38
  require_paths:
37
39
  - lib
@@ -46,7 +48,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
46
48
  - !ruby/object:Gem::Version
47
49
  version: '0'
48
50
  requirements: []
49
- rubygems_version: 3.6.6
51
+ rubygems_version: 3.5.22
52
+ signing_key:
50
53
  specification_version: 4
51
54
  summary: A bundler plugin to enforce resolutions without specifying a concrete dependency
52
55
  test_files: []