#
# s3fs - FUSE-based file system backed by Amazon S3
#
# Copyright(C) 2007 Takeshi Nakatani <ggtakec.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#

name: s3fs-fuse CI

on:
  push:
  pull_request:
  #
  # CRON event is fired on every sunday (UTC).
  #
  schedule:
    - cron: '0 0 * * 0'

#
# Jobs
#
jobs:
  Linux:
    runs-on: ubuntu-latest
    #
    # build matrix for containers
    #
    strategy:
      #
      # do not stop jobs automatically if any of the jobs fail
      #
      fail-fast: false

      #
      # matrix for containers
      #
      matrix:
        container:
          - ubuntu:25.10
          - ubuntu:24.04
          - ubuntu:22.04
          - debian:trixie
          - debian:bookworm
          - debian:bullseye
          - rockylinux/rockylinux:10
          - rockylinux/rockylinux:9
          - rockylinux/rockylinux:8
          - fedora:43
          - fedora:42
          - opensuse/leap:15
          - opensuse/leap:16.0
          - alpine:3.22

    container:
      image: ${{ matrix.container }}
      options: "--privileged --cap-add SYS_ADMIN --device /dev/fuse"

    env:
      # [NOTE]
      # Installation special environment variables for debian and ubuntu.
      #
      DEBIAN_FRONTEND:  noninteractive

    steps:
      # [NOTE]
      # On openSUSE, tar and gzip must be installed before action/checkout.
      #
      - name: Install openSUSE packages before checkout
        if: matrix.container == 'opensuse/leap:15' || matrix.container == 'opensuse/leap:16.0'
        run: zypper install -y tar gzip

      - name: Install Alpine packages before checkout
        if: matrix.container == 'alpine:3.22'
        run: apk add --no-progress --no-cache bash

      - name: Checkout source code
        uses: actions/checkout@v4

      # [NOTE]
      # Matters that depend on OS:VERSION are determined and executed in the following script.
      # Please note that the option to configure (CONFIGURE_OPTIONS) is set in the environment variable.
      #
      - name: Install packages
        run: |
          .github/workflows/linux-ci-helper.sh ${{ matrix.container }}

      - name: Build
        run: |
          ./autogen.sh
          /bin/sh -c "./configure ${CONFIGURE_OPTIONS}"
          make --jobs=$(nproc)

      - name: Test suite
        run: |
          make check -C src
          make ALL_TESTS=1 check -C test || (test/filter-suite-log.sh test/test-suite.log; exit 1)

  # [NOTE]
  # Using macos-fuse-t
  #   This product(package) is a workaround for osxfuse which required an OS reboot(macos 11 and later).
  #   see. https://github.com/macos-fuse-t/fuse-t
  # About osxfuse
  #   This job doesn't work with GitHub Actions using macOS 11+ because "load_osxfuse" returns
  #   "exit code = 1".(requires OS reboot)
  #
  macos-14:
    runs-on: macos-14

    # [NOTE]
    # In macos-14 (and maybe later), the location of the CA certificate is different and you need to specify it.
    # We give the CA path as an environment variable.
    #
    env:
        CURL_CA_BUNDLE: "/opt/homebrew/etc/ca-certificates/cert.pem"

    steps:
      - name: Checkout source code
        uses: actions/checkout@v4

      - name: Brew tap
        run: |
          TAPS="$(brew --repository)/Library/Taps";
          if [ -e "$TAPS/caskroom/homebrew-cask" ]; then rm -rf "$TAPS/caskroom/homebrew-cask"; fi;
          HOMEBREW_NO_AUTO_UPDATE=1 brew tap homebrew/homebrew-cask
          HOMEBREW_NO_AUTO_UPDATE=1 brew tap macos-fuse-t/homebrew-cask

      - name: Install fuse-t
        run: |
          if [ ! -d /usr/local/include ]; then sudo mkdir -p /usr/local/include; echo "Created /usr/local/include directory"; fi
          HOMEBREW_NO_AUTO_UPDATE=1 brew install fuse-t

      - name: Install brew other packages
        run: |
          S3FS_BREW_PACKAGES='automake cppcheck python3 coreutils gnu-sed shellcheck jq';
          for s3fs_brew_pkg in ${S3FS_BREW_PACKAGES}; do
            if brew list | grep -q ${s3fs_brew_pkg}; then if brew outdated | grep -q ${s3fs_brew_pkg}; then HOMEBREW_NO_AUTO_UPDATE=1 brew upgrade ${s3fs_brew_pkg}; fi; else HOMEBREW_NO_AUTO_UPDATE=1 brew install ${s3fs_brew_pkg}; fi
          done

      - name: Build
        run: |
          ./autogen.sh
          PKG_CONFIG_PATH=/usr/local/opt/curl/lib/pkgconfig:/usr/local/opt/openssl/lib/pkgconfig ./configure
          make --jobs=$(sysctl -n hw.ncpu)

      - name: Cppcheck
        run: make cppcheck

      - name: Shellcheck
        run: make shellcheck

      - name: Test suite
        run: |
          make check -C src
          make ALL_TESTS=1 check -C test || (test/filter-suite-log.sh test/test-suite.log; exit 1)

  MemoryTest:
    runs-on: ubuntu-latest

    #
    # build matrix for containers
    #
    strategy:
      #
      # do not stop jobs automatically if any of the jobs fail
      #
      fail-fast: false

      #
      # matrix for type of checking
      #
      # [NOTE]
      # Currently following test is not supported:
      #    - sanitize_memory   : Future support planned
      #
      matrix:
        checktype:
          - glibc_debug
          - sanitize_address
          - sanitize_others
          - sanitize_thread
          - thread_safety
          - valgrind

    container:
      image: fedora:43

      options: "--privileged --cap-add SYS_ADMIN --device /dev/fuse"

    steps:
      - name: Checkout source code
        uses: actions/checkout@v4

      - name: Install packages
        run: |
          .github/workflows/linux-ci-helper.sh fedora:43

      - name: Install clang
        run: |
          dnf install -y \
            clang \
            libcxx \
            libcxx-devel

      - name: Install Valgrind
        if: matrix.checktype == 'valgrind'
        run: dnf install -y valgrind

      #
      # Set CXX/CXXFLAGS and Variables for test
      #
      - name: Set variables
        run: |
          COMMON_CXXFLAGS='-g -Wno-cpp'
          {
            if [ "${{ matrix.checktype }}" = "glibc_debug" ]; then
                echo "CXXFLAGS=${COMMON_CXXFLAGS} -O0 -D_GLIBCXX_DEBUG"
            elif [ "${{ matrix.checktype }}" = "sanitize_address" ]; then
                echo 'CXX=clang++'
                echo "CXXFLAGS=${COMMON_CXXFLAGS} -O0 -fsanitize=address -fsanitize-address-use-after-scope"
                echo 'ASAN_OPTIONS=detect_leaks=1,detect_stack_use_after_return=1'
            elif [ "${{ matrix.checktype }}" = "sanitize_memory" ]; then
                echo 'CXX=clang++'
                echo "CXXFLAGS=${COMMON_CXXFLAGS} -O0 -fsanitize=memory"
            elif [ "${{ matrix.checktype }}" = "sanitize_thread" ]; then
                echo 'CXX=clang++'
                echo "CXXFLAGS=${COMMON_CXXFLAGS} -O0 -fsanitize=thread"
                echo 'TSAN_OPTIONS=halt_on_error=1'
                # [NOTE]
                # Set this to avoid following error when running configure.
                # "FATAL: ThreadSanitizer: unexpected memory mapping"
                sysctl vm.mmap_rnd_bits=28
            elif [ "${{ matrix.checktype }}" = "sanitize_others" ]; then
                echo 'CXX=clang++'
                echo "CXXFLAGS=${COMMON_CXXFLAGS} -O1 -fsanitize=undefined,implicit-conversion,local-bounds,unsigned-integer-overflow"
            elif [ "${{ matrix.checktype }}" = "thread_safety" ]; then
                echo 'CXX=clang++'
                echo "CXXFLAGS=${COMMON_CXXFLAGS} -O1 -Wthread-safety -Wthread-safety-beta -stdlib=libc++ -D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS -Werror"
                echo 'LDFLAGS=-DCLANG_DEFAULT_LINKER=lld'
            elif [ "${{ matrix.checktype }}" = "valgrind" ]; then
                echo "CXXFLAGS=${COMMON_CXXFLAGS} -O1"
                echo 'VALGRIND="--leak-check=full --error-exitcode=1"'
                echo 'RETRIES=100'
                echo 'S3_URL=http://127.0.0.1:8081'
            fi
          } >> "$GITHUB_ENV"

      - name: Build
        run: |
          ./autogen.sh
          /bin/sh -c "CXX=${CXX} CXXFLAGS=\"${CXXFLAGS}\" LDFLAGS=\"${LDFLAGS}\" ./configure --prefix=/usr --with-openssl"
          make --jobs=$(nproc)

      - name: Test suite
        run: |
          /bin/sh -c "ALL_TESTS=1 ASAN_OPTIONS=${ASAN_OPTIONS} TSAN_OPTIONS=${TSAN_OPTIONS} VALGRIND=${VALGRIND} RETRIES=${RETRIES} make check -C test || (test/filter-suite-log.sh test/test-suite.log; exit 1)"

  static-checks:
    runs-on: ubuntu-latest
    container:
      image: fedora:43

    steps:
      - name: Checkout source code
        uses: actions/checkout@v4

      - name: Install packages
        run: |
          .github/workflows/linux-ci-helper.sh fedora:43

      - name: Install extra packages
        run: |
          dnf install -y \
            clang-tools-extra \
            cppcheck \
            python3 \
            ShellCheck

      - name: Build
        run: |
          ./autogen.sh
          /bin/sh -c "./configure ${CONFIGURE_OPTIONS}"
          make --jobs=$(nproc)

      - name: clang-tidy
        run: |
          make clang-tidy

      - name: Cppcheck
        run: |
          make cppcheck

      - name: Shellcheck
        run: |
          make shellcheck

#
# Local variables:
# tab-width: 4
# c-basic-offset: 4
# End:
# vim600: expandtab sw=4 ts=4 fdm=marker
# vim<600: expandtab sw=4 ts=4
#
