Skip to content

Commit eed3780

Browse files
jeremyevanshsbt
authored andcommitted
Switch bundle add to use optimistic versioning by default
Add the recent developer meeting, we discussed switching from using pessimistic versioning by default to using optimistic versioning by default. This is the a step in that direction. It makes bundle add without a explicit version given to use >= (optimistic) instead of ~> (pessimistic). With this, the bundle add --optimistic option is now ignored, since the behavior is now the default. This add a --pessimistic option to set a pessimistic version.
1 parent 763f111 commit eed3780

6 files changed

Lines changed: 59 additions & 44 deletions

File tree

bundler/lib/bundler/cli.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,8 @@ def binstubs(*gems)
403403
method_option "glob", type: :string, banner: "The location of a dependency's .gemspec, expanded within Ruby (single quotes recommended)"
404404
method_option "quiet", type: :boolean, banner: "Only output warnings and errors."
405405
method_option "skip-install", type: :boolean, banner: "Adds gem to the Gemfile but does not install it"
406-
method_option "optimistic", type: :boolean, banner: "Adds optimistic declaration of version to gem"
406+
method_option "optimistic", type: :boolean, banner: "Ignored (now default behavior)"
407+
method_option "pessimistic", type: :boolean, banner: "Adds pessimistic declaration of version to gem"
407408
method_option "strict", type: :boolean, banner: "Adds strict declaration of version to gem"
408409
def add(*gems)
409410
require_relative "cli/add"

bundler/lib/bundler/cli/add.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ def inject_dependencies
3131

3232
Injector.inject(dependencies,
3333
conservative_versioning: options[:version].nil?, # Perform conservative versioning only when version is not specified
34-
optimistic: options[:optimistic],
34+
pessimistic: options[:pessimistic],
3535
strict: options[:strict])
3636
end
3737

@@ -46,7 +46,7 @@ def validate_options!
4646

4747
raise InvalidOption, "You cannot specify `--branch` and `--ref` at the same time." if options["branch"] && options["ref"]
4848

49-
raise InvalidOption, "You cannot specify `--strict` and `--optimistic` at the same time." if options[:strict] && options[:optimistic]
49+
raise InvalidOption, "You cannot specify `--strict` and `--pessimistic` at the same time." if options[:strict] && options[:pessimistic]
5050

5151
# raise error when no gems are specified
5252
raise InvalidOption, "Please specify gems to add." if gems.empty?

bundler/lib/bundler/injector.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,10 @@ def conservative_version(spec)
8989
def version_prefix
9090
if @options[:strict]
9191
"= "
92-
elsif @options[:optimistic]
93-
">= "
94-
else
92+
elsif @options[:pessimistic]
9593
"~> "
94+
else
95+
">= "
9696
end
9797
end
9898

