Use RubyGems and Bundler with JFrog CLI

Configure and run RubyGems and Bundler with JFrog CLI and Artifactory.

Use JFrog CLI to configure RubyGems and Bundler for JFrog Artifactory, run native gem and bundle commands with Artifactory authentication, and collect build-info. The jf ruby command is available in JFrog CLI 2.121.0 and later.

This topic covers the following tasks:

When to Use

Use the Ruby commands for the following workflows:

  • Run jf setup ruby once per user environment to persist an Artifactory source, a Bundler mirror, and credentials in native Ruby configuration.
  • Run jf ruby bundle <subcommand> or jf ruby gem <subcommand> when you want JFrog CLI to discover an Artifactory RubyGems repository and provide authentication to the native tool.
  • Add --build-name and --build-number to supported operations to save Ruby dependency or artifact build-info locally. Publish the saved build-info separately with jf rt build-publish.
  • Continue using jf ruby-config for the existing project configuration workflow. jf ruby doesn't read .jfrog/projects/ruby.yaml. It uses command arguments and native RubyGems or Bundler sources.

Prerequisites

  • JFrog CLI 2.121.0 or later for jf ruby.
  • RubyGems or Bundler on PATH: JFrog CLI invokes the local gem or bundle binary and doesn't install Ruby.
  • A configured JFrog server: Run jf config add or jf c add. Use --server-id to select a non-default configuration. For more information, see Configure JFrog CLI.
  • Artifactory RubyGems repositories: Use a remote or virtual repository to resolve gems and a local repository to push gems. For more information, see RubyGems Repositories.
  • Write access to your Ruby user configuration when using jf setup ruby. Setup updates ~/.bundle/config and ~/.gemrc.

Configure RubyGems and Bundler

The recommended native setup command is jf setup ruby. It configures plain bundle and gem commands to resolve from Artifactory.

Synopsis

jf setup ruby [--server-id=<SERVER_ID>] [--repo=<REPOSITORY_KEY>] [--project=<PROJECT_KEY>]

Where:

  • <SERVER_ID>: JFrog CLI server ID from jf config add
  • <REPOSITORY_KEY>: Artifactory RubyGems repository key
  • <PROJECT_KEY>: JFrog project key used when listing repositories interactively

Setup Options

The following table lists the setup options.

FlagDefaultDescription
--server-idDefault serverJFrog CLI server configuration to use
--repoInteractive selectionArtifactory RubyGems repository key. When omitted in an interactive terminal, JFrog CLI prompts for a compatible virtual repository
--projectNoneJFrog project key used when listing repositories interactively
--urlNoneJFrog Artifactory URL. Use with command-line credentials instead of --server-id
--userNoneJFrog username for command-line authentication
--passwordNoneJFrog password for command-line authentication
--access-tokenNoneJFrog access token for command-line authentication
--client-cert-pathNoneClient certificate in PEM format
--client-cert-key-pathNonePrivate key for the client certificate in PEM format
--ssh-key-pathNoneSSH key used for authentication
--ssh-passphraseNonePassphrase for the SSH key

To configure RubyGems and Bundler persistently:

  1. Run:

    jf setup ruby --server-id=<SERVER_ID> --repo=<REPOSITORY_KEY>

    Where:

    • <SERVER_ID>: JFrog CLI server ID from jf config add
    • <REPOSITORY_KEY>: Artifactory RubyGems repository key

    For example:

    jf setup ruby --server-id=my-server --repo=gems-virtual
  2. Verify the native configuration:

    gem sources --list
    bundle config list

After setup, Bundler uses a two-part configuration in ~/.bundle/config:

  • A mirror so a Gemfile that still says source "https://rubygems.org" resolves through Artifactory. Bundler stores credentials in the mirror URL.
  • Per-host credentials so a Gemfile that names the Artifactory gems API URL can authenticate without embedding a password in Gemfile.

For example, after jf setup ruby --repo=gems-virtual against https://mycompany.jfrog.io/artifactory/, ~/.bundle/config contains entries similar to:

---
BUNDLE_MIRROR__HTTPS://RUBYGEMS__ORG/: "https://<USER>:<PASSWORD>@mycompany.jfrog.io/artifactory/api/gems/gems-virtual/"
BUNDLE_MYCOMPANY__JFROG__IO: "<USER>:<PASSWORD>"

