diff --git a/.bash_bazel b/.bash_bazel new file mode 100644 index 00000000..9277e80c --- /dev/null +++ b/.bash_bazel @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +# +# Install me in your ${HOME} folder, and add me to your ~/.bashrc: +# +# cp .bash_bazel ~/ && echo 'source ~/.bash_bazel' >> ~/.bashrc +# + +[[ -n $(command -V brew) ]] && { + completion="$(brew --prefix)/etc/bash_completion" + [[ -f "${completion}" ]] && { + source "${completion}" + } +} + +alias bb='bazel build' +alias bba='bazel build //...:all' +alias bbr='bazel run' +alias bbx='bazel clean --expunge' +alias bbq='bazel query' +alias bbt='bazel test' +alias bbqa='bazel query //...:all' + diff --git a/.bazelrc b/.bazelrc new file mode 100644 index 00000000..18a2a1e5 --- /dev/null +++ b/.bazelrc @@ -0,0 +1,29 @@ +# Bazel RC file for Local +# +# Flare Folks: please feel free to update this as you see fit. I put +# initial values here that make the output pretty and github caching +# possible. I am not as certain about the JVM args. + +# Startup Options +startup --host_jvm_args=-Xmx500m + +# Build Options +build --verbose_failures +build --jobs 30 +build --progress_report_interval=2 +build --color yes +build --incompatible_strict_action_env +build --show_timestamps + +# These inherit from Build +test --verbose_failures +test --test_verbose_timeout_warnings +test --verbose_explanations + +# These also inherit from build +query --keep_going + +# Custom user overrides +# https://docs.bazel.build/versions/master/best-practices.html#bazelrc +try-import %workspace%/.bazelrc.user +try-import %workspace%/user.bazelrc diff --git a/.bazelversion b/.bazelversion index 3e3c2f1e..ee74734a 100644 --- a/.bazelversion +++ b/.bazelversion @@ -1 +1 @@ -2.1.1 +4.1.0 diff --git a/.circleci/.bazelrc b/.circleci/.bazelrc deleted file mode 100644 index 3d8914d9..00000000 --- a/.circleci/.bazelrc +++ /dev/null @@ -1,17 +0,0 @@ -# Common options -common --color=yes -common --show_progress -common --show_progress_rate_limit=0.5 - -# Build options -build --spawn_strategy=standalone -build --strategy=Genrule=standalone -build --show_timestamps -build --curses=no -build --jobs=10 - -# Test options -test --spawn_strategy=standalone -test --test_output=all -test --test_verbose_timeout_warnings -test --verbose_failures diff --git a/.circleci/Dockerfile b/.circleci/Dockerfile index 155b09c1..cff3ce50 100644 --- a/.circleci/Dockerfile +++ b/.circleci/Dockerfile @@ -1,7 +1,7 @@ # # rules_ruby circleci Docker file. # -FROM ruby:2.7.0 +FROM ruby:3.0.2 # make Apt non-interactive RUN echo 'APT::Get::Assume-Yes "true";' > /etc/apt/apt.conf.d/90circleci \ @@ -95,7 +95,10 @@ RUN apt-get install -y openjdk-11-jdk python2.7 python3 golang-go RUN curl -L -o /usr/bin/bazel https://github.com/bazelbuild/bazelisk/releases/download/v1.3.0/bazelisk-linux-amd64 \ && sudo chmod +x /usr/bin/bazel +RUN cd /usr/bin && ln -s python3 python + USER circleci ENV PATH /home/circleci/.local/bin:/home/circleci/bin:/usr/local/bin:/usr/bin:/bin:/sbin:${PATH} -CMD ["/bin/sh"] + +CMD ["/bin/bash"] diff --git a/.circleci/config.yml b/.circleci/config.yml index b9e98849..5ee0d7e9 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -5,7 +5,7 @@ jobs: working_directory: /home/circleci/repo resource_class: medium docker: - - image: bazelruby/ruby-2.7.0 + - image: bazelruby/ruby-3.0.2 environment: PATH: "/usr/local/bin:/usr/bin:/sbin:/opt/bin:/home/circleci/repo/bin:/bin:/sbin:/usr/sbin" BUNDLE_PATH: /home/circleci/.bundle_cache @@ -19,13 +19,12 @@ jobs: - run: name: "Install ~/.bazelrc and run setup" command: | - cp .circleci/.bazelrc ${HOME} /usr/bin/env bash bin/setup - run: name: Install Bundler command: | - gem install bundler:2.0.2 --no-doc + gem install bundler:2.2.28 --no-doc bundle install --jobs=4 --retry=3 --path ${BUNDLE_PATH} - run: @@ -40,7 +39,6 @@ jobs: - run: name: "Install ~/.bazelrc and run setup" command: | - cp .circleci/.bazelrc ${HOME} /usr/bin/env bash bin/setup - run: @@ -57,7 +55,6 @@ jobs: - run: name: "Install ~/.bazelrc and run setup" command: | - cp .circleci/.bazelrc ${HOME} /usr/bin/env bash bin/setup - run: @@ -74,7 +71,6 @@ jobs: - run: name: "Install ~/.bazelrc and run setup" command: | - cp .circleci/.bazelrc ${HOME} /usr/bin/env bash bin/setup - run: @@ -91,7 +87,6 @@ jobs: - run: name: "Install ~/.bazelrc and run setup" command: | - cp .circleci/.bazelrc ${HOME} /usr/bin/env bash bin/setup - run: diff --git a/.envrc b/.envrc index f8ae38d8..72e49b34 100644 --- a/.envrc +++ b/.envrc @@ -1,4 +1,6 @@ # vi: ft=sh PATH_add bin - +eval "$(rbenv init -)" +rbenv local $(cat .ruby-version) +echo "Ruby Version is $(ruby --version)" diff --git a/.gitignore b/.gitignore index 32327d79..3cecada6 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,6 @@ **/vendor/bundle/** **/.DS_Store **/.vscode + +.bazelrc.user +user.bazelrc diff --git a/.readme b/.readme new file mode 100644 index 00000000..ec69a7ed --- /dev/null +++ b/.readme @@ -0,0 +1,10 @@ +=Ruby Rulesยฎ for Bazel +:subtitle: Version %VERSION% +:doctype: book +:source-highlighter: rouge +:rouge-style: base16.monokai +:toclevels: 5 +:toc: +:sectnums: 9 +:icons: font +:license: apache diff --git a/.rubocop.yml b/.rubocop.yml index 0d331a58..632114d5 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,4 +1,8 @@ -inherit_from: .relaxed-rubocop-2.4.yml +inherit_from: + - .rubocop_todo.yml + - .relaxed-rubocop-2.4.yml + + AllCops: TargetRubyVersion: 2.6 @@ -23,6 +27,7 @@ AllCops: - '**/*.ru' - '**/Gemfile' - '**/Rakefile' + NewCops: enable Layout/HashAlignment: Enabled: true diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml new file mode 100644 index 00000000..e7302d7d --- /dev/null +++ b/.rubocop_todo.yml @@ -0,0 +1,20 @@ +# This configuration was generated by +# `rubocop --auto-gen-config` +# on 2021-11-08 22:06:35 UTC using RuboCop version 0.93.1. +# The point is for the user to remove these configuration records +# one by one as the offenses are removed from the code base. +# Note that changes in the inspected code, or installation of new +# versions of RuboCop, may require this file to be generated again. + +# Offense count: 1 +Lint/UnreachableLoop: + Exclude: + - 'ruby/tests/testdata/bundle_includes_workspace/script.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. +# SupportedStyles: always, always_true, never +Style/FrozenStringLiteralComment: + Exclude: + - 'ruby/tests/testdata/bundle_includes_workspace/script.rb' diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 00000000..b5021469 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +3.0.2 diff --git a/.rules_version b/.rules_version index d917d3e2..a918a2aa 100644 --- a/.rules_version +++ b/.rules_version @@ -1 +1 @@ -0.1.2 +0.6.0 diff --git a/.shellcheckrc b/.shellcheckrc new file mode 100644 index 00000000..7e8bf495 --- /dev/null +++ b/.shellcheckrc @@ -0,0 +1 @@ +disable=SC1090,SC1091,SC2155,SC2154,SC2059,SC2046 diff --git a/.travis.yml b/.travis.yml index 3363cb20..8ba055bf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,7 @@ jdk: openjdk11 cache: directories: - ${HOME}/.rbenv + - ${HOME}/.bazel - ${HOME}/.bundle/gems addons: @@ -15,9 +16,30 @@ addons: - libstdc++6 - build-essential - g++ + - autoconf + - bison + - libssl-dev + - libyaml-dev + - libreadline6-dev + - zlib1g-dev + - libncurses5-dev + - libffi-dev + - libgdbm-dev -script: +before_script: + - rm -f /home/travis/.phpenv/bin/rbenv + - hash -r + - mkdir -p /home/travis/.cache/bazel-out + - mkdir -p /home/travis/.cache/bazel-cache + - rm -f .bazelrc.user + - echo 'build --disk_cache=/home/travis/.cache/bazel-cache' >> .bazelrc.user + - echo 'startup --output_base=/home/travis/.cache/bazel-out' >> .bazelrc.user + - cat .bazelrc + - cat .bazelrc.user - /usr/bin/env bash bin/setup + - /usr/bin/env bash bin/show-env + +script: - /usr/bin/env bash bin/test-suite after_script: @@ -26,6 +48,8 @@ after_script: env: global: - CI=true + - SCREEN_WIDTH=70 + - RBENV_ROOT="${HOME}/.rbenv" - BUNDLE_PATH="${HOME}/.bundle/gems" - PATH="${HOME}/.rbenv/bin:${HOME}/.rbenv/shims:/usr/local/bin:/usr/bin:/bin:/sbin:/usr/sbin:/opt/local/bin:${PATH}" - BAZEL_OPTS="--host_jvm_args=-Xmx1200m --host_jvm_args=-Xms1200m" diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..3d1c3afe --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,170 @@ +# Changelog + +## [v0.6.0](https://github.com/bazelruby/rules_ruby/tree/v0.6.0) (2021-11-09) + +[Full Changelog](https://github.com/bazelruby/rules_ruby/compare/v0.5.2...v0.6.0) + +**Merged pull requests:** + +- Bump nokogiri from 1.11.7 to 1.12.5 in /examples/simple\_rails\_api [\#120](https://github.com/bazelruby/rules_ruby/pull/120) ([dependabot[bot]](https://github.com/apps/dependabot)) +- Upstream changes from Selenium's fork [\#118](https://github.com/bazelruby/rules_ruby/pull/118) ([p0deje](https://github.com/p0deje)) +- Bump puma from 4.3.8 to 4.3.9 in /examples/simple\_rails\_api [\#117](https://github.com/bazelruby/rules_ruby/pull/117) ([dependabot[bot]](https://github.com/apps/dependabot)) +- Bump nokogiri from 1.11.7 to 1.12.5 in /examples/simple\_rails\_api [\#116](https://github.com/bazelruby/rules_ruby/pull/116) ([dependabot[bot]](https://github.com/apps/dependabot)) +- Bump Ruby primary to 3.0.2 & Add sdk versions: 2.5.9, 2.6.8, 2.7.3, 2.7.4, 3.0.2 [\#114](https://github.com/bazelruby/rules_ruby/pull/114) ([kigster](https://github.com/kigster)) + +## [v0.5.2](https://github.com/bazelruby/rules_ruby/tree/v0.5.2) (2021-07-09) + +[Full Changelog](https://github.com/bazelruby/rules_ruby/compare/v0.5.1...v0.5.2) + +**Closed issues:** + +- require\_paths attribute does not work [\#97](https://github.com/bazelruby/rules_ruby/issues/97) +- google-protobuf and grpc gems fail [\#86](https://github.com/bazelruby/rules_ruby/issues/86) +- Ruby Gem isn't including generated files [\#85](https://github.com/bazelruby/rules_ruby/issues/85) + +**Merged pull requests:** + +- Add `includes` option to `ruby_bundle` rule for per-gem load path customization [\#102](https://github.com/bazelruby/rules_ruby/pull/102) ([mmizutani](https://github.com/mmizutani)) + +## [v0.5.1](https://github.com/bazelruby/rules_ruby/tree/v0.5.1) (2021-07-08) + +[Full Changelog](https://github.com/bazelruby/rules_ruby/compare/v0.5.0...v0.5.1) + +**Closed issues:** + +- `ruby_bundle` should support local gems [\#62](https://github.com/bazelruby/rules_ruby/issues/62) + +**Merged pull requests:** + +- feat: Support mapping the vendor cache from workspace [\#92](https://github.com/bazelruby/rules_ruby/pull/92) ([russell](https://github.com/russell)) + +## [v0.5.0](https://github.com/bazelruby/rules_ruby/tree/v0.5.0) (2021-07-08) + +[Full Changelog](https://github.com/bazelruby/rules_ruby/compare/v0.4.1...v0.5.0) + +**Closed issues:** + +- ruby\_binary - how to package up runfiles dir [\#101](https://github.com/bazelruby/rules_ruby/issues/101) +- bin/setup Failure [\#95](https://github.com/bazelruby/rules_ruby/issues/95) +- `warning: string literal in condition` from generated wrapper [\#87](https://github.com/bazelruby/rules_ruby/issues/87) +- Setup script attempts to delete ~/.rbenv if rbenv is installed with Homebrew [\#81](https://github.com/bazelruby/rules_ruby/issues/81) +- ruby\_rspec specs argument not resolved [\#79](https://github.com/bazelruby/rules_ruby/issues/79) +- ruby\_test and ruby\_rspec rules use system ruby [\#63](https://github.com/bazelruby/rules_ruby/issues/63) + +**Merged pull requests:** + +- Adding makefile for auto-generating PDF [\#106](https://github.com/bazelruby/rules_ruby/pull/106) ([kigster](https://github.com/kigster)) +- Massive upgrade of everything at once ;-\) [\#105](https://github.com/bazelruby/rules_ruby/pull/105) ([kigster](https://github.com/kigster)) +- Support ruby 3 [\#103](https://github.com/bazelruby/rules_ruby/pull/103) ([mmizutani](https://github.com/mmizutani)) +- Bump nokogiri from 1.11.2 to 1.11.5 in /examples/simple\_rails\_api [\#99](https://github.com/bazelruby/rules_ruby/pull/99) ([dependabot[bot]](https://github.com/apps/dependabot)) +- Bump nokogiri from 1.10.10 to 1.11.2 in /examples/simple\_rails\_api [\#94](https://github.com/bazelruby/rules_ruby/pull/94) ([dependabot[bot]](https://github.com/apps/dependabot)) +- Update README.md [\#93](https://github.com/bazelruby/rules_ruby/pull/93) ([JustusFT](https://github.com/JustusFT)) +- Fix warning due to string literal in condition [\#91](https://github.com/bazelruby/rules_ruby/pull/91) ([russell](https://github.com/russell)) +- Add description for how to configure ASDF [\#90](https://github.com/bazelruby/rules_ruby/pull/90) ([russell](https://github.com/russell)) +- Remove print statements from ruby\_runtime.bzl [\#84](https://github.com/bazelruby/rules_ruby/pull/84) ([adzenith](https://github.com/adzenith)) +- Document path argument to ruby\_test [\#80](https://github.com/bazelruby/rules_ruby/pull/80) ([sayrer](https://github.com/sayrer)) + +## [v0.4.1](https://github.com/bazelruby/rules_ruby/tree/v0.4.1) (2020-08-10) + +[Full Changelog](https://github.com/bazelruby/rules_ruby/compare/v0.4.0...v0.4.1) + +## [v0.4.0](https://github.com/bazelruby/rules_ruby/tree/v0.4.0) (2020-08-04) + +[Full Changelog](https://github.com/bazelruby/rules_ruby/compare/v0.3.0...v0.4.0) + +**Closed issues:** + +- private method `define\_method' called for Dir:Class \(NoMethodError\) [\#74](https://github.com/bazelruby/rules_ruby/issues/74) + +**Merged pull requests:** + +- Version vandidate 0.4.0 โ€” upgrade Rubies + Setup [\#77](https://github.com/bazelruby/rules_ruby/pull/77) ([kigster](https://github.com/kigster)) +- Upgrading Gemfiles [\#76](https://github.com/bazelruby/rules_ruby/pull/76) ([kigster](https://github.com/kigster)) +- Ruby 2.3 compatibility for binary\_wrapper [\#75](https://github.com/bazelruby/rules_ruby/pull/75) ([lalten](https://github.com/lalten)) +- Bump puma from 4.3.3 to 4.3.5 in /examples/simple\_rails\_api [\#71](https://github.com/bazelruby/rules_ruby/pull/71) ([dependabot[bot]](https://github.com/apps/dependabot)) +- Bump puma from 4.3.1 to 4.3.3 in /examples/simple\_rails\_api [\#70](https://github.com/bazelruby/rules_ruby/pull/70) ([dependabot[bot]](https://github.com/apps/dependabot)) + +## [v0.3.0](https://github.com/bazelruby/rules_ruby/tree/v0.3.0) (2020-03-03) + +[Full Changelog](https://github.com/bazelruby/rules_ruby/compare/v0.2.0...v0.3.0) + +**Closed issues:** + +- ๐Ÿ› "Could not create symlink... \(File exists\)" [\#54](https://github.com/bazelruby/rules_ruby/issues/54) +- When using a local ruby installation it includes the local `LOAD_PATH` [\#44](https://github.com/bazelruby/rules_ruby/issues/44) +- \[Cleanup\] Pretty sure `eval` is never used in `repository_context` [\#43](https://github.com/bazelruby/rules_ruby/issues/43) +- Importing a bundle gem adds all gems onto the load path \(although they are not there\) [\#42](https://github.com/bazelruby/rules_ruby/issues/42) +- Support Ruby Lambda with the Gemfile full of dependencies. [\#33](https://github.com/bazelruby/rules_ruby/issues/33) +- Support AWS Ruby Lambda with Bazel Rules [\#27](https://github.com/bazelruby/rules_ruby/issues/27) +- Want to understand better why native extensions are failing on CircleCI [\#24](https://github.com/bazelruby/rules_ruby/issues/24) +- First class support for Ruby RSpec gem with Bazel [\#19](https://github.com/bazelruby/rules_ruby/issues/19) +- Use sorbets Ruby 2.6 build instead of host [\#9](https://github.com/bazelruby/rules_ruby/issues/9) + +**Merged pull requests:** + +- Renaming the repo to @bazelruby\_rules\_ruby [\#69](https://github.com/bazelruby/rules_ruby/pull/69) ([kigster](https://github.com/kigster)) +- Fixing outdated rule names in the README [\#68](https://github.com/bazelruby/rules_ruby/pull/68) ([kigster](https://github.com/kigster)) +- Adding method Dir.children when it's not found. [\#67](https://github.com/bazelruby/rules_ruby/pull/67) ([kigster](https://github.com/kigster)) +- Merging select features from Coinbase upstream branch [\#66](https://github.com/bazelruby/rules_ruby/pull/66) ([kigster](https://github.com/kigster)) +- Upgrade Bazel and Bazelist; add ruby 2.7.0 [\#65](https://github.com/bazelruby/rules_ruby/pull/65) ([kigster](https://github.com/kigster)) +- Bump nokogiri from 1.10.7 to 1.10.8 in /examples/simple\_rails\_api [\#64](https://github.com/bazelruby/rules_ruby/pull/64) ([dependabot[bot]](https://github.com/apps/dependabot)) +- This PR refactors bundle steps and :bin generation [\#61](https://github.com/bazelruby/rules_ruby/pull/61) ([kigster](https://github.com/kigster)) +- Adds ruby\_rspec and refactors the ruby\_bundle rule, plus some more [\#60](https://github.com/bazelruby/rules_ruby/pull/60) ([kigster](https://github.com/kigster)) + +## [v0.2.0](https://github.com/bazelruby/rules_ruby/tree/v0.2.0) (2019-12-31) + +[Full Changelog](https://github.com/bazelruby/rules_ruby/compare/v0.1.0...v0.2.0) + +**Fixed bugs:** + +- Make `rules_ruby/examples` a deeper tree structure and ensure CircleCI integration pass [\#10](https://github.com/bazelruby/rules_ruby/issues/10) + +**Closed issues:** + +- Ability to package all files related to a bazel target in a zip file [\#29](https://github.com/bazelruby/rules_ruby/issues/29) +- Build rules\_ruby on CircleCI using workflows \(in addition to Travis\) [\#26](https://github.com/bazelruby/rules_ruby/issues/26) +- Restore functionality that supported symlinking an existing Ruby interpreter [\#21](https://github.com/bazelruby/rules_ruby/issues/21) +- Move ruby files under ruby\_rules/examples into a mini-mono repo [\#8](https://github.com/bazelruby/rules_ruby/issues/8) + +**Merged pull requests:** + +- Fixing brittle Host Ruby version detection. [\#56](https://github.com/bazelruby/rules_ruby/pull/56) ([kigster](https://github.com/kigster)) +- Upgrading Bazel version to 2.0.0 [\#53](https://github.com/bazelruby/rules_ruby/pull/53) ([kigster](https://github.com/kigster)) +- Renaming and making consistent all scripts [\#52](https://github.com/bazelruby/rules_ruby/pull/52) ([kigster](https://github.com/kigster)) +- Adding auto-fix buildifier and auto-fix rubocop [\#50](https://github.com/bazelruby/rules_ruby/pull/50) ([kigster](https://github.com/kigster)) +- Bump rack from 2.0.7 to 2.0.8 in /examples/simple\_rails\_api [\#49](https://github.com/bazelruby/rules_ruby/pull/49) ([dependabot[bot]](https://github.com/apps/dependabot)) +- Deprecate ruby/def.bzl + spelling + v0.1.2 [\#48](https://github.com/bazelruby/rules_ruby/pull/48) ([kigster](https://github.com/kigster)) +- Speed up CircleCI/Travis ensure \*correctness\* with builds [\#46](https://github.com/bazelruby/rules_ruby/pull/46) ([kigster](https://github.com/kigster)) +- \[Feature\] example rails server running [\#41](https://github.com/bazelruby/rules_ruby/pull/41) ([grahamjenson](https://github.com/grahamjenson)) +- \[Fix\] rubocop builds [\#40](https://github.com/bazelruby/rules_ruby/pull/40) ([grahamjenson](https://github.com/grahamjenson)) +- Adding CircleCI + upgrade Rubocop [\#39](https://github.com/bazelruby/rules_ruby/pull/39) ([kigster](https://github.com/kigster)) +- \[Fix\] no spaces in files bug, remove deprecated code, remove host [\#38](https://github.com/bazelruby/rules_ruby/pull/38) ([grahamjenson](https://github.com/grahamjenson)) +- Sight facelift to shell files: [\#35](https://github.com/bazelruby/rules_ruby/pull/35) ([kigster](https://github.com/kigster)) +- \[Feature\] install ruby if none exists [\#34](https://github.com/bazelruby/rules_ruby/pull/34) ([grahamjenson](https://github.com/grahamjenson)) +- Add `files` to DefaultInfo of the ruby\_library [\#32](https://github.com/bazelruby/rules_ruby/pull/32) ([kigster](https://github.com/kigster)) +- Upgrade Bazel version to 1.2.1 + use bin/setup\(s\) [\#31](https://github.com/bazelruby/rules_ruby/pull/31) ([kigster](https://github.com/kigster)) +- Fixing Gemfile bundle dependency and bin/setup [\#30](https://github.com/bazelruby/rules_ruby/pull/30) ([kigster](https://github.com/kigster)) +- Expose rake, erb and other commands as sh\_binary [\#28](https://github.com/bazelruby/rules_ruby/pull/28) ([yugui](https://github.com/yugui)) +- Reorganize sections in README [\#23](https://github.com/bazelruby/rules_ruby/pull/23) ([yugui](https://github.com/yugui)) +- Run ruby\_binary with the interpreter in a SDK again [\#22](https://github.com/bazelruby/rules_ruby/pull/22) ([yugui](https://github.com/yugui)) +- Upgrade bundler [\#18](https://github.com/bazelruby/rules_ruby/pull/18) ([yugui](https://github.com/yugui)) +- Make ruby\_binary compatible with container [\#17](https://github.com/bazelruby/rules_ruby/pull/17) ([yugui](https://github.com/yugui)) +- Fix errors in the simple\_script example [\#16](https://github.com/bazelruby/rules_ruby/pull/16) ([yugui](https://github.com/yugui)) +- Adding relaxed-rubocop and fixing styling issues [\#15](https://github.com/bazelruby/rules_ruby/pull/15) ([grahamjenson](https://github.com/grahamjenson)) + +## [v0.1.0](https://github.com/bazelruby/rules_ruby/tree/v0.1.0) (2019-11-20) + +[Full Changelog](https://github.com/bazelruby/rules_ruby/compare/59deebc086f9c64a4626e2c98d7aa9c746d0d382...v0.1.0) + +**Fixed bugs:** + +- Unable to run `bazel build //...:all` [\#3](https://github.com/bazelruby/rules_ruby/issues/3) + +**Merged pull requests:** + +- Ignore examples/ because it is an independent workspace to test rules\_ruby [\#5](https://github.com/bazelruby/rules_ruby/pull/5) ([yugui](https://github.com/yugui)) +- Updating the remote reference to match the Org [\#4](https://github.com/bazelruby/rules_ruby/pull/4) ([kigster](https://github.com/kigster)) + + + +\* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)* diff --git a/Gemfile b/Gemfile index 8232bbec..aecd445d 100644 --- a/Gemfile +++ b/Gemfile @@ -2,4 +2,5 @@ source 'https://rubygems.org' -gem 'rubocop', '~> 0.78' +gem 'bundler' +gem 'rubocop', '~> 0.88' diff --git a/Gemfile.lock b/Gemfile.lock index 30808877..92438240 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,29 +1,33 @@ GEM remote: https://rubygems.org/ specs: - ast (2.4.0) - jaro_winkler (1.5.4) - parallel (1.19.1) - parser (2.7.0.3) - ast (~> 2.4.0) + ast (2.4.2) + parallel (1.21.0) + parser (3.0.2.0) + ast (~> 2.4.1) rainbow (3.0.0) - rexml (3.2.4) - rubocop (0.80.0) - jaro_winkler (~> 1.5.1) + regexp_parser (2.1.1) + rexml (3.2.5) + rubocop (0.93.1) parallel (~> 1.10) - parser (>= 2.7.0.1) + parser (>= 2.7.1.5) rainbow (>= 2.2.2, < 4.0) + regexp_parser (>= 1.8) rexml + rubocop-ast (>= 0.6.0) ruby-progressbar (~> 1.7) - unicode-display_width (>= 1.4.0, < 1.7) - ruby-progressbar (1.10.1) - unicode-display_width (1.6.1) + unicode-display_width (>= 1.4.0, < 2.0) + rubocop-ast (1.11.0) + parser (>= 3.0.1.1) + ruby-progressbar (1.11.0) + unicode-display_width (1.8.0) PLATFORMS ruby DEPENDENCIES - rubocop (~> 0.78) + bundler + rubocop (~> 0.88) BUNDLED WITH - 2.1.2 + 2.2.27 diff --git a/Makefile b/Makefile new file mode 100755 index 00000000..51231a58 --- /dev/null +++ b/Makefile @@ -0,0 +1,45 @@ +# vim: tabstop=8 +# vim: shiftwidth=8 +# vim: noexpandtab + +# grep '^[a-z\-]*:' Makefile | cut -d: -f 1 | tr '\n' ' ' +.PHONY: help update-changelog update-readme update + +red := \033[0;31m +bold := \033[1;45m +yellow := \033[0;33m +blue := \033[0;34m +green := \033[0;35m +clear := \033[0m + +RUBY_VERSION := $(shell cat .ruby-version) +RULES_VERSION := $(shell cat .rules_version) +OS := $(shell uname -s | tr '[:upper:]' '[:lower:]') + +# see: https://stackoverflow.com/questions/18136918/how-to-get-current-relative-directory-of-your-makefile/18137056#18137056 +SCREEN_WIDTH := 100 +MAKEFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIR := $(notdir $(patsubst %/,%,$(dir $(MAKEFILE_PATH)))) +PATH := $(shell echo "$(HOME)/.rbenv/shims:$(PATH)") +RULES_VERSION := $(shell cat .rules_version) + +help: ## Prints help message auto-generated from the comments. + @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' + +update: update-changelog update-readme ## Runs all of the updates, add locally modiofied files to git. + +update-changelog: ## Auto-generate the doc/CHANGELOG (requires GITHUB_TOKEN env var set) + @printf "\n$(bold) ๐Ÿ‘‰ $(red)๎‚ฐ$(clear) $(green)Regenerating CHANGELOG....$(clear)\n" + @bash -c "$(BASHMATIC_HOME)/bin/regen-changelog" + +update-readme: ## Generate the PDF version of the README + @rm -fv README.pdf + @printf "\n$(bold) ๐Ÿ‘‰ $(red)๎‚ฐ$(clear) $(green)Converting ASCIIDOC into the PDF...$(clear)\n" + @$(BASHMATIC_HOME)/bin/adoc2pdf README.adoc + @git add README.pdf + @open README.pdf + +tag: ## Tag this commit with .rules_version and push to remote + @git tag "v$(RULES_VERSION)" -f + @git push --tags -f + diff --git a/README.adoc b/README.adoc new file mode 100644 index 00000000..d5cac3c6 --- /dev/null +++ b/README.adoc @@ -0,0 +1,992 @@ += 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 + +* <> + ** <> + ** <> + ** <> + ** <> + *** <> + *** <> *** <> *** <> + ** <> + *** <> + *** <> + *** <> + *** <> + *** <> + *** <> + ** <> + ** <> + *** <> + *** <> + *** <> + *** <> + *** <> + *** <> + ** <> + +== Usage + +=== `WORKSPACE` File + +==== Load dependencies, select Ruby SDK and define one or more Bundles + +[source,python] +---- +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") + +#โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€” +# To get the latest ruby rules, grab the 'master' branch. +#โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€” + +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() + +#โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€” +# Specify Ruby version โ€” this will either build Ruby or use a local +# RBENV installation if the Ruby version matches. +#โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€” + +load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace") +bazel_skylib_workspace() + +rules_ruby_select_sdk(version = "3.0.2") + +#โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€” +# Now, load the ruby_bundle rule & install gems specified in the Gemfile +#โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€” + +load( + "@bazelruby_rules_ruby//ruby:defs.bzl", + "ruby_bundle", +) + +ruby_bundle( + name = "bundle", + # Specify additional paths to be loaded from the gems at runtime, if any. + # 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", +) + +# You can specify more than one bundle in the WORKSPACE file +ruby_bundle( + name = "bundle_app_shopping", + gemfile = "//:apps/shopping/Gemfile", + gemfile_lock = "//:apps/shopping/Gemfile.lock", +) + +# You can also install from Gemfile using `gemspec`. +ruby_bundle( + name = "bundle_gemspec", + srcs = ["//:lib/my_gem/my_gem.gemspec"], + gemfile = "//:lib/my_gem/Gemfile", + gemfile_lock = "//:lib/my_gem/Gemfile.lock", +) +---- + +=== `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. + +[source,python] +---- +#โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€” +# Define Ruby executable, test, spec and package a gem +#โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€” + +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"], +) + +ruby_rspec( + name = "foo-spec", + specs = glob(["spec/**/*.rb"]), + rspec_args = { "--format": "progress" }, + 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. + +[source,python] +---- +load( + "@bazelruby_rules_ruby//ruby:defs.bzl", + "ruby_gem", +) + +ruby_gem( + name = "awesome-sauce-gem", # name of the build target + gem_name = "awesome-sauce", # name of the gem + gem_version = "0.1.0", + gem_summary = "Example gem to demonstrate Bazel Gem packaging", + gem_description = "Example gem to demonstrate Bazel Gem packaging", + gem_homepage = "https://github.com/bazelruby/rules_ruby", + gem_authors = [ + "BazelRuby", + "Konstantin Gredeskoul" + ], + gem_author_emails = [ + "bazelruby@googlegroups.com", + ], + gem_runtime_dependencies = { + "colored2": "~> 3.1.2", + "hashie": "", + }, + gem_development_dependencies = { + "rspec": "", + "rspec-its": "", + "rubocop": "", + }, + srcs = [ + glob("{bin,exe,lib,spec}/**/*.rb") + ], + deps = [ + "//lib:example_gem", + ], +) +---- + +=== Tool Specific Setup + +==== ASDF + +If you are using ASDF to manage your ruby installs, you can use them by adding `.bazelrc`: + +---- +build --test_env=ASDF_DIR --test_env=ASDF_DATA_DIR +build --action_env=ASDF_DIR --test_env=ASDF_DATA_DIR +---- + +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` + +[source,python] +---- +ruby_library( + name, + deps, + srcs, + data, + compatible_with, + deprecation, + distribs, + features, + licenses, + restricted_to, + tags, + testonly, + toolchains, + visibility) +---- + +[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+ 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 + +icon:square[fw] Releasing your gems with Bazel (https://github.com/coinbase/rules_ruby[Coinbase fork] might have this feature, worth checking) +==== + +== 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: + +[source,bash] +---- +โฏ bin/setup +---- + +This runs a complete setup, shouldn't take too long. You can explore various script options with the `help` command: + +[source,bash] +---- +โฏ bin/setup -h + +USAGE + # without any arguments runs a complete setup. + bin/setup + + # alternatively, a sub-setup function name can be passed: + 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: + +[source,bash] +---- +โฏ bin/show-env +---- + +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 <> section. +. hack, hack, hack... +. Make sure all tests pass -- you can run a single command for that (but see more on it <>. + +[source,bash] +---- +bin/test-suite +---- + +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: + +[source,python] +---- +bazel build //...:all +bazel query //...:all +bazel test //...:all +---- + +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: + +[source,bash] +---- +bin/test-suite +---- + +Run it with `help` command to see other options, and to see what parts you can run individually. At the moment they are: + +[source,bash] +---- +# alternatively, a partial test name can be passed: +bin/test-suite [ all | bazel-info | buildifier | help | rspec | rubocop | simple-script | workspace ] +---- + +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: + +[source,bash] +---- +bin/linter +---- + +The following are the partial linting functions you can run: + +[source,bash] +---- +# alternatively, a partial linter name can be passed: +bin/linter [ all | buildifier | help | rubocop ] +---- + +=== 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: + +[source,bash] +---- +export GITHUB_TOKEN=.... +---- + +Then use the `make` target: + +[source,bash] +---- +make update +---- + +Or, manually: + +[source,bash] +---- +gem install github_changelog_generator +github_changelog_generator -u bazelruby -p rules_ruby -t your-github-token +---- + +== Copyright + +ยฉ 2018-2021 BazelRuby Contributors. + +Core Team: + +* https://github.com/yugui/[Yuki Yugui Sonoda] +* https://kig.re/[Konstantin Gredeskoul] + +Core Team (Emeritus): + +* https://github.com/grahamjenson[Graham Jenson] + +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. diff --git a/README.md b/README.md deleted file mode 100644 index 5827ad27..00000000 --- a/README.md +++ /dev/null @@ -1,698 +0,0 @@ - - -* [Usage](#usage) - * [WORKSPACE File](#workspace-file) - * [BUILD.bazel files](#buildbazel-files) -* [Rules](#rules) - * [ruby_library](#ruby_library) - * [ruby_binary](#ruby_binary) - * [ruby_test](#ruby_test) - * [ruby_bundle](#ruby_bundle) - * [ruby_gem](#rb_gem) -* [What's coming next](#whats-coming-next) -* [Contributing](#contributing) - * [Setup](#setup) - * [Using the Script](#using-the-script) - * [OS-Specific Setup](#os-specific-setup) - * [Issues During Setup](#issues-during-setup) - * [Developing Rules](#developing-rules) - * [Running Tests](#running-tests) - * [Test Script](#test-script) - * [Linter](#linter) -* [Copyright](#copyright) - - - -### Build Status - -| Build | Status | -|---------: |--------------------------------------------------------------------------------------------------------------------------------------------------- | -| CircleCI Develop: | [![CircleCI](https://circleci.com/gh/bazelruby/rules_ruby/tree/develop.svg?style=svg)](https://circleci.com/gh/bazelruby/rules_ruby/tree/develop) | -| CircleCI Default: | [![CircleCI](https://circleci.com/gh/bazelruby/rules_ruby.svg?style=svg)](https://circleci.com/gh/bazelruby/rules_ruby) | -| Develop: | [![Build Status](https://travis-ci.org/bazelruby/rules_ruby.svg?branch=develop)](https://travis-ci.org/bazelruby/rules_ruby) | -| Master: | [![Build Status](https://travis-ci.org/bazelruby/rules_ruby.svg?branch=master)](https://travis-ci.org/bazelruby/rules_ruby) | - - -# Rules Ruby - -Ruby rules for [Bazel](https://bazel.build). - -** Current Status:** *Work in progress.* - -Note: we have a short guide on [Building your first Ruby Project](https://github.com/bazelruby/rules_ruby/wiki/Build-your-ruby-project) on the Wiki. We encourage you to check it out. - -## Usage - -### `WORKSPACE` File - -Add `ruby_rules_dependencies` and `ruby_register_toolchains` into your `WORKSPACE` file. - -```python -# To get the latest, grab the 'develop' branch. - -git_repository( - name = "bazelruby_ruby_rules", - remote = "https://github.com/bazelruby/rules_ruby.git", - branch = "develop", -) - -load( - "@bazelruby_ruby_rules//ruby:deps.bzl", - "ruby_register_toolchains", - "ruby_rules_dependencies", -) - -ruby_rules_dependencies() - -ruby_register_toolchains() -``` - -Next, add any external Gem dependencies you may have via `ruby_bundle` command. -The name of the bundle becomes a reference to this particular Gemfile.lock. - -Install external gems that can be later referenced as `@//:`, -and the executables from each gem can be accessed as `@` -for instance, `@bundle//:bin/rubocop`. - -You can install more than one bundle per WORKSPACE, but that's not recommended. - -```python -ruby_bundle( - name = "bundle", - gemfile = ":Gemfile", - gemfile_lock = ":Gemfile.lock", - bundler_version = "2.1.2", -) - -ruby_bundle( - name = "bundle_app_shopping", - gemfile = "//apps/shopping:Gemfile", - gemfile_lock = "//apps/shopping:Gemfile.lock", - bundler_version = "2.1.2", -) -``` - -### `BUILD.bazel` files - -Add `ruby_library`, `ruby_binary` or `ruby_test` into your `BUILD.bazel` files. - -```python -load( - "@bazelruby_ruby_rules//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"], -) - -ruby_rspec( - name = "foo-spec", - specs = glob(["spec/**/*.rb"]), - rspec_args = { "--format": "progress" }, - deps = [":foo"] -} - -``` - -## Rules - -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: - -![Ruby Rules](docs/img/ruby_rules.png) - - -### `ruby_library` - -
-ruby_library(name, deps, srcs, data, compatible_with, deprecation, distribs, features, licenses, restricted_to, tags, testonly, toolchains, visibility)
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Attributes
name - Name, required -

