appraisal2 3.0.9 → 3.1.1
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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +50 -1
- data/README.md +149 -19
- data/SECURITY.md +1 -1
- data/lib/appraisal/appraisal.rb +11 -3
- data/lib/appraisal/appraisal_file.rb +10 -0
- data/lib/appraisal/bundler_dsl.rb +4 -0
- data/lib/appraisal/cli.rb +58 -8
- data/lib/appraisal/hooks.rb +67 -0
- data/lib/appraisal/task.rb +2 -2
- data/lib/appraisal/version.rb +1 -1
- data/lib/appraisal2/version.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +5 -4
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2c2316bffba1559cb55b0c393052bd487630867af9e7a41d37c73c43315bc2b9
|
|
4
|
+
data.tar.gz: a37397565aa148f422d031621cb715d2b48bffcd3f9ddba06aa773488f984995
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f9a4fe27e3fb3e5979021df8b565f32ad454c924f2aaa1a15d0517d66b5fa2fd095c2daaae9cf0d422f4445510d44f6e0604d0acd735d3131189d7c54ab79ca9
|
|
7
|
+
data.tar.gz: 1415ef332fc92e289a1f28fe4b9cfcd401d5699e2556d1bacfb463e67420121fd45b6184fca10c6b88a445c83f59c5e573b4bab5b047bd8707d2667046448a15
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/CHANGELOG.md
CHANGED
|
@@ -30,6 +30,51 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
30
30
|
|
|
31
31
|
### Security
|
|
32
32
|
|
|
33
|
+
## [3.1.1] - 2026-06-06
|
|
34
|
+
|
|
35
|
+
- TAG: [v3.1.1][3.1.1t]
|
|
36
|
+
- COVERAGE: 90.23% -- 822/911 lines in 29 files
|
|
37
|
+
- BRANCH COVERAGE: 80.51% -- 157/195 branches in 29 files
|
|
38
|
+
- 42.25% documented
|
|
39
|
+
|
|
40
|
+
### Added
|
|
41
|
+
|
|
42
|
+
- Added the `plugin` Appraisals DSL for generator-only companion gems that
|
|
43
|
+
should be loaded while Appraisal2 generates gemfiles without being serialized
|
|
44
|
+
into generated appraisal gemfiles.
|
|
45
|
+
- Added the `generator_only` root Gemfile DSL for dependencies that Bundler
|
|
46
|
+
should install in the active generator bundle but Appraisal2 should not
|
|
47
|
+
serialize into generated appraisal gemfiles.
|
|
48
|
+
|
|
49
|
+
## [3.1.0] - 2026-06-06
|
|
50
|
+
|
|
51
|
+
- TAG: [v3.1.0][3.1.0t]
|
|
52
|
+
- COVERAGE: 90.14% -- 814/903 lines in 29 files
|
|
53
|
+
- BRANCH COVERAGE: 80.00% -- 148/185 branches in 29 files
|
|
54
|
+
- 42.70% documented
|
|
55
|
+
|
|
56
|
+
### Added
|
|
57
|
+
|
|
58
|
+
- Added Appraisal lifecycle hooks, including `Appraisal.transform_gemfile`
|
|
59
|
+
for plugins that need to normalize generated Appraisal gemfiles in memory
|
|
60
|
+
before Appraisal2 writes them.
|
|
61
|
+
- Added explicit `generate-install` and `generate-update` CLI commands for
|
|
62
|
+
workflows that need to regenerate Appraisal gemfiles before resolving them.
|
|
63
|
+
- Added named appraisal support for `generate`, `generate-install`, and
|
|
64
|
+
`generate-update`.
|
|
65
|
+
|
|
66
|
+
### Changed
|
|
67
|
+
|
|
68
|
+
- Changed `install` and `update` to resolve existing Appraisal gemfiles without
|
|
69
|
+
rewriting them, while still generating missing Appraisal gemfiles to preserve
|
|
70
|
+
the basic install workflow.
|
|
71
|
+
- Updated the deprecated `rake appraisal:install` task to delegate to
|
|
72
|
+
`appraisal generate-install`, preserving its historical generate-and-install
|
|
73
|
+
behavior.
|
|
74
|
+
|
|
75
|
+
- Documented the Appraisal2 3.1.0 command lifecycle changes, named appraisal
|
|
76
|
+
generation commands, and generated gemfile transform hooks in the README.
|
|
77
|
+
|
|
33
78
|
## [3.0.9] - 2026-06-05
|
|
34
79
|
|
|
35
80
|
- TAG: [v3.0.9][3.0.9t]
|
|
@@ -316,7 +361,11 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
316
361
|
- code coverage tracked with Coveralls, QLTY.sh, and the kettle-soup-cover gem
|
|
317
362
|
- other minor fixes and improvements
|
|
318
363
|
|
|
319
|
-
[Unreleased]: https://github.com/appraisal-rb/appraisal2/compare/v3.
|
|
364
|
+
[Unreleased]: https://github.com/appraisal-rb/appraisal2/compare/v3.1.1...HEAD
|
|
365
|
+
[3.1.1]: https://github.com/appraisal-rb/appraisal2/compare/v3.1.0...v3.1.1
|
|
366
|
+
[3.1.1t]: https://github.com/appraisal-rb/appraisal2/releases/tag/v3.1.1
|
|
367
|
+
[3.1.0]: https://github.com/appraisal-rb/appraisal2/compare/v3.0.9...v3.1.0
|
|
368
|
+
[3.1.0t]: https://github.com/appraisal-rb/appraisal2/releases/tag/v3.1.0
|
|
320
369
|
[3.0.9]: https://github.com/appraisal-rb/appraisal2/compare/v3.0.8...v3.0.9
|
|
321
370
|
[3.0.9t]: https://github.com/appraisal-rb/appraisal2/releases/tag/v3.0.9
|
|
322
371
|
[3.0.8]: https://github.com/appraisal-rb/appraisal2/compare/v3.0.7...v3.0.8
|
data/README.md
CHANGED
|
@@ -34,6 +34,14 @@ and [Joe Ferris](https://github.com/jferris), the original author!
|
|
|
34
34
|
Appraisal2 adds:
|
|
35
35
|
|
|
36
36
|
- support for `eval_gemfile`
|
|
37
|
+
- explicit `generate`, `install`, and `update` workflows, so CI can resolve
|
|
38
|
+
already-generated appraisal gemfiles without rewriting them
|
|
39
|
+
- `generate-install` and `generate-update` commands for workflows that need to
|
|
40
|
+
regenerate appraisal gemfiles before resolving dependencies
|
|
41
|
+
- named appraisal support for `generate`, `generate-install`, and
|
|
42
|
+
`generate-update`
|
|
43
|
+
- lifecycle hooks, including `Appraisal.transform_gemfile`, for plugins that
|
|
44
|
+
need to normalize generated appraisal gemfiles before Appraisal2 writes them
|
|
37
45
|
- support for caching gems across appraisals in CI workflows by setting `BUNDLE_PATH` in env
|
|
38
46
|
- support for [ORE](https://github.com/contriboss/ore-light) as an alternative gem manager (faster than bundler!)
|
|
39
47
|
- For easy setup in **Gitea** [Actions](https://docs.gitea.com/usage/actions/overview), **Forgejo** [Actions](https://forgejo.org/docs/next/admin/actions/), **Codeberg** [Actions](https://docs.codeberg.org/ci/actions/), or **GitHub** [Actions](https://github.com/marketplace/actions/setup-ruby-with-rv-and-ore) check out [appraisal-rb/setup-ruby-flash](https://github.com/appraisal-rb/setup-ruby-flash)
|
|
@@ -53,7 +61,7 @@ Appraisal2 adds:
|
|
|
53
61
|
| Works with Truffle Ruby | [![Truffle Ruby 22.3 Compat][💎truby-22.3i]][🚎truby-22.3-wf] [![Truffle Ruby 23.0 Compat][💎truby-23.0i]][🚎truby-23.0-wf] [![Truffle Ruby 23.1 Compat][💎truby-23.1i]][🚎truby-23.1-wf] <br/> [![Truffle Ruby 24.2 Compat][💎truby-24.2i]][🚎truby-24.2-wf] [![Truffle Ruby 25.0 Compat][💎truby-25.0i]][🚎truby-25.0-wf] [![Truffle Ruby current Compat][💎truby-c-i]][🚎9-t-wf]|
|
|
54
62
|
| Works with MRI Ruby 4 | [![Ruby 4.0 Compat][💎ruby-4.0i]][🚎11-c-wf] [![Ruby current Compat][💎ruby-c-i]][🚎11-c-wf] [![Ruby HEAD Compat][💎ruby-headi]][🚎3-hd-wf]|
|
|
55
63
|
| Works with MRI Ruby 3 | [![Ruby 3.0 Compat][💎ruby-3.0i]][🚎ruby-3.0-wf] [![Ruby 3.1 Compat][💎ruby-3.1i]][🚎ruby-3.1-wf] [![Ruby 3.2 Compat][💎ruby-3.2i]][🚎ruby-3.2-wf] [![Ruby 3.3 Compat][💎ruby-3.3i]][🚎ruby-3.3-wf] [![Ruby 3.4 Compat][💎ruby-3.4i]][🚎ruby-3.4-wf]|
|
|
56
|
-
| Works with MRI Ruby 2 | ![Ruby 2.0 Compat][💎ruby-2.0i] ![Ruby 2.1 Compat][💎ruby-2.1i] ![Ruby 2.2 Compat][💎ruby-2.2i] <br/> [![Ruby 2.4 Compat][💎ruby-2.4i]][🚎ruby-2.4-wf] [![Ruby 2.5 Compat][💎ruby-2.5i]][🚎ruby-2.5-wf] [![Ruby 2.6 Compat][💎ruby-2.6i]][🚎ruby-2.6-wf] [![Ruby 2.7 Compat][💎ruby-2.7i]][🚎ruby-2.7-wf]|
|
|
64
|
+
| Works with MRI Ruby 2 | ![Ruby 2.0 Compat][💎ruby-2.0i] ![Ruby 2.1 Compat][💎ruby-2.1i] ![Ruby 2.2 Compat][💎ruby-2.2i] ![Ruby 2.3 Compat][💎ruby-2.3i] <br/> [![Ruby 2.4 Compat][💎ruby-2.4i]][🚎ruby-2.4-wf] [![Ruby 2.5 Compat][💎ruby-2.5i]][🚎ruby-2.5-wf] [![Ruby 2.6 Compat][💎ruby-2.6i]][🚎ruby-2.6-wf] [![Ruby 2.7 Compat][💎ruby-2.7i]][🚎ruby-2.7-wf]|
|
|
57
65
|
| Works with MRI Ruby 1 | ![Ruby 1.9 Compat][💎ruby-1.9i]|
|
|
58
66
|
| Support & Community | [![Join Me on Daily.dev's RubyFriends][✉️ruby-friends-img]][✉️ruby-friends] [![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite] [![Get help from me on Upwork][👨🏼🏫expsup-upwork-img]][👨🏼🏫expsup-upwork] [![Get help from me on Codementor][👨🏼🏫expsup-codementor-img]][👨🏼🏫expsup-codementor] |
|
|
59
67
|
| Source | [![Source on GitLab.com][📜src-gl-img]][📜src-gl] [![Source on CodeBerg.org][📜src-cb-img]][📜src-cb] [![Source on Github.com][📜src-gh-img]][📜src-gh] [![The best SHA: dQw4w9WgXcQ!][🧮kloc-img]][🧮kloc] |
|
|
@@ -130,6 +138,87 @@ gem install appraisal2
|
|
|
130
138
|
|
|
131
139
|
## ⚙️ Configuration
|
|
132
140
|
|
|
141
|
+
Create an `Appraisals` file at the root of your project, then define one or
|
|
142
|
+
more dependency scenarios:
|
|
143
|
+
|
|
144
|
+
```ruby
|
|
145
|
+
appraise "rails-7" do
|
|
146
|
+
gem "rails", "~> 7.0"
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
appraise "rails-8" do
|
|
150
|
+
gem "rails", "~> 8.0"
|
|
151
|
+
end
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Each appraisal starts from your root `Gemfile`, then applies the dependency
|
|
155
|
+
changes declared in the matching `appraise` block. Generated appraisal gemfiles
|
|
156
|
+
are written to `gemfiles/*.gemfile`.
|
|
157
|
+
|
|
158
|
+
### Generated Gemfile Hooks
|
|
159
|
+
|
|
160
|
+
Appraisal2 3.1.0 adds lifecycle hooks for companion gems and local tooling.
|
|
161
|
+
The primary hook is `Appraisal.transform_gemfile`, which receives generated
|
|
162
|
+
gemfile content before Appraisal2 writes it.
|
|
163
|
+
|
|
164
|
+
```ruby
|
|
165
|
+
Appraisal.transform_gemfile do |content, context|
|
|
166
|
+
# context.appraisal is the Appraisal::Appraisal instance.
|
|
167
|
+
# context.path is the generated gemfile path.
|
|
168
|
+
content.gsub(%(source "https://rubygems.org"), %(source "https://gem.coop"))
|
|
169
|
+
end
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Hooks run in memory. Appraisal2 writes the final transformed content once, after
|
|
173
|
+
all registered transforms have run. A transform may accept only `content`, or it
|
|
174
|
+
may accept `content, context`. Returning `nil` leaves the current content
|
|
175
|
+
unchanged.
|
|
176
|
+
|
|
177
|
+
This is intended for plugin gems that need deterministic generated output, such
|
|
178
|
+
as style normalization of appraisal gemfiles, without monkey-patching Appraisal2
|
|
179
|
+
internals.
|
|
180
|
+
|
|
181
|
+
### Generator Plugins
|
|
182
|
+
|
|
183
|
+
Use `plugin` in `Appraisals` for companion gems that must be loaded while
|
|
184
|
+
Appraisal2 evaluates and generates appraisal gemfiles, but must not be written
|
|
185
|
+
as dependencies in the generated appraisal gemfiles.
|
|
186
|
+
|
|
187
|
+
```ruby
|
|
188
|
+
plugin "appraisal2-rubocop",
|
|
189
|
+
:require => "appraisal2/rubocop",
|
|
190
|
+
:optional => true
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
`plugin` requires the requested path in the active generator bundle. It does not
|
|
194
|
+
call `gem`, and it is not serialized into `gemfiles/*.gemfile`. This keeps
|
|
195
|
+
generator-only tooling out of appraisals that target older Rubies, while still
|
|
196
|
+
allowing modern generator workflows to load hooks such as
|
|
197
|
+
`Appraisal.transform_gemfile`.
|
|
198
|
+
|
|
199
|
+
Set `:optional => true` when some workflows evaluate `Appraisals` without the
|
|
200
|
+
plugin dependency installed. This is useful when a CI matrix uses one generator
|
|
201
|
+
bundle for old-Ruby appraisals and another modern workflow provides the plugin.
|
|
202
|
+
|
|
203
|
+
If the generator bundle needs dependencies that must not be copied into every
|
|
204
|
+
generated appraisal gemfile, wrap those root Gemfile declarations with
|
|
205
|
+
`generator_only` for Appraisal2 and leave the Bundler branch unchanged:
|
|
206
|
+
|
|
207
|
+
```ruby
|
|
208
|
+
if respond_to?(:generator_only)
|
|
209
|
+
generator_only do
|
|
210
|
+
eval_gemfile "gemfiles/modular/style.gemfile"
|
|
211
|
+
end
|
|
212
|
+
else
|
|
213
|
+
eval_gemfile "gemfiles/modular/style.gemfile"
|
|
214
|
+
end
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Bundler evaluates the `else` branch while installing the active generator
|
|
218
|
+
bundle. Appraisal2 evaluates the `generator_only` branch while parsing the root
|
|
219
|
+
Gemfile, but intentionally does not serialize that block into generated
|
|
220
|
+
appraisal gemfiles.
|
|
221
|
+
|
|
133
222
|
## 🔧 Basic Usage
|
|
134
223
|
|
|
135
224
|
Once you've configured the appraisals you want to use, you need to install the
|
|
@@ -137,9 +226,17 @@ dependencies for each appraisal:
|
|
|
137
226
|
|
|
138
227
|
$ bundle exec appraisal install
|
|
139
228
|
|
|
140
|
-
This
|
|
141
|
-
bundler.
|
|
142
|
-
|
|
229
|
+
This resolves, installs, and locks dependencies for each generated appraisal
|
|
230
|
+
gemfile using bundler. If an appraisal gemfile is missing, `install` generates
|
|
231
|
+
that missing gemfile first, preserving the basic setup workflow.
|
|
232
|
+
|
|
233
|
+
When you intentionally want to regenerate every appraisal gemfile before
|
|
234
|
+
installing dependencies, use:
|
|
235
|
+
|
|
236
|
+
$ bundle exec appraisal generate-install
|
|
237
|
+
|
|
238
|
+
Once you have your dependencies set up, you can run any command in a single
|
|
239
|
+
appraisal:
|
|
143
240
|
|
|
144
241
|
$ bundle exec appraisal rails-3 rake test
|
|
145
242
|
|
|
@@ -173,40 +270,65 @@ default.
|
|
|
173
270
|
```bash
|
|
174
271
|
appraisal clean # Remove all generated gemfiles and lockfiles from gemfiles folder
|
|
175
272
|
appraisal generate # Generate a gemfile for each appraisal
|
|
273
|
+
appraisal generate-install # Generate gemfiles, then resolve and install dependencies
|
|
274
|
+
appraisal generate-update [LIST_OF_GEMS] # Generate gemfiles, then update dependencies
|
|
176
275
|
appraisal help [COMMAND] # Describe available commands or one specific command
|
|
177
|
-
appraisal install # Resolve and install dependencies for each appraisal
|
|
276
|
+
appraisal install # Resolve and install dependencies for each generated appraisal gemfile
|
|
178
277
|
appraisal list # List the names of the defined appraisals
|
|
179
|
-
appraisal update [LIST_OF_GEMS] #
|
|
278
|
+
appraisal update [LIST_OF_GEMS] # Update dependencies for each generated appraisal gemfile
|
|
180
279
|
appraisal version # Display the version and exit
|
|
181
280
|
```
|
|
182
281
|
|
|
282
|
+
Since Appraisal2 3.1.0, `install` and `update` do not rewrite existing appraisal
|
|
283
|
+
gemfiles. They operate on the generated files already present under `gemfiles/`.
|
|
284
|
+
This matters in CI and plugin workflows where generated gemfiles may be
|
|
285
|
+
normalized by hooks or committed as stable inputs.
|
|
286
|
+
|
|
287
|
+
Use the command that matches the lifecycle you want:
|
|
288
|
+
|
|
289
|
+
| Command | Regenerates appraisal gemfiles? | Resolves dependencies? | Typical use |
|
|
290
|
+
|---------|---------------------------------|-------------------------|-------------|
|
|
291
|
+
| `generate` | Yes | No | Refresh generated gemfiles after editing `Appraisals` |
|
|
292
|
+
| `install` | Only missing gemfiles | Yes, via install | CI or local setup using existing generated gemfiles |
|
|
293
|
+
| `update` | Only missing gemfiles | Yes, via update | Refresh lockfiles/dependencies using existing generated gemfiles |
|
|
294
|
+
| `generate-install` | Yes | Yes, via install | First setup, or after intentional Appraisals changes |
|
|
295
|
+
| `generate-update` | Yes | Yes, via update | Regenerate gemfiles, then update dependency locks |
|
|
296
|
+
|
|
297
|
+
The deprecated rake task `rake appraisal:install` now delegates to
|
|
298
|
+
`appraisal generate-install`, preserving its historical generate-and-install
|
|
299
|
+
behavior while the CLI commands remain explicit.
|
|
300
|
+
|
|
183
301
|
### Command Options
|
|
184
302
|
|
|
185
|
-
|
|
303
|
+
Built-in dependency commands support the following options:
|
|
186
304
|
|
|
187
|
-
**Important:** These options apply **only** to Appraisal's
|
|
188
|
-
They do **not** apply when running external commands like
|
|
305
|
+
**Important:** These options apply **only** to Appraisal's built-in dependency
|
|
306
|
+
commands. They do **not** apply when running external commands like
|
|
307
|
+
`bundle install` or `bundle update`.
|
|
189
308
|
|
|
190
309
|
| Option | Description |
|
|
191
310
|
|--------|-------------|
|
|
192
|
-
| `--gem-manager`, `-g` | Gem manager to use: `bundler` (default) or `ore` |
|
|
193
|
-
| `--jobs`, `-j` | Install gems in parallel using the given number of workers |
|
|
194
|
-
| `--retry` | Retry network and git requests that have failed (default: 1) |
|
|
195
|
-
| `--without` | A space-separated list of groups to skip during installation |
|
|
196
|
-
| `--full-index` | Run bundle install with the full-index argument |
|
|
197
|
-
| `--path` | Install gems in the specified directory |
|
|
311
|
+
| `--gem-manager`, `-g` | Gem manager to use: `bundler` (default) or `ore`; applies to `install`, `update`, `generate-install`, and `generate-update` |
|
|
312
|
+
| `--jobs`, `-j` | Install gems in parallel using the given number of workers; applies to `install` and `generate-install` |
|
|
313
|
+
| `--retry` | Retry network and git requests that have failed; applies to `install` and `generate-install` (default: 1) |
|
|
314
|
+
| `--without` | A space-separated list of groups to skip during installation; applies to `install` and `generate-install` |
|
|
315
|
+
| `--full-index` | Run bundle install with the full-index argument; applies to `install` and `generate-install` |
|
|
316
|
+
| `--path` | Install gems in the specified directory; applies to `install` and `generate-install` |
|
|
198
317
|
|
|
199
318
|
### Using Commands with Named Appraisals
|
|
200
319
|
|
|
201
320
|
#### Using Appraisal's built-in commands with named appraisals
|
|
202
321
|
|
|
203
|
-
When using Appraisal's
|
|
204
|
-
|
|
322
|
+
When using Appraisal's built-in commands with a specific appraisal name, place
|
|
323
|
+
the appraisal name first, then the command, then any options:
|
|
205
324
|
|
|
206
325
|
```bash
|
|
207
326
|
# ✅ Correct order: appraisal <NAME> <COMMAND> [OPTIONS]
|
|
327
|
+
bundle exec appraisal rails-7 generate
|
|
208
328
|
bundle exec appraisal rails-7 install --gem-manager=ore
|
|
329
|
+
bundle exec appraisal rails-7 generate-install --gem-manager=ore
|
|
209
330
|
bundle exec appraisal rails-7 update rails --gem-manager=ore
|
|
331
|
+
bundle exec appraisal rails-7 generate-update rails --gem-manager=ore
|
|
210
332
|
bundle exec appraisal rails-7 install --jobs=4
|
|
211
333
|
|
|
212
334
|
# ❌ Wrong order (won't work)
|
|
@@ -219,6 +341,9 @@ More examples with Appraisal's built-in commands:
|
|
|
219
341
|
# Install dependencies for a specific appraisal
|
|
220
342
|
bundle exec appraisal rails-7 install
|
|
221
343
|
|
|
344
|
+
# Regenerate and install dependencies for a specific appraisal
|
|
345
|
+
bundle exec appraisal rails-7 generate-install
|
|
346
|
+
|
|
222
347
|
# Install with options
|
|
223
348
|
bundle exec appraisal rails-7 install --gem-manager=ore --jobs=4
|
|
224
349
|
|
|
@@ -228,6 +353,10 @@ bundle exec appraisal rails-7 update
|
|
|
228
353
|
# Update specific gems in a specific appraisal
|
|
229
354
|
bundle exec appraisal rails-7 update rails rack
|
|
230
355
|
bundle exec appraisal rails-7 update rails rack --gem-manager=ore
|
|
356
|
+
|
|
357
|
+
# Regenerate before updating a specific appraisal
|
|
358
|
+
bundle exec appraisal rails-7 generate-update
|
|
359
|
+
bundle exec appraisal rails-7 generate-update rails rack
|
|
231
360
|
```
|
|
232
361
|
|
|
233
362
|
#### Running external commands with named appraisals
|
|
@@ -612,6 +741,7 @@ Thanks for RTFM. ☺️
|
|
|
612
741
|
[💎ruby-2.0i]: https://img.shields.io/badge/Ruby-2.0_(%F0%9F%9A%ABCI)-AABBCC?style=for-the-badge&logo=ruby&logoColor=white
|
|
613
742
|
[💎ruby-2.1i]: https://img.shields.io/badge/Ruby-2.1_(%F0%9F%9A%ABCI)-AABBCC?style=for-the-badge&logo=ruby&logoColor=white
|
|
614
743
|
[💎ruby-2.2i]: https://img.shields.io/badge/Ruby-2.2_(%F0%9F%9A%ABCI)-AABBCC?style=for-the-badge&logo=ruby&logoColor=white
|
|
744
|
+
[💎ruby-2.3i]: https://img.shields.io/badge/Ruby-2.3_(%F0%9F%9A%ABCI)-AABBCC?style=for-the-badge&logo=ruby&logoColor=white
|
|
615
745
|
[💎ruby-2.4i]: https://img.shields.io/badge/Ruby-2.4-DF00CA?style=for-the-badge&logo=ruby&logoColor=white
|
|
616
746
|
[💎ruby-2.5i]: https://img.shields.io/badge/Ruby-2.5-DF00CA?style=for-the-badge&logo=ruby&logoColor=white
|
|
617
747
|
[💎ruby-2.6i]: https://img.shields.io/badge/Ruby-2.6-DF00CA?style=for-the-badge&logo=ruby&logoColor=white
|
|
@@ -661,7 +791,7 @@ Thanks for RTFM. ☺️
|
|
|
661
791
|
[📌gitmoji]: https://gitmoji.dev
|
|
662
792
|
[📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
|
|
663
793
|
[🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
|
664
|
-
[🧮kloc-img]: https://img.shields.io/badge/KLOC-0.
|
|
794
|
+
[🧮kloc-img]: https://img.shields.io/badge/KLOC-0.911-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
|
|
665
795
|
[🔐security]: https://github.com/appraisal-rb/appraisal2/blob/main/SECURITY.md
|
|
666
796
|
[🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
|
|
667
797
|
[📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
|
|
@@ -689,7 +819,7 @@ Thanks for RTFM. ☺️
|
|
|
689
819
|
| Package | appraisal2 |
|
|
690
820
|
| Description | 🔍️ Appraisal2 integrates with bundler and rake to test your library against different versions of dependencies in repeatable scenarios called "appraisals." |
|
|
691
821
|
| Homepage | https://github.com/appraisal-rb/appraisal2 |
|
|
692
|
-
| Source | https://github.com/appraisal-rb/appraisal2/tree/v3.0
|
|
822
|
+
| Source | https://github.com/appraisal-rb/appraisal2/tree/v3.1.0 |
|
|
693
823
|
| License | `MIT` |
|
|
694
824
|
| Funding | https://github.com/sponsors/pboling, https://issuehunt.io/u/pboling, https://ko-fi.com/pboling, https://liberapay.com/pboling/donate, https://opencollective.com/appraisal-rb, https://patreon.com/galtzo, https://polar.sh/pboling, https://thanks.dev/u/gh/pboling, https://tidelift.com/funding/github/rubygems/appraisal2, https://www.buymeacoffee.com/pboling |
|
|
695
825
|
<!-- kettle-jem:metadata:end -->
|
data/SECURITY.md
CHANGED
data/lib/appraisal/appraisal.rb
CHANGED
|
@@ -8,6 +8,7 @@ require "pathname"
|
|
|
8
8
|
require "appraisal/gemfile"
|
|
9
9
|
require "appraisal/command"
|
|
10
10
|
require "appraisal/customize"
|
|
11
|
+
require "appraisal/hooks"
|
|
11
12
|
require "appraisal/utils"
|
|
12
13
|
require "appraisal/gem_manager"
|
|
13
14
|
|
|
@@ -70,14 +71,14 @@ module Appraisal
|
|
|
70
71
|
end
|
|
71
72
|
|
|
72
73
|
def write_gemfile
|
|
74
|
+
content = ::Appraisal::Hooks.run_transform_gemfile(self, gemfile_path, generated_gemfile)
|
|
73
75
|
File.open(gemfile_path, "w") do |file|
|
|
74
|
-
|
|
75
|
-
Customize.heading(self) || "This file was generated by Appraisal2"
|
|
76
|
-
file.puts([comment_lines(signature), quoted_gemfile].join("\n\n"))
|
|
76
|
+
file.write(content)
|
|
77
77
|
end
|
|
78
78
|
end
|
|
79
79
|
|
|
80
80
|
def install(options = {})
|
|
81
|
+
write_gemfile unless File.exist?(gemfile_path)
|
|
81
82
|
gem_manager = options.delete(:gem_manager) || options.delete("gem_manager") ||
|
|
82
83
|
options.delete(:"gem-manager") || options.delete("gem-manager")
|
|
83
84
|
manager = GemManager::Factory.create(gemfile_path, project_root, :manager => gem_manager)
|
|
@@ -85,6 +86,7 @@ module Appraisal
|
|
|
85
86
|
end
|
|
86
87
|
|
|
87
88
|
def update(gems = [], options = {})
|
|
89
|
+
write_gemfile unless File.exist?(gemfile_path)
|
|
88
90
|
gem_manager = options[:gem_manager] || options["gem_manager"] ||
|
|
89
91
|
options[:"gem-manager"] || options["gem-manager"]
|
|
90
92
|
manager = GemManager::Factory.create(gemfile_path, project_root, :manager => gem_manager)
|
|
@@ -136,6 +138,12 @@ module Appraisal
|
|
|
136
138
|
name.gsub(/[^\w.]/, "_")
|
|
137
139
|
end
|
|
138
140
|
|
|
141
|
+
def generated_gemfile
|
|
142
|
+
signature =
|
|
143
|
+
Customize.heading(self) || "This file was generated by Appraisal2"
|
|
144
|
+
[comment_lines(signature), quoted_gemfile].join("\n\n") + "\n"
|
|
145
|
+
end
|
|
146
|
+
|
|
139
147
|
def comment_lines(heading)
|
|
140
148
|
heading.lines.map do |line|
|
|
141
149
|
if line.lstrip.empty?
|
|
@@ -41,6 +41,16 @@ module Appraisal
|
|
|
41
41
|
Customize.new(args)
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
+
def plugin(name, *args)
|
|
45
|
+
options = args.last.is_a?(Hash) ? args.last : {}
|
|
46
|
+
require_path = options.key?(:require) ? options[:require] : name
|
|
47
|
+
optional = options.key?(:optional) ? options[:optional] : false
|
|
48
|
+
|
|
49
|
+
require require_path if require_path
|
|
50
|
+
rescue LoadError
|
|
51
|
+
raise unless optional
|
|
52
|
+
end
|
|
53
|
+
|
|
44
54
|
private
|
|
45
55
|
|
|
46
56
|
def run(definitions)
|
data/lib/appraisal/cli.rb
CHANGED
|
@@ -53,7 +53,7 @@ module Appraisal
|
|
|
53
53
|
end
|
|
54
54
|
end
|
|
55
55
|
|
|
56
|
-
desc "install", "Resolve and install dependencies for each appraisal"
|
|
56
|
+
desc "install", "Resolve and install dependencies for each generated appraisal gemfile"
|
|
57
57
|
method_option "jobs",
|
|
58
58
|
:aliases => "j",
|
|
59
59
|
:type => :numeric,
|
|
@@ -78,8 +78,6 @@ module Appraisal
|
|
|
78
78
|
"Bundler will remember this option."
|
|
79
79
|
|
|
80
80
|
def install
|
|
81
|
-
invoke(:generate, [], {})
|
|
82
|
-
|
|
83
81
|
install_options = options.to_h
|
|
84
82
|
AppraisalFile.each do |appraisal|
|
|
85
83
|
appraisal.install(install_options)
|
|
@@ -87,6 +85,34 @@ module Appraisal
|
|
|
87
85
|
end
|
|
88
86
|
end
|
|
89
87
|
|
|
88
|
+
desc "generate-install", "Generate gemfiles, then resolve and install dependencies for each appraisal"
|
|
89
|
+
method_option "jobs",
|
|
90
|
+
:aliases => "j",
|
|
91
|
+
:type => :numeric,
|
|
92
|
+
:default => 1,
|
|
93
|
+
:banner => "SIZE",
|
|
94
|
+
:desc => "Install gems in parallel using the given number of workers."
|
|
95
|
+
method_option "retry",
|
|
96
|
+
:type => :numeric,
|
|
97
|
+
:default => 1,
|
|
98
|
+
:desc => "Retry network and git requests that have failed"
|
|
99
|
+
method_option "without",
|
|
100
|
+
:banner => "GROUP_NAMES",
|
|
101
|
+
:desc => "A space-separated list of groups referencing gems to skip " \
|
|
102
|
+
"during installation. Bundler will remember this option."
|
|
103
|
+
method_option "full-index",
|
|
104
|
+
:type => :boolean,
|
|
105
|
+
:desc => "Run bundle install with the " \
|
|
106
|
+
"full-index argument."
|
|
107
|
+
method_option "path",
|
|
108
|
+
:type => :string,
|
|
109
|
+
:desc => "Install gems in the specified directory. " \
|
|
110
|
+
"Bundler will remember this option."
|
|
111
|
+
def generate_install
|
|
112
|
+
invoke(:generate, [], {})
|
|
113
|
+
invoke(:install, [], options.to_h)
|
|
114
|
+
end
|
|
115
|
+
|
|
90
116
|
desc "generate", "Generate a gemfile for each appraisal"
|
|
91
117
|
def generate
|
|
92
118
|
AppraisalFile.each do |appraisal|
|
|
@@ -99,10 +125,8 @@ module Appraisal
|
|
|
99
125
|
FileUtils.rm_f(Dir["gemfiles/*.{gemfile,gemfile.lock}"])
|
|
100
126
|
end
|
|
101
127
|
|
|
102
|
-
desc "update [LIST_OF_GEMS]", "
|
|
128
|
+
desc "update [LIST_OF_GEMS]", "Update dependencies for each generated appraisal gemfile"
|
|
103
129
|
def update(*gems)
|
|
104
|
-
invoke(:generate, [], {})
|
|
105
|
-
|
|
106
130
|
gem_manager = options["gem-manager"] || options[:gem_manager]
|
|
107
131
|
update_options = gem_manager ? {:gem_manager => gem_manager} : {}
|
|
108
132
|
AppraisalFile.each do |appraisal|
|
|
@@ -110,6 +134,12 @@ module Appraisal
|
|
|
110
134
|
end
|
|
111
135
|
end
|
|
112
136
|
|
|
137
|
+
desc "generate-update [LIST_OF_GEMS]", "Generate gemfiles, then update dependencies for each appraisal"
|
|
138
|
+
def generate_update(*gems)
|
|
139
|
+
invoke(:generate, [], {})
|
|
140
|
+
update(*gems)
|
|
141
|
+
end
|
|
142
|
+
|
|
113
143
|
desc "list", "List the names of the defined appraisals"
|
|
114
144
|
def list
|
|
115
145
|
AppraisalFile.new.appraisals.each { |appraisal| puts appraisal.name }
|
|
@@ -132,8 +162,10 @@ module Appraisal
|
|
|
132
162
|
# This handles cases where Thor doesn't pass arguments
|
|
133
163
|
actual_args = (args.empty? && ARGV.any?) ? ARGV.dup : args
|
|
134
164
|
|
|
135
|
-
# Check if the first argument is
|
|
136
|
-
if actual_args.first == "
|
|
165
|
+
# Check if the first argument is an appraisal subcommand.
|
|
166
|
+
if actual_args.first == "generate"
|
|
167
|
+
matching_appraisal.write_gemfile
|
|
168
|
+
elsif actual_args.first == "install"
|
|
137
169
|
# Extract Thor options from the remaining arguments
|
|
138
170
|
# Filter out the command name and pass options to install
|
|
139
171
|
filtered_args = actual_args[1..-1] || []
|
|
@@ -145,6 +177,15 @@ module Appraisal
|
|
|
145
177
|
gem_manager = options["gem-manager"] || options[:gem_manager]
|
|
146
178
|
parsed_options[:gem_manager] = gem_manager if gem_manager && !parsed_options.key?(:gem_manager)
|
|
147
179
|
|
|
180
|
+
matching_appraisal.install(parsed_options)
|
|
181
|
+
matching_appraisal.relativize
|
|
182
|
+
elsif actual_args.first == "generate-install"
|
|
183
|
+
filtered_args = actual_args[1..-1] || []
|
|
184
|
+
parsed_options = parse_external_options(filtered_args)
|
|
185
|
+
|
|
186
|
+
gem_manager = options["gem-manager"] || options[:gem_manager]
|
|
187
|
+
parsed_options[:gem_manager] = gem_manager if gem_manager && !parsed_options.key?(:gem_manager)
|
|
188
|
+
|
|
148
189
|
matching_appraisal.write_gemfile
|
|
149
190
|
matching_appraisal.install(parsed_options)
|
|
150
191
|
matching_appraisal.relativize
|
|
@@ -157,6 +198,15 @@ module Appraisal
|
|
|
157
198
|
gem_manager = options["gem-manager"] || options[:gem_manager]
|
|
158
199
|
parsed_options[:gem_manager] = gem_manager if gem_manager && !parsed_options.key?(:gem_manager)
|
|
159
200
|
|
|
201
|
+
matching_appraisal.update(gems, parsed_options)
|
|
202
|
+
elsif actual_args.first == "generate-update"
|
|
203
|
+
filtered_args = actual_args[1..-1] || []
|
|
204
|
+
gems, parsed_options = extract_gems_and_options(filtered_args)
|
|
205
|
+
|
|
206
|
+
gem_manager = options["gem-manager"] || options[:gem_manager]
|
|
207
|
+
parsed_options[:gem_manager] = gem_manager if gem_manager && !parsed_options.key?(:gem_manager)
|
|
208
|
+
|
|
209
|
+
matching_appraisal.write_gemfile
|
|
160
210
|
matching_appraisal.update(gems, parsed_options)
|
|
161
211
|
else
|
|
162
212
|
# Run as an external command
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Appraisal
|
|
4
|
+
# Lifecycle hooks used by companion gems to extend Appraisal without
|
|
5
|
+
# monkey-patching command or generation internals.
|
|
6
|
+
module Hooks
|
|
7
|
+
GEMFILE_TRANSFORM_MUTEX = Mutex.new
|
|
8
|
+
GEMFILE_TRANSFORMS = [].freeze
|
|
9
|
+
|
|
10
|
+
class GemfileContext
|
|
11
|
+
attr_accessor :content
|
|
12
|
+
attr_reader :appraisal, :path
|
|
13
|
+
|
|
14
|
+
def initialize(appraisal, path, content)
|
|
15
|
+
@appraisal = appraisal
|
|
16
|
+
@path = path
|
|
17
|
+
@content = content
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
class << self
|
|
22
|
+
def transform_gemfile(&block)
|
|
23
|
+
raise ArgumentError, "transform_gemfile requires a block" unless block
|
|
24
|
+
|
|
25
|
+
GEMFILE_TRANSFORM_MUTEX.synchronize do
|
|
26
|
+
set_gemfile_transforms(gemfile_transforms + [block])
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def run_transform_gemfile(appraisal, path, content)
|
|
31
|
+
context = GemfileContext.new(appraisal, path, content)
|
|
32
|
+
gemfile_transforms.each do |hook|
|
|
33
|
+
result = if hook.arity == 1
|
|
34
|
+
hook.call(context.content)
|
|
35
|
+
else
|
|
36
|
+
hook.call(context.content, context)
|
|
37
|
+
end
|
|
38
|
+
context.content = result unless result.nil?
|
|
39
|
+
end
|
|
40
|
+
context.content
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def reset!
|
|
44
|
+
GEMFILE_TRANSFORM_MUTEX.synchronize do
|
|
45
|
+
set_gemfile_transforms([])
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
|
|
51
|
+
def gemfile_transforms
|
|
52
|
+
::Appraisal::Hooks.const_get(:GEMFILE_TRANSFORMS)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def set_gemfile_transforms(transforms)
|
|
56
|
+
::Appraisal::Hooks.__send__(:remove_const, :GEMFILE_TRANSFORMS)
|
|
57
|
+
::Appraisal::Hooks.const_set(:GEMFILE_TRANSFORMS, transforms.freeze)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
class << self
|
|
63
|
+
def transform_gemfile(&block)
|
|
64
|
+
Hooks.transform_gemfile(&block)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
data/lib/appraisal/task.rb
CHANGED
|
@@ -19,8 +19,8 @@ module Appraisal
|
|
|
19
19
|
desc("DEPRECATED: Resolve and install dependencies for each appraisal")
|
|
20
20
|
task(:install) do
|
|
21
21
|
warn("`rake appraisal:install` task is deprecated and will be removed soon. " \
|
|
22
|
-
"Please use `appraisal install`.")
|
|
23
|
-
exec("bundle exec appraisal install")
|
|
22
|
+
"Please use `appraisal generate-install`.")
|
|
23
|
+
exec("bundle exec appraisal generate-install")
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
desc("DEPRECATED: Remove all generated gemfiles from gemfiles/ folder")
|
data/lib/appraisal/version.rb
CHANGED
data/lib/appraisal2/version.rb
CHANGED
data.tar.gz.sig
CHANGED
|
Binary file
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: appraisal2
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Peter Boling
|
|
@@ -421,6 +421,7 @@ files:
|
|
|
421
421
|
- lib/appraisal/gemspec.rb
|
|
422
422
|
- lib/appraisal/git.rb
|
|
423
423
|
- lib/appraisal/group.rb
|
|
424
|
+
- lib/appraisal/hooks.rb
|
|
424
425
|
- lib/appraisal/ordered_hash.rb
|
|
425
426
|
- lib/appraisal/path.rb
|
|
426
427
|
- lib/appraisal/platform.rb
|
|
@@ -436,10 +437,10 @@ licenses:
|
|
|
436
437
|
- MIT
|
|
437
438
|
metadata:
|
|
438
439
|
homepage_uri: https://appraisal2.galtzo.com
|
|
439
|
-
source_code_uri: https://github.com/appraisal-rb/appraisal2/tree/v3.
|
|
440
|
-
changelog_uri: https://github.com/appraisal-rb/appraisal2/blob/v3.
|
|
440
|
+
source_code_uri: https://github.com/appraisal-rb/appraisal2/tree/v3.1.1
|
|
441
|
+
changelog_uri: https://github.com/appraisal-rb/appraisal2/blob/v3.1.1/CHANGELOG.md
|
|
441
442
|
bug_tracker_uri: https://github.com/appraisal-rb/appraisal2/issues
|
|
442
|
-
documentation_uri: https://www.rubydoc.info/gems/appraisal2/3.
|
|
443
|
+
documentation_uri: https://www.rubydoc.info/gems/appraisal2/3.1.1
|
|
443
444
|
funding_uri: https://github.com/sponsors/pboling
|
|
444
445
|
wiki_uri: https://github.com/appraisal-rb/appraisal2/wiki
|
|
445
446
|
news_uri: https://www.railsbling.com/tags/appraisal2
|
metadata.gz.sig
CHANGED
|
Binary file
|