Ruby Gems CI using GitHub Action
Tags: ruby, gems, ci, github
Published: 2020-11-20 06:07:40

Travis CI is probably "gone" for Open Source Projects.  
And for small ruby gem projects I think GitHub Action is enough.  

Some other articles if you want to read more about Travis CI:
- https://www.reddit.com/r/ruby/comments/jt2uub/deep_dive_moving_ruby_projects_from_travis_to/

GitHub Action Official Doc:
https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-syntax-for-github-actions


# TL;DR
Wait shouldn't that be put at the end?
Anyway here is my version of workflow.

For most basic testing like rspec,  
Create `.github/workflows/tests.yaml`
Taken from [One of my own gem's GitHub Action config](https://github.com/PikachuEXE/contracted_value/blob/master/.github/workflows/tests.yaml)
```yaml
name: Tests

on:
  pull_request:
    branches:
      - master
    paths-ignore:
      - 'README.md'
  push:
    branches:
      - master
    paths-ignore:
      - 'README.md'


jobs:
  unit_tests:
    name: Unit Tests
    if: "contains(github.event.commits[0].message, '[ci skip]') == false"
    strategy:
      fail-fast: false
      matrix:
        os:
          - ubuntu
        ruby:
          - 2.4
          - 2.5
          - 2.6
          - 2.7
        gemfile:
          - gemfiles/contracts_15_0.gemfile
          - gemfiles/contracts_16_0.gemfile
        allow_failures:
          - false
        include:
          - os: ubuntu
            ruby: ruby-head
            gemfile: gemfiles/contracts_16_0.gemfile
            allow_failures: true
    env:
      BUNDLE_GEMFILE: "${{ matrix.gemfile }}"
      ALLOW_FAILURES: "${{ matrix.allow_failures }}"
    runs-on: ${{ matrix.os }}-latest
    continue-on-error: ${{ endsWith(matrix.ruby, 'head') || matrix.ruby == 'debug' }}
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Setup Ruby
        uses: ruby/setup-ruby@v1
        with:
          ruby-version: ${{ matrix.ruby }}
          bundler-cache: true
      - name: Test
        run: bundle exec rake spec || $ALLOW_FAILURES
```

# GitHub Action Config with comment
OK You got some more time to read
Let me post one with comments inside

```yaml
# Just the workflow name, you will see this on project's action tab
# Do give it a good name and stick to it
name: Tests

# When do you want this workflow to run
# https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-syntax-for-github-actions#on
on:
  # On pull request
  pull_request:
    # For some branches only (base branch)
    branches:
      - master
    # Don't run if changes only include these files
    paths-ignore:
      - 'README.md'
  # On push
  push:
    # For some branches only (base branch)
    branches:
      - master
    # Don't run if changes only include these files
    paths-ignore:
      - 'README.md'

jobs:
  # `unit_tests` is the job id here & can be renamed
  unit_tests:
    name: Unit Tests
    # Emulates Travis skip build on `[ci skip]` in commit message
    # But you can customize this or just remove it
    if: "contains(github.event.commits[0].message, '[ci skip]') == false"
    strategy:
      # Depends on whether you want to see result of all spawned jobs when one failed
      fail-fast: false
      # This is like Travis CI
      # But the keys can be renamed except a few keywords
      matrix:
        os:
          - ubuntu
        ruby:
          - 2.4
          - 2.5
          - 2.6
          - 2.7
        gemfile:
          - gemfiles/contracts_15_0.gemfile
          - gemfiles/contracts_16_0.gemfile
        allow_failures:
          - false
        # Part of a technique to allow some jobs to fail
        include:
          - os: ubuntu
            ruby: ruby-head
            gemfile: gemfiles/contracts_16_0.gemfile
            allow_failures: true
    env:
      # Required for action `ruby/setup-ruby` & other steps with bundler
      BUNDLE_GEMFILE: "${{ matrix.gemfile }}"
      # Part of a technique to allow some jobs to fail
      ALLOW_FAILURES: "${{ matrix.allow_failures }}"
    runs-on: ${{ matrix.os }}-latest
    # Actually unnecessary if we use `allow_failures` technique
    continue-on-error: ${{ endsWith(matrix.ruby, 'head') || matrix.ruby == 'debug' }}
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Setup Ruby
        # NOT `action/setup-ruby` which is deprecated
        uses: ruby/setup-ruby@v1
        with:
          ruby-version: ${{ matrix.ruby }}
          # With this option enabled
          # Running `bundle install` is not needed since it's included
          bundler-cache: true
      - name: Test
        # `$ALLOW_FAILURES` is part of a technique to allow some jobs to fail
        run: bundle exec rake spec || $ALLOW_FAILURES
```

## Replacement for `allow-failure` on Travis CI
This one is tricky.  
Currently (2020-11-20) I am not aware of any complete replacement `allow-failure` on GitHub Action.  
Related:
- https://github.com/actions/toolkit/issues/399

A close one would be like the `allow_failures` I put above.  
Any job with `allow_failures: true` would look passed due to `$ALLOW_FAILURES`.  
However there is no place that shows the test or whatever command run failed unless you look into the log.  
But using `continue-on-error` would make the Check shown as failed (even we allow it to fail). This is not good looking in Pull Request UI & some project even require all Checks to be passed before merging a PR (sometimes auto merging).  
This is a design issue so we have to wait.  


## Replacement of `Cron Jobs` on Travis CI
Nothing special just read the doc

https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows#scheduled-events

## Fixing coverage report on Coverall
I don't use Coverall on every gem I have (maybe I should)
Use these as examples:
- https://github.com/svenfuchs/gem-release/pull/98/files
- https://github.com/DmitryTsepelev/ar_lazy_preload/pull/45/files

Basically generate the coverage reports using `simplecov-lcov` and upload via action `coverallsapp/github-action@master`.  

## Gotcha on $stdout
GitHub Action's runner (the one that runs all the action/commands) has `$stdout.tty? == false`

This is the one that took me some time to figure out when [migrating `gem-release` to GitHub Action](https://github.com/svenfuchs/gem-release/pull/98)