Ruby workflow (reactjs/react-rails)
The Ruby workflow from reactjs/react-rails, explained and optimized by Latchkey.
CI health: F - at risk
Point runs-on at Latchkey and get caching, run de-duplication, job timeouts, SHA-pinned actions, self-healing for flaky steps, and up to 58% lower cost, applied automatically.
What it does
This is the Ruby workflow from the reactjs/react-rails repository, a real project running GitHub Actions. It is shown here with attribution under its Apache-2.0 license.
Below, Latchkey shows a faster, safer version produced by its optimization engine.
The workflow
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
# This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
# For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
name: Ruby
on:
push:
branches:
- 'main'
pull_request:
jobs:
check_react_and_ujs:
strategy:
fail-fast: true
matrix:
ruby: ['2.7']
runs-on: ubuntu-latest
env:
PACKAGE_JSON_FALLBACK_MANAGER: yarn_classic
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: actions/setup-node@v3
with:
node-version: 20
- name: Save root node_modules to cache
uses: actions/cache@v3
with:
path: node_modules
key: package-node-modules-cache-${{ hashFiles('yarn.lock') }}
- name: Save react-builds/node_modules to cache
uses: actions/cache@v3
with:
path: react-builds/node_modules
key: dummy-app-node-modules-cache-${{ hashFiles('react-builds/yarn.lock') }}
- uses: ruby/setup-ruby@v1
with:
bundler: 2.4.9
ruby-version: ${{ matrix.ruby }}
- name: Save ruby gems to cache
uses: actions/cache@v3
with:
path: vendor/bundle
key: root-gem-cache-${{ matrix.ruby }}-${{ hashFiles('Gemfile.lock') }}
- name: Install Ruby Gems
run: bundle check --path=vendor/bundle || bundle _2.4.9_ install --path=vendor/bundle --jobs=4 --retry=3
- run: yarn
- run: bundle exec rake react:update
- run: bundle exec rake ujs:update
- run: ./check_for_uncommitted_files.sh
test:
needs: check_react_and_ujs
strategy:
fail-fast: false
matrix:
js_package_manager:
- name: npm
installer: npm
- name: yarn_classic
installer: yarn
- name: pnpm
installer: pnpm
- name: bun
installer: bun
ruby: ['2.7']
gemfile:
# These have shakapacker:
- base
- shakapacker
# These don't have shakapacker:
- propshaft
- sprockets_3
- sprockets_4
runs-on: ubuntu-latest
env:
# $BUNDLE_GEMFILE must be set at the job level, so it is set for all steps
BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/${{ matrix.gemfile }}.gemfile
# Workaround b/c upgrading Minitest broke some mocking expectations
# having to do with automatic kwarg splatting
MT_KWARGS_HACK: 1
PACKAGE_JSON_FALLBACK_MANAGER: ${{ matrix.js_package_manager.name }}
SHAKAPACKER_USE_PACKAGE_JSON_GEM: true
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: actions/setup-node@v3
with:
node-version: 20
- run: sudo npm -g install yalc ${{ matrix.js_package_manager.installer }}
- run: yalc publish
- name: Save root node_modules to cache
uses: actions/cache@v3
with:
path: node_modules
key: package-node-modules-cache-${{ hashFiles('yarn.lock') }}
- name: Save test/dummy/node_modules to cache
uses: actions/cache@v3
with:
path: test/dummy/node_modules
key: dummy-app-node-modules-cache-${{ matrix.js_package_manager.name }}-${{ hashFiles('test/dummy/yarn.lock') }}
- uses: ruby/setup-ruby@v1
with:
bundler: 2.4.9
ruby-version: ${{ matrix.ruby }}
- run: bundle config set --local path 'test/dummy/vendor/bundle'
- run: ./test/bin/create-fake-js-package-managers ${{ matrix.js_package_manager.installer }}
- name: Save dummy app ruby gems to cache
uses: actions/cache@v3
with:
path: test/dummy/vendor/bundle
key: dummy-app-gem-cache-${{ matrix.ruby }}-${{ hashFiles(format('{0}/gemfiles/{1}.gemfile.lock', github.workspace, matrix.gemfile)) }}
- name: Install Ruby Gems for dummy app
run: bundle lock --add-platform 'x86_64-linux' && bundle check --path=test/dummy/vendor/bundle || bundle _2.4.9_ install --frozen --path=test/dummy/vendor/bundle --jobs=4 --retry=3
- run: cd test/dummy && yalc add react_ujs && ${{ matrix.js_package_manager.installer }} install
- run: bundle exec rake test
env:
NODE_OPTIONS: --openssl-legacy-provider
test_connection_pool_v3:
needs: check_react_and_ujs
strategy:
fail-fast: false
matrix:
js_package_manager:
- name: npm
installer: npm
- name: yarn_classic
installer: yarn
- name: pnpm
installer: pnpm
- name: bun
installer: bun
ruby: [3.2]
gemfile: [connection_pool_3]
runs-on: ubuntu-latest
env:
# $BUNDLE_GEMFILE must be set at the job level, so it is set for all steps
BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/${{ matrix.gemfile }}.gemfile
# Workaround b/c upgrading Minitest broke some mocking expectations
# having to do with automatic kwarg splatting
MT_KWARGS_HACK: 1
PACKAGE_JSON_FALLBACK_MANAGER: ${{ matrix.js_package_manager.name }}
SHAKAPACKER_USE_PACKAGE_JSON_GEM: true
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: actions/setup-node@v3
with:
node-version: 20
- run: sudo npm -g install yalc ${{ matrix.js_package_manager.installer }}
- run: yalc publish
- name: Save root node_modules to cache
uses: actions/cache@v3
with:
path: node_modules
key: package-node-modules-cache-${{ hashFiles('yarn.lock') }}
- name: Save test/dummy/node_modules to cache
uses: actions/cache@v3
with:
path: test/dummy/node_modules
key: dummy-app-node-modules-cache-${{ matrix.js_package_manager.name }}-${{ hashFiles('test/dummy/yarn.lock') }}
- uses: ruby/setup-ruby@v1
with:
bundler: 2.4.9
ruby-version: ${{ matrix.ruby }}
- run: bundle config set --local path 'test/dummy/vendor/bundle'
- run: ./test/bin/create-fake-js-package-managers ${{ matrix.js_package_manager.installer }}
- name: Save dummy app ruby gems to cache
uses: actions/cache@v3
with:
path: test/dummy/vendor/bundle
key: dummy-app-gem-cache-${{ hashFiles(format('{0}/gemfiles/{1}.gemfile.lock', github.workspace, matrix.gemfile)) }}
- name: Install Ruby Gems for dummy app
run: bundle lock --add-platform 'x86_64-linux' && bundle check --path=test/dummy/vendor/bundle || bundle _2.4.9_ install --frozen --path=test/dummy/vendor/bundle --jobs=4 --retry=3
- run: cd test/dummy && yalc add react_ujs && ${{ matrix.js_package_manager.installer }} install
- run: bundle exec rake test
env:
NODE_OPTIONS: --openssl-legacy-provider
The same workflow, on Latchkey
Estimated ~20% faster on cache hits, plus fewer wasted runs and a safer supply chain. Added and changed lines are highlighted.
# This workflow uses actions that are not certified by GitHub. # They are provided by a third-party and are governed by # separate terms of service, privacy policy, and support # documentation. # This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake # For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby name: Ruby on: push: branches: - 'main' pull_request: concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: check_react_and_ujs: timeout-minutes: 30 strategy: fail-fast: true matrix: ruby: ['2.7'] runs-on: latchkey-small env: PACKAGE_JSON_FALLBACK_MANAGER: yarn_classic steps: - uses: actions/checkout@v4 with: persist-credentials: false - uses: actions/setup-node@v3 with: cache: 'npm' node-version: 20 - name: Save root node_modules to cache uses: actions/cache@v3 with: path: node_modules key: package-node-modules-cache-${{ hashFiles('yarn.lock') }} - name: Save react-builds/node_modules to cache uses: actions/cache@v3 with: path: react-builds/node_modules key: dummy-app-node-modules-cache-${{ hashFiles('react-builds/yarn.lock') }} - uses: ruby/setup-ruby@v1 with: bundler: 2.4.9 ruby-version: ${{ matrix.ruby }} - name: Save ruby gems to cache uses: actions/cache@v3 with: path: vendor/bundle key: root-gem-cache-${{ matrix.ruby }}-${{ hashFiles('Gemfile.lock') }} - name: Install Ruby Gems run: bundle check --path=vendor/bundle || bundle _2.4.9_ install --path=vendor/bundle --jobs=4 --retry=3 - run: yarn - run: bundle exec rake react:update - run: bundle exec rake ujs:update - run: ./check_for_uncommitted_files.sh test: timeout-minutes: 30 needs: check_react_and_ujs strategy: fail-fast: false matrix: js_package_manager: - name: npm installer: npm - name: yarn_classic installer: yarn - name: pnpm installer: pnpm - name: bun installer: bun ruby: ['2.7'] gemfile: # These have shakapacker: - base - shakapacker # These don't have shakapacker: - propshaft - sprockets_3 - sprockets_4 runs-on: latchkey-small env: # $BUNDLE_GEMFILE must be set at the job level, so it is set for all steps BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/${{ matrix.gemfile }}.gemfile # Workaround b/c upgrading Minitest broke some mocking expectations # having to do with automatic kwarg splatting MT_KWARGS_HACK: 1 PACKAGE_JSON_FALLBACK_MANAGER: ${{ matrix.js_package_manager.name }} SHAKAPACKER_USE_PACKAGE_JSON_GEM: true steps: - uses: actions/checkout@v4 with: persist-credentials: false - uses: actions/setup-node@v3 with: cache: 'npm' node-version: 20 - run: sudo npm -g install yalc ${{ matrix.js_package_manager.installer }} - run: yalc publish - name: Save root node_modules to cache uses: actions/cache@v3 with: path: node_modules key: package-node-modules-cache-${{ hashFiles('yarn.lock') }} - name: Save test/dummy/node_modules to cache uses: actions/cache@v3 with: path: test/dummy/node_modules key: dummy-app-node-modules-cache-${{ matrix.js_package_manager.name }}-${{ hashFiles('test/dummy/yarn.lock') }} - uses: ruby/setup-ruby@v1 with: bundler: 2.4.9 ruby-version: ${{ matrix.ruby }} - run: bundle config set --local path 'test/dummy/vendor/bundle' - run: ./test/bin/create-fake-js-package-managers ${{ matrix.js_package_manager.installer }} - name: Save dummy app ruby gems to cache uses: actions/cache@v3 with: path: test/dummy/vendor/bundle key: dummy-app-gem-cache-${{ matrix.ruby }}-${{ hashFiles(format('{0}/gemfiles/{1}.gemfile.lock', github.workspace, matrix.gemfile)) }} - name: Install Ruby Gems for dummy app run: bundle lock --add-platform 'x86_64-linux' && bundle check --path=test/dummy/vendor/bundle || bundle _2.4.9_ install --frozen --path=test/dummy/vendor/bundle --jobs=4 --retry=3 - run: cd test/dummy && yalc add react_ujs && ${{ matrix.js_package_manager.installer }} install - run: bundle exec rake test env: NODE_OPTIONS: --openssl-legacy-provider test_connection_pool_v3: timeout-minutes: 30 needs: check_react_and_ujs strategy: fail-fast: false matrix: js_package_manager: - name: npm installer: npm - name: yarn_classic installer: yarn - name: pnpm installer: pnpm - name: bun installer: bun ruby: [3.2] gemfile: [connection_pool_3] runs-on: latchkey-small env: # $BUNDLE_GEMFILE must be set at the job level, so it is set for all steps BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/${{ matrix.gemfile }}.gemfile # Workaround b/c upgrading Minitest broke some mocking expectations # having to do with automatic kwarg splatting MT_KWARGS_HACK: 1 PACKAGE_JSON_FALLBACK_MANAGER: ${{ matrix.js_package_manager.name }} SHAKAPACKER_USE_PACKAGE_JSON_GEM: true steps: - uses: actions/checkout@v4 with: persist-credentials: false - uses: actions/setup-node@v3 with: cache: 'npm' node-version: 20 - run: sudo npm -g install yalc ${{ matrix.js_package_manager.installer }} - run: yalc publish - name: Save root node_modules to cache uses: actions/cache@v3 with: path: node_modules key: package-node-modules-cache-${{ hashFiles('yarn.lock') }} - name: Save test/dummy/node_modules to cache uses: actions/cache@v3 with: path: test/dummy/node_modules key: dummy-app-node-modules-cache-${{ matrix.js_package_manager.name }}-${{ hashFiles('test/dummy/yarn.lock') }} - uses: ruby/setup-ruby@v1 with: bundler: 2.4.9 ruby-version: ${{ matrix.ruby }} - run: bundle config set --local path 'test/dummy/vendor/bundle' - run: ./test/bin/create-fake-js-package-managers ${{ matrix.js_package_manager.installer }} - name: Save dummy app ruby gems to cache uses: actions/cache@v3 with: path: test/dummy/vendor/bundle key: dummy-app-gem-cache-${{ hashFiles(format('{0}/gemfiles/{1}.gemfile.lock', github.workspace, matrix.gemfile)) }} - name: Install Ruby Gems for dummy app run: bundle lock --add-platform 'x86_64-linux' && bundle check --path=test/dummy/vendor/bundle || bundle _2.4.9_ install --frozen --path=test/dummy/vendor/bundle --jobs=4 --retry=3 - run: cd test/dummy && yalc add react_ujs && ${{ matrix.js_package_manager.installer }} install - run: bundle exec rake test env: NODE_OPTIONS: --openssl-legacy-provider
What changed
- Run on Latchkey managed runners with one line (
runs-on), which apply the fixes below automatically and self-heal transient failures. This example useslatchkey-small; pick the runner size that fits the job. - Cancel superseded runs when a branch or PR gets a newer push.
- Cache dependency installs on the setup step so they are served from cache.
- Add a job timeout so a hung step cannot burn hours of runner time.
1 third-party action is referenced by a movable tag. Pin it to the commit SHA (Latchkey resolves and applies this automatically) so a repointed tag cannot change what runs.
This workflow runs 3 jobs (25 with the matrix expanded) per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.