bundler/lib/bundler/man/bundle-add.1

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,10 @@ Do not print progress information to the standard output\.
4646
Adds the gem to the Gemfile but does not install it\.
4747
.TP
4848
\fB\-\-optimistic\fR
49-
Adds optimistic declaration of version\.
49+
Ignored (now default behavior)
50+
.TP
51+
\fB\-\-pessimistic\fR
52+
Adds pessimistic declaration of version\.
5053
.TP
5154
\fB\-\-strict\fR
5255
Adds strict declaration of version\.
@@ -62,7 +65,7 @@ You can add the \fBrails\fR gem with version greater than 1\.1 (not including 1\
6265
.IP "3." 4
6366
You can use the \fBhttps://gems\.example\.com\fR custom source and assign the gem to a group\.
6467
.IP
65-
\fBbundle add rails \-\-version "~> 5\.0\.0" \-\-source "https://gems\.example\.com" \-\-group "development"\fR
68+
\fBbundle add rails \-\-version ">= 5\.0\.0" \-\-source "https://gems\.example\.com" \-\-group "development"\fR
6669
.IP "4." 4
6770
The following adds the \fBgem\fR entry to the Gemfile without installing the gem\. You can install gems later via \fBbundle install\fR\.
6871
.IP

bundler/lib/bundler/man/bundle-add.1.ronn

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,10 @@ Adds the named gem to the [`Gemfile(5)`][Gemfile(5)] and run `bundle install`.
5151
Adds the gem to the Gemfile but does not install it.
5252

5353
* `--optimistic`:
54-
Adds optimistic declaration of version.
54+
Ignored (now default behavior)
55+
56+
* `--pessimistic`:
57+
Adds pessimistic declaration of version.
5558

5659
* `--strict`:
5760
Adds strict declaration of version.
@@ -70,7 +73,7 @@ Adds the named gem to the [`Gemfile(5)`][Gemfile(5)] and run `bundle install`.
7073
3. You can use the `https://gems.example.com` custom source and assign the gem
7174
to a group.
7275

73-
`bundle add rails --version "~> 5.0.0" --source "https://gems.example.com" --group "development"`
76+
`bundle add rails --version ">= 5.0.0" --source "https://gems.example.com" --group "development"`
7477

7578
4. The following adds the `gem` entry to the Gemfile without installing the
7679
gem. You can install gems later via `bundle install`.

spec/commands/add_spec.rb

Lines changed: 42 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -38,34 +38,34 @@
3838
end
3939

4040
describe "without version specified" do
41-
it "version requirement becomes ~> major.minor.patch when resolved version is < 1.0" do
41+
it "version requirement becomes >= major.minor.patch when resolved version is < 1.0" do
4242
bundle "add 'bar'"
43-
expect(bundled_app_gemfile.read).to match(/gem "bar", "~> 0.12.3"/)
43+
expect(bundled_app_gemfile.read).to match(/gem "bar", ">= 0.12.3"/)
4444
expect(the_bundle).to include_gems "bar 0.12.3"
4545
end
4646

47-
it "version requirement becomes ~> major.minor when resolved version is > 1.0" do
47+
it "version requirement becomes >= major.minor when resolved version is > 1.0" do
4848
bundle "add 'baz'"
49-
expect(bundled_app_gemfile.read).to match(/gem "baz", "~> 1.2"/)
49+
expect(bundled_app_gemfile.read).to match(/gem "baz", ">= 1.2"/)
5050
expect(the_bundle).to include_gems "baz 1.2.3"
5151
end
5252

53-
it "version requirement becomes ~> major.minor.patch.pre when resolved version is < 1.0" do
53+
it "version requirement becomes >= major.minor.patch.pre when resolved version is < 1.0" do
5454
bundle "add 'cat'"
55-
expect(bundled_app_gemfile.read).to match(/gem "cat", "~> 0.12.3.pre"/)
55+
expect(bundled_app_gemfile.read).to match(/gem "cat", ">= 0.12.3.pre"/)
5656
expect(the_bundle).to include_gems "cat 0.12.3.pre"
5757
end
5858

59-
it "version requirement becomes ~> major.minor.pre when resolved version is > 1.0.pre" do
59+
it "version requirement becomes >= major.minor.pre when resolved version is >= 1.0.pre" do
6060
bundle "add 'dog'"
61-
expect(bundled_app_gemfile.read).to match(/gem "dog", "~> 1.1.pre"/)
61+
expect(bundled_app_gemfile.read).to match(/gem "dog", ">= 1.1.pre"/)
6262
expect(the_bundle).to include_gems "dog 1.1.3.pre"
6363
end
6464

65-
it "version requirement becomes ~> major.minor.pre.tail when resolved version has a very long tail pre version" do
65+
it "version requirement becomes >= major.minor.pre.tail when resolved version has a very long tail pre version" do
6666
bundle "add 'lemur'"
6767
# the trailing pre purposely matches the release version to ensure that subbing the release doesn't change the pre.version"
68-
expect(bundled_app_gemfile.read).to match(/gem "lemur", "~> 3.1.pre.2023.1.1"/)
68+
expect(bundled_app_gemfile.read).to match(/gem "lemur", ">= 3.1.pre.2023.1.1"/)
6969
expect(the_bundle).to include_gems "lemur 3.1.1.pre.2023.1.1"
7070
end
7171
end
@@ -100,13 +100,13 @@
100100
describe "with --group" do
101101
it "adds dependency for the specified group" do
102102
bundle "add 'foo' --group='development'"
103-
expect(bundled_app_gemfile.read).to match(/gem "foo", "~> 2.0", group: :development/)
103+
expect(bundled_app_gemfile.read).to match(/gem "foo", ">= 2.0", group: :development/)
104104
expect(the_bundle).to include_gems "foo 2.0"
105105
end
106106

107107
it "adds dependency to more than one group" do
108108
bundle "add 'foo' --group='development, test'"
109-
expect(bundled_app_gemfile.read).to match(/gem "foo", "~> 2.0", groups: \[:development, :test\]/)
109+
expect(bundled_app_gemfile.read).to match(/gem "foo", ">= 2.0", groups: \[:development, :test\]/)
110110
expect(the_bundle).to include_gems "foo 2.0"
111111
end
112112
end
@@ -115,7 +115,7 @@
115115
it "adds dependency with specified source" do
116116
bundle "add 'foo' --source='https://gem.repo2'"
117117

118-
expect(bundled_app_gemfile.read).to match(%r{gem "foo", "~> 2.0", source: "https://gem.repo2"})
118+
expect(bundled_app_gemfile.read).to match(%r{gem "foo", ">= 2.0", source: "https://gem.repo2"})
119119
expect(the_bundle).to include_gems "foo 2.0"
120120
end
121121
end
@@ -124,7 +124,7 @@
124124
it "adds dependency with specified path" do
125125
bundle "add 'foo' --path='#{lib_path("foo-2.0")}'"
126126

127-
expect(bundled_app_gemfile.read).to match(/gem "foo", "~> 2.0", path: "#{lib_path("foo-2.0")}"/)
127+
expect(bundled_app_gemfile.read).to match(/gem "foo", ">= 2.0", path: "#{lib_path("foo-2.0")}"/)
128128
expect(the_bundle).to include_gems "foo 2.0"
129129
end
130130
end
@@ -133,7 +133,7 @@
133133
it "adds dependency with specified git source" do
134134
bundle "add foo --git=#{lib_path("foo-2.0")}"
135135

136-
expect(bundled_app_gemfile.read).to match(/gem "foo", "~> 2.0", git: "#{lib_path("foo-2.0")}"/)
136+
expect(bundled_app_gemfile.read).to match(/gem "foo", ">= 2.0", git: "#{lib_path("foo-2.0")}"/)
137137
expect(the_bundle).to include_gems "foo 2.0"
138138
end
139139
end
@@ -146,7 +146,7 @@
146146
it "adds dependency with specified git source and branch" do
147147
bundle "add foo --git=#{lib_path("foo-2.0")} --branch=test"
148148

149-
expect(bundled_app_gemfile.read).to match(/gem "foo", "~> 2.0", git: "#{lib_path("foo-2.0")}", branch: "test"/)
149+
expect(bundled_app_gemfile.read).to match(/gem "foo", ">= 2.0", git: "#{lib_path("foo-2.0")}", branch: "test"/)
150150
expect(the_bundle).to include_gems "foo 2.0"
151151
end
152152
end
@@ -155,7 +155,7 @@
155155
it "adds dependency with specified git source and branch" do
156156
bundle "add foo --git=#{lib_path("foo-2.0")} --ref=#{revision_for(lib_path("foo-2.0"))}"
157157

158-
expect(bundled_app_gemfile.read).to match(/gem "foo", "~> 2\.0", git: "#{lib_path("foo-2.0")}", ref: "#{revision_for(lib_path("foo-2.0"))}"/)
158+
expect(bundled_app_gemfile.read).to match(/gem "foo", ">= 2\.0", git: "#{lib_path("foo-2.0")}", ref: "#{revision_for(lib_path("foo-2.0"))}"/)
159159
expect(the_bundle).to include_gems "foo 2.0"
160160
end
161161
end
@@ -169,47 +169,47 @@
169169
it "adds dependency with specified github source" do
170170
bundle "add rake --github=ruby/rake"
171171

172-
expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.\d+", github: "ruby\/rake"})
172+
expect(bundled_app_gemfile.read).to match(%r{gem "rake", ">= 13\.\d+", github: "ruby\/rake"})
173173
end
174174

175175
it "adds dependency with specified github source and branch" do
176176
bundle "add rake --github=ruby/rake --branch=main"
177177

178-
expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.\d+", github: "ruby\/rake", branch: "main"})
178+
expect(bundled_app_gemfile.read).to match(%r{gem "rake", ">= 13\.\d+", github: "ruby\/rake", branch: "main"})
179179
end
180180

181181
it "adds dependency with specified github source and ref" do
182182
ref = revision_for(lib_path("rake-13.0"))
183183
bundle "add rake --github=ruby/rake --ref=#{ref}"
184184

185-
expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.\d+", github: "ruby\/rake", ref: "#{ref}"})
185+
expect(bundled_app_gemfile.read).to match(%r{gem "rake", ">= 13\.\d+", github: "ruby\/rake", ref: "#{ref}"})
186186
end
187187

188188
it "adds dependency with specified github source and glob" do
189189
bundle "add rake --github=ruby/rake --glob='./*.gemspec'"
190190

191-
expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.\d+", github: "ruby\/rake", glob: "\.\/\*\.gemspec"})
191+
expect(bundled_app_gemfile.read).to match(%r{gem "rake", ">= 13\.\d+", github: "ruby\/rake", glob: "\.\/\*\.gemspec"})
192192
end
193193

194194
it "adds dependency with specified github source, branch and glob" do
195195
bundle "add rake --github=ruby/rake --branch=main --glob='./*.gemspec'"
196196

197-
expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.\d+", github: "ruby\/rake", branch: "main", glob: "\.\/\*\.gemspec"})
197+
expect(bundled_app_gemfile.read).to match(%r{gem "rake", ">= 13\.\d+", github: "ruby\/rake", branch: "main", glob: "\.\/\*\.gemspec"})
198198
end
199199

200200
it "adds dependency with specified github source, ref and glob" do
201201
ref = revision_for(lib_path("rake-13.0"))
202202
bundle "add rake --github=ruby/rake --ref=#{ref} --glob='./*.gemspec'"
203203

204-
expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.\d+", github: "ruby\/rake", ref: "#{ref}", glob: "\.\/\*\.gemspec"})
204+
expect(bundled_app_gemfile.read).to match(%r{gem "rake", ">= 13\.\d+", github: "ruby\/rake", ref: "#{ref}", glob: "\.\/\*\.gemspec"})
205205
end
206206
end
207207

208208
describe "with --git and --glob" do
209209
it "adds dependency with specified git source" do
210210
bundle "add foo --git=#{lib_path("foo-2.0")} --glob='./*.gemspec'"
211211

212-
expect(bundled_app_gemfile.read).to match(%r{gem "foo", "~> 2.0", git: "#{lib_path("foo-2.0")}", glob: "\./\*\.gemspec"})
212+
expect(bundled_app_gemfile.read).to match(%r{gem "foo", ">= 2.0", git: "#{lib_path("foo-2.0")}", glob: "\./\*\.gemspec"})
213213
expect(the_bundle).to include_gems "foo 2.0"
214214
end
215215
end
@@ -222,7 +222,7 @@
222222
it "adds dependency with specified git source and branch" do
223223
bundle "add foo --git=#{lib_path("foo-2.0")} --branch=test --glob='./*.gemspec'"
224224

225-
expect(bundled_app_gemfile.read).to match(%r{gem "foo", "~> 2.0", git: "#{lib_path("foo-2.0")}", branch: "test", glob: "\./\*\.gemspec"})
225+
expect(bundled_app_gemfile.read).to match(%r{gem "foo", ">= 2.0", git: "#{lib_path("foo-2.0")}", branch: "test", glob: "\./\*\.gemspec"})
226226
expect(the_bundle).to include_gems "foo 2.0"
227227
end
228228
end
@@ -231,7 +231,7 @@
231231
it "adds dependency with specified git source and branch" do
232232
bundle "add foo --git=#{lib_path("foo-2.0")} --ref=#{revision_for(lib_path("foo-2.0"))} --glob='./*.gemspec'"
233233

234-
expect(bundled_app_gemfile.read).to match(%r{gem "foo", "~> 2\.0", git: "#{lib_path("foo-2.0")}", ref: "#{revision_for(lib_path("foo-2.0"))}", glob: "\./\*\.gemspec"})
234+
expect(bundled_app_gemfile.read).to match(%r{gem "foo", ">= 2\.0", git: "#{lib_path("foo-2.0")}", ref: "#{revision_for(lib_path("foo-2.0"))}", glob: "\./\*\.gemspec"})
235235
expect(the_bundle).to include_gems "foo 2.0"
236236
end
237237
end
@@ -308,13 +308,21 @@
308308
end
309309

310310
describe "with --optimistic" do
311-
it "adds optimistic version" do
311+
it "ignores option" do
312312
bundle "add 'foo' --optimistic"
313313
expect(bundled_app_gemfile.read).to include %(gem "foo", ">= 2.0")
314314
expect(the_bundle).to include_gems "foo 2.0"
315315
end
316316
end
317317

318+
describe "with --pessimistic" do
319+
it "adds pessimistic version" do
320+
bundle "add 'foo' --pessimistic"
321+
expect(bundled_app_gemfile.read).to include %(gem "foo", "~> 2.0")
322+
expect(the_bundle).to include_gems "foo 2.0"
323+
end
324+
end
325+
318326
describe "with --quiet option" do
319327
it "is quiet when there are no warnings" do
320328
bundle "add 'foo' --quiet"
@@ -356,27 +364,27 @@ def run
356364
end
357365

358366
describe "with no option" do
359-
it "adds pessimistic version" do
367+
it "adds optimistic version" do
360368
bundle "add 'foo'"
361-
expect(bundled_app_gemfile.read).to include %(gem "foo", "~> 2.0")
369+
expect(bundled_app_gemfile.read).to include %(gem "foo", ">= 2.0")
362370
expect(the_bundle).to include_gems "foo 2.0"
363371
end
364372
end
365373

366-
describe "with --optimistic and --strict" do
374+
describe "with --pessimistic and --strict" do
367375
it "throws error" do
368-
bundle "add 'foo' --strict --optimistic", raise_on_error: false
376+
bundle "add 'foo' --strict --pessimistic", raise_on_error: false
369377

370-
expect(err).to include("You cannot specify `--strict` and `--optimistic` at the same time")
378+
expect(err).to include("You cannot specify `--strict` and `--pessimistic` at the same time")
371379
end
372380
end
373381

374382
context "multiple gems" do
375383
it "adds multiple gems to gemfile" do
376384
bundle "add bar baz"
377385

378-
expect(bundled_app_gemfile.read).to match(/gem "bar", "~> 0.12.3"/)
379-
expect(bundled_app_gemfile.read).to match(/gem "baz", "~> 1.2"/)
386+
expect(bundled_app_gemfile.read).to match(/gem "bar", ">= 0.12.3"/)
387+
expect(bundled_app_gemfile.read).to match(/gem "baz", ">= 1.2"/)
380388
end
381389

382390
it "throws error if any of the specified gems are present in the gemfile with different version" do

0 commit comments

Comments
 (0)