Where:

  • <USER>: Username from the selected JFrog CLI server configuration
  • <PASSWORD>: Password or access token from that configuration

If the Artifactory host contains a dash, setup also writes Bundler 1.x's older key spelling. For more information, see Runtime Authentication.

The ~/.gemrc file contains the Artifactory source with credentials in the source URL. Setup removes the public RubyGems source so native gem install resolves through the configured virtual repository. Other Artifactory sources are preserved, with the most recently configured source first.

JFrog CLI preserves existing unrelated settings in both files. It writes both files with owner-only permissions.

⚠️

Warning

jf setup ruby writes persistent credentials to native Ruby configuration. Protect ~/.bundle/config and ~/.gemrc, and run setup again after the configured credential changes or expires.

Existing Ruby Configuration Workflow

jf ruby-config remains available, with alias jf rubyc, for saving project or global JFrog Ruby configuration.

jf ruby-config \
  --server-id-resolve=<SERVER_ID> \
  --repo-resolve=<RESOLVE_REPOSITORY>

Where:

  • <SERVER_ID>: JFrog CLI server ID from jf config add
  • <RESOLVE_REPOSITORY>: Artifactory repository key used for gem resolution

For example:

jf ruby-config --server-id-resolve=my-server --repo-resolve=gems-virtual

Its options are --global, --server-id-resolve, --repo-resolve, --server-id-deploy, and --repo-deploy. The command writes .jfrog/projects/ruby.yaml for a project, or the corresponding global JFrog configuration when --global is set.

This file is separate from native Ruby configuration. jf ruby doesn't read ruby.yaml. Use jf setup ruby, a Gemfile source, native source options, or gem sources to provide the repository used at runtime.


Ruby Command Syntax

jf ruby selects either RubyGems or Bundler, removes only its JFrog-specific options, and passes the remaining arguments to the selected native binary in their original order. JFrog CLI passes through standard input, output, errors, and the native exit status. jf ruby always invokes the native gem or bundle binary. For more information, see Native Mode.

Synopsis

jf ruby gem <GEM_SUBCOMMAND_OR_OPTION> [gem arguments...] [JFrog options]
jf ruby bundle <BUNDLE_SUBCOMMAND_OR_OPTION> [bundle arguments...] [JFrog options]

Arguments

The following table lists the arguments.

ArgumentRequiredDescription
gem or bundleYesNative Ruby tool to invoke
<GEM_SUBCOMMAND_OR_OPTION> or <BUNDLE_SUBCOMMAND_OR_OPTION>YesNative subcommand such as install, fetch, build, push, update, add, or lock. Standalone native options such as --version are also valid
Native argumentsNoArguments and options forwarded to the selected native tool

JFrog CLI doesn't provide top-level jf gem or jf bundle commands. Use jf ruby gem and jf ruby bundle.

The following table lists the JFrog options.

FlagDefaultDescription
--server-idDefault serverJFrog CLI server configuration used for repository URL construction and runtime authentication
--repoDiscovered sourceArtifactory repository key. JFrog CLI constructs https://<HOST>/artifactory/api/gems/<REPOSITORY_KEY>/ from the selected server. For gem install and gem fetch, it supplies the URL as the native source. For gem push, it supplies the URL as the native host. For Bundler, the Gemfile or configured mirror must still select the source
--build-nameNoneBuild name for local build-info. Must be provided with --build-number
--build-numberNoneBuild number for local build-info. Must be provided with --build-name
--moduleDerived module IDModule name override in build-info
--projectNoneJFrog project key associated with the build-info

JFrog options can appear among the native arguments. Other options, including native --source, -s, --host, --clear-sources, --path, -i/--install-dir, version, and group options, are passed to RubyGems or Bundler.

Runtime Authentication

JFrog CLI injects credentials into the native subprocess when it discovers an Artifactory target and the native tool doesn't already have credentials for that host.

The following table lists the environment variables JFrog CLI may set.

VariableFormat JFrog CLI writesUsed by
GEM_HOST_API_KEYBasic <BASE64(user:password)> HTTP Basic value, not user:passwordRubyGems for install, fetch, and push
BUNDLE_<HOST_KEY>user:passwordBundler

If you set GEM_HOST_API_KEY yourself, use the same Basic format RubyGems expects: Basic followed by the Base64 encoding of user:password. A value of user:password without the Basic prefix doesn't match what JFrog CLI injects and isn't the format RubyGems uses for this variable.

