name: Testing

on:
  push:
    branches:
      - '**'
  pull_request:

permissions:
  contents: read # to fetch code (actions/checkout)

jobs:
  rack-protection:
    name: rack-protection (${{ matrix.ruby }}, rack ${{ matrix.rack }})
    runs-on: ubuntu-latest
    timeout-minutes: 5
    strategy:
      fail-fast: false
      matrix:
        rack:
          - stable
        ruby:
          - "2.7"
          - "3.0"
          - "3.1"
          - "3.2"
          - "3.3"
          - "3.4"
          - "jruby"
          - "truffleruby"
        include:
          # Rack
          - { ruby: 3.2, rack: "~>3.0.0" }
          - { ruby: 3.2, rack: head }
          # Never fail our build due to problems with Ruby head
          - { ruby: ruby-head, rack: stable, allow-failure: true }
    env:
      rack: ${{ matrix.rack }}
    steps:
    - uses: actions/checkout@v4
    - uses: ruby/setup-ruby@v1
      continue-on-error: ${{ matrix.allow-failure || false }}
      id: setup-ruby
      with:
        bundler-cache: true
        ruby-version: ${{ matrix.ruby }}
        working-directory: rack-protection
    - name: Run rack-protection tests
      continue-on-error: ${{ matrix.allow-failure || false }}
      id: protection-tests
      working-directory: rack-protection
      run: |
        bundle exec rake
    # because continue-on-error marks the steps as pass even if they fail
    - name: "setup-ruby (bundle install) outcome: ${{ steps.setup-ruby.outcome }}"
      run: ""
    - name: "rack-protection tests outcome: ${{ steps.protection-tests.outcome }}"
      run: ""
    - uses: zzak/action-discord@v6
      if: failure() && github.ref_name == 'main'
      continue-on-error: true # always allow failure
      with:
        github-token: ${{ secrets.GITHUB_TOKEN }}
        webhook: ${{ secrets.DISCORD_WEBHOOK }}
  sinatra:
    name: |
      ${{ matrix.ruby }}
      (Rack ${{ matrix.rack }}, Rack::Session ${{ matrix.rack_session }}, Puma ${{ matrix.puma }}, Tilt ${{ matrix.tilt }}, Zeitwerk ${{ matrix.zeitwerk }})
    runs-on: ubuntu-latest
    timeout-minutes: 15
    strategy:
      fail-fast: false
      matrix:
        puma:
          - stable
        rack:
          - stable
        rack_session:
          - stable
        tilt:
          - stable
        zeitwerk:
          - stable
        ruby:
          - "2.7"
          - "3.0"
          - "3.1"
          - "3.2"
          - "3.3"
          - "3.4"
        rubyopt:
          - "--enable-frozen-string-literal --debug-frozen-string-literal"
        include:
          # Rack
          - { ruby: 3.2, rack: "~>3.0.0", puma: stable, tilt: stable, rack_session: stable, zeitwerk: stable }
          - { ruby: 3.2, rack: head, puma: stable, tilt: stable, rack_session: stable, zeitwerk: stable }
          # Rack::Session
          - { ruby: 3.2, rack: stable, puma: stable, tilt: stable, rack_session: head, zeitwerk: stable }
          # Puma
          - { ruby: 3.2, rack: stable, puma: head, tilt: stable, rack_session: stable, zeitwerk: stable }
          # Tilt
          - { ruby: 3.2, rack: stable, puma: stable, tilt: head, rack_session: stable, zeitwerk: stable }
          # Test Zeitwerk < 2.7.0 separately
          - { ruby: 3.2, rack: stable, puma: stable, tilt: head, rack_session: stable, zeitwerk: '<2.7.0' }
          # JRuby, tests are notable flaky
          - { ruby: jruby,            rubyopt: "", rack: stable, puma: stable, tilt: stable, rack_session: stable, zeitwerk: stable, allow-failure: true }
          # Never fail our build due to problems with head rubies
          - { ruby: ruby-head,        rack: stable, puma: stable, tilt: stable, rack_session: stable, zeitwerk: stable, allow-failure: true }
          - { ruby: jruby-head,       rubyopt: "", rack: stable, puma: stable, tilt: stable, rack_session: stable, zeitwerk: stable, allow-failure: true }
          - { ruby: truffleruby-head, rack: stable, puma: stable, tilt: stable, rack_session: stable, zeitwerk: stable, allow-failure: true }
          # truffleruby 24.1 fails, see https://github.com/oracle/truffleruby/issues/3788
          - { ruby: truffleruby,      rack: stable, puma: stable, tilt: stable, rack_session: stable, zeitwerk: stable, allow-failure: true }

    env:
      rack: ${{ matrix.rack }}
      rack_session: ${{ matrix.rack_session }}
      puma: ${{ matrix.puma }}
      tilt: ${{ matrix.tilt }}
      zeitwerk: ${{ matrix.zeitwerk }}
      RUBYOPT: "${{ matrix.rubyopt }}"
      # need to unset RUBYOPT for JRuby: https://github.com/jruby/ruby-maven/issues/12

    steps:
    - name: Install dependencies
      run: |
        sudo apt-get update
        sudo apt-get install --yes \
          pandoc \
          nodejs \
          pkg-config \
          libxml2-dev \
          libxslt-dev \
          libyaml-dev

    - uses: actions/checkout@v4

    - uses: ruby/setup-ruby@v1
      continue-on-error: ${{ matrix.allow-failure || false }}
      id: setup-ruby
      with:
        ruby-version: ${{ matrix.ruby }}
        bundler-cache: true
        # Update rubygems due to https://github.com/rubygems/rubygems/pull/6490 (3.0)
        # and https://github.com/sinatra/sinatra/issues/2051 (3.1)
        rubygems: ${{ matrix.ruby == '3.0' && 'latest' || matrix.ruby == '3.1' && 'latest' || 'default' }}

    - name: Run sinatra tests
      continue-on-error: ${{ matrix.allow-failure || false }}
      id: tests
      run: bundle exec rake

    - name: Run sinatra-contrib tests
      continue-on-error: ${{ matrix.allow-failure || false }}
      id: contrib-tests
      working-directory: sinatra-contrib
      run: |
        bundle install --jobs=3 --retry=3
        bundle exec rake

    # because continue-on-error marks the steps as pass even if they fail
    - name: "setup-ruby (bundle install) outcome: ${{ steps.setup-ruby.outcome }}"
      run: ""
    - name: "sinatra tests outcome: ${{ steps.tests.outcome }}"
      run: ""
    - name: "sinatra-contrib tests outcome: ${{ steps.contrib-tests.outcome }}"
      run: ""

    - uses: zzak/action-discord@v6
      if: failure() && github.ref_name == 'main'
      continue-on-error: true # always allow failure
      with:
        github-token: ${{ secrets.GITHUB_TOKEN }}
        webhook: ${{ secrets.DISCORD_WEBHOOK }}
