Skip to content

feat: add extra_args passthrough to bundle install - #394

Open
DhashS wants to merge 6 commits into
bazel-contrib:mainfrom
DhashS:feat/bundle-install-extra-args
Open

feat: add extra_args passthrough to bundle install#394
DhashS wants to merge 6 commits into
bazel-contrib:mainfrom
DhashS:feat/bundle-install-extra-args

Conversation

@DhashS

@DhashS DhashS commented Aug 5, 2026

Copy link
Copy Markdown

What

Adds an extra_args attribute that appends extra command-line arguments to the bundle install invocation, plumbed through all three entry points:

  • the ruby.bundle_fetch bzlmod tag (extensions.bzl)
  • the rb_bundle_fetch repo rule (bundle_fetch.bzl, used by both bzlmod and WORKSPACE)
  • the rb_bundle_install rule (bundle_install.bzl)

Why

Cross-platform bundles. Bundler 2.6 / RubyGems 3.4 added bundle install --target-rbconfig=<rbconfig.rb> (Gem::TargetRbConfig), which lets the host Ruby install a different platform's precompiled gems. There's currently no way to pass that (or any other) flag through rb_bundle_install — the command is hardcoded to install --standalone --local, the env attr isn't consulted by bundler for --target-rbconfig (it's a Thor CLI option, not a Bundler::Settings key), and BUNDLE_IGNORE_CONFIG=1 rules out .bundle/config.

With extra_args, an arm64-darwin host can assemble an x86_64-linux vendor/bundle for a container image layer without a Linux executor:

ruby.bundle_fetch(
    name = "bundle",
    gemfile = "//:Gemfile",
    gemfile_lock = "//:Gemfile.lock",
    extra_args = ["--target-rbconfig", "/path/to/linux/rbconfig.rb"],
)

