##
# CI using GitHub Actions.
#
# NOTE: GitHub Actions DSL.
# - https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions#understanding-the-workflow-file
# - https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions
#
# NOTE: Ruby workflow example.
# - https://github.com/ruby/setup-ruby#usage
#
# NOTE: Building and testing Ruby.
# - https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-ruby
#
# NOTE: More examples.
# - https://gist.github.com/geonizeli/57376c15f23feecdabf5ea213c3d7f41
# - https://docs.knapsackpro.com/2019/how-to-run-rspec-on-github-actions-for-ruby-on-rails-app-using-parallel-jobs
#
# NOTE: Sharing data between jobs and post-workflow artifacts.
# - https://docs.github.com/en/actions/learn-github-actions/essential-features-of-github-actions#sharing-data-between-jobs
# - https://github.com/actions/upload-artifact
# - https://github.com/actions/download-artifact
#
# NOTE: Virtual Environments.
# - https://github.com/actions/virtual-environments
#
# NOTE: How to collect and upload coverage reports for Coveralls?
# - https://github.com/marketplace/actions/coveralls-github-action#complete-parallel-job-example
# - https://github.com/coverallsapp/github-action/issues/29
# - https://github.com/coverallsapp/github-action/issues/29#issuecomment-704366557
#
# NOTE: What is the purpose of bundle-audit?
# - https://github.com/rubysec/bundler-audit
#
# IMPORTANT: This workflow is heavily based on Shopify/packwerk workflow.
# - https://github.com/Shopify/packwerk/blob/main/.github/workflows/ci.yml
# - https://github.com/Shopify/packwerk/actions/runs/331834549/workflow
#
name: CI

on:
  pull_request:
    branches:
      - main
  push:
    branches:
      - main

jobs:
  lint:
    ##
    # NOTE: If there are no memory, performance, or cost constraints, prefer to use as standard Linux distribution as it is possible.
    # In a general case, you simply won't have enough time to resolve all the "quirks" of more specific distributions if you are an application developer.
    # That is why the well-known Ubuntu is used.
    # https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#choosing-github-hosted-runners
    #
    runs-on: ubuntu-20.04
    name: Lint
    steps:
      - uses: actions/checkout@v2
      - name: Set up Ruby
        uses: ruby/setup-ruby@v1
        with:
          ruby-version: 3.2
          ##
          # NOTE: Installs the latest compatible Bundler version, runs `bundle install` and caches installed gems.
          # - https://github.com/ruby/setup-ruby#usage
          # - https://github.com/ruby/setup-ruby#bundler
          #
          bundler-cache: true
      ##
      # NOTE: Installs Task (task runner).
      # https://taskfile.dev/installation/#github-actions
      # https://github.com/go-task/task
      #
      - name: Install Task (task runner)
        uses: arduino/setup-task@v1
      - name: Run Rubocop
        run: task rubocop
      - name: Run Yard-Junk (docs linter)
        run: task docs:lint

  test:
    needs:
      - lint
    ##
    # NOTE: If there are no memory, performance, or cost constraints, prefer to use as standard Linux distribution as it is possible.
    # In a general case, you simply won't have enough time to resolve all the "quirks" of more specific distributions if you are an application developer.
    # That is why the well-known Ubuntu is used.
    # https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#choosing-github-hosted-runners
    #
    # NOTE: List of all possible Ruby, JRuby versions.
    # https://github.com/ruby/setup-ruby/blob/master/ruby-builder-versions.json
    #
    runs-on: ubuntu-20.04
    strategy:
      matrix:
        gemfile:
          - Gemfile
        ruby:
          - 2.7
          ##
          # NOTE: 3.0 is wrapped by quotes in order to avoid misparsing it as integer.
          # https://github.com/actions/runner/issues/849
          #
          - "3.0"
          - 3.1
          - 3.2
          ##
          # NOTE: JRuby 9.4 aims CRuby 3.1 compatibility.
          # - https://www.jruby.org/download
          #
          - "jruby-9.4"
          ##
          # NOTE: TruffleRuby 22.3 aims CRuby 3.1 compatibility.
          # - https://www.jruby.org/download
          #
          # IMPORTANT: TruffleRuby 22.3 is currently disabled since too many specs are failing due to CRuby uncompatible code.
          #
          # NOTE: Use `task docker:bash:truffleruby_22.3` and then `task rspec` to reproduce them locally.
          #
          # TODO: Make ConvenientService TruffleRuby 22.3 compatible.
          #
          # - "truffleruby-22.3"
    env:
      BUNDLE_GEMFILE: ${{ matrix.gemfile }}

    name: "Test Ruby `${{ matrix.ruby }}` with Gemfile `${{ matrix.gemfile }}`"
    steps:
      - uses: actions/checkout@v2
      - name: "Set up Ruby `${{ matrix.ruby }}`"
        uses: ruby/setup-ruby@v1
        with:
          ruby-version: ${{ matrix.ruby }}
          ##
          # NOTE: Installs the latest compatible Bundler version, runs `bundle install` and caches installed gems.
          # - https://github.com/ruby/setup-ruby#usage
          # - https://github.com/ruby/setup-ruby#bundler
          #
          bundler-cache: true
      ##
      # NOTE: Installs Task (task runner).
      # - https://taskfile.dev/installation/#github-actions
      # - https://github.com/go-task/task
      #
      - name: Install Task (task runner)
        uses: arduino/setup-task@v1
      - name: Run RSpec without appraisals
        run: task rspec:standard
      - name: Install dependencies for appraisals
        run: task deps:install
      - name: Run RSpec with Rails 7.0
        run: task rspec:rails_7.0
      - name: Run RSpec with Rails 6.1
        run: task rspec:rails_6.1
      - name: Run RSpec with Rails 6.0
        run: task rspec:rails_6.0
      - name: Run RSpec with Rails 5.2
        run: task rspec:rails_5.2
      - name: Run RSpec with Dry
        run: task rspec:dry
      - name: Run Minitest
        run: task minitest
      ##
      # NOTE: `lcov-result-merger` is written in JS.
      #
      - name: Set up Node.js 16.x
        uses: actions/setup-node@v3
        with:
          node-version: 16.x
      ##
      # NOTE: `lcov-result-merger` docs.
      # - https://github.com/mweibel/lcov-result-merger
      #
      # NOTE: `npx --yes` option.
      # - https://stackoverflow.com/questions/70742968/automatically-accept-installing-npx-package
      #
      # NOTE: `lcov-result-merger` uses `vinyl-fs` for globs which in turn uses `node-glob`.
      # - https://github.com/mweibel/lcov-result-merger/blob/v3.3.0/bin/lcov-result-merger.js#L38
      # - https://github.com/gulpjs/vinyl-fs#srcglobs-options
      # - https://github.com/isaacs/node-glob#glob-primer
      #
      # NOTE: Append `&& cat coverage/lcov.info` to debug.
      #
      # IMPORTANT: 'coverage/**/lcov.info' single quotes are mandatory.
      #
      - name: Merge coverage reports into single file
        run: task coverage:lcov:merge
      - name: Configure coverage reports for Coveralls
        uses: coverallsapp/github-action@master
        with:
          github-token: ${{ secrets.github_token }}
          flag-name: run-${{ matrix.ruby }}-${{ matrix.gemfile }}
          parallel: true
          path-to-lcov: "./coverage/lcov.info"

  coverage:
    needs:
      - test
    ##
    # NOTE: If there are no memory, performance, or cost constraints, prefer to use as standard Linux distribution as it is possible.
    # In a general case, you simply won't have enough time to resolve all the "quirks" of more specific distributions if you are an application developer.
    # That is why the well-known Ubuntu is used.
    # - https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#choosing-github-hosted-runners
    #
    runs-on: ubuntu-20.04
    name: Gather coverage
    steps:
      - name: Upload coverage reports to Coveralls
        uses: coverallsapp/github-action@master
        with:
          github-token: ${{ secrets.github_token }}
          parallel-finished: true