Skip to content

Conversation

@schneems
Copy link
Contributor

@schneems schneems commented May 29, 2025

What was the end-user or developer problem that led to this PR?

I need to know what versions of gems are installed for a given application programmatically. I'm currently parsing the bundle list output, but I'm worried that the format may change in the future.

What is your fix for the problem, implemented in this PR?

Introduce a stable, machine-readable formatting output to this command via adding a --format=json flag.

More

The bundle list command is a convenient way for human to know what gems and versions are available. By introducing a --format=json option, we can provide the same information to machines in a stable format that is robust to UI additions or modifications. It indirectly supports Gemfile.lock modifications by discouraging external tools from attempting to parse that format.

This addition allows for the scripting of installation tools, such as buildpacks, that wish to branch logic based on gem versions. For example:

require "json"

command = "bundle list --format=json"
output = `#{command}`
raise "Command `#{command}` errored: #{output}" unless $?.success?

railties = JSON.parse(output).find {|gem| gem["name"] == railties }
if railties && Gem::Version.new(railties["version"]) >= Gem::Version.new("7")
  puts "Using Rails greater than 7!"
end

The top level is an object with a single key, "gems", this structure allows us to add other information in the future (should we desire) without having to change the json schema.

This JSON format is also useful in a bash scripting context, where command-line tools such as jq are commonly available to manipulate and extract information.

Make sure the following tasks are checked

@schneems schneems marked this pull request as draft May 29, 2025 16:53
@schneems schneems force-pushed the schneems/list-json branch 4 times, most recently from 87f6e03 to e0e5f69 Compare May 29, 2025 21:46
@schneems schneems marked this pull request as ready for review May 30, 2025 16:33
@schneems schneems force-pushed the schneems/list-json branch 3 times, most recently from 1221548 to 9474c94 Compare May 31, 2025 21:19
Copy link

@soulcutter soulcutter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this idea a lot.

What about --format=json as an alternate syntax? It opens the door for other formats like csv or json lines etc. I'm not sure if there's a most-common name for that option, I've also seen --output json off the top of my head.

@schneems schneems force-pushed the schneems/list-json branch 3 times, most recently from 3af66cf to abbad0e Compare June 2, 2025 18:03
@schneems
Copy link
Contributor Author

schneems commented Jun 2, 2025

What about --format=json as an alternate syntax?

Short: Seems good. I updated in a new commit.

Longer: For some numbers, I searched on GitHub:

Seems that --format= is the preferred syntax in the community. As an alternative, could later add --xml etc. The only benefit I see to unifying behind a flag is this would be invalid --json --xml but that's not possible via --format=json (though you could --format=json --format=xml), but IIRC that's protected at the top level (thor).

@schneems schneems force-pushed the schneems/list-json branch 2 times, most recently from 811e3f7 to d8896be Compare June 2, 2025 21:22
@schneems schneems changed the title Introduce bundle list --json Introduce bundle list --format=json Jun 2, 2025
@schneems schneems force-pushed the schneems/list-json branch 3 times, most recently from ef593b0 to 485a892 Compare June 3, 2025 01:40
@edmorley
Copy link

edmorley commented Jun 4, 2025

Seems that --format= is the preferred syntax in the community

As another couple of datapoints, --format also seems common with Ruby-specific tools too, eg:
https://rspec.info/features/3-12/rspec-core/command-line/format-option/
https://docs.rubocop.org/rubocop/1.76/formatters.html

@schneems
Copy link
Contributor Author

I'm interested in any feedback that could help advance or close this out. Baring strong blockers or actionable requests: a temperature reading of the feature is helpful too. Does this seem reasonable (warm) or does something about it make you say "ick" (ice cold)?

@deivid-rodriguez
Copy link
Contributor

I like this and I'm happy to introduce it, just did not find time to review it.

Naming seems also fine, some commands already have a --parseable flag, but I don't think that prescribes a specific format, just promises a "minimal formatting for more parseable output". I think something more specific like --format=json is better.

@schneems
Copy link
Contributor Author

schneems commented Aug 1, 2025

I'm unsure on timeline, but it would be nice to get this in before bundler 4 (if possible).

Copy link
Contributor

@deivid-rodriguez deivid-rodriguez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I commented some super minor nitpicks, but this PR looks good!

@schneems schneems force-pushed the schneems/list-json branch 5 times, most recently from 0bb8b24 to f52314e Compare August 7, 2025 18:39
Copy link
Contributor

@deivid-rodriguez deivid-rodriguez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me! Do you mind squashing all commits to a single one?

The `bundle list` command is a convenient way for human to know what gems and versions are available. By introducing a `--format=json` option, we can provide the same information to machines in a stable format that is robust to UI additions or modifications. It indirectly supports  `Gemfile.lock` modifications by discouraging external tools from attempting to parse that format.

This addition allows for the scripting of installation tools, such as buildpacks, that wish to branch logic based on gem versions. For example:

```ruby
require "json"

command = "bundle list --format=json"
output = `#{command}`
raise "Command `#{command}` errored: #{output}" unless $?.success?

railties = JSON.parse(output).find {|gem| gem["name"] == railties }
if railties && Gem::Version.new(railties["version"]) >= Gem::Version.new("7")
  puts "Using Rails greater than 7!"
end
```

The top level is an object with a single key, "gems", this structure allows us to add other information in the future (should we desire) without having to change the json schema.
@schneems schneems force-pushed the schneems/list-json branch from 14dfefe to 9e081b0 Compare August 8, 2025 15:15
@schneems
Copy link
Contributor Author

schneems commented Aug 8, 2025

Squashed and rebased, waiting for tests to run. Going to resolve prior comments.

@schneems
Copy link
Contributor Author

schneems commented Aug 8, 2025

CI is all green. Thanks for the review and your work 🙏

@deivid-rodriguez
Copy link
Contributor

No problem, I'll merge on Monday just to leave other maintainers some more time in case they have feedback.

@deivid-rodriguez deivid-rodriguez merged commit e9574e0 into ruby:master Aug 11, 2025
76 checks passed
@deivid-rodriguez
Copy link
Contributor

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants