name: sqlite3-ruby test suite
concurrency:
  group: "${{ github.workflow }}-${{ github.ref }}"
  cancel-in-progress: true
on:
  workflow_dispatch:
  schedule:
    - cron: "0 8 * * 3" # At 08:00 on Wednesday # https://crontab.guru/#0_8_*_*_3
  push:
    branches:
      - main
      - "*-stable"
    tags:
      - v*.*.*
  pull_request:
    types: [opened, synchronize]
    branches:
      - '*'

env:
  BUNDLE_WITHOUT: "development"

jobs:
  ruby_versions:
    outputs:
      setup_ruby: "['3.1', '3.2', '3.3', '3.4']"
      image_tag: "['3.1', '3.2', '3.3', '3.4']"
    runs-on: ubuntu-latest
    steps:
      - run: echo "generating rubies ..."

  #
  #  basic tests
  #
  rubocop:
    runs-on: ubuntu-latest
    env:
      BUNDLE_WITHOUT: "" # we need rubocop, obviously
    steps:
      - uses: actions/checkout@v5
      - uses: ruby/setup-ruby@v1
        with:
          ruby-version: "3.3"
          bundler-cache: true
      - run: bundle exec rake rubocop

  basic:
    needs: rubocop
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - uses: ruby/setup-ruby-pkgs@v1
        with:
          ruby-version: "3.3"
          bundler-cache: true
          apt-get: libsqlite3-dev
      - run: bundle exec rake compile -- --enable-system-libraries
      - run: bundle exec rake test

  test:
    needs: [basic, ruby_versions]
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu, macos, windows]
        ruby: ${{ fromJSON(needs.ruby_versions.outputs.setup_ruby) }}
        syslib: [enable, disable]
        include:
          # additional compilation flags for homebrew
          - { os: macos, syslib: enable, compile_flags: "--with-opt-dir=$(brew --prefix sqlite3)" }
          # additional versions of ruby to test
          - { os: ubuntu, ruby: truffleruby, syslib: disable }
          - { os: windows, ruby: ucrt, syslib: enable }
          - { os: windows, ruby: mswin, syslib: enable }
    runs-on: ${{ matrix.os }}-latest
    steps:
      - if: matrix.os == 'windows'
        name: configure git crlf
        run: |
          git config --system core.autocrlf false
          git config --system core.eol lf
      - uses: actions/checkout@v5
      - uses: ruby/setup-ruby-pkgs@v1
        with:
          ruby-version: ${{ matrix.ruby }}
          bundler-cache: true
          apt-get: libsqlite3-dev
          mingw: sqlite3
          vcpkg: sqlite3
      - if: matrix.syslib == 'disable'
        uses: actions/cache@v4
        with:
          path: ports
          key: ports-${{ matrix.os }}-${{ hashFiles('ext/sqlite3/extconf.rb','dependencies.yml') }}
      - run: bundle exec rake compile -- --${{ matrix.syslib }}-system-libraries ${{ matrix.compile_flags }}
      - run: bundle exec rake test

  fedora:
    # reported at https://github.com/sparklemotion/sqlite3-ruby/issues/354
    # TODO remove once https://github.com/flavorjones/mini_portile/issues/118 is fixed
    needs: basic
    name: "fedora:40"
    runs-on: ubuntu-latest
    container:
      image: fedora:40
    steps:
      - run: |
          dnf group install -y "C Development Tools and Libraries"
          dnf install -y ruby ruby-devel patch
      - uses: actions/checkout@v5
      - run: bundle install
      - run: bundle exec rake compile -- --disable-system-libraries
      - run: bundle exec rake test

  bsd:
    needs: basic
    name: "FreeBSD"
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - uses: vmactions/freebsd-vm@v1
        with:
          usesh: true
          copyback: false
          prepare: pkg install -y ruby devel/ruby-gems pkgconf
          envs: BUNDLE_WITHOUT
          run: |
            gem install bundler
            bundle install --local || bundle install
            bundle exec rake compile -- --disable-system-libraries
            bundle exec rake test

  sqlcipher:
    needs: [basic, ruby_versions]
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu, macos, windows]
        ruby: ${{ fromJSON(needs.ruby_versions.outputs.setup_ruby) }}
        include:
          - { os: windows, ruby: mingw }
          - { os: windows, ruby: mswin }
    runs-on: ${{ matrix.os }}-latest
    steps:
      - if: matrix.os == 'windows'
        name: configure git crlf
        run: |
          git config --system core.autocrlf false
          git config --system core.eol lf
      - uses: actions/checkout@v5
      - uses: ruby/setup-ruby-pkgs@v1
        with:
          ruby-version: ${{ matrix.ruby }}
          bundler-cache: true
          apt-get: libsqlcipher-dev
          brew: sqlcipher
          mingw: sqlcipher
          vcpkg: sqlcipher
      - run: bundle exec rake compile -- --with-sqlcipher
      - run: bundle exec rake test

  valgrind:
    needs: basic
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - uses: ruby/setup-ruby-pkgs@v1
        with:
          ruby-version: "3.3"
          bundler-cache: true
          apt-get: valgrind
      - uses: actions/cache@v4
        with:
          path: ports
          key: ports-ubuntu-${{ hashFiles('ext/sqlite3/extconf.rb','dependencies.yml') }}
      - run: bundle exec rake compile
      - run: bundle exec rake test:valgrind

  #
  #  gem tests (source and native)
  #
  native_setup:
    needs: basic
    name: "Setup for native gem tests"
    runs-on: ubuntu-latest
    outputs:
      rcd_image_version: ${{ steps.rcd_image_version.outputs.rcd_image_version }}
    steps:
      - uses: actions/checkout@v5
      - uses: actions/cache@v4
        with:
          path: ports/archives
          key: ports-archives-tarball-${{ hashFiles('ext/sqlite3/extconf.rb','dependencies.yml') }}
      - uses: ruby/setup-ruby@v1
        with:
          ruby-version: "3.3"
          bundler-cache: true
      - run: bundle exec ruby ./ext/sqlite3/extconf.rb --download-dependencies
      - id: rcd_image_version
        run: bundle exec ruby -e 'require "rake_compiler_dock"; puts "rcd_image_version=#{RakeCompilerDock::IMAGE_VERSION}"' >> $GITHUB_OUTPUT

  build_source_gem:
    needs: native_setup
    name: "build source"
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - uses: actions/cache@v4
        with:
          path: ports/archives
          key: ports-archives-tarball-${{ hashFiles('ext/sqlite3/extconf.rb','dependencies.yml') }}
      - uses: ruby/setup-ruby@v1
        with:
          ruby-version: "3.3"
          bundler-cache: true
      - run: ./bin/test-gem-build gems ruby
      - uses: actions/upload-artifact@v4
        with:
          name: source-gem
          path: gems
          retention-days: 1

  install_source_linux:
    needs: [build_source_gem, ruby_versions]
    name: "test source"
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu, macos, windows]
        ruby: ${{ fromJSON(needs.ruby_versions.outputs.setup_ruby) }}
        syslib: [enable, disable]
        include:
          # additional compilation flags for homebrew
          - { os: macos, syslib: enable, compile_flags: "--with-opt-dir=$(brew --prefix sqlite3)" }
    runs-on: ${{ matrix.os }}-latest
    steps:
      - uses: actions/checkout@v5
      - uses: ruby/setup-ruby-pkgs@v1
        with:
          ruby-version: ${{ matrix.ruby }}
          apt-get: libsqlite3-dev pkg-config
          mingw: sqlite3
      - uses: actions/download-artifact@v5
        with:
          name: source-gem
          path: gems
      - run: ./bin/test-gem-install gems -- --${{ matrix.syslib }}-system-libraries ${{ matrix.compile_flags }}
        shell: sh

  build_native_gem:
    needs: native_setup
    name: "build native"
    strategy:
      fail-fast: false
      matrix:
        platform:
          - aarch64-linux-gnu
          - aarch64-linux-musl
          - arm-linux-gnu
          - arm-linux-musl
          - arm64-darwin
          - x64-mingw-ucrt
          - x86-linux-gnu
          - x86-linux-musl
          - x86_64-darwin
          - x86_64-linux-gnu
          - x86_64-linux-musl
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - uses: actions/cache@v4
        with:
          path: ports/archives
          key: ports-archives-tarball-${{ hashFiles('ext/sqlite3/extconf.rb','dependencies.yml') }}
      - run: |
          docker run --rm -v $PWD:/work -w /work \
            ghcr.io/rake-compiler/rake-compiler-dock-image:${{ needs.native_setup.outputs.rcd_image_version }}-mri-${{ matrix.platform }} \
            ./bin/test-gem-build gems ${{ matrix.platform }}
      - uses: actions/upload-artifact@v4
        with:
          name: "cruby-${{ matrix.platform }}-gem"
          path: gems
          retention-days: 1

  test_architecture_matrix:
    name: "${{ matrix.platform }} ${{ matrix.ruby }}"
    needs: [build_native_gem, ruby_versions]
    strategy:
      fail-fast: false
      matrix:
        platform:
          - aarch64-linux-gnu
          - aarch64-linux-musl
          - arm-linux-gnu
          - arm-linux-musl
          - x86-linux-gnu
          - x86-linux-musl
          - x86_64-linux-gnu
          - x86_64-linux-musl
        ruby: ${{ fromJSON(needs.ruby_versions.outputs.image_tag) }}
        include:
          # declare docker image for each platform
          - { platform: aarch64-linux-musl, docker_tag: "-alpine", bootstrap: "apk add build-base &&" }
          - { platform: arm-linux-musl, docker_tag: "-alpine", bootstrap: "apk add build-base &&" }
          - { platform: x86-linux-musl, docker_tag: "-alpine", bootstrap: "apk add build-base &&" }
          - { platform: x86_64-linux-musl, docker_tag: "-alpine", bootstrap: "apk add build-base &&" }
          # declare docker platform for each platform
          - { platform: aarch64-linux-gnu, docker_platform: "--platform=linux/arm64" }
          - { platform: aarch64-linux-musl, docker_platform: "--platform=linux/arm64" }
          - { platform: arm-linux-gnu, docker_platform: "--platform=linux/arm/v7" }
          - { platform: arm-linux-musl, docker_platform: "--platform=linux/arm/v7" }
          - { platform: x86-linux-gnu, docker_platform: "--platform=linux/386" }
          - { platform: x86-linux-musl, docker_platform: "--platform=linux/386" }
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - uses: actions/download-artifact@v5
        with:
          name: cruby-${{ matrix.platform }}-gem
          path: gems
      - run: |
          docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
          docker run --rm -v $PWD:/work -w /work \
            ${{ matrix.docker_platform}} ruby:${{ matrix.ruby }}${{ matrix.docker_tag }} \
            sh -c "
              ${{ matrix.bootstrap }}
              ./bin/test-gem-install ./gems
            "

  test_the_rest:
    name: "${{ matrix.platform }} ${{ matrix.ruby }}"
    needs: [build_native_gem, ruby_versions]
    strategy:
      fail-fast: false
      matrix:
        os: [windows-latest, macos-13, macos-14]
        ruby: ${{ fromJSON(needs.ruby_versions.outputs.setup_ruby) }}
        include:
          - os: macos-13
            platform: x86_64-darwin
          - os: macos-14
            platform: arm64-darwin
          - os: windows-latest
            platform: x64-mingw-ucrt
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v5
      - uses: ruby/setup-ruby@v1
        with:
          ruby-version: "${{ matrix.ruby }}"
      - uses: actions/download-artifact@v5
        with:
          name: cruby-${{ matrix.platform }}-gem
          path: gems
      - run: ./bin/test-gem-install gems
        shell: sh

  cruby-x86_64-linux-musl-install:
    needs: build_native_gem
    strategy:
      fail-fast: false
      matrix:
        include:
          - { ruby: "3.1", flavor: "alpine3.18" }
          - { ruby: "3.1", flavor: "alpine3.19" }
          - { ruby: "3.2", flavor: "alpine3.18" }
          - { ruby: "3.2", flavor: "alpine3.19" }
          - { ruby: "3.3", flavor: "alpine3.18" }
          - { ruby: "3.3", flavor: "alpine3.19" }
          - { ruby: "3.4", flavor: "alpine" }
    runs-on: ubuntu-latest
    container:
      image: ruby:${{matrix.ruby}}-${{matrix.flavor}}
    steps:
      - uses: actions/checkout@v5
      - uses: actions/download-artifact@v5
        with:
          name: cruby-x86_64-linux-musl-gem
          path: gems
      - run: apk add build-base
      - run: ./bin/test-gem-install ./gems