A unique name for this rule.

-
srcs - List of Labels, optional -

- List of .rb files. -

-

At least srcs or deps must be present

-
deps - List of labels, optional -

- List of targets that are required by the srcs Ruby - files. -

-

At least srcs or deps must be present

-
includes - 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 - 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. -

-
And other common attributes
- -### `ruby_binary` - -
-ruby_binary(name, deps, srcs, data, main, compatible_with, deprecation, distribs, features, licenses, restricted_to, tags, testonly, toolchains, visibility, args, output_licenses)
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Attributes
name - Name, required -

A unique name for this rule.

-
srcs - List of Labels, required -

- List of .rb files. -

-
deps - List of labels, optional -

- List of targets that are required by the srcs Ruby - files. -

-
main - 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 - 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 - 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. -

-
And other common attributes
- -### `ruby_test` - -
-ruby_test(name, deps, srcs, data, main, compatible_with, deprecation, distribs, features, licenses, restricted_to, tags, testonly, toolchains, visibility, args, size, timeout, flaky, local, shard_count)
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Attributes
name - Name, required -

A unique name for this rule.

-
srcs - List of Labels, required -

- List of .rb files. -

-
deps - List of labels, optional -

- List of targets that are required by the srcs Ruby - files. -

-
main - 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 - 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 - 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. -

-
And other common attributes
- -### `ruby_bundle` - -Installs gems with Bundler, and make them available as a `ruby_library`. - -Example: `WORKSPACE`: - -```python -git_repository( - name = "bazelruby_ruby_rules", - remote = "https://github.com/bazelruby/rules_ruby.git", - tag = "v0.1.0", -) - -load( - "@bazelruby_ruby_rules//ruby:deps.bzl", - "ruby_register_toolchains", - "ruby_rules_dependencies", -) - -ruby_rules_dependencies() - -ruby_register_toolchains() - -load("@bazelruby_ruby_rules//ruby:defs.bzl", "ruby_bundle") - -ruby_bundle( - name = "gems", - gemfile = "//:Gemfile", - gemfile_lock = "//:Gemfile.lock", -) -``` - -Example: `lib/BUILD.bazel`: - -```python -ruby_library( - name = "foo", - srcs = ["foo.rb"], - deps = ["@gems//:all"], -) -``` - -Or declare many gems in your `Gemfile`, and only use some of them in each ruby library: - -```python -ruby_binary( - name = "rubocop", - srcs = [":foo", ".rubocop.yml"], - args = ["-P", "-D", "-c" ".rubocop.yml"], - main = "@gems//:bin/rubocop", - deps = ["@gems//:rubocop"], -) -``` - -
-ruby_bundle(name, gemfile, gemfile_lock, bundler_version = "2.1.2")
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Attributes
name - Name, required -

A unique name for this rule.

-
gemfile - Label, required -

- The Gemfile which Bundler runs with. -

-
gemfile_lock - Label, required -

The Gemfile.lock which Bundler runs with.

-

NOTE: This rule never updates the Gemfile.lock. It is your responsibility to generate/update Gemfile.lock

-
bundler_version - String, optional -

The Version of Bundler to use. Defaults to 2.1.2.

-

NOTE: This rule never updates the Gemfile.lock. It is your responsibility to generate/update Gemfile.lock

-
- -## rb_gem -Used to generate a zipped gem containing its srcs, dependencies and a gemspec. - -
-rb_gem(name, gem_name, version, srcs, authors, deps, data, includes)
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Attributes
name - Name, required -

A unique name for this rule.

-
gem_name - Name of the gem, required -

The name of the gem to be generated.

-
version - Label, required -

- The version of the gem. Is used to name the output file, - which becomes name-version.zip, and also - included in the Gemspec. -

-
authors - List of Strings, required -

- List of human readable names of the gem authors. - Required to generate a valid gemspec. -

-
srcs - List of Labels, optional -

- List of .rb files. -

-

At least srcs or deps must be present

-
deps - List of labels, optional -

- List of targets that are required by the srcs Ruby - files. -

-

At least srcs or deps must be present

