# SPDX-FileCopyrightText: 2020-2026 Sébastien Helleu <flashcode@flashtux.org>
#
# SPDX-License-Identifier: GPL-3.0-or-later

name: CI

on:
  push:
  pull_request:
  schedule:
    - cron: '22 9 * * 2'

env:
  CHECK_DEPS_UBUNTU: >-
    curl
    gettext
    hunspell
    hunspell-en-us
    hunspell-fr
    pipx
    shellcheck
  WEECHAT_DEPS_UBUNTU: >-
    asciidoctor
    build-essential
    cmake
    curl
    devscripts
    equivs
    gem2deb
    guile-3.0-dev
    lcov
    libargon2-dev
    libaspell-dev
    libcjson-dev
    libcpputest-dev
    libcurl4-gnutls-dev
    libgcrypt20-dev
    libgnutls28-dev
    liblua5.4-dev
    libncurses-dev
    libperl-dev
    libphp-embed
    libsodium-dev
    libv8-dev
    libzstd-dev
    ninja-build
    php-dev
    pipx
    pkgconf
    python3-dev
    ruby-pygments.rb
    tcl8.6-dev
    zlib1g-dev
  WEECHAT_DEPS_REDHAT: >-
    asciidoctor
    aspell-devel
    cjson-devel
    clang
    cmake
    cpputest-devel
    gcc
    gettext
    glibc-langpack-en
    gnutls-devel
    guile30-devel
    libcurl-devel
    libgcrypt-devel
    libzstd-devel
    lua-devel
    ncurses-devel
    perl-devel
    php-devel
    php-embedded
    python-devel
    ruby-devel
    sudo
    tcl-devel
    zlib-devel
  WEECHAT_DEPS_FREEBSD: >-
    aspell
    cmake
    cpputest
    curl
    gcc
    gettext
    git
    gnutls
    guile3
    libargon2
    libcjson
    libgcrypt
    libiconv
    llvm
    lua54
    ncurses
    perl5
    php83
    pkgconf
    python3
    ruby
    rubygem-asciidoctor
    sudo
    tcl86
    zstd
  WEECHAT_DEPS_MACOS: >-
    asciidoctor
    aspell
    cjson
    guile
    lua
    pkg-config
    ruby

