name: ci
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
      - v*.*.x
    tags:
      - v*.*.*
  pull_request:
    types: [opened, synchronize]
    branches:
      - '*'

jobs:
  #
  #  SECTION pre-checks for fast feedback loops, and to gate the rest of the suite
  #
  rubocop:
    runs-on: ubuntu-latest
    container:
      image: ghcr.io/sparklemotion/nokogiri-test:mri-3.3
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: true
      - run: bundle install --local || bundle install
      - run: bundle exec rake rubocop

  basic:
    needs: ["rubocop"]
    strategy:
      fail-fast: false
      matrix:
        image: ["ubuntu"]
        sys: ["enable"]
    runs-on: ubuntu-latest
    container:
      image: ghcr.io/sparklemotion/nokogiri-test:${{matrix.image}}
    steps:
      - uses: actions/checkout@v1 # v1 because of https://github.com/actions/checkout/issues/334
        with:
          submodules: true
      - run: bundle install --local || bundle install
      - run: bundle exec rake compile -- --${{matrix.sys}}-system-libraries
      - run: bundle exec rake test
      - run: bundle exec rake test:bench

  gumbo:
    needs: ["rubocop"]
    strategy:
      fail-fast: false
      matrix:
        plat: ["ubuntu", "windows", "macos"]
    runs-on: ${{matrix.plat}}-latest
    steps:
      - name: configure git crlf
        if: matrix.plat == 'windows'
        run: |
          git config --system core.autocrlf false
          git config --system core.eol lf
      - uses: actions/checkout@v4
        with:
          submodules: true
      - uses: ruby/setup-ruby@v1
        with:
          ruby-version: "3.3"
          bundler-cache: true
          bundler: latest
      - run: bundle exec rake gumbo:test

  css:
    name: "css parser"
    needs: ["basic"]
    runs-on: ubuntu-latest
    container:
      image: ghcr.io/sparklemotion/nokogiri-test:ubuntu
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: true
      - run: bundle install --local || bundle install
      - run: bundle exec rake css:clean css:generate
      - run: bundle exec rake compile -- --enable-system-libraries
      - run: bundle exec rake test

  #
  #  SECTION run the test suite across a broad matrix of rubies, configs, and systems
  #
  linux:
    needs: ["basic"]
    strategy:
      fail-fast: false
      matrix:
        sys: ["enable", "disable"]
        ruby: ["3.0", "3.1", "3.2", "3.3"]
    runs-on: ubuntu-latest
    container:
      image: ghcr.io/sparklemotion/nokogiri-test:mri-${{matrix.ruby}}
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: true
      - uses: actions/cache@v4
        if: matrix.sys == 'disable'
        with:
          path: ports
          key: ports-ubuntu-${{matrix.ruby}}-${{hashFiles('dependencies.yml', 'patches/**/*.patch', 'ext/nokogiri/extconf.rb')}}
      - run: bundle install --local || bundle install
      - run: bundle exec rake compile -- --${{matrix.sys}}-system-libraries
      - run: bundle exec rake test
      - run: bundle exec rake test:bench

  valgrind:
    needs: ["linux"]
    strategy:
      fail-fast: false
      matrix:
        sys: ["enable", "disable"]
        ruby: ["3.0", "3.1", "3.2", "3.3"]
        mem: ["ruby"]
        include:
          - sys: "disable"
            ruby: "3.3"
            mem: "default"
    runs-on: ubuntu-latest
    container:
      image: ghcr.io/sparklemotion/nokogiri-test:mri-${{matrix.ruby}}
    env:
      NOKOGIRI_LIBXML_MEMORY_MANAGEMENT: ${{matrix.mem}}
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: true
      - uses: actions/cache@v4
        if: matrix.sys == 'disable'
        with:
          path: ports
          key: ports-ubuntu-${{matrix.ruby}}-${{hashFiles('dependencies.yml', 'patches/**/*.patch', 'ext/nokogiri/extconf.rb')}}
      - run: bundle install --local || bundle install
      - run: bundle exec rake compile -- --${{matrix.sys}}-system-libraries
      - run: bundle exec rake test:valgrind

  musl:
    needs: ["basic"]
    strategy:
      fail-fast: false
      matrix:
        sys: ["enable", "disable"]
    runs-on: ubuntu-latest
    container:
      image: ghcr.io/sparklemotion/nokogiri-test:alpine
    steps:
      - uses: actions/checkout@v1 # v1 because of https://github.com/actions/checkout/issues/334
        with:
          submodules: true
      # skip cache because of https://github.com/actions/cache/issues/675
      - run: bundle install --local || bundle install
      - run: bundle exec rake compile -- --${{matrix.sys}}-system-libraries
      - run: bundle exec rake test

  musl-valgrind:
    needs: ["musl"]
    strategy:
      fail-fast: false
      matrix:
        sys: ["disable"]
    runs-on: ubuntu-latest
    container:
      image: ghcr.io/sparklemotion/nokogiri-test:alpine
    steps:
      - uses: actions/checkout@v1 # v1 because of https://github.com/actions/checkout/issues/334
        with:
          submodules: true
      # skip cache because of https://github.com/actions/cache/issues/675
      - run: bundle install --local || bundle install
      - run: bundle exec rake compile -- --${{matrix.sys}}-system-libraries
      - run: bundle exec rake test:valgrind

  libxmlruby:
    needs: ["basic"]
    strategy:
      fail-fast: false
      matrix:
        sys: ["enable"]
        ruby: ["3.3"]
    env:
      BUNDLE_GEMFILE: "Gemfile-libxml-ruby"
    runs-on: ubuntu-latest
    container:
      image: ghcr.io/sparklemotion/nokogiri-test:mri-${{matrix.ruby}}
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: true
      - uses: actions/cache@v4
        if: matrix.sys == 'disable'
        with:
          path: ports
          key: ports-ubuntu-${{matrix.ruby}}-${{hashFiles('dependencies.yml', 'patches/**/*.patch', 'ext/nokogiri/extconf.rb')}}
      - run: bundle install --local || bundle install
      - run: bundle exec rake compile -- --${{matrix.sys}}-system-libraries
      - run: bundle exec rake test

  libxmlruby-valgrind:
    needs: ["libxmlruby"]
    strategy:
      fail-fast: false
      matrix:
        sys: ["disable"]
        ruby: ["3.3"]
    env:
      BUNDLE_GEMFILE: "Gemfile-libxml-ruby"
    runs-on: ubuntu-latest
    container:
      image: ghcr.io/sparklemotion/nokogiri-test:mri-${{matrix.ruby}}
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: true
      - uses: actions/cache@v4
        if: matrix.sys == 'disable'
        with:
          path: ports
          key: ports-ubuntu-${{matrix.ruby}}-${{hashFiles('dependencies.yml', 'patches/**/*.patch', 'ext/nokogiri/extconf.rb')}}
      - run: bundle install --local || bundle install
      - run: bundle exec rake compile -- --${{matrix.sys}}-system-libraries
      - run: bundle exec rake test:valgrind

  osx:
    needs: ["basic"]
    strategy:
      fail-fast: false
      matrix:
        sys: ["enable", "disable"]
        ruby: ["3.0", "3.1", "3.2", "3.3"]
    runs-on: macos-latest
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: true
      - uses: ruby/setup-ruby@v1
        with:
          ruby-version: ${{matrix.ruby}}
          bundler-cache: true
          bundler: latest
      - uses: actions/cache@v4
        if: matrix.sys == 'disable'
        with:
          path: ports
          key: ports-macos-${{hashFiles('dependencies.yml', 'patches/**/*.patch', 'ext/nokogiri/extconf.rb')}}
      - run: bundle exec rake compile -- --${{matrix.sys}}-system-libraries
      - run: bundle exec rake test

  windows:
    needs: ["basic"]
    strategy:
      fail-fast: false
      matrix:
        sys: ["enable", "disable"]
        ruby: ["3.0", "3.1", "3.2", "3.3"]
    runs-on: windows-2022
    steps:
      - name: configure git crlf
        run: |
          git config --system core.autocrlf false
          git config --system core.eol lf
      - uses: actions/checkout@v4
        with:
          submodules: true
      - uses: ruby/setup-ruby-pkgs@v1
        with:
          ruby-version: "${{matrix.ruby}}"
          mingw: "libxml2 libxslt"
          bundler-cache: true
          bundler: latest
      - uses: actions/cache@v4
        if: matrix.sys == 'disable'
        with:
          path: ports
          key: ports-windows-${{hashFiles('dependencies.yml', 'patches/**/*.patch', 'ext/nokogiri/extconf.rb')}}
      - run: bundle exec rake compile -- --${{matrix.sys}}-system-libraries
      - run: bundle exec rake test

  jruby:
    needs: ["basic"]
    strategy:
      fail-fast: false
      matrix:
        ruby: ["jruby-9.4"]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: true
      - uses: ruby/setup-ruby@v1
        with:
          ruby-version: ${{matrix.ruby}}
          bundler-cache: true
          bundler: latest
      - run: bundle exec rake compile
      - run: bundle exec rake test
      - run: bundle exec rake test:bench

  truffleruby-head:
    needs: ["basic"]
    strategy:
      fail-fast: false
      matrix:
        flags:
          - "--disable-system-libraries --disable-static"
          - "--disable-system-libraries --enable-static"
          - "--enable-system-libraries"
    runs-on: ubuntu-latest
    container:
      image: ghcr.io/sparklemotion/nokogiri-test:truffle-nightly
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: true
      - uses: actions/cache@v4
        with:
          path: ports/archives
          key: tarballs-ubuntu-${{hashFiles('dependencies.yml', 'patches/**/*.patch')}}
      - run: bundle install --local || bundle install
      - run: bundle exec rake compile -- ${{matrix.flags}}
      - run: bundle exec rake test

  bsd:
    continue-on-error: true # let's see if it's really fixed
    needs: ["basic"]
    strategy:
      fail-fast: false
      matrix:
        sys: ["enable", "disable"]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: true
      - uses: vmactions/freebsd-vm@v1
        with:
          usesh: true
          copyback: false
          prepare: pkg install -y ruby devel/ruby-gems pkgconf libxml2 libxslt git
          run: |
            gem install bundler
            bundle install --local || bundle install
            bundle exec rake compile -- --${{matrix.sys}}-system-libraries
            bundle exec rake test

  #
  #  SECTION let's look for memory leaks
  #
  memory_suite:
    continue-on-error: true # still pressure testing the value of this suite
    needs: ["basic"]
    strategy:
      fail-fast: false
      matrix:
        sys: ["disable"]
        ruby: ["3.3"]
    runs-on: ubuntu-latest
    container:
      image: ghcr.io/sparklemotion/nokogiri-test:mri-${{matrix.ruby}}
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: true
      - uses: actions/cache@v4
        if: matrix.sys == 'disable'
        with:
          path: ports
          key: ports-ubuntu-${{matrix.ruby}}-${{hashFiles('dependencies.yml', 'patches/**/*.patch', 'ext/nokogiri/extconf.rb')}}
      - run: bundle install --local || bundle install
      - run: bundle exec rake compile -- --${{matrix.sys}}-system-libraries
      - run: bundle exec rake test:memory_suite

  memcheck:
    needs: ["basic"]
    strategy:
      fail-fast: false
      matrix:
        sys: ["disable"]
        ruby: ["3.3"]
    runs-on: ubuntu-latest
    container:
      image: ghcr.io/sparklemotion/nokogiri-test:mri-${{matrix.ruby}}
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: true
      - uses: actions/cache@v4
        if: matrix.sys == 'disable'
        with:
          path: ports
          key: ports-ubuntu-${{matrix.ruby}}-${{hashFiles('dependencies.yml', 'patches/**/*.patch', 'ext/nokogiri/extconf.rb')}}
      - run: bundle install --local || bundle install
      - run: bundle exec rake compile -- --${{matrix.sys}}-system-libraries
      - run: bundle exec rake test:memcheck

  #
  #  SECTION the end-to-end gem installation tests
  #
  rcd_image_version:
    needs: ["basic"]
    runs-on: ubuntu-latest
    outputs:
      rcd_image_version: ${{steps.rcd_image_version.outputs.rcd_image_version}}
    steps:
      - uses: actions/checkout@v4
      - uses: ruby/setup-ruby@v1
        with:
          ruby-version: "3.3"
          bundler-cache: true
          bundler: latest
      - id: rcd_image_version
        run: bundle exec ruby -e 'require "rake_compiler_dock"; puts "rcd_image_version=#{RakeCompilerDock::IMAGE_VERSION}"' >> $GITHUB_OUTPUT

  generic-package:
    needs: ["rcd_image_version"]
    name: "generic-package"
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: true
      - uses: actions/cache@v4
        with:
          path: ports/archives
          key: tarballs-ubuntu-${{hashFiles('dependencies.yml', 'patches/**/*.patch')}}
      - env:
          DOCKER_IMAGE: "ghcr.io/rake-compiler/rake-compiler-dock-image:${{needs.rcd_image_version.outputs.rcd_image_version}}-mri-x86_64-linux"
        run: |
          docker run --rm -v "$(pwd):/nokogiri" -w /nokogiri \
            ${DOCKER_IMAGE} \
            ./scripts/test-gem-build gems ruby
      - uses: actions/upload-artifact@v4
        with:
          name: generic-gem
          path: gems
          retention-days: 1

  generic-linux-install:
    needs: ["generic-package"]
    strategy:
      fail-fast: false
      matrix:
        sys: ["enable", "disable"]
        ruby: ["3.0", "3.1", "3.2", "3.3"]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: true
      - uses: ruby/setup-ruby-pkgs@v1
        with:
          ruby-version: "${{matrix.ruby}}"
          apt-get: "libxml2-dev libxslt1-dev pkg-config"
      - uses: actions/download-artifact@v4
        with:
          name: generic-gem
          path: gems
      - run: ./scripts/test-gem-install gems --${{matrix.sys}}-system-libraries

  generic-darwin-install:
    needs: ["generic-package"]
    strategy:
      fail-fast: false
      matrix:
        sys: ["enable", "disable"]
        ruby: ["3.0", "3.1", "3.2", "3.3"]
    runs-on: macos-latest
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: true
      - uses: ruby/setup-ruby@v1
        with:
          ruby-version: "${{matrix.ruby}}"
      - uses: actions/download-artifact@v4
        with:
          name: generic-gem
          path: gems
      - run: ./scripts/test-gem-install gems --${{matrix.sys}}-system-libraries

  generic-windows-install:
    needs: ["generic-package"]
    strategy:
      fail-fast: false
      matrix:
        sys: ["enable", "disable"]
        ruby: ["3.0"]
    runs-on: windows-latest
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: true
      - uses: ruby/setup-ruby-pkgs@v1
        with:
          ruby-version: "${{matrix.ruby}}"
          mingw: "libxml2 libxslt"
      - uses: actions/download-artifact@v4
        with:
          name: generic-gem
          path: gems
      - run: ./scripts/test-gem-install gems --${{matrix.sys}}-system-libraries
        shell: bash

  generic-windows-install-ucrt:
    needs: ["generic-package"]
    strategy:
      fail-fast: false
      matrix:
        sys: ["enable", "disable"]
        ruby: ["3.1", "3.2", "3.3"]
    runs-on: windows-2022
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: true
      - uses: ruby/setup-ruby-pkgs@v1
        with:
          ruby-version: "${{matrix.ruby}}"
          mingw: "libxml2 libxslt"
      - uses: actions/download-artifact@v4
        with:
          name: generic-gem
          path: gems
      - run: ./scripts/test-gem-install gems --${{matrix.sys}}-system-libraries
        shell: bash

  cruby-package:
    needs: ["rcd_image_version"]
    name: "cruby-package"
    strategy:
      fail-fast: false
      matrix:
        plat:
          - "aarch64-linux"
          - "arm-linux"
          - "arm64-darwin" # github actions does not support this runtime as of 2022-12, but let's build anyway
          - "x64-mingw-ucrt"
          - "x64-mingw32"
          - "x86-linux"
          - "x86-mingw32" # github actions does not support this runtime as of 2022-12, but let's build anyway
          - "x86_64-darwin"
          - "x86_64-linux"
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: true
      - uses: actions/cache@v4
        with:
          path: ports/archives
          key: tarballs-ubuntu-${{hashFiles('dependencies.yml', 'patches/**/*.patch')}}
      - env:
          DOCKER_IMAGE: "ghcr.io/rake-compiler/rake-compiler-dock-image:${{needs.rcd_image_version.outputs.rcd_image_version}}-mri-${{matrix.plat}}"
        run: |
          docker run --rm -v "$(pwd):/nokogiri" -w /nokogiri \
            ${DOCKER_IMAGE} \
            ./scripts/test-gem-build gems ${{matrix.plat}}
      - uses: actions/upload-artifact@v4
        with:
          name: "cruby-${{matrix.plat}}-gem"
          path: gems
          retention-days: 1

  cruby-x86-linux-install:
    needs: ["cruby-package"]
    strategy:
      fail-fast: false
      matrix:
        ruby: ["3.0", "3.1", "3.2", "3.3"]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: true
      - uses: actions/download-artifact@v4
        with:
          name: cruby-x86-linux-gem
          path: gems
      - run: |
          docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
          docker run --rm -v "$(pwd):/nokogiri" -w /nokogiri \
            --platform=linux/386 \
            ruby:${{matrix.ruby}} \
            ./scripts/test-gem-install gems

  cruby-aarch64-linux-install:
    needs: ["cruby-package"]
    strategy:
      fail-fast: false
      matrix:
        ruby: ["3.0", "3.1", "3.2", "3.3"]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: true
      - uses: actions/download-artifact@v4
        with:
          name: cruby-aarch64-linux-gem
          path: gems
      - run: |
          docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
          docker run --rm -v "$(pwd):/nokogiri" -w /nokogiri \
            --platform=linux/arm64/v8 \
            ruby:${{matrix.ruby}} \
            ./scripts/test-gem-install gems

  cruby-arm-linux-install:
    needs: ["cruby-package"]
    strategy:
      fail-fast: false
      matrix:
        ruby: ["3.0", "3.1", "3.2", "3.3"]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: true
      - uses: actions/download-artifact@v4
        with:
          name: cruby-arm-linux-gem
          path: gems
      - run: |
          docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
          docker run --rm -v "$(pwd):/nokogiri" -w /nokogiri \
            --platform=linux/arm/v7 \
            ruby:${{matrix.ruby}} \
            ./scripts/test-gem-install gems

  cruby-x86_64-linux-install:
    needs: ["cruby-package"]
    strategy:
      fail-fast: false
      matrix:
        ruby: ["3.0", "3.1", "3.2", "3.3"]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: true
      - uses: ruby/setup-ruby@v1
        with:
          ruby-version: "${{matrix.ruby}}"
      - uses: actions/download-artifact@v4
        with:
          name: cruby-x86_64-linux-gem
          path: gems
      - run: ./scripts/test-gem-install gems

  cruby-x86_64-musl-install:
    needs: ["cruby-package"]
    strategy:
      fail-fast: false
    runs-on: ubuntu-latest
    container:
      image: ghcr.io/sparklemotion/nokogiri-test:alpine
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: true
      - uses: actions/download-artifact@v4
        with:
          name: cruby-x86_64-linux-gem
          path: gems
      - run: ./scripts/test-gem-install gems

  cruby-x86_64-darwin-install:
    needs: ["cruby-package"]
    strategy:
      fail-fast: false
      matrix:
        ruby: ["3.0", "3.1", "3.2", "3.3"]
    runs-on: macos-latest
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: true
      - uses: ruby/setup-ruby@v1
        with:
          ruby-version: "${{matrix.ruby}}"
      - uses: actions/download-artifact@v4
        with:
          name: cruby-x86_64-darwin-gem
          path: gems
      - run: ./scripts/test-gem-install gems

  cruby-x64-mingw32-install:
    needs: ["cruby-package"]
    strategy:
      fail-fast: false
      matrix:
        ruby: ["3.0"]
    runs-on: windows-latest
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: true
      - uses: ruby/setup-ruby@v1
        with:
          ruby-version: "${{matrix.ruby}}"
      - uses: actions/download-artifact@v4
        with:
          name: cruby-x64-mingw32-gem
          path: gems
      - run: ./scripts/test-gem-install gems
        shell: bash

  cruby-x64-mingw-ucrt-install:
    needs: ["cruby-package"]
    strategy:
      fail-fast: false
      matrix:
        ruby: ["3.1", "3.2", "3.3"]
    runs-on: windows-2022
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: true
      - uses: ruby/setup-ruby@v1
        with:
          ruby-version: "${{matrix.ruby}}"
      - uses: actions/download-artifact@v4
        with:
          name: cruby-x64-mingw-ucrt-gem
          path: gems
      - run: ./scripts/test-gem-install gems
        shell: bash

  jruby-package:
    needs: ["rcd_image_version"]
    runs-on: ubuntu-latest
    container:
      image: "ghcr.io/rake-compiler/rake-compiler-dock-image:${{needs.rcd_image_version.outputs.rcd_image_version}}-jruby"
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: true
      - run: ./scripts/test-gem-build gems java
      - uses: actions/upload-artifact@v4
        with:
          name: jruby-gem
          path: gems
          retention-days: 1

  jruby-install:
    needs: ["jruby-package"]
    strategy:
      fail-fast: false
      matrix:
        jruby: ["9.4"]
        jre: ["8", "11"]
    name: "jruby-${{matrix.jruby}}-jre${{matrix.jre}}-install"
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: true
      - uses: actions/download-artifact@v4
        with:
          name: jruby-gem
          path: gems
      - run: |
          docker run --rm -v "$(pwd):/nokogiri" -w /nokogiri \
            jruby:${{matrix.jruby}}-jre${{matrix.jre}} \
            ./scripts/test-gem-install gems