(Today the documented cross-platform story is RBE via the multi-platform toolchains from #377 — this offers a complementary, executor-free path for precompiled gems.)

Verified

Threaded end-to-end: with extra_args set, the generated @bundle//:BUILD carries extra_args = [...] and the generated install script runs:

bundle install --standalone --local --target-rbconfig /…/rbconfig.rb

Notes / open questions

  • extra_args is a verbatim string_list. For file-valued flags like --target-rbconfig, a natural follow-up is $(location) expansion + threading the file as an action input (hermetic). Happy to add that here or in a follow-up — whichever you prefer.
  • Windows .cmd template updated symmetrically.
  • Can add an example/e2e test under examples/ if you'd like — guidance welcome on the preferred shape.

🤖 Generated with Claude Code

DhashS added 4 commits August 5, 2026 14:03
Threads extra command-line arguments to `bundle install` from the
`ruby.bundle_fetch` bzlmod tag / `rb_bundle_fetch` repo rule / `rb_bundle_install`
rule down onto the install command line.

Primary use case: cross-platform bundles. With bundler's `--target-rbconfig`
(RubyGems 3.4+ / Gem::TargetRbConfig), the host ruby can install a DIFFERENT
platform's precompiled gems — e.g. assembling an x86_64-linux vendor/bundle on
an arm64-darwin host for a container image layer, without a linux executor:

    ruby.bundle_fetch(
        name = "bundle",
        gemfile = "//:Gemfile",
        gemfile_lock = "//:Gemfile.lock",
        extra_args = ["--target-rbconfig", "/path/to/linux/rbconfig.rb"],
    )

Covers both the bzlmod and WORKSPACE paths (shared rb_bundle_fetch repo rule)
and the standalone rb_bundle_install rule.
extra_args now supports $(location)/$(rootpath)/$(execpath) make-variable
expansion (built-in ctx.expand_location) against a new `data` label_list, which
is also threaded as inputs to the bundle install action. This lets a file-valued
flag reference a target instead of a raw path:

    ruby.bundle_fetch(
        name = "bundle_linux_amd64",
        gemfile = "//:Gemfile",
        gemfile_lock = "//:Gemfile.lock",
        data = ["//image:x86_64-linux-rbconfig.rb"],
        extra_args = ["--target-rbconfig", "$(location //image:x86_64-linux-rbconfig.rb)"],
    )

Threaded through the bzlmod tag, repo rule, generated BUILD, and install rule.
Adds a public dist_files filegroup (glob dist/**/*) to each per-platform ruby
repo, aliased on the @ruby hub. Lets you package the interpreter into a
container image (portable-ruby is relocatable), e.g.:

    pkg_tar(name = "ruby_runtime", srcs = ["@ruby//:dist_files"],
            package_dir = "/usr/local", strip_prefix = "dist")
Adds the pieces needed to install a bundle for a FOREIGN platform (e.g. build a
linux gems layer from a macOS host via --target-rbconfig) and package it into a
container image:

* env values now support $(location ...)/$(execpath ...) expansion against
  `data` (mirrors extra_args) — lets an env var reference a build artifact,
  e.g. prepend a generated cross-compiler wrapper dir onto PATH.
* new `rbconfig` filegroup on the ruby dist (+ hub alias): the interpreter's
  own relocatable rbconfig.rb, for `gem install --target-rbconfig` cross-builds.
* `binstubs` attr (default True): skip `bundle binstubs --all` for
  cross-platform bundles, where the host ruby can't validate the target's
  native extensions; the (empty) binstubs dir is still materialized.
* `gems` output group: just the vendor/bundle tree (no Gemfile/binstubs), so
  consumers can lay the gems into a container BUNDLE_PATH with a clean
  strip_prefix.
@p0deje

p0deje commented Aug 8, 2026

Copy link
Copy Markdown
Member

Can add an example/e2e test under examples/ if you'd like — guidance welcome on the preferred shape.

It would be great to have a sample test so that it doesn't break in the future.

# to `gem install --target-rbconfig` cross-compiles source gems for THIS Ruby's
# platform — its rubyhdrdir/libdir auto-resolve to the staged `dist` tree. Under
# a platform transition it resolves to the target arch's Ruby.
filegroup(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If all files are Ruby, it's better to use rb_library for it.

# The complete Ruby install tree (bin/, lib/, include/, ...). Useful for
# packaging the interpreter into a container image (portable-ruby is relocatable
# via relative rpaths, so this tars cleanly to e.g. /usr/local).
filegroup(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You should be able to use @ruby//:files already to get this.

Comment on lines +60 to +62
# Expand `$(location ...)`/`$(execpath ...)` in env values (against `data`),
# mirroring `extra_args`. Lets an env var reference a build artifact by label
# — e.g. prepending a generated cross-compiler wrapper dir onto PATH.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

No need for trivial comments, the code is self-explanatory.

@p0deje

p0deje commented Aug 12, 2026

Copy link
Copy Markdown
Member

Let's get CI passing before merge too.

DhashS added 2 commits August 12, 2026 18:32
…h example

Addresses review feedback on bazel-contrib#394 (comment 5223558709): "It would be great
to have a sample test so that it doesn't break in the future," in reply to
the offer to add an example/e2e test for the new extra_args attribute.

Adds extra_args = ["--quiet"] to the existing bundle_fetch() used by
examples/gem (both the bzlmod MODULE.bazel and legacy WORKSPACE entry
points), so the extra_args -> rb_bundle_fetch -> rb_bundle_install plumbing
is exercised by every existing examples/gem CI job. If that threading ever
regresses (e.g. the flag gets dropped or the bundle install command line
gets mangled), the existing `bazel build ...` step fails instead of the
regression going unnoticed.

Verified locally: built @bundle//bin:rake with this change (bzlmod mode)
and confirmed the generated install script contains
`bundle install --standalone --local --quiet`.
Fixes the failing docs:update_0_test/docs:update_1_test (stardoc diff
tests) in the Ruleset CI job. The rb_bundle_install and rb_bundle_fetch
attrs added earlier in this PR (extra_args, data, binstubs) changed the
.bzl docstrings but docs/*.md were never regenerated to match.

Ran `bazel run //docs:update` and committed the resulting diff verbatim.
@DhashS

DhashS commented Aug 13, 2026

Copy link
Copy Markdown
Author

Pushed a fix for the failing docs:update_0_test/docs:update_1_test (ran bazel run //docs:update and committed the resulting diff — the new extra_args/data/binstubs attrs had changed docstrings but the generated docs/*.md were never refreshed to match) and added a small e2e sample test in examples/gem exercising extra_args end-to-end (per the review comment above).

Also validated the extra_args/data $(location) mechanism against a real downstream consumer outside this repo, which confirmed it works as designed for its primary intended use case (--target-rbconfig).

CI on this branch is showing action_required for the last few pushes (https://github.com/bazel-contrib/rules_ruby/actions/runs/31658692525) — would appreciate someone with repo write access approving the workflow run so it can actually execute. I don't have permission to approve it myself (fork PR + first/repeat-contributor gating).

p0deje
p0deje previously approved these changes Aug 13, 2026
@p0deje
p0deje self-requested a review August 13, 2026 14:29
@p0deje

p0deje commented Aug 13, 2026

Copy link
Copy Markdown
Member

@DhashS Can you please address other inline comments I left?

@p0deje
p0deje dismissed their stale review August 13, 2026 14:30

Comments need to be addressed

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.

2 participants