For Bundler, JFrog CLI may inject two host-key spellings so Bundler 1.x and Bundler 2.x both authenticate:

  • Bundler 2.x and later: uppercase host, . becomes __, - becomes ___. For example, my-company.jfrog.io becomes BUNDLE_MY___COMPANY__JFROG__IO.
  • Bundler 1.x: uppercase host, . becomes __, and dashes stay in the key. JFrog CLI adds this spelling only when it differs from the Bundler 2.x key.

JFrog CLI doesn't overwrite a variable that is already set in the environment.

Repository Discovery and Authentication

JFrog CLI discovers the Artifactory gems URL in this order:

  1. --repo. JFrog CLI constructs https://<HOST>/artifactory/api/gems/<REPOSITORY_KEY>/ from the selected server configuration
  2. A native --source, -s, or --host URL in the command
  3. An Artifactory source URL in the active Gemfile, including Bundler's BUNDLE_GEMFILE and parent-directory lookup
  4. The first Artifactory source returned by gem sources --list

Native --clear-sources is forwarded to RubyGems. It doesn't supply a URL for this discovery sequence. This discovery doesn't use .jfrog/projects/ruby.yaml.

For a matching Artifactory target, JFrog CLI passes authentication to the native subprocess while respecting credentials already configured by the native tool. For gem push, it also adds a temporary entry for the target host to ~/.gem/credentials, then restores the previous file or removes the temporary entry after the command. Cleanup also runs when the process receives an interrupt or termination signal.

If a discovered target host differs from the configured Artifactory host, JFrog CLI doesn't inject that server's credentials by default. Select the intended configuration explicitly with --server-id, or configure the target in Bundler or RubyGems.


Run Bundler Commands

Use jf ruby bundle with native Bundler subcommands. install, update, and add can collect dependencies from Gemfile.lock. JFrog CLI passes lock through but doesn't collect build-info.

To install dependencies and collect build-info:

  1. From the directory containing the Gemfile, run:

    jf ruby bundle install \
      --build-name=<BUILD_NAME> \
      --build-number=<BUILD_NUMBER>

    Where:

    • <BUILD_NAME>: Build name for local build-info
    • <BUILD_NUMBER>: Build number for local build-info

    For example:

    jf ruby bundle install --build-name=my-app --build-number=1
  2. Publish the saved build-info:

    jf rt build-publish <BUILD_NAME> <BUILD_NUMBER>

    For example:

    jf rt build-publish my-app 1

Bundler resolves and installs the project dependencies, and JFrog CLI saves dependency build-info from Gemfile.lock. Native Bundler output varies by project and installed Bundler version.

The same dependency collection applies to:

jf ruby bundle update <GEM> --build-name=<BUILD_NAME> --build-number=<BUILD_NUMBER>
jf ruby bundle add <GEM> --build-name=<BUILD_NAME> --build-number=<BUILD_NUMBER>

Where:

  • <GEM>: Gem name passed to Bundler
  • <BUILD_NAME>: Build name for local build-info
  • <BUILD_NUMBER>: Build number for local build-info

For example:

jf ruby bundle update rake --build-name=my-app --build-number=1

jf ruby bundle lock can update Gemfile.lock. It doesn't collect build-info, even if you pass --build-name and --build-number. The operation only resolves and writes the lockfile.

Bundler honors --without and --with during bundle install. Build-info includes only the gems that are actually installed after those filters.


Install and Fetch Gems

Use --repo to select an Artifactory repository without supplying a full native source URL.

To install a gem and collect dependency build-info:

  • Run:

    jf ruby gem install <GEM_NAME> \
      --repo=<RESOLVE_REPOSITORY> \
      --build-name=<BUILD_NAME> \
      --build-number=<BUILD_NUMBER>

    Where:

    • <GEM_NAME>: Gem to install
    • <RESOLVE_REPOSITORY>: Artifactory RubyGems repository key used for resolution
    • <BUILD_NAME>: Build name for local build-info
    • <BUILD_NUMBER>: Build number for local build-info

    For example:

    jf ruby gem install rake --repo=gems-virtual --build-name=my-app --build-number=1