jobs:

  checks:

    env:
      POEXAM_VERSION: "0.0.12"

    strategy:
      matrix:
        os:
          - ubuntu-26.04

    runs-on: ${{ matrix.os }}

    steps:

    - uses: actions/checkout@v6

    - name: Install dependencies
      run: |
        sudo apt-get update -qq
        sudo apt-get --yes --no-install-recommends install ${{ env.CHECK_DEPS_UBUNTU }}
        pipx install ruff

    - name: Cache poexam
      id: cache-poexam
      uses: actions/cache@v6
      with:
        path: ~/.cargo/bin/poexam
        key: poexam-${{ env.POEXAM_VERSION }}-${{ runner.os }}

    - name: Install poexam
      if: steps.cache-poexam.outputs.cache-hit != 'true'
      run: cargo install --version "$POEXAM_VERSION" poexam

    - name: Check gettext files
      run: poexam check --file-stats --rule-stats

    - name: Check shell and Python scripts
      run: ./tools/check_scripts.sh

    - name: Check Python stub file
      run: ./tools/generate_python_stub.py | diff src/plugins/python/weechat.pyi -

    - name: Check Curl symbols
      run: curl --silent --show-error --fail --retry 10 https://raw.githubusercontent.com/curl/curl/master/docs/libcurl/symbols-in-versions | ./tools/check_curl_symbols.py

  install:

    strategy:
      matrix:
        os:
          - ubuntu-26.04
        config:
          - name: "gcc"
            cc: "gcc"
            cxx: "g++"
            buildargs: "-DENABLE_MAN=ON -DENABLE_DOC=ON -DENABLE_TESTS=ON"
          - name: "gcc_ninja"
            cc: "gcc"
            cxx: "g++"
            buildargs: "-G Ninja -DENABLE_MAN=ON -DENABLE_DOC=ON -DENABLE_TESTS=ON"
          - name: "gcc_release_hardened"
            cc: "gcc"
            cxx: "g++"
            buildargs: "-DENABLE_TESTS=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_FLAGS=\"-Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3\" -DCMAKE_CXX_FLAGS=\"-Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3\""
          - name: "gcc_no_nls"
            cc: "gcc"
            cxx: "g++"
            buildargs: "-DENABLE_MAN=ON -DENABLE_TESTS=ON -DENABLE_NLS=OFF"
          - name: "gcc_no_zstd"
            cc: "gcc"
            cxx: "g++"
            buildargs: "-DENABLE_TESTS=ON -DENABLE_ZSTD=OFF"
          - name: "gcc_no_cjson"
            cc: "gcc"
            cxx: "g++"
            buildargs: "-DENABLE_TESTS=ON -DENABLE_CJSON=OFF"
          - name: "gcc_no_perl_multiplicity"
            cc: "gcc"
            cxx: "g++"
            buildargs: "-DENABLE_TESTS=ON -DCMAKE_C_FLAGS=\"-DNO_PERL_MULTIPLICITY=1\""
          - name: "gcc_coverage"
            cc: "gcc"
            cxx: "g++"
            buildargs: "-DENABLE_MAN=ON -DENABLE_DOC=ON -DENABLE_TESTS=ON -DENABLE_CODE_COVERAGE=ON"
          - name: "clang"
            cc: "clang"
            cxx: "clang++"
            buildargs: "-DENABLE_CODE_COVERAGE=ON -DENABLE_FUZZ=ON"

    name: "install (${{ matrix.os }}, ${{ matrix.config.name }})"
    runs-on: ${{ matrix.os }}
    env:
      PHP_INI_SCAN_DIR: /tmp/php-noscan  # embed PHP loads no add-on extensions (see #2009)

    steps:

    - uses: actions/checkout@v6

    - name: Install dependencies
      run: |
        sudo apt-get update -qq
        sudo apt-get --yes --no-install-recommends install ${{ env.WEECHAT_DEPS_UBUNTU }}
        mkdir -p /tmp/php-noscan
        pipx install schemathesis

    - name: Build and run tests
      env:
        CC: ${{ matrix.config.cc }}
        CXX: ${{ matrix.config.cxx }}
      run: ./tools/build_test.sh ${{ matrix.config.buildargs }}

    - name: Run WeeChat
      env:
        TERM: xterm-256color
      run: |
        weechat --help
        weechat-curses --help
        weechat --version
        weechat --build-info
        weechat --colors
        weechat --license
        weechat --run-command "/debug dirs;/debug libs" --run-command "/quit"

    - name: Test Relay OpenAPI
      if: ${{ matrix.config.name == 'gcc' }}
      env:
        RELAY_PASSWORD: test
      run: |
        weechat-headless \
          --dir /tmp/weechat-test-api \
          --run-command '/set relay.network.password "${{ env.RELAY_PASSWORD }}"' \
          --run-command '/set relay.network.password_hash_iterations 100' \
          --run-command '/set relay.network.max_clients 0' \
          --run-command '/relay add api 9000' \
          --daemon \
        ;
        sleep 5
        schemathesis run --url http://localhost:9000/api ./src/plugins/relay/api/weechat-relay-api.yaml
        echo '*/quit' >/tmp/weechat-test-api/weechat_fifo_*

    - name: Code coverage
      if: ${{ matrix.config.name == 'gcc_coverage' }}
      env:
        CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
      run: |
        cd build-tmp-*
        lcov --directory . --capture --output-file coverage.info
        lcov --remove coverage.info '/usr/*' --output-file coverage.info
        lcov --list coverage.info
        bash <(curl -s https://codecov.io/bash) -f coverage.info || echo 'Codecov error'

  install_fedora:

    strategy:
      matrix:
        os:
          - ubuntu-26.04
        config:
          - name: "gcc"
            cc: "gcc"
            cxx: "g++"
            buildargs: "-DENABLE_MAN=ON -DENABLE_DOC=ON -DENABLE_TESTS=ON"
          - name: "clang"
            cc: "clang"
            cxx: "clang++"
            buildargs: "-DENABLE_MAN=ON -DENABLE_DOC=ON -DENABLE_TESTS=ON -DENABLE_CODE_COVERAGE=ON -DENABLE_FUZZ=ON"

    name: "install (fedora:43, ${{ matrix.config.name }})"
    runs-on: ${{ matrix.os }}
    container:
      image: fedora:43

    steps:

    - uses: actions/checkout@v6

    - name: Install dependencies
      run: dnf install -y ${{ env.WEECHAT_DEPS_REDHAT }}

    - name: Build and run tests
      env:
        CC: ${{ matrix.config.cc }}
        CXX: ${{ matrix.config.cxx }}
      run: ./tools/build_test.sh ${{ matrix.config.buildargs }}

    - name: Run WeeChat
      env:
        TERM: xterm-256color
      run: |
        weechat --help
        weechat-curses --help
        weechat --version
        weechat --build-info
        weechat --colors
        weechat --license
        weechat --run-command "/debug dirs;/debug libs" --run-command "/quit"

  install_rockylinux:

    strategy:
      matrix:
        os:
          - ubuntu-26.04
        config:
          - name: "gcc"
            cc: "gcc"
            cxx: "g++"
            buildargs: "-DENABLE_MAN=ON -DENABLE_DOC=ON -DENABLE_TESTS=ON"
          - name: "clang"
            cc: "clang"
            cxx: "clang++"
            buildargs: "-DENABLE_MAN=ON -DENABLE_DOC=ON -DENABLE_TESTS=ON -DENABLE_CODE_COVERAGE=ON -DENABLE_FUZZ=ON"

    name: "install (rockylinux:9, ${{ matrix.config.name }})"
    runs-on: ${{ matrix.os }}
    container:
      image: rockylinux:9

    steps:

    - uses: actions/checkout@v6

    - name: Install dependencies
      run: |
        dnf install -y epel-release dnf-plugins-core
        dnf config-manager --set-enabled crb
        # pin a working ruby stream (ruby:4.0 has broken module metadata on Rocky 9.8)
        dnf module enable -y ruby:3.3
        dnf install -y ${{ env.WEECHAT_DEPS_REDHAT }}

    - name: Build and run tests
      env:
        CC: ${{ matrix.config.cc }}
        CXX: ${{ matrix.config.cxx }}
      run: ./tools/build_test.sh ${{ matrix.config.buildargs }}

    - name: Run WeeChat
      env:
        TERM: xterm-256color
      run: |
        weechat --help
        weechat-curses --help
        weechat --version
        weechat --build-info
        weechat --colors
        weechat --license
        weechat --run-command "/debug dirs;/debug libs" --run-command "/quit"

  install_freebsd:

    strategy:
      matrix:
        os:
          - ubuntu-26.04
        config:
          # - name: "gcc"
          # cc: "gcc"
          # cxx: "g++"
          # buildargs: "-DENABLE_MAN=ON -DENABLE_DOC=ON -DENABLE_TESTS=ON"
          - name: "clang"
            cc: "clang"
            cxx: "clang++"
            buildargs: "-DENABLE_MAN=ON -DENABLE_DOC=ON -DENABLE_TESTS=ON -DENABLE_CODE_COVERAGE=ON -DENABLE_FUZZ=ON"

    name: "install (freebsd, ${{ matrix.config.name }})"
    runs-on: ${{ matrix.os }}

    steps:

    - uses: actions/checkout@v6

    - name: Install dependencies, build and run tests, run WeeChat
      uses: vmactions/freebsd-vm@v1
      env:
        CC: ${{ matrix.config.cc }}
        CXX: ${{ matrix.config.cxx }}
        TERM: xterm-256color
      with:
        envs: "CC CXX TERM"
        usesh: true
        prepare: pkg install -y ${{ env.WEECHAT_DEPS_FREEBSD }}
        run: |
          ./tools/build_test.sh ${{ matrix.config.buildargs }}
          weechat --help
          weechat-curses --help
          weechat --version
          weechat --build-info
          weechat --colors
          weechat --license
          weechat --run-command "/debug dirs;/debug libs" --run-command "/quit"

  install_macos:

    strategy:
      matrix:
        os:
          - macos-14
        config:
          - name: "gcc"
            cc: "gcc"
            cxx: "g++"
            buildargs: "-DENABLE_MAN=ON -DENABLE_DOC=ON -DENABLE_DOC_INCOMPLETE=ON -DENABLE_PHP=OFF -DENABLE_TESTS=OFF"
          - name: "clang"
            cc: "clang"
            cxx: "clang++"
            buildargs: "-DENABLE_MAN=ON -DENABLE_DOC=ON -DENABLE_DOC_INCOMPLETE=ON -DENABLE_PHP=OFF -DENABLE_TESTS=OFF"

    name: "install (${{ matrix.os }}, ${{ matrix.config.name }})"
    runs-on: ${{ matrix.os }}

    steps:

    - name: Setup Homebrew
      id: setup-homebrew
      uses: Homebrew/actions/setup-homebrew@main

    - name: Install dependencies
      run: |
        brew update
        brew install ${{ env.WEECHAT_DEPS_MACOS }}

    - uses: actions/checkout@v6

    - name: Build
      env:
        CC: ${{ matrix.config.cc }}
        CXX: ${{ matrix.config.cxx }}
        RUN_TESTS: "0"
        JOBS: "2"
      run: ./tools/build_test.sh ${{ matrix.config.buildargs }}

    - name: Run WeeChat
      env:
        TERM: xterm-256color
      run: |
        weechat --help
        weechat-curses --help
        weechat --version
        weechat --build-info
        weechat --colors
        weechat --license
        weechat --run-command "/debug dirs;/debug libs" --run-command "/quit"

  build_debian:

    strategy:
      matrix:
        os:
          - ubuntu-26.04

    runs-on: ${{ matrix.os }}

    steps:

    - uses: actions/checkout@v6

    - name: Install dependencies
      run: |
        sudo apt-get update -qq
        sudo apt-get --yes --no-install-recommends install ${{ env.WEECHAT_DEPS_UBUNTU }}

    - name: Test Debian patches
      run: ./tools/build_debian.sh test-patches

    - name: Build Debian packages
      run: ./tools/build_debian.sh devel ubuntu/noble

    - name: Install Debian packages
      run: sudo dpkg -i ../weechat-devel*.deb

    - name: Run WeeChat
      env:
        TERM: xterm-256color
      run: |
        weechat --help
        weechat-curses --help
        weechat --version
        weechat --build-info
        weechat --run-command "/debug dirs;/debug libs" --run-command "/quit"

  codeql_analysis:

    strategy:
      matrix:
        os:
          - ubuntu-26.04

    runs-on: ${{ matrix.os }}

    permissions:
      actions: read
      contents: read
      security-events: write

    steps:

    - name: Checkout repository
      uses: actions/checkout@v6

    - name: Install dependencies
      run: |
        sudo apt-get update -qq
        sudo apt-get --yes --no-install-recommends install ${{ env.WEECHAT_DEPS_UBUNTU }}

    - name: Initialize CodeQL
      uses: github/codeql-action/init@v3
      with:
        languages: cpp

    - name: Autobuild
      uses: github/codeql-action/autobuild@v3

    - name: Perform CodeQL Analysis
      uses: github/codeql-action/analyze@v3
      with:
        category: "/language:cpp"
