bundler-conservative-update 1.0.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 +7 -0
- data/CHANGELOG.md +23 -0
- data/LICENSE.txt +21 -0
- data/README.md +192 -0
- data/lib/bundler_conservative_update/version.rb +5 -0
- data/lib/bundler_conservative_update.rb +143 -0
- data/plugins.rb +26 -0
- metadata +86 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: b1a4ccaabd989d98fa9366f6d41905b4b0f343c2bf82aab17e73e3b561ab4db0
|
|
4
|
+
data.tar.gz: a50dc2157b5e28562b8a1af937e5408eb58c0f25021ac3999b663078a57c3b37
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 7fcf8501218bd8f636e5b4e2174c20061f9e02f0030aaa4296e0b2f93157903a843b740bff1ad4d23fe0beac63b371ca697c8d8d75fbdbf31de5bafcfb8f7d46
|
|
7
|
+
data.tar.gz: 2ca8818cdd1524c7c4ad3399997e1e0d0ed381f0a2219fdb1a533f451ab80f1428838fc2d286db747a82b76c257786583ee7a2467bf3733e4477e6d9d9acb9a1
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
This project follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
|
|
4
|
+
and [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
5
|
+
|
|
6
|
+
## Unreleased
|
|
7
|
+
|
|
8
|
+
## 1.0.0 - 2026-08-05
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Initial release: `bundle update` invocations that name gems, or a group, are
|
|
13
|
+
re-executed with `--conservative`, so only those gems are unlocked and
|
|
14
|
+
transitive dependencies stay locked.
|
|
15
|
+
- Invocations that name nothing to update are left to Bundler, since
|
|
16
|
+
`--conservative` without an explicit unlock widens the resolution to every
|
|
17
|
+
direct dependency: a bare `bundle update`, `--all`, `--bundler`, `--source`
|
|
18
|
+
and `--ruby`.
|
|
19
|
+
- Explicit update strategies are respected: `--conservative`, `--patch`,
|
|
20
|
+
`--minor`, `--major` and `--strict` all suppress the injection.
|
|
21
|
+
- Values of `--gemfile`, `--jobs`/`-j`, `--cooldown` and `--retry`/`-r` are not
|
|
22
|
+
mistaken for gem names.
|
|
23
|
+
- `BUNDLER_CONSERVATIVE_UPDATE_DISABLE=1` (or `true`) opts a single run out.
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Buk
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# bundler-conservative-update
|
|
2
|
+
|
|
3
|
+
[](https://github.com/bukhr/bundler-conservative-update/actions/workflows/ci.yml)
|
|
4
|
+
[](https://rubygems.org/gems/bundler-conservative-update)
|
|
5
|
+
|
|
6
|
+
A [Bundler plugin](https://bundler.io/guides/bundler_plugins.html) that makes
|
|
7
|
+
[`bundle update`](https://bundler.io/man/bundle-update.1.html) conservative by
|
|
8
|
+
default: only the gems you name get updated, and transitive dependencies stay
|
|
9
|
+
locked.
|
|
10
|
+
|
|
11
|
+
```console
|
|
12
|
+
$ bundle update rails # behaves like `bundle update --conservative rails`
|
|
13
|
+
$ bundle update --all # untouched: explicit "update everything"
|
|
14
|
+
$ bundle update --minor rails # untouched: explicit strategy
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## The problem
|
|
18
|
+
|
|
19
|
+
`bundle update rails` does not just update `rails`. Bundler also unlocks its
|
|
20
|
+
dependencies and moves them to the newest versions the `Gemfile` allows, so a
|
|
21
|
+
one-gem bump produces a `Gemfile.lock` diff nobody asked for or reviewed:
|
|
22
|
+
|
|
23
|
+
```console
|
|
24
|
+
bundle update rails && git diff --stat Gemfile.lock
|
|
25
|
+
Gemfile.lock | 74 +++++++++++++++++++++++-----------------------
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
[`--conservative`](https://bundler.io/man/bundle-update.1.html) avoids this, but
|
|
29
|
+
it is opt-in per invocation: it only helps when every person and every script
|
|
30
|
+
remembers to type it, and Bundler has no setting to make it the default
|
|
31
|
+
(`prefer_patch` is related but different, see
|
|
32
|
+
[Relationship to prefer_patch](#relationship-to-prefer_patch)).
|
|
33
|
+
|
|
34
|
+
This plugin turns that behavior into the project's default. Because it is
|
|
35
|
+
declared in the `Gemfile`, the policy covers every `bundle update` run on the
|
|
36
|
+
project — yours, your teammates', and CI's — with no flag to remember.
|
|
37
|
+
|
|
38
|
+
## Installation
|
|
39
|
+
|
|
40
|
+
Add the plugin to your `Gemfile`:
|
|
41
|
+
|
|
42
|
+
```ruby
|
|
43
|
+
plugin "bundler-conservative-update"
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
The next `bundle install` installs the plugin.
|
|
47
|
+
|
|
48
|
+
See [bundle-plugin](https://bundler.io/man/bundle-plugin.1.html).
|
|
49
|
+
|
|
50
|
+
## Usage
|
|
51
|
+
|
|
52
|
+
There is nothing to configure. Run `bundle update` as usual:
|
|
53
|
+
|
|
54
|
+
```console
|
|
55
|
+
bundle update rails
|
|
56
|
+
bundler-conservative-update: re-running with --conservative (only requested gems are updated; set BUNDLER_CONSERVATIVE_UPDATE_DISABLE=1 to opt out)
|
|
57
|
+
Pass --patch, --minor, --major or --all to choose a different update strategy.
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The plugin re-executes the command as `bundle update --conservative rails`. It
|
|
61
|
+
injects only when the invocation **names something to update** and has not
|
|
62
|
+
already stated its own update strategy:
|
|
63
|
+
|
|
64
|
+
| Invocation | `--conservative` injected? | Why |
|
|
65
|
+
|---|---|---|
|
|
66
|
+
| `bundle update rails` | yes | names a gem |
|
|
67
|
+
| `bundle update rails --local` | yes | flags that do not change resolution scope are preserved |
|
|
68
|
+
| `bundle update --group dev` | yes | Bundler expands the group into the gems to unlock |
|
|
69
|
+
| `bundle update` (no gems) | no | names nothing; see note below |
|
|
70
|
+
| `bundle install`, `bundle exec`, `bundle lock`, … | no | not an update |
|
|
71
|
+
| `bundle update --conservative rails` | no | already requested; also the recursion guard |
|
|
72
|
+
| `bundle update --patch/--minor/--major/--strict rails` | no | explicit update strategy |
|
|
73
|
+
| `bundle update --all` | no | explicit "update everything" |
|
|
74
|
+
| `bundle update --bundler[=X]`, `--source[=X]`, `--ruby` | no | see note below |
|
|
75
|
+
| any of the above with `BUNDLER_CONSERVATIVE_UPDATE_DISABLE=1` | no | [opt-out](#opting-out) |
|
|
76
|
+
|
|
77
|
+
> All the "names nothing" cases share one reason. `--conservative` restricts the
|
|
78
|
+
> resolution through the list of gems Bundler was explicitly asked to unlock;
|
|
79
|
+
> when that list is empty, Bundler falls back to unlocking **every** direct
|
|
80
|
+
> dependency of the `Gemfile` — the exact outcome this plugin exists to prevent.
|
|
81
|
+
> A bare `bundle update` names no gem, and `--bundler`, `--source` and `--ruby`
|
|
82
|
+
> change *what* is being resolved rather than naming gems, so injecting there
|
|
83
|
+
> would not restrict anything. Those invocations are left to Bundler.
|
|
84
|
+
|
|
85
|
+
The re-execution uses `Kernel.exec`, which replaces the current process: stdin
|
|
86
|
+
and the TTY are inherited, and the exit code you get is the real
|
|
87
|
+
`bundle update`'s.
|
|
88
|
+
|
|
89
|
+
### Opting out
|
|
90
|
+
|
|
91
|
+
To let a single update reach transitive dependencies on purpose, set
|
|
92
|
+
`BUNDLER_CONSERVATIVE_UPDATE_DISABLE` to `1` or `true` (case-insensitive):
|
|
93
|
+
|
|
94
|
+
```console
|
|
95
|
+
BUNDLER_CONSERVATIVE_UPDATE_DISABLE=1 bundle update rails
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
There is no permanent, per-project opt-out by design: a project that wants
|
|
99
|
+
unconstrained updates should not declare the plugin. For the periodic "update
|
|
100
|
+
everything" chore no variable is needed — `--all` is already respected:
|
|
101
|
+
|
|
102
|
+
```console
|
|
103
|
+
bundle update --all
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Relationship to `prefer_patch`
|
|
107
|
+
|
|
108
|
+
Bundler's [`prefer_patch`](https://bundler.io/man/bundle-config.1.html) setting
|
|
109
|
+
(`BUNDLE_PREFER_PATCH`) makes `bundle update` behave like
|
|
110
|
+
`bundle update --patch`. That controls the **level** of the updates (prefer
|
|
111
|
+
patch releases over minor/major), not their **scope**: shared and transitive
|
|
112
|
+
dependencies can still move.
|
|
113
|
+
|
|
114
|
+
`--conservative` controls the scope: only the gems you named are unlocked,
|
|
115
|
+
everything else stays exactly as locked. This plugin automates the scope part
|
|
116
|
+
only.
|
|
117
|
+
|
|
118
|
+
The two compose. The hook inspects `ARGV`, not Bundler's configuration, so
|
|
119
|
+
`BUNDLE_PREFER_PATCH` does not suppress the injection: with both in place,
|
|
120
|
+
`bundle update rails` updates only `rails` and prefers a patch release. Passing
|
|
121
|
+
`--patch` explicitly on the command line does suppress it, because then the
|
|
122
|
+
invocation already states its own strategy.
|
|
123
|
+
|
|
124
|
+
## Limitations
|
|
125
|
+
|
|
126
|
+
- **`bundle update` with no gems named is not protected.** The plugin steps
|
|
127
|
+
aside there, so the run behaves like a plain full update. Name the gems you
|
|
128
|
+
want, or pass `--all` to be explicit about it.
|
|
129
|
+
- **`bundle lock --update` is not covered.** It resolves through a code path
|
|
130
|
+
that never fires plugin hooks, so the plugin cannot see the invocation, let
|
|
131
|
+
alone re-execute it. Prefer `bundle update`, and review the `Gemfile.lock`
|
|
132
|
+
diff by hand when you do reach for
|
|
133
|
+
[`bundle lock --update`](https://bundler.io/man/bundle-lock.1.html).
|
|
134
|
+
- **`--bundler`, `--source` and `--ruby` are left unprotected**, for the reason
|
|
135
|
+
described in [Usage](#usage).
|
|
136
|
+
- **Tools that resolve the lockfile without running `bundle update` locally**
|
|
137
|
+
(Dependabot, Renovate, and similar) are not covered.
|
|
138
|
+
- **A fresh clone is unprotected until `bundle install` has run**, since that is
|
|
139
|
+
what installs the plugin.
|
|
140
|
+
|
|
141
|
+
## How it works
|
|
142
|
+
|
|
143
|
+
[`plugins.rb`](plugins.rb) registers a `before-install-all` hook, which also
|
|
144
|
+
runs for `bundle update`. On that hook,
|
|
145
|
+
[`BundlerConservativeUpdate::Hook`](lib/bundler_conservative_update.rb) inspects
|
|
146
|
+
`ARGV`: it locates the subcommand (the first argument that is not an option,
|
|
147
|
+
skipping the value of options like `--retry 3`), checks that the invocation
|
|
148
|
+
names a gem or a group and carries no explicit strategy, and then re-executes
|
|
149
|
+
`bundle` with `--conservative` inserted right after the subcommand.
|
|
150
|
+
|
|
151
|
+
The decision tables live in
|
|
152
|
+
[`lib/bundler_conservative_update.rb`](lib/bundler_conservative_update.rb) —
|
|
153
|
+
`SKIP_FLAGS`, `SKIP_FLAG_PREFIXES`, `VALUE_FLAGS` and `UPDATE_VALUE_FLAGS`. That
|
|
154
|
+
is the one place to touch when a flag needs to be added.
|
|
155
|
+
|
|
156
|
+
No environment marker is involved. Recursion stops on its own because the
|
|
157
|
+
re-executed command carries `--conservative` in its own `ARGV`, and that flag is
|
|
158
|
+
one of the reasons the hook declines to inject.
|
|
159
|
+
|
|
160
|
+
## Development
|
|
161
|
+
|
|
162
|
+
```console
|
|
163
|
+
bundle install
|
|
164
|
+
bundle exec rake test
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
The suite includes an integration test that installs the plugin into a
|
|
168
|
+
throwaway project and runs a real `bundle update` against it. To run only the
|
|
169
|
+
unit tests, or a single file:
|
|
170
|
+
|
|
171
|
+
```console
|
|
172
|
+
SKIP_INTEGRATION=1 bundle exec rake test
|
|
173
|
+
bundle exec ruby -Itest test/hook_test.rb
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
[CI](.github/workflows/ci.yml) runs the full suite on Ruby 3.0 through 3.4.
|
|
177
|
+
|
|
178
|
+
## Contributing
|
|
179
|
+
|
|
180
|
+
Bug reports and pull requests are welcome at
|
|
181
|
+
[github.com/bukhr/bundler-conservative-update](https://github.com/bukhr/bundler-conservative-update/issues).
|
|
182
|
+
Please include the Bundler version and the exact `bundle update` invocation in
|
|
183
|
+
bug reports, and make sure `bundle exec rake test` passes on pull requests.
|
|
184
|
+
|
|
185
|
+
## Changelog
|
|
186
|
+
|
|
187
|
+
See [CHANGELOG.md](CHANGELOG.md).
|
|
188
|
+
|
|
189
|
+
## License
|
|
190
|
+
|
|
191
|
+
The gem is available as open source under the terms of the
|
|
192
|
+
[MIT License](LICENSE.txt).
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "bundler_conservative_update/version"
|
|
4
|
+
|
|
5
|
+
module BundlerConservativeUpdate
|
|
6
|
+
# Flags that suppress the injection, matched exactly.
|
|
7
|
+
#
|
|
8
|
+
# --conservative is both the "the user already asked for it" case and the
|
|
9
|
+
# recursion guard: the re-executed command carries the flag, so the hook
|
|
10
|
+
# declines the second time around.
|
|
11
|
+
#
|
|
12
|
+
# --patch, --minor, --major and --strict are explicit update strategies, and
|
|
13
|
+
# --all is an explicit "update everything" request. In all of them the user
|
|
14
|
+
# has already stated how far the update may reach.
|
|
15
|
+
#
|
|
16
|
+
# --ruby changes what the resolution is about instead of naming gems to
|
|
17
|
+
# update. Combined with an injected --conservative, Bundler's conservative
|
|
18
|
+
# branch finds no explicit gem unlocks and falls back to unlocking every
|
|
19
|
+
# direct dependency, which is the exact outcome this plugin prevents.
|
|
20
|
+
SKIP_FLAGS = %w[--conservative --patch --minor --major --strict --all --ruby].freeze
|
|
21
|
+
|
|
22
|
+
# Flags suppressed by prefix, so `--source foo` and `--source=foo` are both
|
|
23
|
+
# covered. Same reasoning as --ruby: with an injected --conservative they
|
|
24
|
+
# would unlock all direct dependencies.
|
|
25
|
+
SKIP_FLAG_PREFIXES = %w[--bundler --source].freeze
|
|
26
|
+
|
|
27
|
+
# Global options that take a separate value argument. That value must not be
|
|
28
|
+
# mistaken for the subcommand, as in the `3` of `--retry 3`.
|
|
29
|
+
VALUE_FLAGS = %w[--retry -r].freeze
|
|
30
|
+
|
|
31
|
+
# Options of `bundle update` that take a separate value argument. That value
|
|
32
|
+
# must not be mistaken for a gem name, as in the `4` of `--jobs 4`.
|
|
33
|
+
UPDATE_VALUE_FLAGS = %w[--gemfile --jobs -j --cooldown --retry -r].freeze
|
|
34
|
+
|
|
35
|
+
# Escape hatch: set to "1" or "true" to run a genuinely unrestricted
|
|
36
|
+
# `bundle update` when transitive updates are intended.
|
|
37
|
+
DISABLE_ENV = "BUNDLER_CONSERVATIVE_UPDATE_DISABLE"
|
|
38
|
+
|
|
39
|
+
# Decides whether a `bundle update` invocation should be re-executed with
|
|
40
|
+
# --conservative. Instantiated with injected argv and env so it can be tested
|
|
41
|
+
# without a real Bundler run.
|
|
42
|
+
class Hook
|
|
43
|
+
def initialize(argv:, env:)
|
|
44
|
+
@argv = argv
|
|
45
|
+
@env = env
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# True when the current command is a `bundle update` that names a scope to
|
|
49
|
+
# update and has not already stated its own update strategy.
|
|
50
|
+
def should_inject?
|
|
51
|
+
index = update_index
|
|
52
|
+
|
|
53
|
+
return false if index.nil?
|
|
54
|
+
return false unless @argv[index] == "update"
|
|
55
|
+
|
|
56
|
+
args = @argv[(index + 1)..] || []
|
|
57
|
+
|
|
58
|
+
return false if skip_flag?(args)
|
|
59
|
+
return false unless scope?(args)
|
|
60
|
+
return false if disabled?
|
|
61
|
+
|
|
62
|
+
true
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# The original argv with --conservative inserted right after the
|
|
66
|
+
# subcommand, leaving the receiver's argv untouched.
|
|
67
|
+
def conservative_argv
|
|
68
|
+
new_argv = @argv.dup
|
|
69
|
+
new_argv.insert(update_index + 1, "--conservative")
|
|
70
|
+
new_argv
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
private
|
|
74
|
+
|
|
75
|
+
# Index of the subcommand: the first argument that is not an option,
|
|
76
|
+
# skipping the value of the global options that take one.
|
|
77
|
+
def update_index
|
|
78
|
+
index = 0
|
|
79
|
+
|
|
80
|
+
while index < @argv.length
|
|
81
|
+
arg = @argv[index]
|
|
82
|
+
|
|
83
|
+
if VALUE_FLAGS.include?(arg)
|
|
84
|
+
index += 2
|
|
85
|
+
next
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
return index unless arg.start_with?("-")
|
|
89
|
+
|
|
90
|
+
index += 1
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
nil
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# True when the invocation names something to update: gems, or a group
|
|
97
|
+
# whose direct dependencies Bundler expands into the gem list.
|
|
98
|
+
#
|
|
99
|
+
# A bare `bundle update` names nothing. Bundler treats that as a full
|
|
100
|
+
# update and, with a --conservative that carries no explicit unlocks,
|
|
101
|
+
# falls back to unlocking every direct dependency of the Gemfile. The
|
|
102
|
+
# injection would neither restrict the resolution nor match the message the
|
|
103
|
+
# plugin prints, so the invocation is left alone, same as --all.
|
|
104
|
+
def scope?(args)
|
|
105
|
+
gem_names?(args) || group_flag?(args)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def gem_names?(args)
|
|
109
|
+
index = 0
|
|
110
|
+
|
|
111
|
+
while index < args.length
|
|
112
|
+
arg = args[index]
|
|
113
|
+
|
|
114
|
+
if UPDATE_VALUE_FLAGS.include?(arg)
|
|
115
|
+
index += 2
|
|
116
|
+
next
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
return true unless arg.start_with?("-")
|
|
120
|
+
|
|
121
|
+
index += 1
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
false
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# --group is matched by prefix so `--group foo` and `--group=foo` are both
|
|
128
|
+
# covered, plus the -g alias.
|
|
129
|
+
def group_flag?(args)
|
|
130
|
+
args.any? { |arg| arg == "-g" || arg.start_with?("--group") }
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def skip_flag?(args)
|
|
134
|
+
args.any? do |arg|
|
|
135
|
+
SKIP_FLAGS.include?(arg) || SKIP_FLAG_PREFIXES.any? { |prefix| arg.start_with?(prefix) }
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def disabled?
|
|
140
|
+
%w[1 true].include?(@env[DISABLE_ENV].to_s.downcase)
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
data/plugins.rb
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Bundler plugin entrypoint. When a `bundle update` without an explicit update
|
|
4
|
+
# strategy is detected, the process is re-executed with --conservative so only
|
|
5
|
+
# the requested gems are updated and transitive dependencies stay locked.
|
|
6
|
+
|
|
7
|
+
require "bundler_conservative_update"
|
|
8
|
+
|
|
9
|
+
Bundler::Plugin.add_hook("before-install-all") do |_dependencies|
|
|
10
|
+
hook = BundlerConservativeUpdate::Hook.new(argv: ARGV, env: ENV)
|
|
11
|
+
|
|
12
|
+
next unless hook.should_inject?
|
|
13
|
+
|
|
14
|
+
spec = Gem.loaded_specs["bundler"]
|
|
15
|
+
|
|
16
|
+
# Without a loaded bundler spec there is no reliable path to re-execute, so
|
|
17
|
+
# the plugin steps aside and lets the plain update run.
|
|
18
|
+
next if spec.nil?
|
|
19
|
+
|
|
20
|
+
# CLI::Update raises the ui level to warn before this hook runs, so info
|
|
21
|
+
# messages are invisible under --quiet. The headline goes through warn.
|
|
22
|
+
Bundler.ui.warn("bundler-conservative-update: re-running with --conservative (only requested gems are updated; set BUNDLER_CONSERVATIVE_UPDATE_DISABLE=1 to opt out)")
|
|
23
|
+
Bundler.ui.info(" Pass --patch, --minor, --major or --all to choose a different update strategy.")
|
|
24
|
+
|
|
25
|
+
Kernel.exec(Gem.ruby, spec.bin_file("bundle"), *hook.conservative_argv)
|
|
26
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: bundler-conservative-update
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Javier Omar Pacheco Moreno
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: minitest
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '5.25'
|
|
19
|
+
type: :development
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '5.25'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: rake
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - "~>"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '13.0'
|
|
33
|
+
type: :development
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '13.0'
|
|
40
|
+
description: Re-executes `bundle update` with --conservative, so only the gems you
|
|
41
|
+
name are updated and transitive dependencies stay locked. Explicit strategies (--patch,
|
|
42
|
+
--minor, --major, --strict), explicit scopes (--all, --source, --bundler, --ruby)
|
|
43
|
+
and an opt-out are respected.
|
|
44
|
+
email:
|
|
45
|
+
- contacto@buk.cl
|
|
46
|
+
executables: []
|
|
47
|
+
extensions: []
|
|
48
|
+
extra_rdoc_files:
|
|
49
|
+
- CHANGELOG.md
|
|
50
|
+
- LICENSE.txt
|
|
51
|
+
- README.md
|
|
52
|
+
files:
|
|
53
|
+
- CHANGELOG.md
|
|
54
|
+
- LICENSE.txt
|
|
55
|
+
- README.md
|
|
56
|
+
- lib/bundler_conservative_update.rb
|
|
57
|
+
- lib/bundler_conservative_update/version.rb
|
|
58
|
+
- plugins.rb
|
|
59
|
+
homepage: https://github.com/bukhr/bundler-conservative-update
|
|
60
|
+
licenses:
|
|
61
|
+
- MIT
|
|
62
|
+
metadata:
|
|
63
|
+
allowed_push_host: https://rubygems.org
|
|
64
|
+
source_code_uri: https://github.com/bukhr/bundler-conservative-update
|
|
65
|
+
documentation_uri: https://github.com/bukhr/bundler-conservative-update/blob/main/README.md
|
|
66
|
+
changelog_uri: https://github.com/bukhr/bundler-conservative-update/blob/main/CHANGELOG.md
|
|
67
|
+
bug_tracker_uri: https://github.com/bukhr/bundler-conservative-update/issues
|
|
68
|
+
rubygems_mfa_required: 'true'
|
|
69
|
+
rdoc_options: []
|
|
70
|
+
require_paths:
|
|
71
|
+
- lib
|
|
72
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
73
|
+
requirements:
|
|
74
|
+
- - ">="
|
|
75
|
+
- !ruby/object:Gem::Version
|
|
76
|
+
version: '3.0'
|
|
77
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - ">="
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '0'
|
|
82
|
+
requirements: []
|
|
83
|
+
rubygems_version: 4.0.14
|
|
84
|
+
specification_version: 4
|
|
85
|
+
summary: A Bundler plugin that makes `bundle update` conservative by default
|
|
86
|
+
test_files: []
|