To fetch a gem and collect dependency build-info:

  • Run:

    jf ruby gem fetch <GEM_NAME> \
      --repo=<RESOLVE_REPOSITORY> \
      --build-name=<BUILD_NAME> \
      --build-number=<BUILD_NUMBER>

    Where:

    • <GEM_NAME>: Gem to fetch
    • <RESOLVE_REPOSITORY>: Artifactory RubyGems repository key used for resolution
    • <BUILD_NAME>: Build name for local build-info
    • <BUILD_NUMBER>: Build number for local build-info

    For example:

    jf ruby gem fetch rake --repo=gems-virtual --build-name=my-app --build-number=1

JFrog CLI constructs the repository URL, RubyGems installs or downloads the requested gem, and JFrog CLI records the gems changed by that invocation as dependencies.

gem install -i <DIR> and gem install --install-dir <DIR> are supported. JFrog CLI scopes the before-and-after gem snapshot to that directory so you can install into a custom location and still collect build-info.


Build and Push Gems

gem build is a local operation. JFrog CLI doesn't inject repository authentication for it. With build flags, it records dependencies only when a Gemfile.lock is available. It doesn't record the locally built .gem file as an artifact.

To record lockfile dependencies while building a gem:

  • Run:

    jf ruby gem build <GEMSPEC> \
      --build-name=<BUILD_NAME> \
      --build-number=<BUILD_NUMBER>

    Where:

    • <GEMSPEC>: Path to the gemspec file
    • <BUILD_NAME>: Build name for local build-info
    • <BUILD_NUMBER>: Build number for local build-info

    For example:

    jf ruby gem build my-gem.gemspec --build-name=my-app --build-number=1

To push a gem and collect artifact build-info:

  1. Run:

    jf ruby gem push <GEM_FILE> \
      --repo=<LOCAL_REPOSITORY> \
      --build-name=<BUILD_NAME> \
      --build-number=<BUILD_NUMBER>

    Where:

    • <GEM_FILE>: Local .gem file to upload
    • <LOCAL_REPOSITORY>: Artifactory local RubyGems repository key
    • <BUILD_NAME>: Build name for local build-info
    • <BUILD_NUMBER>: Build number for local build-info

    For example:

    jf ruby gem push my-gem-1.0.0.gem --repo=gems-local --build-name=my-app --build-number=1
  2. Publish the saved build-info:

    jf rt build-publish <BUILD_NAME> <BUILD_NUMBER>

    For example:

    jf rt build-publish my-app 1

RubyGems uploads the gem to the selected Artifactory repository, and JFrog CLI records the uploaded .gem as a build artifact.

JFrog CLI strips a trailing slash from --host before gem push. RubyGems builds the upload URL as #{host}/api/v1/gems. A trailing slash on the host would produce a double slash, and Artifactory rejects that request.


Collect and Publish Build-Info

Build-info collection occurs only when both --build-name and --build-number are set.

The following table lists build-info collection by native operation.

Native operationDependenciesArtifactsNotes
bundle installYesNoReads gems that Bundler actually installed from Gemfile.lock, including --without and --with filters
bundle updateYesNoReads resolved dependencies from Gemfile.lock
bundle addYesNoReads resolved dependencies from Gemfile.lock
bundle lockNoNoNative passthrough only. --build-name and --build-number don't collect build-info
gem installYesNoRecords gems installed by this invocation
gem fetchYesNoRecords gems fetched by this invocation
gem buildOnly when Gemfile.lock existsNoThe local .gem isn't an Artifactory artifact
gem pushNoYesRecords the uploaded .gem artifact
Other gem or bundle subcommandsNoNoNative passthrough

GIT and PATH dependencies appear in build-info when Bundler resolved them, but JFrog CLI skips Artifactory checksum enrichment for those gems. They aren't stored in the RubyGems repository, so AQL can't look them up.

If checksum enrichment fails, JFrog CLI still saves the build-info. You can still publish it. Dependencies are recorded without checksums, and the CLI logs a warning. A common cause is passing a virtual repository to AQL. Use --repo with a local or remote repository when you need checksums.

jf ruby saves build-info locally. It doesn't publish it automatically.

To publish saved Ruby build-info:

  • Run:

    jf rt build-publish <BUILD_NAME> <BUILD_NUMBER> [--project=<PROJECT_KEY>]

    Where:

    • <BUILD_NAME>: Build name used when collecting build-info
    • <BUILD_NUMBER>: Build number used when collecting build-info
    • <PROJECT_KEY>: Optional JFrog project key associated with the build-info

    For example:

    jf rt build-publish my-app 1
