= Ruby Rules® for Bazel :subtitle: Version 0.5.2 :author: Yuki (Yugui) Sonoda, Konstantin Gredeskoul & Contributors. :doctype: book :source-highlighter: rouge :rouge-style: base16.monokai :toclevels: 5 :toc: :sectnums: 9 :icons: font :license: apache
== New Rules Ruby!
This repo will be retired eventually, as these rules have not been actively maintained and are in the process of being replaced by the new rules, which you can find here: https://github.com/bazel-contrib/rules_ruby
TIP: You can read or print this README in a proper PDF format by grabbing our link:README.pdf[README.pdf].
== Build Status & Activity
[cols="3,9",options="header",] |=== | CI Status | Activity & Documentation
| image:https://circleci.com/gh/bazelruby/rules_ruby.svg?style=shield[CircleCI,link=https://circleci.com/gh/bazelruby/rules_ruby] | image:https://img.shields.io/github/commit-activity/m/bazelruby/rules_ruby?style=for-the-badge[activity]
| image:https://travis-ci.org/bazelruby/rules_ruby.svg?branch=master[Build Status,link=https://travis-ci.org/bazelruby/rules_ruby] | xref:CHANGELOG.md[image:https://img.shields.io/badge/change-log-brightgreen[changelog]] link:README.pdf[image:https://img.shields.io/badge/README-pdf-blue[readme.pdf]] |===
== Rules Development Status
[cols="3,9",options="header",] |=== | Readiness | Types of Applications
| image:docs/img/status-ready.svg[Ready] | ruby apps, ruby gems, micro-services, ideally in a mono-repo
| image:docs/img/status-ready.svg[Wait] | medium-sized Ruby on Rails apps, ideally in a mono-repo
| image:docs/img/status-wait.svg[Not Ready] | complex Ruby on Rails monoliths, single-repo |===
NOTE: we have a short guide on https://github.com/bazelruby/rules_ruby/wiki/Build-your-ruby-project[Building your first Ruby Project] on the Wiki. We encourage you to check it out.
== Table of Contents
WORKSPACE
File>>
<<buildbazel-files,BUILD.bazel
file(s)>> <<tool-specific-setup,Tool Specific Setup>> <<rule-dependency-diagram,Rule Dependency Diagram>>
<<rules,Rules>>
** <<ruby_library,ruby_library
>>
<<ruby_binary,ruby_binary
>>
<<ruby_test,ruby_test
>>
<<ruby_bundle,ruby_bundle
>>
<<ruby_rspec,ruby_rspec
>>
<<ruby_gem,ruby_gem
>>
<<potential-future-features,Potential Future Features>>
<<contributing,Contributing>>
<<setup,Setup>>
<<verifying-your-environment,Verifying Your Environment>>
<<developing-rules,Developing Rules>>
<<running-tests,Running Tests>>
<<linter,Linter>>
<<regenerating-readmepdf-changelog,Regenerating README.pdf & Changelog>>
** <<copyright,Copyright>>== Usage
=== WORKSPACE
File
==== Load dependencies, select Ruby SDK and define one or more Bundles
workspace(name = "my_ruby_project")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
git_repository( name = "bazelruby_rules_ruby", remote = "https://github.com/bazelruby/rules_ruby.git", branch = "master" )
load( "@bazelruby_rules_ruby//ruby:deps.bzl", "rules_ruby_dependencies", "rules_ruby_select_sdk", )
rules_ruby_dependencies()
load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace") bazel_skylib_workspace()
rules_ruby_select_sdk(version = "3.0.2")
load( "@bazelruby_rules_ruby//ruby:defs.bzl", "ruby_bundle", )
ruby_bundle( name = "bundle",
# Since spec.require_paths in Gem specifications are auto-included, directory paths
# in spec.require_paths do not need to be listed in includes hash.
includes = {
"grpc": ["etc"],
},
excludes = {
"mini_portile": ["test/**/*"],
},
gemfile = "//:Gemfile",
gemfile_lock = "//:Gemfile.lock",
)
ruby_bundle( name = "bundle_app_shopping", gemfile = "//:apps/shopping/Gemfile", gemfile_lock = "//:apps/shopping/Gemfile.lock", )
gemspec
.=== BUILD.bazel
file(s)
Any of the project BUILD
files can now reference any gems included in the Gemfile
referenced by the ruby_bundle
rule, and defined in the project's WORKSPACE
file.
==== Define Ruby Executable, Library and an RSpec
Add ruby_library
, ruby_binary
, ruby_rspec
or ruby_test
into your BUILD.bazel
files.
load( "@bazelruby_rules_ruby//ruby:defs.bzl", "ruby_binary", "ruby_library", "ruby_test", "ruby_rspec", )
ruby_library( name = "foo", srcs = glob(["lib/*/.rb"]), includes = ["lib"], deps = [ "@bundle//:activesupport", "@bundle//:awesome_print", "@bundle//:rubocop", ] )
ruby_binary( name = "bar", srcs = ["bin/bar"], deps = [":foo"], )
ruby_test( name = "foo-test", srcs = ["test/foo_test.rb"], deps = [":foo"], )
==== Package Ruby files as a Gem
Use ruby_gem
rule to package any number of ruby files or folders into a Ruby-Gem compatible ZIP archive.
load( "@bazelruby_rules_ruby//ruby:defs.bzl", "ruby_gem", )
=== Tool Specific Setup
==== ASDF
If you are using ASDF to manage your ruby installs, you can use them by adding .bazelrc
:
You will have to be sure to export the ASDF_DATA_DIR
in your profile since it's not set by default. e.g. export ASDF_DATA_DIR="$HOME/.asdf"
=== Rule Dependency Diagram
NOTE: this diagram is somewhat outdated.
The following diagram attempts to capture the implementation behind ruby_library
that depends on the result of bundle install
, and a ruby_binary
that depends on both:
image::docs/img/ruby_rules.png[Ruby Rules]
== Rules
=== ruby_library
[cols="15,85",options="header",]
|===
|Attributes |
|name
a|
Name, required
A unique name for this rule.
|srcs
a|
List of Labels, optional
List of .rb
files.
At least srcs
or deps
must be present
|deps
a|
List of labels, optional
List of targets that are required by the srcs
Ruby files.
At least srcs
or deps
must be present
|includes
a|
List of strings, optional
List of paths to be added to $LOAD_PATH
at runtime. The paths must be relative to the the workspace which this rule belongs to.
|rubyopt
a|
List of strings, optional
List of options to be passed to the Ruby interpreter at runtime.
NOTE: -I
option should usually go to includes
attribute.
2+<e|And other https://docs.bazel.build/versions/master/be/common-definitions.html#common-attributes[common attributes]. |===
=== ruby_binary
[cols="15,85",options="header",]
|===
|Attributes |
|name
a|
Name, required
A unique name for this rule.
|srcs
a|
List of Labels, required
List of .rb
files.
|deps
a|
List of labels, optional
List of targets that are required by the srcs
Ruby files.
|main
a|
Label, optional
The entrypoint file. It must be also in srcs
.
If not specified, $(NAME).rb
where $(NAME)
is the name
of this rule.
|includes
a|
List of strings, optional
List of paths to be added to $LOAD_PATH
at runtime. The paths must be relative to the the workspace which this rule belongs to.
|rubyopt
a|
List of strings, optional
List of options to be passed to the Ruby interpreter at runtime.
NOTE: -I
option should usually go to includes
attribute.
2+<e|And other https://docs.bazel.build/versions/master/be/common-definitions.html#common-attributes[common attributes]. |===
=== ruby_test
[cols="15,85",options="header",]
|===
|Attributes |
|name
a|
Name, required
A unique name for this rule.
|srcs
a|
List of Labels, required
List of .rb
files.
|deps
a|
List of labels, optional
List of targets that are required by the srcs
Ruby files.
|main
a|
Label, optional
The entrypoint file. It must be also in srcs
.
If not specified, $(NAME).rb
where $(NAME)
is the name
of this rule.
|includes
a|
List of strings, optional
List of paths to be added to $LOAD_PATH
at runtime. The paths must be relative to the the workspace which this rule belongs to.
|rubyopt
a|
List of strings, optional
List of options to be passed to the Ruby interpreter at runtime.
NOTE: -I
option should usually go to includes
attribute.
2+<|And other https://docs.bazel.build/versions/master/be/common-definitions.html#common-attributes[common attributes]. |===
=== ruby_bundle
NOTE: This is a repository rule, and can only be used in a WORKSPACE
file.
This rule installs gems defined in a Gemfile using Bundler, and exports individual gems from the bundle, as well as the entire bundle, available as a ruby_library
that can be depended upon from other targets.
[cols="15,85",options="header",]
|===
|Attributes |
|name
a|
Name, required
A unique name for this rule.
|gemfile
a|
Label, required
The Gemfile
which Bundler runs with.
|gemfile_lock
a|
Label, optional
The Gemfile.lock
which Bundler runs with.
NOTE: This rule never updates the Gemfile.lock
. It is your responsibility to generate/update Gemfile.lock
|srcs
a|
List of Labels, optional
List of additional files required for Bundler to install gems. This could usually include *.gemspec
files.
|vendor_cache
a|
Bool, optional
Symlink the vendor directory into the Bazel build space, this allows Bundler to access vendored Gems
|bundler_version
a|
String, optional
The Version of Bundler to use. Defaults to 2.1.4.
NOTE: This rule never updates the Gemfile.lock
. It is your responsibility to generate/update Gemfile.lock
|includes
a|
Dictionary of key-value-pairs (key: string, value: list of strings), optional
List of glob patterns per gem to be additionally loaded from the library. Keys are the names of the gems which require some file/directory paths not listed in the require_paths
attribute of the gemspecs to be also added to $LOAD_PATH
at runtime. Values are lists of blob path patterns, which are relative to the root directories of the gems.
|excludes
a|
Dictionary of key-value-pairs (key: string, value: list of strings), optional
List of glob patterns per gem to be excluded from the library. Keys are the names of the gems. Values are lists of blob path patterns, which are relative to the root directories of the gems. The default value is ["**/* *.*", "**/* */*"]
2+<|And other https://docs.bazel.build/versions/master/be/common-definitions.html#common-attributes[common attributes]. |===
==== Conventions
ruby_bundle
creates several targets that can be used downstream. In the examples below we assume that your ruby_bundle
has a name app_bundle
:
@app_bundle//:bundler
-- references just the Bundler from the bundle.@app_bundle//:gems
-- references all gems in the bundle (i.e. "the entire bundle").@app_bundle//:gem-name
-- references just the specified gem in the bundle, eg. @app_bundle//:awesome_print
.@app_bundle//:bin
-- references to all installed executables from this bundle, with individual executables accessible via eg. @app_bundle//:bin/rubocop
==== WORKSPACE
:
load("@bazelruby_rules_ruby//ruby:defs.bzl", "ruby_bundle")
===== Vendor directory handling
To use the vendor cache, you have to declare a managed_directory
in
your workspace. The name should match the name of the bundle.
load("@bazelruby_rules_ruby//ruby:defs.bzl", "ruby_bundle")
workspace( name = "my_wksp", managed_directories = {"@bundle": ["vendor"]}, )
==== BUILD.bazel
:
ruby_library( name = "foo", srcs = ["foo.rb"], deps = ["@gems//:gems"], )
=== ruby_rspec
[cols="15,85",options="header",]
|===
|Attributes |
|name
a|
Name, required
A unique name for this rule.
|srcs
a|
List of Labels, required
List of .rb
files.
|deps
a|
List of labels, optional
List of targets that are required by the srcs
Ruby files.
|main
a|
Label, optional
The entrypoint file. It must be also in srcs
.
If not specified, $(NAME).rb
where $(NAME)
is the name
of this rule.
|rspec_args
a|
List of strings, optional
Command line arguments to the rspec
binary, eg ["--progress", "-p2", "-b"]
If not specified, the default arguments defined in constants.bzl
are used: --format=documentation --force-color
.
|includes
a|
List of strings, optional
List of paths to be added to $LOAD_PATH
at runtime. The paths must be relative to the the workspace which this rule belongs to.
|rubyopt
a|
List of strings, optional
List of options to be passed to the Ruby interpreter at runtime.
NOTE: -I
option should usually go to includes
attribute.
2+<|And other https://docs.bazel.build/versions/master/be/common-definitions.html#common-attributes[common attributes]. |===
=== ruby_gem
Used to generate a zipped gem containing its srcs, dependencies and a gemspec.
[cols="15,85",options="header",]
|===
|Attributes |
|name
a|
Name, required
A unique name for this build target.
|gem_name
a|
Name of the gem, required
The name of the gem to be generated.
|gem_version
a|
String, optional
The version of the gem. Is used to name the output file, which becomes name-version.zip
, and also included in the Gemspec.
|gem_summary
a|
String, optional
One line summary of the gem purpose.
|gem_description
a|
String, required
Single-line, paragraph-sized description text for the gem.
|gem_homepage
a|
String, optional
Homepage URL of the gem.
|gem_authors
a|
List of Strings, required
List of human readable names of the gem authors. Required to generate a valid gemspec.
|gem_author_emails
a|
List of Strings, optional
List of email addresses of the authors.
|srcs
a|
List of Labels, optional
List of .rb
files.
At least srcs
or deps
must be present
|deps
a|
List of labels, optional
List of targets that are required by the srcs
Ruby files.
At least srcs
or deps
must be present
|require_paths
a|
List of Strings, optional
List of paths to be added to the Ruby LOAD_PATH when using this gem. Typically this value is just lib
(which is also the default).
|gem_runtime_dependencies
a|
String Dictionary, optional
This is a dictionary where keys are gem names, and values are either an empty string or a https://www.devalot.com/articles/2012/04/gem-versions.html[gem version specification]. For instance, the pessimistic version specifier ~> 3.0
means that all versions up to 4.0
are accepted.
|gem_development_dependencies
a|
String Dictionary, optional
Similar to the above, this specifies gems necessary for the development of the above gem, such as testing gems, linters, code coverage and more.
2+<|And other https://docs.bazel.build/versions/master/be/common-definitions.html#common-attributes[common attributes]. |===
== Potential Future Features
==== icon:check-square[fw] Using various versions of Ruby installed locally
icon:square[fw] Building native extensions in gems with Bazel
== Contributing
We welcome contributions to RulesRuby. Please make yourself familiar with the xref:CODE_OF_CONDUCT.adoc[code of conduct], which basically says -- don't be an a-hole.
You may notice that there is more than one Bazel WORKSPACE inside this repo. There is one in examples/simple_script
for instance, because
we use this example to validate and test the rules. So be mindful whether your current directory contains WORKSPACE
file or not.
=== Setup
==== Using the Script
You will need Homebrew installed prior to running the script.
After that, cd into the top level folder and run the setup script in your Terminal:
This runs a complete setup, shouldn't take too long. You can explore various script options with the help
command:
❯ bin/setup -h
USAGE
bin/setup
bin/setup [ gems | git-hook | help | main | os-specific | rbenv | remove-git-hook ]
DESCRIPTION: Runs full setup without any arguments.
Accepts one optional argument — one of the actions that typically run as part of setup, with one exception — remove-git-hook. This action removes the git commit hook installed by the setup.
EXAMPLES: bin/setup
Or, to run only one of the sub-functions (actions), pass it as an argument:
bin/setup help
bin/setup remove-git-hook
==== OS-Specific Setup
Note that the setup contains os-specific
section. This is because there are two extension scripts:
bin/setup-linux
bin/setup-darwin
Those will install Bazel and everything else you need on either platform. In fact, we use the linux version on CI.
=== Verifying Your Environment
We provided a handy script bin/show-env
to display where your dependencies are coming from. Here is an example of running it on a Mac OS-X system:
image::docs/img/env.png[bin/show-env]
==== Issues During Setup
Please report any errors to bin/setup
as Issues on Github. You can assign them to @kigster. If I am not responding fast enough, and you are in a hurry, please email kigster AT gmail directly.
=== Developing Rules
Besides making yourself familiar with the existing code, and https://docs.bazel.build/versions/master/skylark/concepts.html[Bazel documentation on writing rules], you might want to follow this order:
. Setup dev tools as described in the <<Setup,setup>> section. . hack, hack, hack... . Make sure all tests pass -- you can run a single command for that (but see more on it <<test-script,below>>.
OR, you can run individual Bazel test commands from the inside.
bazel test //...
cd examples/simple_script && bazel test //...
. Open a pull request in Github, and please be as verbose as possible in your description.
In general, it's always a good idea to ask questions first -- you can do so by creating an issue.
=== Running Tests
After running setup, and since this is a bazel repo you can use Bazel commands:
But to run tests inside each sub-WORKSPACE, you will need to repeat that in each sub-folder. Luckily, there is a better way.
==== Test Script
This script runs all tests (including sub-workspaces) when ran without arguments:
Run it with help
command to see other options, and to see what parts you can run individually. At the moment they are:
On a MacBook Pro it takes about 3 minutes to run.
=== Linter
We are using RuboCop for ruby and Buildifier for Bazel. Both are represented by a single script bin/linter
, which just like the scripts above runs ALL linters when ran without arguments, accepts help
commnd, and can be run on a subset of linting strategies:
The following are the partial linting functions you can run:
=== Regenerating README.pdf & Changelog
To regenerate, first you may need to grab an https://github.com/settings/tokens[API token] and export the GITHUB_TOKEN
variable:
Then use the make
target:
Or, manually:
== Copyright
© 2018-2021 BazelRuby Contributors.
Core Team:
Core Team (Emeritus):
Licensed under the http://www.apache.org/licenses/LICENSE-2.0[Apache License, Version 2.0 (the "License")].
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.