-
- -## What's coming next - -1. Building native extensions in gems with Bazel -2. Using a specified version of Ruby. -3. Releasing your gems with Bazel - -## Contributing - -We welcome contributions to RulesRuby. Please make yourself familiar with the [CODE_OF_CONDUCT](CODE_OF_CONDUCT.md) document. - -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: - -```bash -โฏ bin/setup -``` - -This runs a complete setup, shouldn't take too long. You can explore various script options with the `help` command: - -```bash -โฏ bin/setup help -USAGE - # without any arguments runs a complete setup. - bin/setup - - # alternatively, a sub-setup function name can be passed: - bin/setup [ gems | git-hook | help | os-specific | main | 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 โ€” runs the entire setup. -``` - -#### 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. - -##### Issues During Setup - -**Please report any errors to `bin/setup` as Issues on Github. You can assign them to @kigster.** - -### Developing Rules - -Besides making yourself familiar with the existing code, and [Bazel documentation on writing rules](https://docs.bazel.build/versions/master/skylark/concepts.html), you might want to follow this order: - - 1. Setup dev tools as described in the [setup](#Setup) section. - 3. hack, hack, hack... - 4. Make sure all tests pass โ€” you can run a single command for that (but see more on it [below](#test-script). - - ```bash - bin/test-suite - ``` - -OR you can run individual Bazel test commands from the inside. - - * `bazel test //...` - * `cd examples/simple_script && bazel test //...` - - 4. 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: - -```bazel -bazel build //...:all -bazel query //...:all -bazel test //...:all -``` - -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: - -```bash -bin/test-suite -``` - -Run it with `help` command to see other options, and to see what parts you can run individually. At the moment they are: - -```bash -# alternatively, a partial test name can be passed: -bin/test-suite [ all | bazel-info | buildifier | help | rspec | rubocop | simple-script | workspace ] -``` - -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: - -```bash -bin/linter -``` - -The following are the partial linting functions you can run: - -```bash -# alternatively, a partial linter name can be passed: -bin/linter [ all | buildifier | help | rubocop ] -``` - -## Copyright - -ยฉ 2018-2019 Yuki Yugui Sonoda & BazelRuby Authors - -Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - - - -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. diff --git a/README.pdf b/README.pdf new file mode 100644 index 00000000..87bfb50c Binary files /dev/null and b/README.pdf differ diff --git a/VERSION.yml b/VERSION.yml new file mode 100644 index 00000000..23aefb4a --- /dev/null +++ b/VERSION.yml @@ -0,0 +1,4 @@ +rules_ruby: + version: 0.6.0 + + diff --git a/WORKSPACE b/WORKSPACE index d31dee82..e08c5ee3 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -1,8 +1,8 @@ -workspace(name = "bazelruby_ruby_rules") +workspace(name = "bazelruby_rules_ruby") -load("@//ruby:deps.bzl", "ruby_register_toolchains", "ruby_rules_dependencies") +load("@//ruby:deps.bzl", "rules_ruby_dependencies", "rules_ruby_select_sdk") -ruby_rules_dependencies() +rules_ruby_dependencies() load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace") @@ -10,37 +10,41 @@ bazel_skylib_workspace() load("@bazel_skylib//lib:versions.bzl", "versions") -versions.check("1.2.1") +versions.check("3.4.1") -ruby_register_toolchains() +rules_ruby_select_sdk("3.0.2") local_repository( - name = "bazelruby_ruby_rules_ruby_tests_testdata_another_workspace", + name = "bazelruby_rules_ruby_ruby_tests_testdata_another_workspace", path = "ruby/tests/testdata/another_workspace", ) +local_repository( + name = "bazelruby_rules_ruby_ruby_tests_testdata_bundle_includes_workspace", + path = "ruby/tests/testdata/bundle_includes_workspace", +) + load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") # installing go for buildifier http_archive( name = "io_bazel_rules_go", - sha256 = "842ec0e6b4fbfdd3de6150b61af92901eeb73681fd4d185746644c338f51d4c0", + sha256 = "8663604808d2738dc615a2c3eb70eba54a9a982089dd09f6ffe5d0e75771bc4f", urls = [ - "https://storage.googleapis.com/bazel-mirror/github.com/bazelbuild/rules_go/releases/download/v0.20.1/rules_go-v0.20.1.tar.gz", - "https://github.com/bazelbuild/rules_go/releases/download/v0.20.1/rules_go-v0.20.1.tar.gz", + "https://github.com/bazelbuild/rules_go/releases/download/v0.23.6/rules_go-v0.23.6.tar.gz", ], ) git_repository( name = "bazel_gazelle", - commit = "11a9ed24876401ee8b570c04de3a132e62415304", + commit = "c00612418c4dbc9f3cd35fe71fe1147748048b69", remote = "https://github.com/bazelbuild/bazel-gazelle", ) git_repository( name = "com_google_protobuf", - commit = "09745575a923640154bcf307fba8aedff47f240a", + commit = "6c61c1e63b9be3c36db6bed19032dfc0d63aadda", remote = "https://github.com/protocolbuffers/protobuf", shallow_since = "1558721209 -0700", ) @@ -49,7 +53,7 @@ load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_depe go_rules_dependencies() -go_register_toolchains(go_version = "1.12.9") +go_register_toolchains(go_version = "1.14.6") load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies") @@ -63,9 +67,9 @@ protobuf_deps() http_archive( name = "io_bazel_rules_docker", - sha256 = "14ac30773fdb393ddec90e158c9ec7ebb3f8a4fd533ec2abbfd8789ad81a284b", - strip_prefix = "rules_docker-0.12.1", - urls = ["https://github.com/bazelbuild/rules_docker/releases/download/v0.12.1/rules_docker-v0.12.1.tar.gz"], + sha256 = "4521794f0fba2e20f3bf15846ab5e01d5332e587e9ce81629c7f96c793bb7036", + strip_prefix = "rules_docker-0.14.4", + urls = ["https://github.com/bazelbuild/rules_docker/releases/download/v0.14.4/rules_docker-v0.14.4.tar.gz"], ) load( @@ -91,11 +95,11 @@ container_pull( repository = "library/ruby", ) -load("@bazelruby_ruby_rules//ruby:defs.bzl", "ruby_bundle") +load("@bazelruby_rules_ruby//ruby:defs.bzl", "ruby_bundle") ruby_bundle( name = "bundle", - bundler_version = "2.1.2", + bundler_version = "2.1.4", excludes = { "mini_portile": ["test/**/*"], }, diff --git a/bin/clean b/bin/clean new file mode 100755 index 00000000..edfc3b59 --- /dev/null +++ b/bin/clean @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +# vim: ft=sh +# โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€” +# NOTE: These setup scripts rely on an open source BASH framework BASHMATIC_HOME. +# https://github.com/kigster/bashmatic +# +# The framework is pretty light-weight, and is installed in your $HOME/.bashmatic folder. +# You can safely remove that folder after the setup if you wish, although re-running the +# setup will re-install it. +# โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€” + +[[ -z ${BASHMATIC_HOME} ]] && export BASHMATIC_HOME="${HOME}/.bashmatic" +[[ -d ${BASHMATIC_HOME} ]] || bash -c "$(curl -fsSL https://bashmatic.re1.re); bashmatic-install -q" + +# shellcheck disable=SC1090 +source "${BASHMATIC_HOME}/init.sh" 1>/dev/null 2>&1 + +export BAZEL_OPTS="--max_idle_secs=10800 --noshutdown_on_low_sys_mem --connect_timeout_secs=30" + +main() { + h1 "Cleaning Bazel directories... Please wait." + # shellcheck disable=SC2207 + local -a du_before=($(du -hs .)) + run "bazel clean --expunge" + # shellcheck disable=SC2207 + local -a examples=($(ls -1 examples)) + for dir in "${examples[@]}"; do + run "cd examples/${dir}" + run "bazel clean --expunge" + run "cd -" + done + + # shellcheck disable=SC2207 + local -a du_after=($(du -hs .)) + h2 "Space before cleaning: ${bldylw}${du_before[0]}" \ + "Space after cleaning: ${bldgrn}${du_after[0]}" +} + +main "$@" diff --git a/bin/deps b/bin/deps index 9244cc61..dfdbbccd 100755 --- a/bin/deps +++ b/bin/deps @@ -1,17 +1,23 @@ #!/usr/bin/env bash # vim: ft=sh +# โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€” +# NOTE: These setup scripts rely on an open source BASH framework BashMatic. +# https://github.com/kigster/bashmatic +# +# The framework is pretty light-weight, and is installed in your $HOME/.bashmatic folder. +# You can safely remove that folder after the setup if you wish, although re-running the +# setup will re-install it. +# โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€” -export BashMatic="${HOME}/.bashmatic" -if [[ ! -f "${BashMatic}/init.sh" ]]; then - rm -rf "${BashMatic}" 2>/dev/null - git clone https://github.com/kigster/bashmatic "${BashMatic}" 1>/dev/null 2>&1 -fi +[[ -z ${BASHMATIC_HOME} ]] && export BASHMATIC_HOME="${HOME}/.bashmatic" +[[ -d ${BASHMATIC_HOME} ]] || bash -c "$(curl -fsSL https://bashmatic.re1.re); bashmatic-install -q" # shellcheck disable=SC1090 -source "${BashMatic}/init.sh" 1>/dev/null 2>&1 +source "${BASHMATIC_HOME}/init.sh" 1>/dev/null 2>&1 +command -v rbenv >/dev/null && eval "$(rbenv init -)" -__version::detect() { +__version.detect() { local file="$1" if [[ -f ${file} ]]; then /bin/cat "${file}" | head -1 @@ -26,9 +32,9 @@ __version::detect() { } # Application Constants -export RulesRuby__RulesVersion=$(__version::detect .rules_version) -export RulesRuby__RubyVersion=2.7.0 -export RulesRuby__BazelVersion=$(__version::detect .bazelversion) +export RulesRuby__RulesVersion="$(__version.detect .rules_version)" +export RulesRuby__RubyVersion="$(__version.detect .ruby-version)" +export RulesRuby__BazelVersion="$(__version.detect .bazelversion)" bazel-sha() { bazel info | grep output_path | awk 'BEGIN{FS="/"}{ for(i = 1; i <= NF; i++) { if (length($i) == 32) print $i; } }' @@ -46,18 +52,17 @@ help-example() { printf " ${bldpur}$*${clr}" } -deps::start-clock() { +deps.start-clock() { export __start=$(millis) } -deps::print-duration() { +deps.print-duration() { local finish=$(millis) - local duration=$(( finish - __start )) - info "Total running time for was ${bldylw}$(lib::time::duration::millis-to-secs ${duration}) seconds.\n\n" + local duration=$((finish - __start)) + info "Total running time for was ${bldylw}$(time.duration.millis-to-secs ${duration}) seconds.\n\n" } - -run::set-all abort-on-error +run.set-all abort-on-error # ensure we can exit with Ctrl-C trap exit 1 INT diff --git a/bin/linter b/bin/linter index fa7ddfa5..255307b8 100755 --- a/bin/linter +++ b/bin/linter @@ -1,6 +1,16 @@ #!/usr/bin/env bash +# vim: ft=bash # # Main dependency shell script that installs BashMatic Library in ~/.bashmatic folder. +# +# โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€” +# NOTE: These setup scripts rely on an open source BASH framework BashMatic. +# https://github.com/kigster/bashmatic +# +# The framework is pretty light-weight, and is installed in your $HOME/.bashmatic folder. +# You can safely remove that folder after the setup if you wish, although re-running the +# setup will re-install it. +# โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€” export COLUMNS=65 @@ -11,34 +21,34 @@ source "bin/deps" [[ -n $(command -v rubocop) ]] || { # shellcheck disable=SC1091 source bin/setup - setup::main gems + setup.main gems } export __git_pre="/tmp/rules-ruby-git-status-before-commit.$$" export __git_post="/tmp/rules-ruby-git-status-after-commit.$$" -__lint::cleanup() { +__lint.cleanup() { for f in "${__git_pre}" "${__git_post}"; do [[ -f "${f}" ]] && rm -f "${f}" done } -deps::start-clock -run::set-all abort-on-error +deps.start-clock +run.set-all abort-on-error -__lint::actions() { +__lint.actions() { local sep="${1:-', '}" - printf "${bldylw}$(lib::array::join "${sep}" $(lib::util::functions-matching "lint::" | sed 's/ main//g'))${clr}" + printf "${bldylw}$(array.join "${sep}" $(util.functions-matching "lint." | sed 's/ main//g'))${clr}" } -lint::help() { +lint.help() { printf " $(help-header USAGE) ${bldblk}# without any arguments runs a complete setup.${clr} $(help-usage "bin/linter") ${bldblk}# alternatively, a partial linter name can be passed:${clr} -$(help-usage "bin/linter [ $(__lint::actions " | ") ]") +$(help-usage "bin/linter [ $(__lint.actions " | ") ]") $(help-header DESCRIPTION:) Runs various linters either all serially, or by name based on @@ -59,8 +69,8 @@ $(help-example bin/linter buildifier) exit 0 } -lint::rubocop() { - h2::green "Running Rubocop, please wait..." +lint.rubocop() { + h2.green "Running Rubocop, please wait..." run "rubocop || rubocop -a" inf "Rubocop completed." ok: @@ -68,8 +78,8 @@ lint::rubocop() { # runs buildifer from the PATH if it exists, otherwise bazel target # we want before-commit to be as fast as possible. -lint::buildifier() { - h2::green "Buildifier" +lint.buildifier() { + h2.green "Buildifier" if [[ -n $(command -v buildifier) ]]; then info "Running $(command -v buildifier).." run "find . -name 'BUILD*' -o -name 'WORKSPACE' -o -name '*.bzl' | grep -v '.git' | xargs buildifier -v" @@ -79,28 +89,28 @@ lint::buildifier() { fi } -lint::all() { +lint.all() { # number of modified files local changes_before=$(git status -s | md5) - trap __lint::cleanup EXIT + trap __lint.cleanup EXIT git status -s >"${__git_pre}" set -e - run::set-all abort-on-error - lint::rubocop + run.set-all abort-on-error + lint.rubocop set -e - run::set-all abort-on-error - lint::buildifier + run.set-all abort-on-error + lint.buildifier git status -s >"${__git_post}" local changes_after=$(git status -s | md5) if [[ ${changes_before} != "${changes_after}" ]]; then - hl::subtle "Git status -s output changed after before-commit hook." + hl.subtle "Git status -s output changed after before-commit hook." info "Changes before before-commit hook:" hr - diff "${pre}" "${post}" + diff "${__git_pre}" "${__git_post}" hr echo info "ACTION: ${bldylw}Please add any respective files to the commit and retry." @@ -113,32 +123,32 @@ lint::all() { } -lint::main() { +lint.main() { local action="$1" [[ "${action}" == "-h" || ${action} == "--help" ]] && action="help" - local func="lint::${action}" + local func="lint.${action}" if [[ -n ${action} ]]; then - if lib::util::is-a-function "${func}"; then + if util.is-a-function "${func}"; then [[ ${action} != "help" ]] && h2 "Executing partial linting for ${bldylw}${action}" shift ${func} "$@" local code=$? [[ ${code} -eq 0 ]] && success "Linter ${action} was successful" [[ ${code} -ne 0 ]] && error "Linter failed for ${action}" - deps::print-duration + deps.print-duration exit ${code} else - h1 "Invalid action provided." "Valid lint actions are: $(__lint::actions)" + h1 "Invalid action provided." "Valid lint actions are: $(__lint.actions)" exit 1 fi else set +e - lint::all - deps::print-duration + lint.all + deps.print-duration fi } -lint::main "$@" +lint.main "$@" exit 0 diff --git a/bin/setup b/bin/setup index b5b18589..c0799cad 100755 --- a/bin/setup +++ b/bin/setup @@ -1,61 +1,99 @@ #!/usr/bin/env bash +# vim: ft=bash # # Runs setup. -# Run bin/setup help for info. # -set -e -# shellcheck disable=SC1091 +# Run "bin/setup help" for usage. +# +# โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€” +# NOTE: These setup scripts rely on an open source BASH framework BashMatic. +# https://github.com/kigster/bashmatic +# +# The framework is pretty light-weight, and is installed in your $HOME/.bashmatic folder. +# You can safely remove that folder after the setup if you wish, although re-running the +# setup will re-install it. +# โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€” + source "bin/deps" #โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€” # Private Functions #โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€” -__setup::actions() { +__setup.actions() { local sep="${1}" - printf "${bldylw}$(lib::array::join "${sep}" $(lib::util::functions-matching "setup::" | sed 's/ main//g'))${clr}" + printf "$(array.join "${sep}" $(util.functions-matching "setup." | sed 's/ main//g'))" } #โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€” # Public Functions #โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€” -setup::help() { - printf " -$(help-header USAGE) - ${bldblk}# without any arguments runs a complete setup.${clr} -$(help-usage "bin/setup") +setup.rbenv() { + local rbenv_home="${HOME}/.rbenv" + local ruby_version="$(cat .ruby-version | tr -d '\n')" - ${bldblk}# alternatively, a sub-setup function name can be passed:${clr} -$(help-usage "bin/setup [ $(__setup::actions " | ") ]") + if [[ -n $(command -v ruby) ]]; then + local installed_version="$(ruby -e 'puts RUBY_VERSION' | tr -d '\n')" + if [[ ${installed_version} == ${ruby_version} ]]; then + info "RUBY already installed, current version: ${bldylw}${ruby_version}" + return 0 + fi + fi -$(help-header DESCRIPTION:) - Runs full setup without any arguments. + [[ -d "${rbenv_home}" && -n "$(command -v rbenv)" ]] || { + if [[ -z ${CI} ]]; then + warning "You are on a local system without any RBENV..." \ + "We are going to move your ~/.rbenv to a backup location and" \ + "install it from scratch to ensure it is up to date." + run.ui.ask "Should we proceed with building a new Ruby and backing up your ~/.rbenv?" + fi - Accepts one optional argument โ€” one of the actions that typically run - as part of setup, with one exception โ€” ${bldylw}remove-git-hook${clr}. - This action removes the git commit hook installed by the setup. + [[ -d ${rbenv_home} ]] && { + local rbenv_backup="${rbenv_home}.backup.$(time.now.db)" + info "Moving your current ${rbenv_home} to ${bldylw}${rbenv_backup}" + run "mv -v ${rbenv_home} ${rbenv_backup}" + } + run "git clone https://github.com/rbenv/rbenv.git ${rbenv_home}" + export PATH="${rbenv_home}/bin:${rbenv_home}/shims:${PATH}" + } -$(help-header EXAMPLES:) -$(help-example "bin/setup") + export PATH="${rbenv_home}/bin:${rbenv_home}/shims:${PATH}" - Or, to run only one of the sub-functions (actions), pass - it as an argument: + [[ $(command -v rbenv) == "${rbenv_home}/bin/rbenv" || $(command -v rbenv) == "/usr/local/bin/rbenv" ]] || { + error "Can't find rbenv in the PATH โ€” which rbenv returns: $(which rbenv)" + error "PATH: ${PATH}" + return 1 + } + + # Set our current ruby version to the desired one, even if it's not yet there. + # This allows the next block to auto-detect it and skip the remainder. + run "rbenv global ${ruby_version} || true" + # see if we even need to install anything: + local ruby_sdk_marker="$(rbenv versions | grep "${ruby_version}" | cut -d ' ' -f 1)" + if [[ ${ruby_sdk_marker} == "*" ]]; then + info "Ruby Version ${ruby_version} is already present, and is RBENV default." + info "Skipping the rest of RBENV setup." + return 0 + fi -$(help-example bin/setup help) -$(help-example bin/setup remove-git-hook) + eval "$(rbenv init -)" + run "mkdir -p ${rbenv_home}/plugins" + run "git clone https://github.com/rbenv/ruby-build.git ${rbenv_home}/plugins/ruby-build" + run "rbenv rehash" + hash -r -etc. - " + run "rbenv install -s ${ruby_version}" + run "rbenv global ${ruby_version}" } -setup::gems() { - for gem in rubocop relaxed-rubocop rubocop-performance; do - lib::gem::install ${gem} +setup.gems() { + for gem in rubocop relaxed-rubocop; do + gem.install "${gem}" done } -setup::remove-git-hook() { +setup.remove-git-hook() { set -e [[ -L .git/hooks/pre-commit ]] && { info 'Removing git commit hook...' @@ -65,7 +103,7 @@ setup::remove-git-hook() { set +e } -setup::git-hook() { +setup.git-hook() { set -e if [[ ! -L .git/hooks/pre-commit ]]; then info 'Installing git pre-commit hook' @@ -76,55 +114,105 @@ setup::git-hook() { set +e } -setup::os-specific() { - local os=$(uname -s | tr '[:upper:]' '[:lower:]') +setup.os-specific() { + local os="$(uname -s | tr '[:upper:]' '[:lower:]')" local setup_script setup_script="./bin/setup-${os}" if [[ -x "${setup_script}" ]]; then set -e - # shellcheck disable=SC1090 source "${setup_script}" # run it's main function - eval "setup::${os} \"$*\"" + eval "setup.${os} \"$*\"" echo if [[ -z ${CI} ]]; then - h2 "Please noteย โ€”ย to print your Bazel environment run " "${bldylw}bin/show-env" + info "Please noteย โ€”ย to print your Bazel environment run " + info "โฏ ${bldylw}bin/show-env" else /usr/bin/env bash bin/show-env || true fi else error "Operating system ${os} is not currently supported." >&2 + return 1 fi echo return 0 } -setup::main() { +setup.main() { local action="$1" - [[ "${action}" == "-h" || ${action} == "--help" ]] && action="help" - local func="setup::${action}" + local is_help=0 + local code=0 + + [[ "${action}" == "-h" || ${action} == "--help" ]] && { + action="help" + is_help=1 + } + + local func="setup.${action}" if [[ -n ${action} ]]; then - if lib::util::is-a-function "${func}"; then - [[ ${action} != "help" ]] && h2 "Executing partial setup for action ${bldylw}${action}" + if util.is-a-function "${func}"; then + ((is_help)) || h2 "Executing partial setup for action ${bldylw}${action}" shift ${func} "$@" - local code=$? - [[ ${code} -eq 0 ]] && success "Setup for ${action} was successful" + code=$? + [[ ${code} -eq 0 ]] && { + ((is_help)) || success "Setup for ${action} was successful" + } [[ ${code} -ne 0 ]] && error "Error setting up ${action}" - exit ${code} else - h1 "Invalid action provided." "Valid actions are: $(__setup::actions " | ")" - exit 1 + error "Invalid action provided โ€” '${action}'" + info "Valid actions are: [ ${bldylw}${action_list}$(txt-info) ]" + echo + code=1 fi else set +e h2 "Installing required development dependencies for working with rules_ruby and Bazel." - setup::gems - [[ -z ${CI} ]] && setup::git-hook - setup::os-specific "$@" + setup.rbenv + setup.gems + [[ -z ${CI} ]] && setup.git-hook + setup.os-specific "$@" fi + + ((is_help)) || bin/show-env + + exit ${code} } -setup::main "$@" +# shellcheck disable=SC2059,SC2155,SC2154 +setup.help() { + trap 'exit 0' INT + + printf " +$(help-header USAGE) + ${bldblk}# without any arguments runs a complete setup.${clr} +$(help-usage "bin/setup") + + ${bldblk}# alternatively, a sub-setup function name can be passed:${clr} +$(help-usage "bin/setup [ ${action_list} ]") + +$(help-header 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 โ€” ${bldylw}remove-git-hook${clr}. + This action removes the git commit hook installed by the setup. + +$(help-header EXAMPLES:) +$(help-example "bin/setup") + + Or, to run only one of the sub-functions (actions), pass + it as an argument: + +$(help-example "bin/setup help") +$(help-example "bin/setup remove-git-hook") + +" +} + +action_list="$(__setup.actions " | " | sed 's/setup\.//g')" +export action_list + +bashmatic.detect-subshell || setup.main "$@" diff --git a/bin/setup-darwin b/bin/setup-darwin index 0c19e79d..3327bb4b 100755 --- a/bin/setup-darwin +++ b/bin/setup-darwin @@ -1,12 +1,23 @@ #!/usr/bin/env bash +# โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€” +# NOTE: These setup scripts rely on an open source BASH framework BashMatic. +# https://github.com/kigster/bashmatic +# +# The framework is pretty light-weight, and is installed in your $HOME/.bashmatic folder. +# You can safely remove that folder after the setup if you wish, although re-running the +# setup will re-install it. +# โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€” set -e # shellcheck disable=SC1091 source "bin/deps" +declare -a BREW_DEPS +BREW_DEPS=(xz ydiff bash-completion) + #โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€” OS-X SPECIFIC INSTALLERS โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€” -__setup::brew-validate() { +__setup.brew-validate() { # Homebrew is required to install Bazel if ! brew help >/dev/null; then echo "brew is not installed, please install from https://brew.sh" @@ -15,49 +26,54 @@ __setup::brew-validate() { fi } -__setup::brew-install-jdk() { - # The JDK homebrew cask is a required to install the java dependencies for Bazel - if ! brew cask list | grep -q openjdk; then - run "brew cask install homebrew/cask-versions/adoptopenjdk8" - else - info: "JDK already installed." - fi +function __setup.brew-deps() { + brew.install.packages "${BREW_DEPS[@]}" } -__setup::brew-deps() { - lib::brew::install::packages 'xz' 'ydiff' +function __setup.is-bazelisk-installed() { + [[ -n "$(command -v bazelisk)" ]] } -__setup::is-bazelisk-installed() { - /bin/ls -al "$(command -v bazel)" | grep -q bazelisk +function __setup.is-bazel-installed() { + [[ -n "$(command -v bazel)" ]] } #โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€” PUBLIC INTERFACE โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€” -setup::brew() { - __setup::brew-validate - __setup::brew-install-jdk - __setup::brew-deps +setup.brew() { + __setup.brew-validate + __setup.brew-deps } -setup::xcode-tools() { +setup.xcode-tools() { # xcode command line tools are required, specifically gcc # if xcode already exists, this command will error, otherwise prompt the user if [[ -n $(xcode-select --install 2>&1) ]]; then info: "xcode-select tools are already installed." fi + + info "Next command requires sudo privileges to accept XCode License" + run.set-next show-output-on + run "sudo xcodebuild -license accept" } -setup::bazelisk() { - if __setup::is-bazelisk-installed; then - info: "Bazelisk is already installed." +setup.bazel() { + brew.package.is-installed bazelisk && + brew.uninstall.package bazelisk && + run "brew unlink bazel" + + if __setup.is-bazelisk-installed && __setup.is-bazel-installed ; then + info: "Bazel & bazelisk are already installed." else - run "brew install bazelbuild/tap/bazelisk" + brew.install.packages bazel bazelisk + run "brew link bazel || true" fi + + } -setup::darwin() { - setup::xcode-tools - setup::brew - setup::bazelisk +setup.darwin() { + setup.xcode-tools + setup.brew + setup.bazel } diff --git a/bin/setup-linux b/bin/setup-linux index 041acd95..7fe3a12f 100755 --- a/bin/setup-linux +++ b/bin/setup-linux @@ -1,20 +1,29 @@ #!/usr/bin/env bash +# โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€” +# NOTE: These setup scripts rely on an open source BASH framework BashMatic. +# https://github.com/kigster/bashmatic # +# The framework is pretty light-weight, and is installed in your $HOME/.bashmatic folder. +# You can safely remove that folder after the setup if you wish, although re-running the +# setup will re-install it. +# โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€” + set -e -# shellcheck disable=SC1091 source "bin/deps" -setup::linux() { - [[ -n $(command -v rvm) ]] && { - run "rvm implode --force" - [[ -d ${HOME}/.rvm ]] && run "rm -rf ${HOME}/.rvm" - } - - [[ -f ${HOME}/.bazelrc ]] || run "cp -v .circleci/.bazelrc ${HOME}" - +setup.linux.bazel() { run "sudo apt update -y || true" run "sudo apt-get install -y libreadline-dev zlib1g-dev" run "sudo curl -L -o /usr/bin/bazel https://github.com/bazelbuild/bazelisk/releases/download/v1.0/bazelisk-linux-amd64" run "sudo chmod +x /usr/bin/bazel" } +setup.linux() { + [[ -n $(command -v rvm) ]] && { + run "rvm implode --force" + [[ -d ${HOME}/.rvm ]] && run "rm -rf ${HOME}/.rvm" + } + + run.set-all abort-on-error + setup.linux.bazel +} diff --git a/bin/show-env b/bin/show-env index be9b984e..7019b626 100755 --- a/bin/show-env +++ b/bin/show-env @@ -1,42 +1,58 @@ #!/usr/bin/env bash -# +# vim: ft=bash # When run, shows current runtime environment, locations of Ruby, Bazel, # python, etc. # # Safe to run, does not modify anything. +# โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€” +# NOTE: These setup scripts rely on an open source BASH framework BashMatic. +# https://github.com/kigster/bashmatic +# +# The framework is pretty light-weight, and is installed in your $HOME/.bashmatic folder. +# You can safely remove that folder after the setup if you wish, although re-running the +# setup will re-install it. +# โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€” + set -e [[ -x bin/deps ]] && source "bin/deps" # prints first argument as the key, right arligned, the second left aligned. -function setup::table-rows() { +function setup.table-rows() { local value="$2" #$value="$(printf "%s" "${value}" | head -1 | tr -C -d '[:digit:][:punct:]' | sed 's/([0-9]+.[0-9]+.[0+9]+)//g;s/[()]/-/g')" value="$(printf "%s" "${value}" | head -1 | cut -b -40)" - printf "${bldylw}%12.12s : ${bldblu}%40.40s | ${txtpur}%s\n${clr}" "$1" "${value}" "$3" + printf "${bldylw}%10.10s : ${bldblu}%40.40s | ${txtpur}%s\n${clr}" "$1" "${value}" "$3" } -function setup::print-versions() { +function setup.print-versions() { local bazelisk_version="$(/bin/ls -ls "$(command -v bazel)" | grep bazelisk | awk 'BEGIN{FS="/"}{print $8}')" set +e h2 "Your Current Runtime Environment:" echo - setup::table-rows 'Bazel' "$(bazel --version)" "$(command -v bazel)" - setup::table-rows 'Bazelisk' "${bazelisk_version}" - setup::table-rows 'Python ' "$(python --version 2>&1)" "$(command -v python) -> $(readlink "$(command -v python)")" - setup::table-rows 'Python2' "$(python2 --version 2>&1)" "$(command -v python2)" - setup::table-rows 'Python3' "$(python3 --version 2>&1)" "$(command -v python3)" - setup::table-rows 'Ruby' "$(ruby --version | sed -E 's/p[0-9]+.*$//g' 2>&1)" "$(command -v ruby)" - setup::table-rows 'BASH' "$(bash --version 2>/dev/null | tr -d ',')" "$(command -v bash)" - setup::table-rows 'CC' "$(cc --version 2>/dev/null)" "$(cc --version | grep clang)" - setup::table-rows 'GO' "$(go version 2>/dev/null)" "$(command -v go)" - set -e + setup.table-rows 'RULES_RUBY' "$(cat .rules_version)" "Last updated on $(file.last-modified-date CHANGELOG.md)" + hr + setup.table-rows 'BAZEL' "$(bazel --version)" "$(command -v bazel)" + setup.table-rows 'BAZELISK' "${bazelisk_version}" + setup.table-rows 'BASH' "$(bash --version 2>/dev/null | tr -d ',')" "$(command -v bash)" + setup.table-rows 'CC' "$(cc --version 2>/dev/null)" "$(cc --version | grep clang)" + setup.table-rows 'GO' "$(go version 2>/dev/null)" "$(command -v go)" hr + setup.table-rows 'RUBY' "$(ruby --version | sed -E 's/p[0-9]+.*$//g' 2>&1)" "$(command -v ruby)" + setup.table-rows 'RBENV' "$(rbenv --version 2>/dev/null)" "$(command -v rbenv)" + setup.table-rows 'RUBIES' "List of installed Ruby Versions" "$(rbenv versions 2>/dev/null | sed 's/ (.*//g; s/[ \*]//g' | sed 's/$/, /g' | tr -d '\n')" + hr + setup.table-rows 'PYTHON' "$(python --version 2>&1)" "$(command -v python) -> $(readlink "$(command -v python)")" + setup.table-rows 'PYTHON2' "$(python2 --version 2>&1)" "$(command -v python2)" + setup.table-rows 'PYTHON3' "$(python3 --version 2>&1)" "$(command -v python3)" + hr + set -e + echo } -setup::print-versions +setup.print-versions exit 0 diff --git a/bin/test-suite b/bin/test-suite index 108b884f..63643f16 100755 --- a/bin/test-suite +++ b/bin/test-suite @@ -1,9 +1,18 @@ #!/usr/bin/env bash # vim: ft=bash +# โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€” +# NOTE: These setup scripts rely on an open source BASH framework BashMatic. +# https://github.com/kigster/bashmatic +# +# The framework is pretty light-weight, and is installed in your $HOME/.bashmatic folder. +# You can safely remove that folder after the setup if you wish, although re-running the +# setup will re-install it. +# โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€” + set -e # shellcheck disable=SC1091 -source "bin/deps" +source "bin/deps" export SHELL_INIT="${HOME}/.bashrc" export BUNDLE_PATH="${BUNDLE_PATH:-${HOME}/.bundle/gems}" @@ -12,11 +21,15 @@ export PATH="${HOME}/.rbenv/bin:${HOME}/.rbenv/shims:/usr/local/bin:/usr/bin:/bi export BAZEL_OPTS="--host_jvm_args=-Xmx500m --host_jvm_args=-Xms500m" export BAZEL_BUILD_OPTS="--curses=no --verbose_failures -j 30 --progress_report_interval=2" export BAZEL_TEST_OPTS="--verbose_failures --test_verbose_timeout_warnings --verbose_explanations" -export RUBY_VERSION=2.7.0 +export RUBY_VERSION="$(__version.detect .ruby-version)" +export BUNDLER_VERSION=$(gem.gemfile.bundler-version) +export RULES_VERSION=$(__version.detect .rules_version) +h3bg "RUBY_VERSION=${RUBY_VERSION}" + export BashMatic__Expr=" - [[ -f ${SHELL_INIT} ]] && source ${SHELL_INIT} - [[ -f ${HOME}/.bashmatic/init.sh ]] && source ${HOME}/.bashmatic/init.sh + [[ -f ${SHELL_INIT} ]] && source ${SHELL_INIT}; + [[ -f ${HOME}/.bashmatic/init.sh ]] && source ${HOME}/.bashmatic/init.sh; set -e " export Bazel__BuildSteps=" @@ -24,17 +37,17 @@ export Bazel__BuildSteps=" bazel ${BAZEL_OPTS} build ${BAZEL_BUILD_OPTS} -- //... ; echo; echo bazel ${BAZEL_OPTS} test ${BAZEL_BUILD_OPTS} ${BAZEL_TEST_OPTS} -- //... ; echo; echo " -deps::start-clock +deps.start-clock -run::set-all abort-on-error +run.set-all abort-on-error show-output-on #โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€” # Private Functions #โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€” -__test-suite::setup::environment() { +__test-suite.setup.environment() { # shellcheck disable=SC2016 - grep -q 'bashmatic/init.sh' ${SHELL_INIT} || echo '[[ -d ${HOME}/.bashmatic ]] && source ${HOME}/.bashmatic/init.sh' >>"${SHELL_INIT}" + grep -q 'bashmatic/init.sh' "${SHELL_INIT}" || echo '[[ -d ${HOME}/.bashmatic ]] && source ${HOME}/.bashmatic/init.sh' >>"${SHELL_INIT}" [[ -n $(command -v rbenv) ]] && { export PATH="${HOME}/.rbenv/shims:${HOME}/.rbenv/bin:/usr/local/bin:/usr/bin:/bin:${PATH}" @@ -51,13 +64,8 @@ __test-suite::setup::environment() { } # Setup rbenv if needed, and install Ruby but only if needed -__test-suite::setup::rbenv-ruby() { - - if [[ ! -d ${HOME}/.rbenv || -z $(command -v rbenv) ]]; then - [[ -d "${HOME}/.rbenv" ]] && run "mv ${HOME}/.rbenv ${HOME}/.rbenv.backup.$(date '+%s')" - run "rm -rf ${HOME}/.rbenv" - run "git clone https://github.com/rbenv/rbenv.git ${HOME}/.rbenv" - fi +__test-suite.setup.rbenv-ruby() { + [[ -d "${HOME}/.rbenv" ]] || run "git clone https://github.com/rbenv/rbenv.git ${HOME}/.rbenv" export PATH="${HOME}/.rbenv/bin:${HOME}/.rbenv/shims:${PATH}" @@ -66,25 +74,27 @@ __test-suite::setup::rbenv-ruby() { run "git clone https://github.com/rbenv/ruby-build.git ${rbenv_plugins}" fi - __test-suite::setup::environment + __test-suite.setup.environment + + set +e + source "${SHELL_INIT}" 2>&1 1>/dev/null + set -e - run "source ${SHELL_INIT}" run "rbenv install -s ${RUBY_VERSION}" run "rbenv global ${RUBY_VERSION}" run "rbenv rehash" run "ruby --version" run "gem update --system --no-doc" - run "gem install bundler --version 2.0.2 --no-doc" - run "bundle install --jobs=4 --retry=3 --path "${BUNDLE_PATH}"" - + run "gem install bundler --version ${BUNDLER_VERSION} --no-doc" + run "bundle install --jobs=4 --retry=3 --path ${BUNDLE_PATH}" } -__test::actions() { +__test.actions() { local sep=', ' - printf "${bldylw}$(lib::array::join "${sep}" $(lib::util::functions-matching "test::"))" + printf "${bldylw}$(array.join "${sep}" $(util.functions-matching "test."))" } -__test::exec() { +__test.exec() { local target target="$1" shift @@ -96,20 +106,25 @@ __test::exec() { " } +__test.header() { + box.green-in-cyan "RulesRuby Test Suite Runner" "RubyRules Version ${bldylw}${RULES_VERSION}" + test-suite.setup +} + [[ -n ${DEBUG} ]] && set -x #โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€” # Public Functions #โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€” -test::help() { +test.help() { printf " $(help-header USAGE) ${bldblk}# without any arguments runs a complete test suite.${clr} $(help-usage "bin/test-suite") ${bldblk}# alternatively, a partial test name can be passed:${clr} -$(help-usage "bin/test-suite [ $(__test::actions " | ") ]") +$(help-usage "bin/test-suite [ $(__test.actions " | ") ]") $(help-header DESCRIPTION:) Shell script that runs all or partial tests. Can be used locally and on CI. @@ -129,23 +144,23 @@ $(help-example bin/test-suite simple-example) } # Runs Rubocop Tests -test::rubocop() { - __test::exec rubocop " +test.rubocop() { + __test.exec rubocop " bundle install --path=${BUNDLE_PATH} bundle exec rubocop -E -D .rubocop.yml --force-exclusion " } # Runs Buildifier -test::buildifier() { - __test::exec buildifier " +test.buildifier() { + __test.exec buildifier " bazel run :buildifier-check " } # Builds and runs workspace inside examples/simple_script -test::simple-script() { - __test::exec simple-script " +test.simple-script() { + __test.exec simple-script " cd examples/simple_script ${Bazel__BuildSteps} echo run :bin; bazel ${BAZEL_OPTS} run ${BAZEL_BUILD_OPTS} :bin @@ -154,20 +169,20 @@ test::simple-script() { } # Builds and runs workspace inside examples/simple_script -test::example-gem() { - __test::exec example-gem " +test.example-gem() { + __test.exec example-gem " cd examples/example_gem echo bazel ${BAZEL_OPTS} build ...:all; bazel ${BAZEL_OPTS} build ...:all " } -test::workspace() { - __test::exec workspace "${Bazel__BuildSteps}" +test.workspace() { + __test.exec workspace "${Bazel__BuildSteps}" } # Private -test::bazel-info() { - __test::exec bazel-info " +test.bazel-info() { + __test.exec bazel-info " bazel ${BAZEL_OPTS} version; echo; echo bazel ${BAZEL_OPTS} info; echo; echo bazel ${BAZEL_OPTS} fetch --curses=no -- '//ruby/...' @@ -175,79 +190,80 @@ test::bazel-info() { } # Run rspecs once we have something in the spec folder. -test::rspec() { +test.rspec() { [[ -d "spec" ]] || return 0 - __test::exec rspec " + __test.exec rspec " bundle check || bundle install bundle exec rspec " } -test::all() { - test::bazel-info - test::workspace - test::simple-script - test::example-gem - test::rubocop - test::rspec - test::buildifier +test.all() { + test.bazel-info + test.workspace + test.simple-script + test.example-gem + test.rubocop + test.rspec + test.buildifier } -test-suite::setup() { +test-suite.setup() { # shellcheck disable=SC1090 [[ -f ${SHELL_INIT} ]] && source "${SHELL_INIT}" if [[ -n $(command -v ruby) ]]; then CURRENT_VERSION=$(ruby -e 'puts RUBY_VERSION') if [[ ${CURRENT_VERSION} != "${RUBY_VERSION}" ]]; then - __test-suite::setup::rbenv-ruby + __test-suite.setup.rbenv-ruby else info "Ruby already exists and matches the version:" info "$(command -v ruby), version: ${bldylw}$(ruby --version)" fi else - hl::subtle "Ruby wasn't found, installing via rbenv..." - __test-suite::setup::rbenv-ruby + hl.subtle "Ruby wasn't found, installing via rbenv..." + __test-suite.setup.rbenv-ruby fi } -test-suite::main() { +test-suite.main() { local action="${1}" [[ "${action}" == "-h" || ${action} == "--help" ]] && action="help" [[ -z ${action} ]] && action=all - local func="test::${action}" + local func="test.${action}" if [[ -n ${action} && ${action} != "all" ]]; then shift - if lib::util::is-a-function "${func}"; then + if util.is-a-function "${func}"; then [[ "${action}" != "help" ]] && { - box::green-in-cyan "RulesRuby Test Suite Runner" "RubyRules Version $(cat .rules_version)" - test-suite::setup + __test.header h1 "Executing partial tests for action ${bldylw}${action}" } ${func} "$@" local code=$? - [[ ${code} -eq 0 ]] && success "Test Suite for ${action} was successful" - [[ ${code} -ne 0 ]] && error "Error running tests for ${action}" - deps::print-duration + if [[ ${code} -eq 0 ]]; then + success "Test Suite for ${action} was successful" + else + error "Error running tests for ${action}" + fi + deps.print-duration exit ${code} else info "Invalid action ${action}." - info "List of valid actions are: $(__test::actions)" + info "List of valid actions are: $(__test.actions)" exit 1 fi else - box::green-in-cyan "RulesRuby Test Suite Runner โ€”โ€” full test suite in series." "RubyRules Version $(cat .rules_version)" - test-suite::setup - run::set-all abort-on-error + __test.header + run.set-all abort-on-error set -e - test::all + test.all success "Test suite was successful!" - deps::print-duration + deps.print-duration fi } -test-suite::main "$@" +test-suite.main "$@" set +x diff --git a/docs/img/env.png b/docs/img/env.png new file mode 100644 index 00000000..3593b88c Binary files /dev/null and b/docs/img/env.png differ diff --git a/docs/img/status-not-ready.svg b/docs/img/status-not-ready.svg new file mode 100644 index 00000000..3a86de9a --- /dev/null +++ b/docs/img/status-not-ready.svg @@ -0,0 +1 @@ + Development StatusDevelopment StatusNot ReadyNot Ready \ No newline at end of file diff --git a/docs/img/status-ready.svg b/docs/img/status-ready.svg new file mode 100644 index 00000000..fcb75e34 --- /dev/null +++ b/docs/img/status-ready.svg @@ -0,0 +1 @@ + Development StatusDevelopment StatusReadyReady \ No newline at end of file diff --git a/docs/img/status-wait.svg b/docs/img/status-wait.svg new file mode 100644 index 00000000..5bd705b7 --- /dev/null +++ b/docs/img/status-wait.svg @@ -0,0 +1 @@ + Development StatusDevelopment StatusWaitWait \ No newline at end of file diff --git a/examples/example_gem/BUILD b/examples/example_gem/BUILD deleted file mode 100644 index 8fb980ba..00000000 --- a/examples/example_gem/BUILD +++ /dev/null @@ -1,16 +0,0 @@ -package(default_visibility = ["//:__subpackages__"]) - -load( - "@bazelruby_ruby_rules//ruby:defs.bzl", - "rb_gem", -) - -rb_gem( - name = "default_gem", - authors = ["Coinbase"], - gem_name = "example_gem", - version = "0.1.0", - deps = [ - "//lib:example_gem", - ], -) diff --git a/examples/example_gem/BUILD.bazel b/examples/example_gem/BUILD.bazel new file mode 100644 index 00000000..55948ee0 --- /dev/null +++ b/examples/example_gem/BUILD.bazel @@ -0,0 +1,35 @@ +load( + "@bazelruby_rules_ruby//ruby:defs.bzl", + "ruby_gem", +) + +package(default_visibility = ["//:__subpackages__"]) + +ruby_gem( + name = "example_gem", + srcs = [ + "//lib:example_gem", + ], + gem_author_emails = [ + "dev@coinbase.com", + "bazelruby@googlegroups.com", + ], + gem_authors = [ + "Coinbase", + "BazelRuby", + ], + gem_description = "Example gem to demonstrate Bazel Gem packaging", + gem_development_dependencies = { + "rspec": "", + "rspec-its": "", + "rubocop": "", + }, + gem_homepage = "https://github.com/bazelruby/rules_ruby", + gem_name = "example-gem", + gem_runtime_dependencies = { + "colored2": "", + "hashie": "", + }, + gem_summary = "Example gem to demonstrate Bazel Gem packaging", + gem_version = "0.1.0", +) diff --git a/examples/example_gem/WORKSPACE b/examples/example_gem/WORKSPACE index 3b377a5c..0f096a77 100644 --- a/examples/example_gem/WORKSPACE +++ b/examples/example_gem/WORKSPACE @@ -1,21 +1,21 @@ -workspace(name = "bazelruby_ruby_rules_example_gem") +workspace(name = "bazelruby_rules_ruby_example_gem") # Importing rules_ruby from the parent directory for developing # rules_ruby itself... local_repository( - name = "bazelruby_ruby_rules", + name = "bazelruby_rules_ruby", path = "../..", ) load( - "@bazelruby_ruby_rules//ruby:deps.bzl", - "ruby_register_toolchains", - "ruby_rules_dependencies", + "@bazelruby_rules_ruby//ruby:deps.bzl", + "rules_ruby_dependencies", + "rules_ruby_select_sdk", ) -ruby_rules_dependencies() +rules_ruby_dependencies() -ruby_register_toolchains() +rules_ruby_select_sdk("3.0.2") load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace") diff --git a/examples/example_gem/lib/BUILD b/examples/example_gem/lib/BUILD index e98ee71f..32394529 100644 --- a/examples/example_gem/lib/BUILD +++ b/examples/example_gem/lib/BUILD @@ -1,11 +1,11 @@ -package(default_visibility = ["//:__subpackages__"]) - load( - "@bazelruby_ruby_rules//ruby:defs.bzl", - "rb_library", + "@bazelruby_rules_ruby//ruby:defs.bzl", + "ruby_library", ) -rb_library( +package(default_visibility = ["//:__subpackages__"]) + +ruby_library( name = "example_gem", srcs = ["example_gem.rb"], deps = ["//lib/foo:default_library"], diff --git a/examples/example_gem/lib/foo/BUILD b/examples/example_gem/lib/foo/BUILD index d08a4597..9e6e2fe3 100644 --- a/examples/example_gem/lib/foo/BUILD +++ b/examples/example_gem/lib/foo/BUILD @@ -1,11 +1,11 @@ -package(default_visibility = ["//:__subpackages__"]) - load( - "@bazelruby_ruby_rules//ruby:defs.bzl", - "rb_library", + "@bazelruby_rules_ruby//ruby:defs.bzl", + "ruby_library", ) -rb_library( +package(default_visibility = ["//:__subpackages__"]) + +ruby_library( name = "default_library", srcs = ["bar.rb"], ) diff --git a/examples/simple_rails_api/.ruby-version b/examples/simple_rails_api/.ruby-version deleted file mode 100644 index 24ba9a38..00000000 --- a/examples/simple_rails_api/.ruby-version +++ /dev/null @@ -1 +0,0 @@ -2.7.0 diff --git a/examples/simple_rails_api/BUILD b/examples/simple_rails_api/BUILD index 686a8a09..c53e54b5 100644 --- a/examples/simple_rails_api/BUILD +++ b/examples/simple_rails_api/BUILD @@ -1,11 +1,10 @@ -package(default_visibility = ["//:__subpackages__"]) - load( - "@bazelruby_ruby_rules//ruby:defs.bzl", + "@bazelruby_rules_ruby//ruby:defs.bzl", "ruby_binary", - "ruby_test", ) +package(default_visibility = ["//:__subpackages__"]) + ruby_binary( name = "server", srcs = glob( diff --git a/examples/simple_rails_api/Gemfile b/examples/simple_rails_api/Gemfile index 8f98992d..3fab5dae 100644 --- a/examples/simple_rails_api/Gemfile +++ b/examples/simple_rails_api/Gemfile @@ -6,7 +6,7 @@ gem 'rails', '~> 6.0.2' # Use sqlite3 as the database for Active Record gem 'sqlite3', '~> 1.4' # Use Puma as the app server -gem 'puma', '~> 4.1' +gem 'puma', '~> 4.3' # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder # gem 'jbuilder', '~> 2.7' # Use Redis adapter to run Action Cable in production diff --git a/examples/simple_rails_api/Gemfile.lock b/examples/simple_rails_api/Gemfile.lock index c89e6128..a4ffd85a 100644 --- a/examples/simple_rails_api/Gemfile.lock +++ b/examples/simple_rails_api/Gemfile.lock @@ -1,149 +1,147 @@ GEM remote: https://rubygems.org/ specs: - actioncable (6.0.2.1) - actionpack (= 6.0.2.1) + actioncable (6.0.4.1) + actionpack (= 6.0.4.1) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (6.0.2.1) - actionpack (= 6.0.2.1) - activejob (= 6.0.2.1) - activerecord (= 6.0.2.1) - activestorage (= 6.0.2.1) - activesupport (= 6.0.2.1) + actionmailbox (6.0.4.1) + actionpack (= 6.0.4.1) + activejob (= 6.0.4.1) + activerecord (= 6.0.4.1) + activestorage (= 6.0.4.1) + activesupport (= 6.0.4.1) mail (>= 2.7.1) - actionmailer (6.0.2.1) - actionpack (= 6.0.2.1) - actionview (= 6.0.2.1) - activejob (= 6.0.2.1) + actionmailer (6.0.4.1) + actionpack (= 6.0.4.1) + actionview (= 6.0.4.1) + activejob (= 6.0.4.1) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (6.0.2.1) - actionview (= 6.0.2.1) - activesupport (= 6.0.2.1) + actionpack (6.0.4.1) + actionview (= 6.0.4.1) + activesupport (= 6.0.4.1) rack (~> 2.0, >= 2.0.8) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (6.0.2.1) - actionpack (= 6.0.2.1) - activerecord (= 6.0.2.1) - activestorage (= 6.0.2.1) - activesupport (= 6.0.2.1) + actiontext (6.0.4.1) + actionpack (= 6.0.4.1) + activerecord (= 6.0.4.1) + activestorage (= 6.0.4.1) + activesupport (= 6.0.4.1) nokogiri (>= 1.8.5) - actionview (6.0.2.1) - activesupport (= 6.0.2.1) + actionview (6.0.4.1) + activesupport (= 6.0.4.1) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.1, >= 1.2.0) - activejob (6.0.2.1) - activesupport (= 6.0.2.1) + activejob (6.0.4.1) + activesupport (= 6.0.4.1) globalid (>= 0.3.6) - activemodel (6.0.2.1) - activesupport (= 6.0.2.1) - activerecord (6.0.2.1) - activemodel (= 6.0.2.1) - activesupport (= 6.0.2.1) - activestorage (6.0.2.1) - actionpack (= 6.0.2.1) - activejob (= 6.0.2.1) - activerecord (= 6.0.2.1) - marcel (~> 0.3.1) - activesupport (6.0.2.1) + activemodel (6.0.4.1) + activesupport (= 6.0.4.1) + activerecord (6.0.4.1) + activemodel (= 6.0.4.1) + activesupport (= 6.0.4.1) + activestorage (6.0.4.1) + actionpack (= 6.0.4.1) + activejob (= 6.0.4.1) + activerecord (= 6.0.4.1) + marcel (~> 1.0.0) + activesupport (6.0.4.1) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 0.7, < 2) minitest (~> 5.1) tzinfo (~> 1.1) - zeitwerk (~> 2.2) - bootsnap (1.4.6) + zeitwerk (~> 2.2, >= 2.2.2) + bootsnap (1.9.1) msgpack (~> 1.0) builder (3.2.4) - byebug (11.1.1) - concurrent-ruby (1.1.6) + byebug (11.1.3) + concurrent-ruby (1.1.10) crass (1.0.6) - erubi (1.9.0) - ffi (1.12.2) - globalid (0.4.2) - activesupport (>= 4.2.0) - i18n (1.8.2) + erubi (1.10.0) + ffi (1.15.4) + globalid (1.0.1) + activesupport (>= 5.0) + i18n (1.12.0) concurrent-ruby (~> 1.0) - listen (3.1.5) + listen (3.0.8) rb-fsevent (~> 0.9, >= 0.9.4) rb-inotify (~> 0.9, >= 0.9.7) - ruby_dep (~> 1.2) - loofah (2.4.0) + loofah (2.12.0) crass (~> 1.0.2) nokogiri (>= 1.5.9) mail (2.7.1) mini_mime (>= 0.1.1) - marcel (0.3.3) - mimemagic (~> 0.3.2) - method_source (0.9.2) - mimemagic (0.3.4) - mini_mime (1.0.2) - mini_portile2 (2.4.0) - minitest (5.14.0) - msgpack (1.3.3) - nio4r (2.5.2) - nokogiri (1.10.8) - mini_portile2 (~> 2.4.0) - puma (4.3.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.1) + mini_portile2 (2.8.0) + minitest (5.17.0) + msgpack (1.4.2) + nio4r (2.5.8) + nokogiri (1.13.4) + mini_portile2 (~> 2.8.0) + racc (~> 1.4) + puma (4.3.12) nio4r (~> 2.0) - rack (2.2.2) + racc (1.6.0) + rack (2.2.3.1) rack-test (1.1.0) rack (>= 1.0, < 3) - rails (6.0.2.1) - actioncable (= 6.0.2.1) - actionmailbox (= 6.0.2.1) - actionmailer (= 6.0.2.1) - actionpack (= 6.0.2.1) - actiontext (= 6.0.2.1) - actionview (= 6.0.2.1) - activejob (= 6.0.2.1) - activemodel (= 6.0.2.1) - activerecord (= 6.0.2.1) - activestorage (= 6.0.2.1) - activesupport (= 6.0.2.1) + rails (6.0.4.1) + actioncable (= 6.0.4.1) + actionmailbox (= 6.0.4.1) + actionmailer (= 6.0.4.1) + actionpack (= 6.0.4.1) + actiontext (= 6.0.4.1) + actionview (= 6.0.4.1) + activejob (= 6.0.4.1) + activemodel (= 6.0.4.1) + activerecord (= 6.0.4.1) + activestorage (= 6.0.4.1) + activesupport (= 6.0.4.1) bundler (>= 1.3.0) - railties (= 6.0.2.1) + railties (= 6.0.4.1) sprockets-rails (>= 2.0.0) rails-dom-testing (2.0.3) activesupport (>= 4.2.0) nokogiri (>= 1.6) - rails-html-sanitizer (1.3.0) + rails-html-sanitizer (1.4.2) loofah (~> 2.3) - railties (6.0.2.1) - actionpack (= 6.0.2.1) - activesupport (= 6.0.2.1) + railties (6.0.4.1) + actionpack (= 6.0.4.1) + activesupport (= 6.0.4.1) method_source rake (>= 0.8.7) thor (>= 0.20.3, < 2.0) - rake (13.0.1) - rb-fsevent (0.10.3) + rake (13.0.6) + rb-fsevent (0.11.0) rb-inotify (0.10.1) ffi (~> 1.0) - ruby_dep (1.5.0) - spring (2.1.0) + spring (2.1.1) spring-watcher-listen (2.0.1) listen (>= 2.7, < 4.0) spring (>= 1.2, < 3.0) - sprockets (4.0.0) + sprockets (4.0.2) concurrent-ruby (~> 1.0) rack (> 1, < 3) - sprockets-rails (3.2.1) + sprockets-rails (3.2.2) actionpack (>= 4.0) activesupport (>= 4.0) sprockets (>= 3.0.0) sqlite3 (1.4.2) - thor (1.0.1) + thor (1.1.0) thread_safe (0.3.6) - tzinfo (1.2.6) + tzinfo (1.2.10) thread_safe (~> 0.1) - websocket-driver (0.7.1) + websocket-driver (0.7.5) websocket-extensions (>= 0.1.0) - websocket-extensions (0.1.4) - zeitwerk (2.2.2) + websocket-extensions (0.1.5) + zeitwerk (2.6.6) PLATFORMS ruby @@ -152,7 +150,7 @@ DEPENDENCIES bootsnap (>= 1.4.2) byebug listen (>= 3.0.5, < 3.2) - puma (~> 4.1) + puma (~> 4.3) rails (~> 6.0.2) spring spring-watcher-listen (~> 2.0.0) @@ -160,4 +158,4 @@ DEPENDENCIES tzinfo-data BUNDLED WITH - 2.1.2 + 2.2.24 diff --git a/examples/simple_rails_api/WORKSPACE b/examples/simple_rails_api/WORKSPACE index daef2e1e..8585cfec 100644 --- a/examples/simple_rails_api/WORKSPACE +++ b/examples/simple_rails_api/WORKSPACE @@ -1,29 +1,29 @@ -workspace(name = "bazelruby_ruby_rules_example") +workspace(name = "bazelruby_rules_ruby_example") # Importing rules_ruby from the parent directory for developing # rules_ruby itself... local_repository( - name = "bazelruby_ruby_rules", + name = "bazelruby_rules_ruby", path = "../..", ) load( - "@bazelruby_ruby_rules//ruby:deps.bzl", - "ruby_register_toolchains", - "ruby_rules_dependencies", + "@bazelruby_rules_ruby//ruby:deps.bzl", + "rules_ruby_dependencies", + "rules_ruby_select_sdk", ) -ruby_rules_dependencies() +rules_ruby_dependencies() -ruby_register_toolchains(version = "2.7.0") +rules_ruby_select_sdk(version = "3.0.2") load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace") bazel_skylib_workspace() -load("@bazelruby_ruby_rules//ruby:defs.bzl", "bundle_install") +load("@bazelruby_rules_ruby//ruby:defs.bzl", "ruby_bundle") -bundle_install( +ruby_bundle( name = "bundle", gemfile = "//:Gemfile", gemfile_lock = "//:Gemfile.lock", diff --git a/examples/simple_script/.rubocop.yml b/examples/simple_script/.rubocop.yml index 7b653d9d..7a33ed81 100644 --- a/examples/simple_script/.rubocop.yml +++ b/examples/simple_script/.rubocop.yml @@ -1,7 +1,7 @@ inherit_from: .relaxed-rubocop-2.4.yml AllCops: - TargetRubyVersion: 2.6 + TargetRubyVersion: 3.0 UseCache: true DefaultFormatter: progress DisplayStyleGuide: true @@ -23,6 +23,7 @@ AllCops: - '**/*.ru' - '**/Gemfile' - '**/Rakefile' + NewCops: enable Layout/HashAlignment: Enabled: true diff --git a/examples/simple_script/.ruby-version b/examples/simple_script/.ruby-version new file mode 100644 index 00000000..b5021469 --- /dev/null +++ b/examples/simple_script/.ruby-version @@ -0,0 +1 @@ +3.0.2 diff --git a/examples/simple_script/BUILD.bazel b/examples/simple_script/BUILD.bazel index e9e382e7..3f81e7b9 100644 --- a/examples/simple_script/BUILD.bazel +++ b/examples/simple_script/BUILD.bazel @@ -1,5 +1,5 @@ load( - "@bazelruby_ruby_rules//ruby:defs.bzl", + "@bazelruby_rules_ruby//ruby:defs.bzl", "ruby_binary", "ruby_rspec", "ruby_rubocop", @@ -31,6 +31,8 @@ ruby_test( ] + glob([ "spec/**/*.rb", ]), + # This is a WORKSPACE-relative path to a spec directory. + # It could be longer, like "my/path/to/spec". args = [ "spec", ], diff --git a/examples/simple_script/Gemfile b/examples/simple_script/Gemfile index d677fb55..9fade231 100644 --- a/examples/simple_script/Gemfile +++ b/examples/simple_script/Gemfile @@ -5,5 +5,5 @@ source 'https://rubygems.org' gem 'awesome_print' gem 'colored2' gem 'rspec', '~> 3.7.0' -gem 'rspec-its' -gem 'rubocop', '~> 0.78.0' +gem 'rspec-its', github: "rspec/rspec-its", ref: "3d36b4a7b004ffa204a0e392f27c8b6b0b674ecf" # v1.3.0 +gem 'rubocop' diff --git a/examples/simple_script/Gemfile.lock b/examples/simple_script/Gemfile.lock index c2b42fd8..ee74d259 100644 --- a/examples/simple_script/Gemfile.lock +++ b/examples/simple_script/Gemfile.lock @@ -1,15 +1,25 @@ +GIT + remote: https://github.com/rspec/rspec-its.git + revision: 3d36b4a7b004ffa204a0e392f27c8b6b0b674ecf + ref: 3d36b4a7b004ffa204a0e392f27c8b6b0b674ecf + specs: + rspec-its (1.3.0) + rspec-core (>= 3.0.0) + rspec-expectations (>= 3.0.0) + GEM remote: https://rubygems.org/ specs: - ast (2.4.0) - awesome_print (1.8.0) + ast (2.4.2) + awesome_print (1.9.2) colored2 (3.1.2) - diff-lcs (1.3) - jaro_winkler (1.5.4) - parallel (1.19.1) - parser (2.7.0.3) - ast (~> 2.4.0) + diff-lcs (1.4.4) + parallel (1.21.0) + parser (3.0.2.0) + ast (~> 2.4.1) rainbow (3.0.0) + regexp_parser (2.1.1) + rexml (3.2.5) rspec (3.7.0) rspec-core (~> 3.7.0) rspec-expectations (~> 3.7.0) @@ -19,22 +29,23 @@ GEM rspec-expectations (3.7.0) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.7.0) - rspec-its (1.3.0) - rspec-core (>= 3.0.0) - rspec-expectations (>= 3.0.0) rspec-mocks (3.7.0) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.7.0) rspec-support (3.7.1) - rubocop (0.78.0) - jaro_winkler (~> 1.5.1) + rubocop (1.21.0) parallel (~> 1.10) - parser (>= 2.6) + parser (>= 3.0.0.0) rainbow (>= 2.2.2, < 4.0) + regexp_parser (>= 1.8, < 3.0) + rexml + rubocop-ast (>= 1.9.1, < 2.0) ruby-progressbar (~> 1.7) - unicode-display_width (>= 1.4.0, < 1.7) - ruby-progressbar (1.10.1) - unicode-display_width (1.6.1) + unicode-display_width (>= 1.4.0, < 3.0) + rubocop-ast (1.11.0) + parser (>= 3.0.1.1) + ruby-progressbar (1.11.0) + unicode-display_width (2.1.0) PLATFORMS ruby @@ -43,8 +54,8 @@ DEPENDENCIES awesome_print colored2 rspec (~> 3.7.0) - rspec-its - rubocop (~> 0.78.0) + rspec-its! + rubocop BUNDLED WITH - 2.1.2 + 2.2.24 diff --git a/examples/simple_script/WORKSPACE b/examples/simple_script/WORKSPACE index bd722d6c..4ad11d15 100644 --- a/examples/simple_script/WORKSPACE +++ b/examples/simple_script/WORKSPACE @@ -1,27 +1,27 @@ -workspace(name = "bazelruby_ruby_rules_example") +workspace(name = "bazelruby_rules_ruby_example") # Importing rules_ruby from the parent directory for developing # rules_ruby itself... local_repository( - name = "bazelruby_ruby_rules", + name = "bazelruby_rules_ruby", path = "../..", ) load( - "@bazelruby_ruby_rules//ruby:deps.bzl", - "ruby_register_toolchains", - "ruby_rules_dependencies", + "@bazelruby_rules_ruby//ruby:deps.bzl", + "rules_ruby_dependencies", + "rules_ruby_select_sdk", ) -ruby_rules_dependencies() +rules_ruby_dependencies() -ruby_register_toolchains(version = "2.7.0") +rules_ruby_select_sdk(version = "3.0.2") -load("@bazelruby_ruby_rules//ruby:defs.bzl", "ruby_bundle") +load("@bazelruby_rules_ruby//ruby:defs.bzl", "ruby_bundle") ruby_bundle( name = "bundle", - bundler_version = "2.1.2", + bundler_version = "2.1.4", excludes = { "mini_portile": ["test/**/*"], }, diff --git a/examples/simple_script/lib/BUILD b/examples/simple_script/lib/BUILD index 46da7757..f125ff86 100644 --- a/examples/simple_script/lib/BUILD +++ b/examples/simple_script/lib/BUILD @@ -1,10 +1,10 @@ -package(default_visibility = ["//:__subpackages__"]) - load( - "@bazelruby_ruby_rules//ruby:defs.bzl", + "@bazelruby_rules_ruby//ruby:defs.bzl", "ruby_library", ) +package(default_visibility = ["//:__subpackages__"]) + ruby_library( name = "foo", srcs = ["foo.rb"], diff --git a/examples/simple_script/spec/script_spec.rb b/examples/simple_script/spec/script_spec.rb index 458b928c..b325d32d 100644 --- a/examples/simple_script/spec/script_spec.rb +++ b/examples/simple_script/spec/script_spec.rb @@ -1,7 +1,8 @@ # frozen_string_literal: true require 'spec_helper' -require 'script' + +require_relative '../script' describe 'oss_rand' do it 'generates a String' do diff --git a/examples/simple_script_vendored/.gitignore b/examples/simple_script_vendored/.gitignore new file mode 100644 index 00000000..a6ef824c --- /dev/null +++ b/examples/simple_script_vendored/.gitignore @@ -0,0 +1 @@ +/bazel-* diff --git a/examples/simple_script_vendored/.relaxed-rubocop-2.4.yml b/examples/simple_script_vendored/.relaxed-rubocop-2.4.yml new file mode 100644 index 00000000..fce806fe --- /dev/null +++ b/examples/simple_script_vendored/.relaxed-rubocop-2.4.yml @@ -0,0 +1,174 @@ +# Relaxed.Ruby.Style +## Version 2.4 + +Style/Alias: + Enabled: false + StyleGuide: https://relaxed.ruby.style/#stylealias + +Style/AsciiComments: + Enabled: false + StyleGuide: https://relaxed.ruby.style/#styleasciicomments + +Style/BeginBlock: + Enabled: false + StyleGuide: https://relaxed.ruby.style/#stylebeginblock + +Style/BlockDelimiters: + Enabled: false + StyleGuide: https://relaxed.ruby.style/#styleblockdelimiters + +Style/CommentAnnotation: + Enabled: false + StyleGuide: https://relaxed.ruby.style/#stylecommentannotation + +Style/Documentation: + Enabled: false + StyleGuide: https://relaxed.ruby.style/#styledocumentation + +Layout/DotPosition: + Enabled: false + StyleGuide: https://relaxed.ruby.style/#layoutdotposition + +Style/DoubleNegation: + Enabled: false + StyleGuide: https://relaxed.ruby.style/#styledoublenegation + +Style/EndBlock: + Enabled: false + StyleGuide: https://relaxed.ruby.style/#styleendblock + +Style/FormatString: + Enabled: false + StyleGuide: https://relaxed.ruby.style/#styleformatstring + +Style/IfUnlessModifier: + Enabled: false + StyleGuide: https://relaxed.ruby.style/#styleifunlessmodifier + +Style/Lambda: + Enabled: false + StyleGuide: https://relaxed.ruby.style/#stylelambda + +Style/ModuleFunction: + Enabled: false + StyleGuide: https://relaxed.ruby.style/#stylemodulefunction + +Style/MultilineBlockChain: + Enabled: false + StyleGuide: https://relaxed.ruby.style/#stylemultilineblockchain + +Style/NegatedIf: + Enabled: false + StyleGuide: https://relaxed.ruby.style/#stylenegatedif + +Style/NegatedWhile: + Enabled: false + StyleGuide: https://relaxed.ruby.style/#stylenegatedwhile + +Style/NumericPredicate: + Enabled: false + StyleGuide: https://relaxed.ruby.style/#stylenumericpredicate + +Style/ParallelAssignment: + Enabled: false + StyleGuide: https://relaxed.ruby.style/#styleparallelassignment + +Style/PercentLiteralDelimiters: + Enabled: false + StyleGuide: https://relaxed.ruby.style/#stylepercentliteraldelimiters + +Style/PerlBackrefs: + Enabled: false + StyleGuide: https://relaxed.ruby.style/#styleperlbackrefs + +Style/Semicolon: + Enabled: false + StyleGuide: https://relaxed.ruby.style/#stylesemicolon + +Style/SignalException: + Enabled: false + StyleGuide: https://relaxed.ruby.style/#stylesignalexception + +Style/SingleLineBlockParams: + Enabled: false + StyleGuide: https://relaxed.ruby.style/#stylesinglelineblockparams + +Style/SingleLineMethods: + Enabled: false + StyleGuide: https://relaxed.ruby.style/#stylesinglelinemethods + +Layout/SpaceBeforeBlockBraces: + Enabled: false + StyleGuide: https://relaxed.ruby.style/#layoutspacebeforeblockbraces + +Layout/SpaceInsideParens: + Enabled: false + StyleGuide: https://relaxed.ruby.style/#layoutspaceinsideparens + +Layout/LineLength: + Enabled: false + +Style/SpecialGlobalVars: + Enabled: false + StyleGuide: https://relaxed.ruby.style/#stylespecialglobalvars + +Style/StringLiterals: + Enabled: false + StyleGuide: https://relaxed.ruby.style/#stylestringliterals + +Style/TrailingCommaInArguments: + Enabled: false + StyleGuide: https://relaxed.ruby.style/#styletrailingcommainarguments + +Style/TrailingCommaInArrayLiteral: + Enabled: false + StyleGuide: https://relaxed.ruby.style/#styletrailingcommainarrayliteral + +Style/TrailingCommaInHashLiteral: + Enabled: false + StyleGuide: https://relaxed.ruby.style/#styletrailingcommainhashliteral + +Style/SymbolArray: + Enabled: false + StyleGuide: http://relaxed.ruby.style/#stylesymbolarray + +Style/WhileUntilModifier: + Enabled: false + StyleGuide: https://relaxed.ruby.style/#stylewhileuntilmodifier + +Style/WordArray: + Enabled: false + StyleGuide: https://relaxed.ruby.style/#stylewordarray + +Lint/AmbiguousRegexpLiteral: + Enabled: false + StyleGuide: https://relaxed.ruby.style/#lintambiguousregexpliteral + +Lint/AssignmentInCondition: + Enabled: false + StyleGuide: https://relaxed.ruby.style/#lintassignmentincondition + +Metrics/AbcSize: + Enabled: false + +Metrics/BlockNesting: + Enabled: false + +Metrics/ClassLength: + Enabled: false + +Metrics/ModuleLength: + Enabled: false + +Metrics/CyclomaticComplexity: + Enabled: false + +Metrics/MethodLength: + Enabled: false + +Metrics/ParameterLists: + Enabled: false + +Metrics/PerceivedComplexity: + Enabled: false + diff --git a/examples/simple_script_vendored/.rubocop.yml b/examples/simple_script_vendored/.rubocop.yml new file mode 100644 index 00000000..0687ca77 --- /dev/null +++ b/examples/simple_script_vendored/.rubocop.yml @@ -0,0 +1,38 @@ +inherit_from: .relaxed-rubocop-2.4.yml + +AllCops: + TargetRubyVersion: 3.0 + UseCache: true + DefaultFormatter: progress + DisplayStyleGuide: true + DisplayCopNames: true + Exclude: + - "external*/**/*" + - "bazel-*/**/*" + - "**/examples/**/*" + - "**/BUILD" + - "**/*.bazel" + - "**/*.bzl" + - "**/rubocop" + - "**/vendor/bundle/**/*" + Include: + - '**/*.rb' + - '**/*.gemfile' + - '**/*.gemspec' + - '**/*.rake' + - '**/*.ru' + - '**/Gemfile' + - '**/Rakefile' + SuggestExtensions: false + NewCops: enable + +Layout/HashAlignment: + Enabled: true + EnforcedColonStyle: table + +Style/Dir: + Enabled: false + +# In Bazel we want to use __FILE__ because __dir__points to the actual sources +Style/ExpandPathArguments: + Enabled: false diff --git a/examples/simple_script_vendored/BUILD.bazel b/examples/simple_script_vendored/BUILD.bazel new file mode 100644 index 00000000..1fc2d136 --- /dev/null +++ b/examples/simple_script_vendored/BUILD.bazel @@ -0,0 +1,94 @@ +load( + "@bazelruby_rules_ruby//ruby:defs.bzl", + "ruby_binary", + "ruby_rspec", + "ruby_rubocop", + "ruby_test", +) + +package(default_visibility = ["//:__subpackages__"]) + +ruby_binary( + name = "bin", + srcs = ["script.rb"], + main = "script.rb", + deps = [ + "//lib:foo", + ], +) + +# This is an example of the RSpec definition that uses autorun +# and points to spec_helper as the main spec file. It specifies +# which specs to run using the args. + +ruby_test( + name = "all-specs", + timeout = "short", + srcs = [ + "script.rb", + "//lib:foo", + ] + glob([ + "spec/**/*.rb", + ]), + # This is a WORKSPACE-relative path to a spec directory. + # It could be longer, like "my/path/to/spec". + args = [ + "spec", + ], + main = "@bundle//:bin/rspec", + deps = [ + "@bundle//:bin", + "@bundle//:rspec", + "@bundle//:rspec-its", + ], +) + +# Finally, this is the short version of the same thing, expressed +# via the ruby_rspec_test rule that does what the above example +# shows but encapsulated in the rule itself. It adds rspec and rspec-its +# gems to the dependency list, executes bin/rspec and passes spec_targets +# as arguments to rspec. +ruby_rspec( + name = "ruby-rspec-test", + srcs = [ + "script.rb", + "//lib:foo", + ], + rspec_args = { + # NOTE: the output is only visible with --test_output=streamed flag + "--format": "progress", # this is how we can override rspec output format + }, + specs = glob([ + "spec/**/*.rb", + ]), + deps = [], +) + +ruby_binary( + name = "rubocop-bin", + srcs = [ + "script.rb", + "//lib:foo", + ] + glob([ + "spec/**/*.rb", + ]), + args = [ + "-- *.rb spec/*.rb lib/*.rb -a", + ], + main = "@bundle//:bin/rubocop", + deps = [ + "//lib:foo", + "@bundle//:bin", + ], +) + +# Rubocop rule +# To check +# bazel run rubocop -- -a +ruby_rubocop( + name = "rubocop", + bin = "@bundle//:bin/rubocop", + deps = [ + "@bundle//:rubocop", + ], +) diff --git a/examples/simple_script_vendored/Gemfile b/examples/simple_script_vendored/Gemfile new file mode 100644 index 00000000..48bd8b2d --- /dev/null +++ b/examples/simple_script_vendored/Gemfile @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +source 'https://rubygems.org' + +gem 'rspec', '~> 3.7.0' +gem 'rspec-its' +gem 'rubocop' diff --git a/examples/simple_script_vendored/Gemfile.lock b/examples/simple_script_vendored/Gemfile.lock new file mode 100644 index 00000000..315f6e68 --- /dev/null +++ b/examples/simple_script_vendored/Gemfile.lock @@ -0,0 +1,51 @@ +GEM + remote: https://rubygems.org/ + specs: + ast (2.4.2) + diff-lcs (1.4.4) + parallel (1.21.0) + parser (3.0.2.0) + ast (~> 2.4.1) + rainbow (3.0.0) + regexp_parser (2.1.1) + rexml (3.2.5) + rspec (3.7.0) + rspec-core (~> 3.7.0) + rspec-expectations (~> 3.7.0) + rspec-mocks (~> 3.7.0) + rspec-core (3.7.1) + rspec-support (~> 3.7.0) + rspec-expectations (3.7.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.7.0) + rspec-its (1.3.0) + rspec-core (>= 3.0.0) + rspec-expectations (>= 3.0.0) + rspec-mocks (3.7.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.7.0) + rspec-support (3.7.1) + rubocop (1.21.0) + parallel (~> 1.10) + parser (>= 3.0.0.0) + rainbow (>= 2.2.2, < 4.0) + regexp_parser (>= 1.8, < 3.0) + rexml + rubocop-ast (>= 1.9.1, < 2.0) + ruby-progressbar (~> 1.7) + unicode-display_width (>= 1.4.0, < 3.0) + rubocop-ast (1.11.0) + parser (>= 3.0.1.1) + ruby-progressbar (1.11.0) + unicode-display_width (2.1.0) + +PLATFORMS + ruby + +DEPENDENCIES + rspec (~> 3.7.0) + rspec-its + rubocop + +BUNDLED WITH + 2.2.24 diff --git a/examples/simple_script_vendored/README.md b/examples/simple_script_vendored/README.md new file mode 100644 index 00000000..4949968e --- /dev/null +++ b/examples/simple_script_vendored/README.md @@ -0,0 +1,17 @@ +# Simple Script Example + +This Workspace includes a simple ruby script that includes and external gem and an internal library + +### Bundle + +Update gemfile using +``` +bundle update +``` + +### Rubocop +Run rubocop with: + +``` +bazel run //:rubocop +``` diff --git a/examples/simple_script_vendored/WORKSPACE b/examples/simple_script_vendored/WORKSPACE new file mode 100644 index 00000000..3aff264d --- /dev/null +++ b/examples/simple_script_vendored/WORKSPACE @@ -0,0 +1,34 @@ +workspace( + name = "bazelruby_rules_ruby_example", + managed_directories = {"@bundle": ["vendor"]}, +) + +# Importing rules_ruby from the parent directory for developing +# rules_ruby itself... +local_repository( + name = "bazelruby_rules_ruby", + path = "../..", +) + +load( + "@bazelruby_rules_ruby//ruby:deps.bzl", + "rules_ruby_dependencies", + "rules_ruby_select_sdk", +) + +rules_ruby_dependencies() + +rules_ruby_select_sdk(version = "2.7.1") + +load("@bazelruby_rules_ruby//ruby:defs.bzl", "ruby_bundle") + +ruby_bundle( + name = "bundle", + bundler_version = "2.1.2", + excludes = { + "mini_portile": ["test/**/*"], + }, + gemfile = "//:Gemfile", + gemfile_lock = "//:Gemfile.lock", + vendor_cache = True, +) diff --git a/examples/simple_script_vendored/lib/BUILD b/examples/simple_script_vendored/lib/BUILD new file mode 100644 index 00000000..f125ff86 --- /dev/null +++ b/examples/simple_script_vendored/lib/BUILD @@ -0,0 +1,11 @@ +load( + "@bazelruby_rules_ruby//ruby:defs.bzl", + "ruby_library", +) + +package(default_visibility = ["//:__subpackages__"]) + +ruby_library( + name = "foo", + srcs = ["foo.rb"], +) diff --git a/examples/simple_script_vendored/lib/foo.rb b/examples/simple_script_vendored/lib/foo.rb new file mode 100644 index 00000000..eff4466c --- /dev/null +++ b/examples/simple_script_vendored/lib/foo.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +class Foo + class << self + def yell_aha + puts aha + end + + def aha + 'You said, aha?' + end + + def rot13(value) + return nil unless value.is_a?(String) + + value.tr('abcdefghijklmnopqrstuvwxyz', 'nopqrstuvwxyzabcdefghijklm') + end + end + + attr_reader :goo, :foo + + def initialize(goo) + @goo = goo + @foo = transform(goo) + end + + def transform(incoming = goo) + Foo.rot13(incoming) + end +end diff --git a/examples/simple_script_vendored/script.rb b/examples/simple_script_vendored/script.rb new file mode 100644 index 00000000..64c6ea20 --- /dev/null +++ b/examples/simple_script_vendored/script.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +require 'openssl' + +require_relative 'lib/foo' + +def oss_rand + OpenSSL::BN.rand(512).to_s +end + +puts Foo.aha + ' ' + oss_rand diff --git a/examples/simple_script_vendored/spec/lib/foo_spec.rb b/examples/simple_script_vendored/spec/lib/foo_spec.rb new file mode 100644 index 00000000..31ca6658 --- /dev/null +++ b/examples/simple_script_vendored/spec/lib/foo_spec.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +require_relative '../spec_helper' +require_relative '../../lib/foo' + +RSpec.describe Foo do + let(:goo) { 'Green slime was dripping down his throat into his lapdomen...' } + subject(:foo) { Foo.new(goo) } + + context 'without the aha' do + before { allow(Foo).to receive(:yell_aha).and_return('tiny dongle') } + + it "should have goo" do + expect(subject.goo).to eql goo + end + it "should have transformed goo" do + expect(subject.transform).not_to eql goo + end + + # Some rot13 old school encryption :) + it "should use rot13 for transform" do + expect(subject.transform).to eql 'Gerra fyvzr jnf qevccvat qbja uvf guebng vagb uvf yncqbzra...' + end + end + + context 'aha' do + it 'should print aha' do + expect(Foo).to receive(:puts).with('You said, aha?').and_return(nil) + Foo.yell_aha + end + end +end diff --git a/examples/simple_script_vendored/spec/script_spec.rb b/examples/simple_script_vendored/spec/script_spec.rb new file mode 100644 index 00000000..458b928c --- /dev/null +++ b/examples/simple_script_vendored/spec/script_spec.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +require 'spec_helper' +require 'script' + +describe 'oss_rand' do + it 'generates a String' do + expect(oss_rand).to be_a_kind_of String + end +end diff --git a/examples/simple_script_vendored/spec/spec_helper.rb b/examples/simple_script_vendored/spec/spec_helper.rb new file mode 100644 index 00000000..9de82de9 --- /dev/null +++ b/examples/simple_script_vendored/spec/spec_helper.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +# Sets HOME here because: +# If otherwise, it causes a runtime failure with the following steps. +# 1. RSpec::Core::ConfigurationOptions.global_options_file raises an exception +# because $HOME is not set in the sandbox environment of Bazel +# 2. the rescue clause calls RSpec::Support.#warning +# 3. #warning calls #warn_with +# 4. #warn_with tries to lookup the first caller which is not a part of RSpec. +# But all the call stack entires are about RSpec at this time because +# it is invoked by rpsec/autorun. So #warn_with raises an exception +# 5. The process fails with an unhandled exception. + +LIB = File.expand_path(File.dirname(__dir__)) +$LOAD_PATH.unshift(LIB) unless $LOAD_PATH.include?(LIB) + +ENV["HOME"] ||= "/" + +require "rspec" +require "script" + +RSpec.configure do |config| + config.expect_with :rspec do |expectations| + expectations.include_chain_clauses_in_custom_matcher_descriptions = true + end + + config.mock_with :rspec do |mocks| + mocks.verify_partial_doubles = true + end + + config.shared_context_metadata_behavior = :apply_to_host_groups + + config.warnings = true + config.filter_run_when_matching :focus + # config.disable_monkey_patching! + config.order = :random + Kernel.srand config.seed +end diff --git a/examples/simple_script_vendored/vendor/cache/ast-2.4.2.gem b/examples/simple_script_vendored/vendor/cache/ast-2.4.2.gem new file mode 100644 index 00000000..abe16436 Binary files /dev/null and b/examples/simple_script_vendored/vendor/cache/ast-2.4.2.gem differ diff --git a/examples/simple_script_vendored/vendor/cache/diff-lcs-1.4.4.gem b/examples/simple_script_vendored/vendor/cache/diff-lcs-1.4.4.gem new file mode 100644 index 00000000..3be4edc1 Binary files /dev/null and b/examples/simple_script_vendored/vendor/cache/diff-lcs-1.4.4.gem differ diff --git a/examples/simple_script_vendored/vendor/cache/parallel-1.21.0.gem b/examples/simple_script_vendored/vendor/cache/parallel-1.21.0.gem new file mode 100644 index 00000000..ca8f6362 Binary files /dev/null and b/examples/simple_script_vendored/vendor/cache/parallel-1.21.0.gem differ diff --git a/examples/simple_script_vendored/vendor/cache/parser-3.0.2.0.gem b/examples/simple_script_vendored/vendor/cache/parser-3.0.2.0.gem new file mode 100644 index 00000000..ee615aaa Binary files /dev/null and b/examples/simple_script_vendored/vendor/cache/parser-3.0.2.0.gem differ diff --git a/examples/simple_script_vendored/vendor/cache/rainbow-3.0.0.gem b/examples/simple_script_vendored/vendor/cache/rainbow-3.0.0.gem new file mode 100644 index 00000000..c53caf7a Binary files /dev/null and b/examples/simple_script_vendored/vendor/cache/rainbow-3.0.0.gem differ diff --git a/examples/simple_script_vendored/vendor/cache/regexp_parser-2.1.1.gem b/examples/simple_script_vendored/vendor/cache/regexp_parser-2.1.1.gem new file mode 100644 index 00000000..4bb25a0e Binary files /dev/null and b/examples/simple_script_vendored/vendor/cache/regexp_parser-2.1.1.gem differ diff --git a/examples/simple_script_vendored/vendor/cache/rexml-3.2.5.gem b/examples/simple_script_vendored/vendor/cache/rexml-3.2.5.gem new file mode 100644 index 00000000..5680fec4 Binary files /dev/null and b/examples/simple_script_vendored/vendor/cache/rexml-3.2.5.gem differ diff --git a/examples/simple_script_vendored/vendor/cache/rspec-3.7.0.gem b/examples/simple_script_vendored/vendor/cache/rspec-3.7.0.gem new file mode 100644 index 00000000..6ce573a5 Binary files /dev/null and b/examples/simple_script_vendored/vendor/cache/rspec-3.7.0.gem differ diff --git a/examples/simple_script_vendored/vendor/cache/rspec-core-3.7.1.gem b/examples/simple_script_vendored/vendor/cache/rspec-core-3.7.1.gem new file mode 100644 index 00000000..d949df80 Binary files /dev/null and b/examples/simple_script_vendored/vendor/cache/rspec-core-3.7.1.gem differ diff --git a/examples/simple_script_vendored/vendor/cache/rspec-expectations-3.7.0.gem b/examples/simple_script_vendored/vendor/cache/rspec-expectations-3.7.0.gem new file mode 100644 index 00000000..119eda3e Binary files /dev/null and b/examples/simple_script_vendored/vendor/cache/rspec-expectations-3.7.0.gem differ diff --git a/examples/simple_script_vendored/vendor/cache/rspec-its-1.3.0.gem b/examples/simple_script_vendored/vendor/cache/rspec-its-1.3.0.gem new file mode 100644 index 00000000..bcff4af6 Binary files /dev/null and b/examples/simple_script_vendored/vendor/cache/rspec-its-1.3.0.gem differ diff --git a/examples/simple_script_vendored/vendor/cache/rspec-mocks-3.7.0.gem b/examples/simple_script_vendored/vendor/cache/rspec-mocks-3.7.0.gem new file mode 100644 index 00000000..f34bef2e Binary files /dev/null and b/examples/simple_script_vendored/vendor/cache/rspec-mocks-3.7.0.gem differ diff --git a/examples/simple_script_vendored/vendor/cache/rspec-support-3.7.1.gem b/examples/simple_script_vendored/vendor/cache/rspec-support-3.7.1.gem new file mode 100644 index 00000000..4d29cf93 Binary files /dev/null and b/examples/simple_script_vendored/vendor/cache/rspec-support-3.7.1.gem differ diff --git a/examples/simple_script_vendored/vendor/cache/rubocop-1.21.0.gem b/examples/simple_script_vendored/vendor/cache/rubocop-1.21.0.gem new file mode 100644 index 00000000..ddeba664 Binary files /dev/null and b/examples/simple_script_vendored/vendor/cache/rubocop-1.21.0.gem differ diff --git a/examples/simple_script_vendored/vendor/cache/rubocop-ast-1.11.0.gem b/examples/simple_script_vendored/vendor/cache/rubocop-ast-1.11.0.gem new file mode 100644 index 00000000..9a444dae Binary files /dev/null and b/examples/simple_script_vendored/vendor/cache/rubocop-ast-1.11.0.gem differ diff --git a/examples/simple_script_vendored/vendor/cache/ruby-progressbar-1.11.0.gem b/examples/simple_script_vendored/vendor/cache/ruby-progressbar-1.11.0.gem new file mode 100644 index 00000000..a9d84e50 Binary files /dev/null and b/examples/simple_script_vendored/vendor/cache/ruby-progressbar-1.11.0.gem differ diff --git a/examples/simple_script_vendored/vendor/cache/unicode-display_width-2.1.0.gem b/examples/simple_script_vendored/vendor/cache/unicode-display_width-2.1.0.gem new file mode 100644 index 00000000..bec8f2a7 Binary files /dev/null and b/examples/simple_script_vendored/vendor/cache/unicode-display_width-2.1.0.gem differ diff --git a/ruby/defs.bzl b/ruby/defs.bzl index f4716e2f..1777d38d 100644 --- a/ruby/defs.bzl +++ b/ruby/defs.bzl @@ -1,56 +1,44 @@ load( - "@bazelruby_ruby_rules//ruby/private:toolchain.bzl", + "@bazelruby_rules_ruby//ruby/private:toolchain.bzl", _toolchain = "ruby_toolchain", ) load( - "@bazelruby_ruby_rules//ruby/private:library.bzl", + "@bazelruby_rules_ruby//ruby/private:library.bzl", _library = "ruby_library", ) load( - "@bazelruby_ruby_rules//ruby/private:binary.bzl", + "@bazelruby_rules_ruby//ruby/private:binary.bzl", _binary = "ruby_binary", _test = "ruby_test", ) load( - "@bazelruby_ruby_rules//ruby/private:bundle.bzl", - _ruby_bundle = "ruby_bundle", + "@bazelruby_rules_ruby//ruby/private/bundle:def.bzl", + _bundle = "bundle_install", + _ruby_bundle = "ruby_bundle_install", ) load( - "@bazelruby_ruby_rules//ruby/private:rspec.bzl", - _ruby_rspec = "ruby_rspec", - _ruby_rspec_test = "ruby_rspec_test", + "@bazelruby_rules_ruby//ruby/private:rspec.bzl", + _rspec = "ruby_rspec", + _rspec_test = "ruby_rspec_test", ) load( - "@bazelruby_ruby_rules//ruby/private/rubocop:def.bzl", + "@bazelruby_rules_ruby//ruby/private/rubocop:def.bzl", _rubocop = "rubocop", ) load( - "@bazelruby_ruby_rules//ruby/private:gemspec.bzl", - _gemspec = "rb_gemspec", -) -load( - "@bazelruby_ruby_rules//ruby/private:gem.bzl", - _gem = "rb_gem", + "@bazelruby_rules_ruby//ruby/private/gemspec:def.bzl", + _gem = "gem", + _gemspec = "gemspec", ) ruby_toolchain = _toolchain - ruby_library = _library ruby_binary = _binary ruby_test = _test -ruby_rspec_test = _ruby_rspec_test -ruby_rspec = _ruby_rspec +ruby_rspec_test = _rspec_test +ruby_rspec = _rspec ruby_bundle = _ruby_bundle +ruby_bundle_install = _bundle ruby_rubocop = _rubocop ruby_gemspec = _gemspec ruby_gem = _gem - -rb_toolchain = _toolchain -rb_library = _library -rb_binary = _binary -rb_test = _test -rb_rspec = _ruby_rspec -rb_bundle = _ruby_bundle -rb_rubocop = _rubocop -rb_gemspec = _gemspec -rb_gem = _gem diff --git a/ruby/deps.bzl b/ruby/deps.bzl index a520bfc1..3a7c45b7 100644 --- a/ruby/deps.bzl +++ b/ruby/deps.bzl @@ -1,13 +1,12 @@ # Repository rules load( - "@bazelruby_ruby_rules//ruby/private:dependencies.bzl", - _ruby_rules_dependencies = "ruby_rules_dependencies", + "@bazelruby_rules_ruby//ruby/private:dependencies.bzl", + _rules_ruby_dependencies = "rules_ruby_dependencies", ) load( - "@bazelruby_ruby_rules//ruby/private:sdk.bzl", - _register_toolchains = "ruby_register_toolchains", + "@bazelruby_rules_ruby//ruby/private:sdk.bzl", + _rules_ruby_select_sdk = "rules_ruby_select_sdk", ) -ruby_rules_dependencies = _ruby_rules_dependencies - -ruby_register_toolchains = _register_toolchains +rules_ruby_dependencies = _rules_ruby_dependencies +rules_ruby_select_sdk = _rules_ruby_select_sdk diff --git a/ruby/private/BUILD.bazel b/ruby/private/BUILD.bazel index cb0b35a8..1c16e04c 100644 --- a/ruby/private/BUILD.bazel +++ b/ruby/private/BUILD.bazel @@ -1,7 +1,6 @@ exports_files( [ "binary_wrapper.tpl", - "gemspec_template.tpl", ], visibility = ["//visibility:public"], ) diff --git a/ruby/private/binary_wrapper.tpl b/ruby/private/binary_wrapper.tpl old mode 100644 new mode 100755 index 159f509b..09e04024 --- a/ruby/private/binary_wrapper.tpl +++ b/ruby/private/binary_wrapper.tpl @@ -20,6 +20,14 @@ require 'rbconfig' +# Ruby 2.4 and older does not have +.children+ +# So we define it. +unless Dir.respond_to?(:children) + Dir.class.send :define_method, :children do |dir| + Dir.entries(dir).reject { |entry| %w(. ..).include?(entry) } + end +end + def find_runfiles stub_filename = File.absolute_path($0) runfiles = "#{stub_filename}.runfiles" @@ -44,7 +52,8 @@ def create_loadpath_entries(custom, runfiles) end def get_repository_imports(runfiles) - Dir.children(runfiles).map {|d| + children = Dir.entries(runfiles) - [".", ".."] + children.map {|d| File.join(runfiles, d) }.select {|d| File.directory? d @@ -110,8 +119,8 @@ def main(args) runfiles_envkey, runfiles_envvalue = runfiles_envvar(runfiles) ENV[runfiles_envkey] = runfiles_envvalue if runfiles_envkey - ENV["GEM_PATH"] = File.join(runfiles, "{gem_path}") if "{gem_path}" - ENV["GEM_HOME"] = File.join(runfiles, "{gem_path}") if "{gem_path}" + ENV["GEM_PATH"] = File.join(runfiles, "{gem_path}") if !"{gem_path}".empty? + ENV["GEM_HOME"] = File.join(runfiles, "{gem_path}") if !"{gem_path}".empty? ruby_program = find_ruby_binary diff --git a/ruby/private/bundle.bzl b/ruby/private/bundle.bzl deleted file mode 100644 index 292d6e11..00000000 --- a/ruby/private/bundle.bzl +++ /dev/null @@ -1,7 +0,0 @@ -load( - "//ruby/private/bundle:bundle.bzl", - _ruby_bundle = "ruby_bundle", -) - -bundle_install = _ruby_bundle -ruby_bundle = _ruby_bundle diff --git a/ruby/private/bundle/create_bundle_build_file.rb b/ruby/private/bundle/create_bundle_build_file.rb index b283b404..2dcc6d4a 100755 --- a/ruby/private/bundle/create_bundle_build_file.rb +++ b/ruby/private/bundle/create_bundle_build_file.rb @@ -33,14 +33,14 @@ srcs = glob( include = [ ".bundle/config", - "{gem_lib_files}", - "lib/ruby/{ruby_version}/specifications/{name}-{version}.gemspec", + {gem_lib_files}, + "{gem_spec}", {gem_binaries} ], exclude = {exclude}, ), deps = {deps}, - includes = ["lib/ruby/{ruby_version}/gems/{name}-{version}/lib"], + includes = [{gem_lib_paths}], ) GEM_TEMPLATE @@ -58,10 +58,34 @@ ) ALL_GEMS +# For ordinary gems, this path is like 'lib/ruby/3.0.0/gems/rspec-3.10.0'. +# For gems with native extension installed via prebuilt packages, the last part of this path can +# contain an OS-specific suffix like 'grpc-1.38.0-universal-darwin' or 'grpc-1.38.0-x86_64-linux' +# instead of 'grpc-1.38.0'. +# +# Since OS platform is unlikely to change between Bazel builds on the same machine, +# `#{gem_name}-#{gem_version}*` would be sufficient to narrow down matches to at most one. +# +# Library path differs across implementations as `lib/ruby` on MRI and `lib/jruby` on JRuby. GEM_PATH = ->(ruby_version, gem_name, gem_version) do - "lib/ruby/#{ruby_version}/gems/#{gem_name}-#{gem_version}" + Dir.glob("lib/#{RbConfig::CONFIG['RUBY_INSTALL_NAME']}/#{ruby_version}/gems/#{gem_name}-#{gem_version}*").first end +# For ordinary gems, this path is like 'lib/ruby/3.0.0/specifications/rspec-3.10.0.gemspec'. +# For gems with native extension installed via prebuilt packages, the last part of this path can +# contain an OS-specific suffix like 'grpc-1.38.0-universal-darwin.gemspec' or +# 'grpc-1.38.0-x86_64-linux.gemspec' instead of 'grpc-1.38.0.gemspec'. +# +# Since OS platform is unlikely to change between Bazel builds on the same machine, +# `#{gem_name}-#{gem_version}*.gemspec` would be sufficient to narrow down matches to at most one. +# +# Library path differs across implementations as `lib/ruby` on MRI and `lib/jruby` on JRuby. +SPEC_PATH = ->(ruby_version, gem_name, gem_version) do + Dir.glob("lib/#{RbConfig::CONFIG['RUBY_INSTALL_NAME']}/#{ruby_version}/specifications/#{gem_name}-#{gem_version}*.gemspec").first +end + +HERE = File.absolute_path '.' + require 'bundler' require 'json' require 'stringio' @@ -96,8 +120,11 @@ class Buildifier # @formatter:off class BuildifierError < StandardError; end + class BuildifierNotFoundError < BuildifierError; end + class BuildifierFailedError < BuildifierError; end + class BuildifierNoBuildFileError < BuildifierError; end # @formatter:on @@ -133,8 +160,7 @@ def buildify! puts 'Buildifier gave ๐Ÿ‘ '.green + (output ? " and said: #{output}" : '') else raise BuildifierFailedError, - 'Generated BUILD file failed buildifier, with error โ€” '.red + "\n\n" + - output.yellow + "Generated BUILD file failed buildifier, with error:\n\n#{output.yellow}\n\n".red end end end @@ -144,6 +170,7 @@ class BundleBuildFileGenerator :repo_name, :build_file, :gemfile_lock, + :includes, :excludes, :ruby_version @@ -155,11 +182,13 @@ def initialize(workspace_name:, repo_name:, build_file: 'BUILD.bazel', gemfile_lock: 'Gemfile.lock', + includes: nil, excludes: nil) @workspace_name = workspace_name @repo_name = repo_name @build_file = build_file @gemfile_lock = gemfile_lock + @includes = includes @excludes = excludes # This attribute returns 0 as the third minor version number, which happens to be # what Ruby uses in the PATH to gems, eg. ruby 2.6.5 would have a folder called @@ -222,8 +251,38 @@ def remove_bundler_version! end def register_gem(spec, template_out, bundle_lib_paths, bundle_binaries) - gem_path = GEM_PATH[ruby_version, spec.name, spec.version] - bundle_lib_paths << gem_lib_path = gem_path + '/lib' + # Do not register local gems + return if spec.source.path? + + base_dir = "lib/ruby/#{ruby_version}" + if spec.source.is_a?(Bundler::Source::Git) + stub = spec.source.specs.find { |s| s.name == spec.name }.stub + gem_path = "#{base_dir}/bundler/gems/#{Pathname(stub.full_gem_path).relative_path_from(stub.base_dir)}" + spec_path = "#{base_dir}/bundler/gems/#{Pathname(stub.loaded_from).relative_path_from(stub.base_dir)}" + + # paths to register to $LOAD_PATH + require_paths = stub.require_paths + else + gem_path = GEM_PATH[ruby_version, spec.name, spec.version] + spec_path = SPEC_PATH[ruby_version, spec.name, spec.version] + + # paths to register to $LOAD_PATH + require_paths = Gem::StubSpecification.gemspec_stub(spec_path, base_dir, "#{base_dir}/gems").require_paths + end + + # Usually, registering the directory paths listed in the `require_paths` of gemspecs is sufficient, but + # some gems also require additional paths to be included in the load paths. + require_paths += include_array(spec.name) + gem_lib_paths = require_paths.map do |require_path| + # Gems with native extensions (like ffi) will sometimes have elements of + # require_paths that are absolute rather than gem-path relative paths. + # It is incorrect to prepend those paths with the gem_path and Bazel will + # only allow relative paths as inputs to its glob() function. + pathname = Pathname.new(require_path) + pathname.absolute? ? pathname.relative_path_from(HERE).to_s : File.join(gem_path, require_path) + end + + bundle_lib_paths.push(*gem_lib_paths) # paths to search for executables gem_binaries = find_bundle_binaries(gem_path) @@ -234,8 +293,9 @@ def register_gem(spec, template_out, bundle_lib_paths, bundle_binaries) warn("registering gem #{spec.name} with binaries: #{gem_binaries}") if bundle_binaries.key?(spec.name) template_out.puts GEM_TEMPLATE - .gsub('{gem_lib_path}', gem_lib_path) - .gsub('{gem_lib_files}', gem_lib_path + '/**/*') + .gsub('{gem_lib_paths}', to_flat_string(gem_lib_paths)) + .gsub('{gem_lib_files}', to_flat_string(gem_lib_paths.map { |p| "#{p}/**/*" })) + .gsub('{gem_spec}', spec_path) .gsub('{gem_binaries}', to_flat_string(gem_binaries)) .gsub('{exclude}', exclude_array(spec.name).to_s) .gsub('{name}', spec.name) @@ -259,7 +319,11 @@ def find_bundle_binaries(gem_path) end.flatten .compact .sort - .map { |binary| 'bin/' + binary } + .map { |binary| "bin/#{binary}" } + end + + def include_array(gem_name) + (includes[gem_name] || []) end def exclude_array(gem_name) @@ -271,18 +335,19 @@ def to_flat_string(array) end end -# ruby ./create_bundle_build_file.rb "BUILD.bazel" "Gemfile.lock" "repo_name" "[]" "wsp_name" +# ruby ./create_bundle_build_file.rb "BUILD.bazel" "Gemfile.lock" "repo_name" "{}" "{}" "wsp_name" if $0 == __FILE__ - if ARGV.length != 5 - warn("USAGE: #{$0} BUILD.bazel Gemfile.lock repo-name [excludes-json] workspace-name".orange) + if ARGV.length != 6 + warn("USAGE: #{$0} BUILD.bazel Gemfile.lock repo-name {includes-json} {excludes-json} workspace-name".orange) exit(1) end - build_file, gemfile_lock, repo_name, excludes, workspace_name, * = *ARGV + build_file, gemfile_lock, repo_name, includes, excludes, workspace_name, * = *ARGV BundleBuildFileGenerator.new(build_file: build_file, gemfile_lock: gemfile_lock, repo_name: repo_name, + includes: JSON.parse(includes), excludes: JSON.parse(excludes), workspace_name: workspace_name).generate! diff --git a/ruby/private/bundle/bundle.bzl b/ruby/private/bundle/def.bzl similarity index 81% rename from ruby/private/bundle/bundle.bzl rename to ruby/private/bundle/def.bzl index afe51ce0..e368bd4c 100644 --- a/ruby/private/bundle/bundle.bzl +++ b/ruby/private/bundle/def.bzl @@ -8,8 +8,7 @@ load( "SCRIPT_BUILD_FILE_GENERATOR", "SCRIPT_INSTALL_GEM", ) -load("//ruby/private:providers.bzl", "RubyRuntimeContext") -load("//ruby/private/tools:deprecations.bzl", "deprecated_attribute") +load("//ruby/private:providers.bzl", "RubyRuntimeInfo") # Runs bundler with arbitrary arguments # eg: run_bundler(runtime_ctx, [ "lock", " --gemfile", "Gemfile.rails5" ]) @@ -20,7 +19,7 @@ def run_bundler(runtime_ctx, bundler_arguments, previous_result): # add --verbose to all commands except install if bundler_command != "install": - bundler_args += ["--verbose"] + bundler_args.append("--verbose") bundler_args += bundler_arguments[1:] @@ -115,16 +114,20 @@ def install_bundler(runtime_ctx, bundler_version): ) def bundle_install(runtime_ctx, previous_result): + cwd = runtime_ctx.ctx.path(".") + bundler_args = [ + "install", + "--binstubs={}".format(cwd.get_child(BUNDLE_BIN_PATH)), + "--path={}".format(cwd.get_child(BUNDLE_PATH)), + "--standalone", + "--gemfile={}".format(runtime_ctx.ctx.attr.gemfile.name), + ] + if runtime_ctx.ctx.attr.gemfile_lock: + bundler_args += ["--deployment", "--frozen"] + result = run_bundler( runtime_ctx, - [ - "install", - "--binstubs={}".format(BUNDLE_BIN_PATH), - "--path={}".format(BUNDLE_PATH), - "--deployment", - "--standalone", - "--frozen", - ], + bundler_args, previous_result, ) @@ -134,6 +137,11 @@ def bundle_install(runtime_ctx, previous_result): return result def generate_bundle_build_file(runtime_ctx, previous_result): + if runtime_ctx.ctx.attr.gemfile_lock: + gemfile_lock = runtime_ctx.ctx.attr.gemfile_lock.name + else: + gemfile_lock = "{}.lock".format(runtime_ctx.ctx.attr.gemfile.name) + # Create the BUILD file to expose the gems to the WORKSPACE # USAGE: ./create_bundle_build_file.rb BUILD.bazel Gemfile.lock repo-name [excludes-json] workspace-name args = [ @@ -143,8 +151,9 @@ def generate_bundle_build_file(runtime_ctx, previous_result): "bundler/lib", SCRIPT_BUILD_FILE_GENERATOR, # The template used to created bundle file "BUILD.bazel", # Bazel build file (can be empty) - "Gemfile.lock", # Gemfile.lock where we list all direct and transitive dependencies + gemfile_lock, # Gemfile.lock where we list all direct and transitive dependencies runtime_ctx.ctx.name, # Name of the target + repr(runtime_ctx.ctx.attr.includes), repr(runtime_ctx.ctx.attr.excludes), RULES_RUBY_WORKSPACE_NAME, ] @@ -154,20 +163,23 @@ def generate_bundle_build_file(runtime_ctx, previous_result): fail("build file generation failed: %s%s" % (result.stdout, result.stderr)) def _ruby_bundle_impl(ctx): - ctx.symlink(ctx.attr.gemfile, "Gemfile") - ctx.symlink(ctx.attr.gemfile_lock, "Gemfile.lock") + ctx.symlink(ctx.attr.gemfile, ctx.attr.gemfile.name) + if ctx.attr.gemfile_lock: + ctx.symlink(ctx.attr.gemfile_lock, ctx.attr.gemfile_lock.name) + if ctx.attr.vendor_cache: + ctx.symlink( + ctx.path(str(ctx.path(ctx.attr.gemfile).dirname) + "/vendor"), + ctx.path("vendor"), + ) ctx.symlink(ctx.attr._create_bundle_build_file, SCRIPT_BUILD_FILE_GENERATOR) ctx.symlink(ctx.attr._install_bundler, SCRIPT_INSTALL_GEM) + for src in ctx.attr.srcs: + ctx.symlink(src, src.name) - # version is too generic for this operation - deprecated_attribute(ctx, "version", "bundler_version") - if ctx.attr.bundler_version: - bundler_version = ctx.attr.bundler_version - else: - bundler_version = ctx.attr.version + bundler_version = ctx.attr.bundler_version # Setup this provider that we pass around between functions for convenience - runtime_ctx = RubyRuntimeContext( + runtime_ctx = RubyRuntimeInfo( ctx = ctx, interpreter = ctx.path(ctx.attr.ruby_interpreter), environment = {"RUBYOPT": "--enable-gems"}, @@ -185,7 +197,7 @@ def _ruby_bundle_impl(ctx): # 4. Generate the BUILD file for the bundle generate_bundle_build_file(runtime_ctx, result) -ruby_bundle = repository_rule( +ruby_bundle_install = repository_rule( implementation = _ruby_bundle_impl, attrs = BUNDLE_ATTRS, ) diff --git a/ruby/private/constants.bzl b/ruby/private/constants.bzl index d3d43e4f..a76f8f3f 100644 --- a/ruby/private/constants.bzl +++ b/ruby/private/constants.bzl @@ -1,9 +1,10 @@ -load(":providers.bzl", "RubyLibrary") +# Ruby Constants +load(":providers.bzl", "RubyLibraryInfo") -RULES_RUBY_WORKSPACE_NAME = "@bazelruby_ruby_rules" +RULES_RUBY_WORKSPACE_NAME = "@bazelruby_rules_ruby" TOOLCHAIN_TYPE_NAME = "%s//ruby:toolchain_type" % RULES_RUBY_WORKSPACE_NAME -DEFAULT_BUNDLER_VERSION = "2.1.2" +DEFAULT_BUNDLER_VERSION = "2.1.4" DEFAULT_RSPEC_ARGS = {"--format": "documentation", "--force-color": None} DEFAULT_RSPEC_GEMS = ["rspec", "rspec-its"] DEFAULT_BUNDLE_NAME = "@bundle//" @@ -20,7 +21,7 @@ RUBY_ATTRS = { allow_files = True, ), "deps": attr.label_list( - providers = [RubyLibrary], + providers = [RubyLibraryInfo], ), "includes": attr.string_list(), "rubyopt": attr.string_list(), @@ -78,14 +79,17 @@ BUNDLE_ATTRS = { "gemfile_lock": attr.label( allow_single_file = True, ), - "version": attr.string( - mandatory = False, + "srcs": attr.label_list( + allow_files = True, + ), + "vendor_cache": attr.bool( + doc = "Symlink the vendor directory into the Bazel build space, this allows Bundler to access vendored Gems", ), "bundler_version": attr.string( default = DEFAULT_BUNDLER_VERSION, ), - "gemspec": attr.label( - allow_single_file = True, + "includes": attr.string_list_dict( + doc = "List of glob patterns per gem to be additionally loaded from the library", ), "excludes": attr.string_list_dict( doc = "List of glob patterns per gem to be excluded from the library", @@ -106,3 +110,47 @@ BUNDLE_ATTRS = { allow_single_file = True, ), } + +GEMSPEC_ATTRS = { + "gem_name": attr.string(), + "gem_version": attr.string(default = "0.0.1"), + "gem_summary": attr.string(), + "gem_description": attr.string(), + "gem_homepage": attr.string(), + "gem_authors": attr.string_list(), + "gem_author_emails": attr.string_list(), + "gem_runtime_dependencies": attr.string_dict( + allow_empty = True, + doc = "Key value pairs of gem dependencies (name, version) where version can be None", + ), + "gem_development_dependencies": attr.string_dict( + allow_empty = True, + default = { + "rspec": "", + "rspec-its": "", + "rubocop": "", + }, + doc = "Key value pairs of gem dependencies (name, version) where version can be None", + ), + "srcs": attr.label_list( + allow_files = True, + default = [], + ), + "require_paths": attr.string_list( + default = ["lib"], + ), + "deps": attr.label_list( + allow_files = True, + ), + "data": attr.label_list( + allow_files = True, + ), + "_gemspec_template": attr.label( + allow_single_file = True, + default = "%s//ruby/private/gemspec:gemspec_template.tpl" % RULES_RUBY_WORKSPACE_NAME, + ), + "_readme_template": attr.label( + allow_single_file = True, + default = "%s//ruby/private/gemspec:readme_template.tpl" % RULES_RUBY_WORKSPACE_NAME, + ), +} diff --git a/ruby/private/dependencies.bzl b/ruby/private/dependencies.bzl index 150754b8..0a51d7a9 100644 --- a/ruby/private/dependencies.bzl +++ b/ruby/private/dependencies.bzl @@ -1,15 +1,18 @@ +""" +Dependencies +""" + load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") -load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") -def ruby_rules_dependencies(): +def rules_ruby_dependencies(): if "bazel_skylib" not in native.existing_rules(): http_archive( name = "bazel_skylib", urls = [ - "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.0.2/bazel-skylib-1.0.2.tar.gz", - "https://github.com/bazelbuild/bazel-skylib/releases/download/1.0.2/bazel-skylib-1.0.2.tar.gz", + "https://github.com/bazelbuild/bazel-skylib/releases/download/1.0.3/bazel-skylib-1.0.3.tar.gz", + "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.0.3/bazel-skylib-1.0.3.tar.gz", ], - sha256 = "97e70364e9249702246c0e9444bccdc4b847bed1eb03c5a3ece4f83dfe6abc44", + sha256 = "1c531376ac7e5a180e0237938a2536de0c54d93f5c278634818e0efc952dd56c", ) if "rules_pkg" not in native.existing_rules(): diff --git a/ruby/private/gem.bzl b/ruby/private/gem.bzl deleted file mode 100644 index 9108192d..00000000 --- a/ruby/private/gem.bzl +++ /dev/null @@ -1,31 +0,0 @@ -load( - ":gemspec.bzl", - _rb_gemspec = "rb_gemspec", -) -load( - "@rules_pkg//:pkg.bzl", - "pkg_zip", -) - -def rb_gem(name, version, gem_name, srcs = [], **kwargs): - _zip_name = "%s-%s" % (gem_name, version) - _gemspec_name = name + "_gemspec" - - _rb_gemspec( - name = _gemspec_name, - gem_name = gem_name, - version = version, - **kwargs - ) - - pkg_zip( - name = _zip_name, - srcs = srcs + [":" + _gemspec_name], - strip_prefix = "./", - ) - - native.alias( - name = name, - actual = ":" + _zip_name, - visibility = ["//visibility:public"], - ) diff --git a/ruby/private/gemspec.bzl b/ruby/private/gemspec.bzl deleted file mode 100644 index ee7bdac0..00000000 --- a/ruby/private/gemspec.bzl +++ /dev/null @@ -1,87 +0,0 @@ -load( - "//ruby/private/tools:deps.bzl", - _transitive_deps = "transitive_deps", -) -load( - "//ruby/private:providers.bzl", - "RubyGem", - "RubyLibrary", -) - -def _get_transitive_srcs(srcs, deps): - for dep in deps: - print(dep[RubyLibrary].transitive_ruby_srcs) - - return depset( - srcs, - transitive = [dep[RubyLibrary].transitive_ruby_srcs for dep in deps], - ) - -def _unique_elems(list): - _out = [] - _prev = None - for elem in sorted(list): - if _prev != elem: - _out.append(elem) - - return _out - -def _rb_gem_impl(ctx): - gemspec = ctx.actions.declare_file("%s.gemspec" % ctx.attr.gem_name) - - _ruby_files = [] - _require_paths = [] - for file in _get_transitive_srcs([], ctx.attr.deps).to_list(): - _ruby_files.append(file.short_path) - _require_paths.append(file.dirname) - - _require_paths = _unique_elems(_require_paths) # Set is not supported in Starlark - - ctx.actions.expand_template( - template = ctx.file._gemspec_template, - output = gemspec, - substitutions = { - "{name}": "\"%s\"" % ctx.label.name, - "{srcs}": repr(_ruby_files), - "{authors}": repr(ctx.attr.authors), - "{version}": ctx.attr.version, - "{require_paths}": repr(_require_paths), - }, - ) - - return [ - DefaultInfo(files = _get_transitive_srcs([gemspec], ctx.attr.deps)), - RubyGem( - ctx = ctx, - version = ctx.attr.version, - ), - ] - -_ATTRS = { - "version": attr.string( - default = "0.0.1", - ), - "authors": attr.string_list(), - "deps": attr.label_list( - allow_files = True, - ), - "data": attr.label_list( - allow_files = True, - ), - "_gemspec_template": attr.label( - allow_single_file = True, - default = "gemspec_template.tpl", - ), - "gem_name": attr.string(), - "srcs": attr.label_list( - allow_files = True, - default = [], - ), - "require_paths": attr.string_list(), -} - -rb_gemspec = rule( - implementation = _rb_gem_impl, - attrs = _ATTRS, - provides = [DefaultInfo, RubyGem], -) diff --git a/ruby/private/gemspec/BUILD.bazel b/ruby/private/gemspec/BUILD.bazel new file mode 100644 index 00000000..64bbe877 --- /dev/null +++ b/ruby/private/gemspec/BUILD.bazel @@ -0,0 +1,9 @@ +package(default_visibility = ["//ruby/private/gemspec:__pkg__"]) + +exports_files( + [ + "gemspec_template.tpl", + "readme_template.tpl", + ], + visibility = ["//visibility:public"], +) diff --git a/ruby/private/gemspec/def.bzl b/ruby/private/gemspec/def.bzl new file mode 100644 index 00000000..2f15a023 --- /dev/null +++ b/ruby/private/gemspec/def.bzl @@ -0,0 +1,176 @@ +load( + "//ruby/private:providers.bzl", + "RubyGemInfo", + "RubyLibraryInfo", +) +load( + "//ruby/private:constants.bzl", + "GEMSPEC_ATTRS", +) +load( + "@rules_pkg//:pkg.bzl", + "pkg_zip", +) + +def _get_transitive_srcs(srcs, deps): + for dep in deps: + print(dep[RubyLibraryInfo].transitive_ruby_srcs) + + return depset( + srcs, + transitive = [dep[RubyLibraryInfo].transitive_ruby_srcs for dep in deps], + ) + +def _unique_elems(list): + _out = [] + _prev = None + for elem in sorted(list): + if _prev != elem: + _out.append(elem) + + return _out + +# Converts gem name and optionally a version into a +# gemspec line "spec.add_[development_]dependency 'gem-name', [ 'gem-version' ]" +def _gem_dependency(name, version = "", development = False): + dependency_type = "spec.add_development_dependency" if development else "spec.add_runtime_dependency" + + output = "%s '%s'" % (dependency_type, name) + if version != "": + output += ", '%s'" % version + + return output + +# Converts gem name and optionally to a bullet list +def _markdown_gem_dependency(name, version = ""): + output = " * %s " % name + if version != "": + output += " (version %s) " % (version) + + return output + +def _markdown_ul(list = []): + return ("\n * " + "\n * ".join(list) + "\n") + +# Converts a dictionary (key = gem name, value = gem version or None) +# to a string to be inserted into the gemspec. +def _gem_runtime_dependencies(gem_dict = {}): + dependencies = [_gem_dependency(k, v) for k, v in gem_dict.items()] + return ("\n " + "\n ".join(dependencies)) + +# Converts a dictionary (key = gem name, value = gem version or None) +# to a string to be inserted into the gemspec. +def _markdown_gem_runtime_dependencies(gem_dict = {}, type = "Runtime"): + dependencies = [_markdown_gem_dependency(k, v) for k, v in gem_dict.items()] + output = "\n### %s Dependencies\n\n" % type + output += "\n " + "\n ".join(dependencies) + "\n\n" + return (output) + +def _gem_impl(ctx): + gemspec = ctx.actions.declare_file("%s.gemspec" % ctx.attr.gem_name) + gem_readme = ctx.actions.declare_file("README.md") + + _ruby_files = [] + _require_paths = [] + + for file in _get_transitive_srcs([], ctx.attr.deps).to_list(): + _ruby_files.append(file.short_path) + _require_paths.append(file.dirname) + + if len(_ruby_files) == 0: + _gem_sources = "`git ls-files -z`.split(\"\\x0\").reject { |f| f.match(/^(test|spec|features)\\//) }" + else: + _gem_sources = repr(_ruby_files) + + if ctx.attr.gem_homepage != "": + _gem_title = "[%s](%s)" % (ctx.attr.gem_name, ctx.attr.gem_homepage) + else: + _gem_title = "%s" % (ctx.attr.gem_name) + + ctx.actions.expand_template( + template = ctx.file._gemspec_template, + output = gemspec, + substitutions = { + "{gem_author_emails}": repr(ctx.attr.gem_author_emails), + "{gem_authors}": repr(ctx.attr.gem_authors), + "{gem_runtime_dependencies}": _gem_runtime_dependencies(ctx.attr.gem_runtime_dependencies), + "{gem_description}": ctx.attr.gem_description if ctx.attr.gem_description else ctx.attr.gem_summary, + "{gem_development_dependencies}": _gem_runtime_dependencies(ctx.attr.gem_development_dependencies), + "{gem_homepage}": ctx.attr.gem_homepage, + "{gem_name}": ctx.attr.gem_name, + "{gem_require_paths}": repr(["lib"]), + "{gem_sources}": _gem_sources, + "{gem_summary}": ctx.attr.gem_summary, + "{gem_version}": ctx.attr.gem_version, + }, + ) + + _dependencies = _markdown_gem_runtime_dependencies(ctx.attr.gem_runtime_dependencies, "Runtime") + _dependencies += _markdown_gem_runtime_dependencies(ctx.attr.gem_development_dependencies, "Development") + + ctx.actions.expand_template( + template = ctx.file._readme_template, + output = gem_readme, + substitutions = { + "{gem_authorship}": _markdown_ul(ctx.attr.gem_authors), + "{gem_runtime_dependencies}": _dependencies, + "{gem_description}": ctx.attr.gem_description if ctx.attr.gem_description else ctx.attr.gem_summary, + "{gem_name}": ctx.attr.gem_name, + "{gem_summary}": ctx.attr.gem_summary, + "{gem_title}": _gem_title, + "{gem_version}": ctx.attr.gem_version, + }, + ) + + return [ + DefaultInfo( + files = _get_transitive_srcs([gemspec, gem_readme], ctx.attr.deps), + ), + RubyGemInfo( + ctx = ctx, + gem_author_emails = ctx.attr.gem_author_emails, + gem_authors = ctx.attr.gem_authors, + gem_runtime_dependencies = ctx.attr.gem_runtime_dependencies, + gem_description = ctx.attr.gem_description, + gem_development_dependencies = ctx.attr.gem_development_dependencies, + gem_homepage = ctx.attr.gem_homepage, + gem_name = ctx.attr.gem_name, + gem_summary = ctx.attr.gem_summary, + gem_version = ctx.attr.gem_version, + ), + ] + +gemspec = rule( + implementation = _gem_impl, + attrs = GEMSPEC_ATTRS, + provides = [DefaultInfo, RubyGemInfo], +) + +def gem( + name, + gem_name, + gem_version, + srcs, + **kwargs): + _zip_name = "%s-%s" % (gem_name, gem_version) + _gemspec_name = name + ".gemspec" + + gemspec( + name = _gemspec_name, + gem_name = gem_name, + gem_version = gem_version, + srcs = srcs, + **kwargs + ) + + pkg_zip( + name = _zip_name, + srcs = srcs + [":" + _gemspec_name], + strip_prefix = "./", + ) + + native.alias( + name = name, + actual = ":" + _zip_name, + visibility = ["//visibility:public"], + ) diff --git a/ruby/private/gemspec/gemspec_template.tpl b/ruby/private/gemspec/gemspec_template.tpl new file mode 100644 index 00000000..7c0da029 --- /dev/null +++ b/ruby/private/gemspec/gemspec_template.tpl @@ -0,0 +1,25 @@ +# vim: ft=ruby +lib = File.expand_path('../lib', __FILE__) +$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) + +Gem::Specification.new do |spec| + spec.name = "{gem_name}" + spec.version = "{gem_version}" + spec.summary = "{gem_summary}" + spec.description = "{gem_description}" + spec.homepage = "{gem_homepage}" + + spec.authors = {gem_authors} + spec.email = {gem_author_emails} + + spec.files = {gem_sources} + spec.bindir = 'exe' + spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } + spec.require_paths = {gem_require_paths} + + spec.required_ruby_version = '>= 2.3' + + {gem_runtime_dependencies} + + {gem_development_dependencies} +end diff --git a/ruby/private/gemspec/readme_template.tpl b/ruby/private/gemspec/readme_template.tpl new file mode 100644 index 00000000..33b71d82 --- /dev/null +++ b/ruby/private/gemspec/readme_template.tpl @@ -0,0 +1,23 @@ +# {gem_title} + +## Version {gem_version} + +> NOTE: You are reading the auto-generated README for Gem {gem_name}. + +## Summary + +{gem_summary} + +## Description + +{gem_description} + +## Dependencies + +{gem_runtime_dependencies} + +## Author(s) + +Copyright © 2020 + +{gem_authorship} diff --git a/ruby/private/gemspec_template.tpl b/ruby/private/gemspec_template.tpl deleted file mode 100644 index 1c65d0b3..00000000 --- a/ruby/private/gemspec_template.tpl +++ /dev/null @@ -1,10 +0,0 @@ -Gem::Specification.new do |s| - s.name = {name} - s.summary = {name} - s.authors = {authors} - s.version = {version} - s.files = {srcs} - s.require_paths = {require_paths} - - s.add_dependency('csf') -end \ No newline at end of file diff --git a/ruby/private/library.bzl b/ruby/private/library.bzl index e91cb09f..b363c764 100644 --- a/ruby/private/library.bzl +++ b/ruby/private/library.bzl @@ -1,5 +1,9 @@ +""" +Constants +""" + load(":constants.bzl", "TOOLCHAIN_TYPE_NAME") -load(":providers.bzl", "RubyLibrary") +load(":providers.bzl", "RubyLibraryInfo") load( "//ruby/private/tools:deps.bzl", _transitive_deps = "transitive_deps", @@ -16,7 +20,7 @@ def _ruby_library_impl(ctx): data_runfiles = deps.data_files, files = deps.srcs, ), - RubyLibrary( + RubyLibraryInfo( transitive_ruby_srcs = deps.srcs, ruby_incpaths = deps.incpaths, rubyopt = deps.rubyopt, @@ -32,7 +36,7 @@ ruby_library = rule( "includes": attr.string_list(), "rubyopt": attr.string_list(), "deps": attr.label_list( - providers = [RubyLibrary], + providers = [RubyLibraryInfo], ), "data": attr.label_list( allow_files = True, diff --git a/ruby/private/providers.bzl b/ruby/private/providers.bzl index 10f466cc..131f3355 100644 --- a/ruby/private/providers.bzl +++ b/ruby/private/providers.bzl @@ -1,4 +1,8 @@ -RubyLibrary = provider( +""" +Provider Structs +""" + +RubyLibraryInfo = provider( fields = [ "transitive_ruby_srcs", "ruby_incpaths", @@ -6,7 +10,7 @@ RubyLibrary = provider( ], ) -RubyRuntimeContext = provider( +RubyRuntimeInfo = provider( doc = "Carries info required to execute Ruby Scripts", fields = [ "ctx", @@ -15,10 +19,18 @@ RubyRuntimeContext = provider( ], ) -RubyGem = provider( +RubyGemInfo = provider( doc = "Carries info required to package a ruby gem", fields = [ "ctx", - "version", + "gem_author_emails", + "gem_authors", + "gem_runtime_dependencies", + "gem_description", + "gem_development_dependencies", + "gem_homepage", + "gem_name", + "gem_summary", + "gem_version", ], ) diff --git a/ruby/private/rspec.bzl b/ruby/private/rspec.bzl index e86603b7..42a9378e 100644 --- a/ruby/private/rspec.bzl +++ b/ruby/private/rspec.bzl @@ -46,7 +46,7 @@ def ruby_rspec( rspec_gems = ["%s:%s" % (bundle, gem) for gem in DEFAULT_RSPEC_GEMS] deps += rspec_gems - deps += ["%s:bin" % bundle] + deps.append("%s:bin" % bundle) ruby_rspec_test( name = name, diff --git a/ruby/private/rubocop/def.bzl b/ruby/private/rubocop/def.bzl index 71a37f64..03199063 100644 --- a/ruby/private/rubocop/def.bzl +++ b/ruby/private/rubocop/def.bzl @@ -1,4 +1,4 @@ -load("@bazelruby_ruby_rules//ruby/private:binary.bzl", "ruby_binary") +load("@bazelruby_rules_ruby//ruby/private:binary.bzl", "ruby_binary") # This wraps an rb_binary in a script that is executed from the workspace folder def rubocop(name, bin, deps): @@ -9,7 +9,7 @@ def rubocop(name, bin, deps): deps = deps, ) - runner = "@bazelruby_ruby_rules//ruby/private/rubocop:runner.sh.tpl" + runner = "@bazelruby_rules_ruby//ruby/private/rubocop:runner.sh.tpl" native.genrule( name = name, tools = [bin_name], diff --git a/ruby/private/sdk.bzl b/ruby/private/sdk.bzl index 5fddabd2..77e1114b 100644 --- a/ruby/private/sdk.bzl +++ b/ruby/private/sdk.bzl @@ -1,19 +1,38 @@ load( - "@bazelruby_ruby_rules//ruby/private/toolchains:ruby_runtime.bzl", + "@bazelruby_rules_ruby//ruby/private/toolchains:ruby_runtime.bzl", _ruby_runtime = "ruby_runtime", ) -def ruby_register_toolchains(version = "host"): +def rules_ruby_select_sdk(version = "host"): """Registers ruby toolchains in the WORKSPACE file.""" - supported_versions = ["host", "2.6.3", "2.6.5", "2.7.0"] + supported_versions = [ + "host", + "2.7.0", + "2.7.1", + "2.7.2", + "2.7.3", + "2.7.4", + "2.7.5", + "2.7.6", + "3.0.0", + "3.0.1", + "3.0.2", + "3.0.3", + "3.0.4", + "3.1.0", + "3.1.1", + "3.1.2", + "3.2.0", + ] + if version in supported_versions: _ruby_runtime( name = "org_ruby_lang_ruby_toolchain", version = version, ) else: - fail("ruby_register_toolchains: unsupported ruby version '%s' not in '%s'" % (version, supported_versions)) + fail("rules_ruby_select_sdk: unsupported ruby version '%s' not in '%s'" % (version, supported_versions)) native.register_toolchains( "@org_ruby_lang_ruby_toolchain//:toolchain", diff --git a/ruby/private/toolchain.bzl b/ruby/private/toolchain.bzl index b8b6dc5d..cbaebd67 100644 --- a/ruby/private/toolchain.bzl +++ b/ruby/private/toolchain.bzl @@ -11,13 +11,15 @@ RubyRuntimeInfo = provider( ) def _ruby_toolchain_impl(ctx): - return [platform_common.ToolchainInfo( - ruby_runtime = RubyRuntimeInfo( - interpreter = ctx.attr.interpreter, - runtime = ctx.files.runtime, - rubyopt = ctx.attr.rubyopt, + return [ + platform_common.ToolchainInfo( + ruby_runtime = RubyRuntimeInfo( + interpreter = ctx.attr.interpreter, + runtime = ctx.files.runtime, + rubyopt = ctx.attr.rubyopt, + ), ), - )] + ] _ruby_toolchain = rule( implementation = _ruby_toolchain_impl, diff --git a/ruby/private/toolchains/repository_context.bzl b/ruby/private/toolchains/repository_context.bzl index b151531f..221a4ac5 100644 --- a/ruby/private/toolchains/repository_context.bzl +++ b/ruby/private/toolchains/repository_context.bzl @@ -45,6 +45,8 @@ def ruby_repository_context(repository_ctx, interpreter_path): rel_interpreter_path = str(interpreter_path) if rel_interpreter_path.startswith("/"): rel_interpreter_path = rel_interpreter_path[1:] + elif rel_interpreter_path.startswith("C:/"): + rel_interpreter_path = rel_interpreter_path[3:] return struct( # Location of the interpreter diff --git a/ruby/private/toolchains/ruby_runtime.bzl b/ruby/private/toolchains/ruby_runtime.bzl index 48550eb7..5e533778 100644 --- a/ruby/private/toolchains/ruby_runtime.bzl +++ b/ruby/private/toolchains/ruby_runtime.bzl @@ -2,15 +2,13 @@ load("//ruby/private:constants.bzl", "RULES_RUBY_WORKSPACE_NAME") load("//ruby/private/toolchains:repository_context.bzl", "ruby_repository_context") def _install_ruby_version(ctx, version): - print("download and extract ruby-build") ctx.download_and_extract( - url = "https://github.com/rbenv/ruby-build/archive/v20200224.tar.gz", - sha256 = "dc3799a1c784c9a0f214a3c0c861a0bb798cd40ee2df49bce95b4c95adf6fc79", - stripPrefix = "ruby-build-20200224", + url = "https://github.com/rbenv/ruby-build/archive/refs/tags/v20220218.tar.gz", + sha256 = "35c82b13b7bc3713eee5615b0145c79fbbac32873f55f2ab796620d76970d8e3", + stripPrefix = "ruby-build-20220218", ) install_path = "./build" - print("./bin/ruby-build", "--verbose", version, install_path) ctx.execute( ["./bin/ruby-build", "--verbose", version, install_path], quiet = False, @@ -34,6 +32,8 @@ def _relativate(path): # TODO(yugui) support windows if path.startswith("/"): return path[1:] + elif path.startswith("C:/"): + return path[3:] else: return path @@ -46,6 +46,19 @@ def _list_libdirs(ruby): def _install_dirs(ctx, ruby, *names): paths = sorted([ruby.rbconfig(ruby, name) for name in names]) + + # JRuby reports some of the directories as nulls. + paths = [path for path in paths if path] + + # Sometimes we end up with the same directory multiple times + # so make sure paths are unique by converting it to set. + # For example, this is what we have on Fedora 34: + # $ ruby -rrbconfig -e "p RbConfig::CONFIG['rubyhdrdir']" + # "/usr/include" + # $ ruby -rrbconfig -e "p RbConfig::CONFIG['rubyarchhdrdir']" + # "/usr/include" + paths = depset(paths).to_list() + rel_paths = [_relativate(path) for path in paths] for i, (path, rel_path) in enumerate(zip(paths, rel_paths)): if not _is_subpath(path, paths[:i]): @@ -57,7 +70,7 @@ def _install_ruby(ctx, ruby): ctx.symlink(ruby.interpreter_realpath, ruby.rel_interpreter_path) # Places the interpreter at a predictable place regardless of the actual binary name - # so that bundle_install can depend on it. + # so that ruby_bundle can depend on it. ctx.template( "ruby", ctx.attr._interpreter_wrapper_template, diff --git a/ruby/private/tools/deprecations.bzl b/ruby/private/tools/deprecations.bzl deleted file mode 100644 index b77f3af5..00000000 --- a/ruby/private/tools/deprecations.bzl +++ /dev/null @@ -1,12 +0,0 @@ -def deprecated_attribute( - ctx, - old_attribute_name, - new_attribute_name = None, - action = None): - if getattr(ctx.attr, old_attribute_name) != None: - if action != None: - print("Attribute \"%s\" is deprecated โ€” \"%s\"" % (old_attribute_name, action)) - elif new_attribute_name != None: - print("Attribute \"%s\" is deprecated in favor of \"%s\"" % (old_attribute_name, new_attribute_name)) - else: - print("Attribute \"%s\" is deprecated. Please do not use it." % (old_attribute_name)) diff --git a/ruby/private/tools/deps.bzl b/ruby/private/tools/deps.bzl index f5377409..9a241404 100644 --- a/ruby/private/tools/deps.bzl +++ b/ruby/private/tools/deps.bzl @@ -1,20 +1,21 @@ load("@bazel_skylib//lib:paths.bzl", "paths") load( "//ruby/private:providers.bzl", - "RubyLibrary", + "RubyLibraryInfo", ) def _transitive_srcs(deps): return struct( - srcs = [d[RubyLibrary].transitive_ruby_srcs for d in deps if RubyLibrary in d], - incpaths = [d[RubyLibrary].ruby_incpaths for d in deps if RubyLibrary in d], - rubyopt = [d[RubyLibrary].rubyopt for d in deps if RubyLibrary in d], + srcs = [d[RubyLibraryInfo].transitive_ruby_srcs for d in deps if RubyLibraryInfo in d], + incpaths = [d[RubyLibraryInfo].ruby_incpaths for d in deps if RubyLibraryInfo in d], + rubyopt = [d[RubyLibraryInfo].rubyopt for d in deps if RubyLibraryInfo in d], data_files = [d[DefaultInfo].data_runfiles.files for d in deps], default_files = [d[DefaultInfo].default_runfiles.files for d in deps], ) def transitive_deps(ctx, extra_files = [], extra_deps = []): - """Calculates transitive sets of args. + """ + Calculates transitive sets of args. Calculates the transitive sets for ruby sources, data runfiles, include flags and runtime flags from the srcs, data and deps attributes @@ -25,6 +26,8 @@ def transitive_deps(ctx, extra_files = [], extra_deps = []): ctx: a ctx object for a ruby_library or a ruby_binary rule. extra_files: a list of File objects to be added to the default_files extra_deps: a list of Target objects. + Returns: + struct """ deps = _transitive_srcs(ctx.attr.deps + extra_deps) files = depset(extra_files + ctx.files.srcs) diff --git a/ruby/tests/BUILD.bazel b/ruby/tests/BUILD.bazel index f1fe9007..b3e7290e 100644 --- a/ruby/tests/BUILD.bazel +++ b/ruby/tests/BUILD.bazel @@ -120,7 +120,7 @@ ruby_binary( main = "load_path_in_runfiles_test.rb", deps = [ "//ruby/tests/testdata:g", - "@bazelruby_ruby_rules_ruby_tests_testdata_another_workspace//baz/qux:j", + "@bazelruby_rules_ruby_ruby_tests_testdata_another_workspace//baz/qux:j", ], ) @@ -137,7 +137,7 @@ ruby_test( main = "load_path_in_runfiles_test.rb", deps = [ "//ruby/tests/testdata:g", - "@bazelruby_ruby_rules_ruby_tests_testdata_another_workspace//baz/qux:j", + "@bazelruby_rules_ruby_ruby_tests_testdata_another_workspace//baz/qux:j", ], ) @@ -250,31 +250,31 @@ pkg_tar( include_runfiles = True, package_dir = "/app", remap_paths = { - "ruby": "load_path_in_runfiles.runfiles/bazelruby_ruby_rules/ruby", + "ruby": "load_path_in_runfiles.runfiles/bazelruby_rules_ruby/ruby", ".": "load_path_in_runfiles.runfiles/", }, strip_prefix = "dummy", symlinks = { - "/app/load_path_in_runfiles.runfiles/bazelruby_ruby_rules/external": "/app/load_path_in_runfiles.runfiles", - "/app/load_path_in_runfiles": "/app/load_path_in_runfiles.runfiles/bazelruby_ruby_rules/ruby/tests/load_path_in_runfiles", + "/app/load_path_in_runfiles.runfiles/bazelruby_rules_ruby/external": "/app/load_path_in_runfiles.runfiles", + "/app/load_path_in_runfiles": "/app/load_path_in_runfiles.runfiles/bazelruby_rules_ruby/ruby/tests/load_path_in_runfiles", }, ) -container_image( - name = "load_path_in_runfiles_container_image", - base = "@ruby_base_container//image", - entrypoint = ["/app/load_path_in_runfiles"], - tars = [":load_path_in_runfiles_container_layer"], -) +# container_image( +# name = "load_path_in_runfiles_container_image", +# base = "@ruby_base_container//image", +# entrypoint = ["/app/load_path_in_runfiles"], +# tars = [":load_path_in_runfiles_container_layer"], +# ) -sh_test( - name = "load_path_in_runfiles_container_test", - size = "small", - srcs = ["container_test.sh"], - args = [ - "$(location :load_path_in_runfiles_container_image)", - "bazel/ruby/tests:load_path_in_runfiles_container_image", - ], - data = [":load_path_in_runfiles_container_image"], - tags = ["docker"], -) +# sh_test( +# name = "load_path_in_runfiles_container_test", +# size = "small", +# srcs = ["container_test.sh"], +# args = [ +# "$(location :load_path_in_runfiles_container_image)", +# "bazel/ruby/tests:load_path_in_runfiles_container_image", +# ], +# data = [":load_path_in_runfiles_container_image"], +# tags = ["docker"], +# ) diff --git a/ruby/tests/load_path_in_runfiles_test.rb b/ruby/tests/load_path_in_runfiles_test.rb index cbc0b023..95218273 100644 --- a/ruby/tests/load_path_in_runfiles_test.rb +++ b/ruby/tests/load_path_in_runfiles_test.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true require 'ruby/tests/testdata/foo/g' -require 'external/bazelruby_ruby_rules_ruby_tests_testdata_another_workspace/baz/qux/j' +require 'external/bazelruby_rules_ruby_ruby_tests_testdata_another_workspace/baz/qux/j' [g, j] diff --git a/ruby/tests/testdata/another_workspace/WORKSPACE b/ruby/tests/testdata/another_workspace/WORKSPACE index 25cbfaa3..86ed1c1f 100644 --- a/ruby/tests/testdata/another_workspace/WORKSPACE +++ b/ruby/tests/testdata/another_workspace/WORKSPACE @@ -1,5 +1,5 @@ -workspace(name = "bazelruby_ruby_rules_ruby_tests_testdata_another_workspace") +workspace(name = "bazelruby_rules_ruby_ruby_tests_testdata_another_workspace") -load("@bazelruby_ruby_rules//ruby:defs.bzl", "ruby_register_toolchains") +load("@bazelruby_rules_ruby//ruby:defs.bzl", "rules_ruby_select_sdk") -ruby_register_toolchains() +rules_ruby_select_sdk() diff --git a/ruby/tests/testdata/another_workspace/baz/qux/BUILD.bazel b/ruby/tests/testdata/another_workspace/baz/qux/BUILD.bazel index 88a99279..89a2dfed 100644 --- a/ruby/tests/testdata/another_workspace/baz/qux/BUILD.bazel +++ b/ruby/tests/testdata/another_workspace/baz/qux/BUILD.bazel @@ -1,6 +1,6 @@ -package(default_visibility = ["//visibility:public"]) +load("@bazelruby_rules_ruby//ruby:defs.bzl", "ruby_library") -load("@bazelruby_ruby_rules//ruby:defs.bzl", "ruby_library") +package(default_visibility = ["//visibility:public"]) ruby_library( name = "j", diff --git a/ruby/tests/testdata/bundle_includes_workspace/BUILD.bazel b/ruby/tests/testdata/bundle_includes_workspace/BUILD.bazel new file mode 100644 index 00000000..01b33fa7 --- /dev/null +++ b/ruby/tests/testdata/bundle_includes_workspace/BUILD.bazel @@ -0,0 +1,16 @@ +load( + "@bazelruby_rules_ruby//ruby:defs.bzl", + "ruby_binary", +) + +package(default_visibility = ["//:__subpackages__"]) + +ruby_binary( + name = "script", + srcs = ["script.rb"], + main = "script.rb", + deps = [ + "@gems//:awesome_print", + "@gems//:grpc", + ], +) diff --git a/ruby/tests/testdata/bundle_includes_workspace/Gemfile b/ruby/tests/testdata/bundle_includes_workspace/Gemfile new file mode 100644 index 00000000..9f5ba60d --- /dev/null +++ b/ruby/tests/testdata/bundle_includes_workspace/Gemfile @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +source 'https://rubygems.org' + +gem 'awesome_print' +gem 'grpc' diff --git a/ruby/tests/testdata/bundle_includes_workspace/Gemfile.lock b/ruby/tests/testdata/bundle_includes_workspace/Gemfile.lock new file mode 100644 index 00000000..20db5464 --- /dev/null +++ b/ruby/tests/testdata/bundle_includes_workspace/Gemfile.lock @@ -0,0 +1,20 @@ +GEM + remote: https://rubygems.org/ + specs: + awesome_print (1.9.2) + google-protobuf (3.17.3) + googleapis-common-protos-types (1.1.0) + google-protobuf (~> 3.14) + grpc (1.38.0) + google-protobuf (~> 3.15) + googleapis-common-protos-types (~> 1.0) + +PLATFORMS + ruby + +DEPENDENCIES + awesome_print + grpc + +BUNDLED WITH + 2.2.28 diff --git a/ruby/tests/testdata/bundle_includes_workspace/WORKSPACE b/ruby/tests/testdata/bundle_includes_workspace/WORKSPACE new file mode 100644 index 00000000..00a3bb41 --- /dev/null +++ b/ruby/tests/testdata/bundle_includes_workspace/WORKSPACE @@ -0,0 +1,35 @@ +workspace(name = "bazelruby_rules_ruby_ruby_tests_testdata_bundle_includes_workspace") + +local_repository( + name = "bazelruby_rules_ruby", + path = "../../../..", +) + +load( + "@bazelruby_rules_ruby//ruby:deps.bzl", + "rules_ruby_dependencies", + "rules_ruby_select_sdk", +) + +rules_ruby_dependencies() + +rules_ruby_select_sdk(version = "3.0.2") + +load("@bazelruby_rules_ruby//ruby:defs.bzl", "ruby_bundle") + +ruby_bundle( + name = "gems", + bundler_version = "2.2.21", + gemfile = "//:Gemfile", + gemfile_lock = "//:Gemfile.lock", + includes = { + # The gemspec of grpc gem lists ['src/ruby/bin', 'src/ruby/lib', 'src/ruby/pb'] as the `require_paths`. When installing + # pre-built versions of the gem using a package downloaded from rubygems.org, these paths are sufficient since the file + # `src/ruby/lib/grpc.rb` in the downloaded gem package does not `require` any file outside these directories. + # However, when installing grpc gem from source using Bundler, `src/ruby/lib/grpc.rb` in the source package does + # `require` 'etc/roots.pem', so the directory containing this `require`-d file also needs to be present in the `$LOAD_PATH`. + # Thus users have to manually add the 'etc' directory to the `$LOAD_PATH` using the `includes` option of `ruby_bundle` rule. + # The `includes` option of `ruby_bundle` rule is a means of workaround for such a peculiar situation. + "grpc": ["etc"], + }, +) diff --git a/ruby/tests/testdata/bundle_includes_workspace/script.rb b/ruby/tests/testdata/bundle_includes_workspace/script.rb new file mode 100644 index 00000000..bc718e56 --- /dev/null +++ b/ruby/tests/testdata/bundle_includes_workspace/script.rb @@ -0,0 +1,24 @@ +expected_gem_require_paths = %w[ + etc + src/ruby/bin + src/ruby/lib + src/ruby/pb +] +gem_require_paths = $LOAD_PATH.map do |load_path| + %r{.+script.runfiles/(?:gems|bundle)/lib/ruby/3.0.0/gems/grpc-.+?/(.+)}.match(load_path).to_a[1] +end.compact + +begin + require 'grpc' +rescue LoadError => e + warn "Failed to load grpc gem: #{e.message}" + raise +end + +pp GRPC::RpcServer.new + +# TODO: what is this? I am not sure I fully understand the purpose of this +# check. Please elaborate, or it will be removed. --@kigster +(expected_gem_require_paths - gem_require_paths).each do |missing_require_path| + raise "Expected requir_path '#{missing_require_path}' is missing in $LOAD_PATH." +end