📘

Note

Providing only --build-name or only --build-number fails with the build-name and build-number options cannot be provided separately.


Package Alias

Package Alias can intercept the native gem and bundle executable names. When either tool is configured in jf mode, routing is:

  • gem <args>jf ruby gem <args>
  • bundle <args>jf ruby bundle <args>

The aliases don't route to top-level jf gem or jf bundle commands. gem and bundle default to pass mode unless you explicitly set their Package Alias mode to jf. For more information, see Use JFrog CLI Package Alias.

Ruby Command Behavior

  • jf ruby requires gem or bundle as the first argument, then at least one native argument. jf ruby pip fails with unsupported ruby tool "pip": expected 'gem' or 'bundle'. jf ruby gem with no subcommand fails with no subcommand provided for 'gem'. For example, use jf ruby gem install rake or jf ruby gem --version.
  • JFrog CLI passes help requests to the native tool without injecting authentication.
  • --repo is a repository key, not a URL. Use native --source or --host when you need to provide a complete URL.
  • jf ruby doesn't change native configuration. Only jf setup ruby changes ~/.bundle/config and ~/.gemrc. gem push may temporarily update ~/.gem/credentials for the duration of the command.
  • Native output varies by Ruby, RubyGems, Bundler, project, and Artifactory configuration.

Troubleshooting

The following table lists common errors and how to resolve them.

Error or symptomCauseResolution
unsupported ruby tool "<tool>": expected 'gem' or 'bundle'The first argument after jf ruby isn't supportedUse jf ruby gem <subcommand> or jf ruby bundle <subcommand>
no subcommand provided for 'gem' or no subcommand provided for 'bundle'The native subcommand is missingAdd a subcommand such as install, fetch, build, push, update, or add
the build-name and build-number options cannot be provided separatelyOnly one build identifier was providedPass both build options, or omit both
Authentication is skipped for a target hostThe discovered source host differs from the configured Artifactory hostPass the correct --server-id, or configure credentials in the native tool
Bundler still resolves from the public registryThe Gemfile source or native mirror doesn't select ArtifactoryRun jf setup ruby, or update the Gemfile to use the Artifactory gems API URL
Build-info is saved without dependency checksumsAQL enrichment failed, often because the repo is virtual, or the gems are GIT or PATH sourcesPublish still succeeds. Pass --repo with a local or remote repository for Artifactory gems. GIT and PATH gems stay in the record without checksums
gem push targets an unintended hostNo Artifactory repository or native host was selectedPass --repo=<LOCAL_REPOSITORY> or native --host=<ARTIFACTORY_GEMS_URL>
No build-info is saved for bundle lockThe operation only resolves and writes the lockfile. Build flags don't change thatRun bundle install, bundle update, or bundle add with both build options
No artifact is recorded for gem buildThe built gem hasn't entered ArtifactoryPush it with jf ruby gem push using the same build name and number

Frequently Asked Questions

This section provides answers to frequently asked questions.

plusFAQs
Q: Does jf ruby use the configuration written by jf ruby-config?

A: No. jf ruby doesn't read .jfrog/projects/ruby.yaml. It discovers repositories from --repo first, then native source or host arguments, the active Gemfile, or gem sources. See Repository Discovery and Authentication.

Q: What is the difference between jf setup ruby and jf ruby-config?

A: jf setup ruby writes native user configuration for RubyGems and Bundler. jf ruby-config writes JFrog project configuration to ruby.yaml. See Configure RubyGems and Bundler.

Q: Does jf ruby publish build-info automatically?

A: No. It saves supported dependency or artifact build-info locally. Run jf rt build-publish <BUILD_NAME> <BUILD_NUMBER> to publish it. See Collect and Publish Build-Info.

Q: Can I pass normal RubyGems and Bundler options?

A: Yes. JFrog CLI removes only --server-id, --repo, --build-name, --build-number, --module, and --project. It forwards the remaining arguments to the selected native tool, including --clear-sources, -i/--install-dir, --without, and --with.

Q: Does jf ruby bundle lock --build-name record build-info?

A: No. bundle lock is native passthrough only. Add --build-name and --build-number to bundle install, bundle update, or bundle add instead. See Collect and Publish Build-Info.

Related Topics


Did this page help you?