name: Windows

on: [push, pull_request]

jobs:
  build-msvc:
    name: ${{matrix.msvc}}-${{matrix.arch}}-C++${{matrix.std}}-${{matrix.build_type}}-${{matrix.lib}}-${{matrix.extra}}
    runs-on: ${{matrix.os}}
    defaults:
      run:
        shell: powershell
    env:
      CL: /MP
      CXXFLAGS: /WX /permissive-
    strategy:
      fail-fast: true
      matrix:
        arch: [Win32, x64]
        build_type: [Debug, Release]
        extra: [no-custom-prefix, custom-prefix]
        lib: [shared, static]
        msvc: [VS-16-2019, VS-17-2022]
        # Visual Studio 17 2022 does not support C++11 and older language standard
        std: [14, 17, 20]
        include:
          - msvc: VS-16-2019
            os: windows-2019
            generator: 'Visual Studio 16 2019'
          - msvc: VS-17-2022
            os: windows-2022
            generator: 'Visual Studio 17 2022'

    steps:
      - uses: actions/checkout@v2

      - name: Cache GTest
        id: cache-gtest
        uses: actions/cache@v2
        with:
          path: gtest/
          key: ${{runner.os}}-gtest-1.11-${{matrix.lib}}-${{matrix.arch}}-${{matrix.build_type}}

      - name: Download GTest
        if: steps.cache-gtest.outputs.cache-hit != 'true'
        run: |
          (New-Object System.Net.WebClient).DownloadFile("https://github.com/google/googletest/archive/refs/tags/release-1.11.0.zip", "release-1.11.0.zip")
          Expand-Archive release-1.11.0.zip .

      - name: Build GTest
        if: steps.cache-gtest.outputs.cache-hit != 'true'
        run: |
          cmake -S googletest-release-1.11.0 -B build-googletest `
                -A ${{matrix.arch}} `
                -DBUILD_SHARED_LIBS=${{matrix.lib == 'shared'}} `
                -Dgtest_force_shared_crt=ON `
                -DCMAKE_INSTALL_PREFIX=${{github.workspace}}/gtest
          cmake --build build-googletest `
                --config ${{matrix.build_type}} `
                --target install

      - name: Cache gflags
        id: cache-gflags
        uses: actions/cache@v2
        with:
          path: gflags/
          key: ${{runner.os}}-gflags-2.2.2-${{matrix.lib}}-${{matrix.arch}}-${{matrix.build_type}}

      - name: Download gflags
        if: steps.cache-gflags.outputs.cache-hit != 'true'
        run: |
          (New-Object System.Net.WebClient).DownloadFile("https://github.com/gflags/gflags/archive/refs/tags/v2.2.2.zip", "v2.2.2.zip")
          Expand-Archive v2.2.2.zip .

      - name: Build gflags
        if: steps.cache-gflags.outputs.cache-hit != 'true'
        run: |
          cmake -S gflags-2.2.2 -B build-gflags `
                -A ${{matrix.arch}} `
                -DBUILD_SHARED_LIBS=${{matrix.lib == 'shared'}} `
                -DCMAKE_INSTALL_PREFIX=${{github.workspace}}/gflags
          cmake --build build-gflags `
                --config ${{matrix.build_type}} `
                --target install

      - name: Setup Environment
        run: |
          echo "GTest_ROOT=$((Get-Item .).FullName)/gtest" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
          echo "gflags_ROOT=$((Get-Item .).FullName)/gflags" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
          echo "${{github.workspace}}/gtest/bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
          echo "${{github.workspace}}/gflags/bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append

      - name: Setup Release Environment
        if: matrix.build_type != 'Debug'
        run: |
          echo "CXXFLAGS=/Zi ${{env.CXXFLAGS}}" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append

      - name: Configure
        run: |
          cmake -S . -B build_${{matrix.build_type}} `
                -A ${{matrix.arch}} `
                -DBUILD_SHARED_LIBS=${{matrix.lib == 'shared'}} `
                -DCMAKE_CXX_EXTENSIONS=OFF `
                -DCMAKE_CXX_STANDARD=${{matrix.std}} `
                -DCMAKE_CXX_STANDARD_REQUIRED=ON `
                -DCMAKE_EXE_LINKER_FLAGS='/NOIMPLIB' `
                -DCMAKE_EXE_LINKER_FLAGS_RELEASE='/INCREMENTAL:NO /DEBUG' `
                -DCMAKE_INSTALL_PREFIX:PATH=./install `
                -DCMAKE_MSVC_RUNTIME_LIBRARY='MultiThreaded$<$<CONFIG:Debug>:Debug>DLL' `
                -DWITH_CUSTOM_PREFIX=${{matrix.extra == 'custom-prefix'}} `
                -G "${{matrix.generator}}" `
                -Werror

      - name: Build
        run: cmake --build build_${{matrix.build_type}} `
                   --config ${{matrix.build_type}}

      - name: Test
        env:
          CTEST_OUTPUT_ON_FAILURE: 1
        run: |
          cmake --build build_${{matrix.build_type}}/ `
                --config ${{matrix.build_type}} `
                --target RUN_TESTS

      - name: Install
        run: |
          cmake --build build_${{matrix.build_type}}/ `
                --config ${{matrix.build_type}} `
                --target install

  build-mingw:
    name: ${{matrix.sys}}-${{matrix.env}}-C++${{matrix.std}}-${{matrix.build_type}}-${{matrix.lib}}-${{matrix.extra}}
    runs-on: windows-2022
    env:
      BUILDDIR: 'build_${{matrix.sys}}-${{matrix.env}}-C++${{matrix.std}}-${{matrix.build_type}}-${{matrix.lib}}-${{matrix.extra}}'
    defaults:
      run:
        shell: msys2 {0}
    strategy:
      fail-fast: true
      matrix:
        build_type: [Debug]
        extra: [no-custom-prefix, custom-prefix]
        lib: [shared, static]
        std: [98, 11, 14, 17, 20]
        sys: [mingw32, mingw64]
        include:
         - sys: mingw32
           env: i686
         - sys: mingw64
           env: x86_64

    steps:
      - uses: actions/checkout@v2
      - uses: msys2/setup-msys2@v2
        with:
          msystem: ${{matrix.sys}}
          install: >-
            lcov
            mingw-w64-${{matrix.env}}-cmake
            mingw-w64-${{matrix.env}}-gcc
            mingw-w64-${{matrix.env}}-gflags
            mingw-w64-${{matrix.env}}-ninja

      - name: Setup C++98 Environment
        if: matrix.std == '98'
        run: |
          echo 'CXXFLAGS=-Wno-error=variadic-macros -Wno-error=long-long ${{env.CXXFLAGS}}' >> $GITHUB_ENV

      - name: Setup Environment
        if: matrix.build_type == 'Debug'
        run: |
          echo 'CXXFLAGS=--coverage ${{env.CXXFLAGS}}' >> $GITHUB_ENV

      - name: Configure
        env:
          CXXFLAGS: -Wall -Wextra -Wpedantic -Wsign-conversion -Wtautological-compare -Wformat-nonliteral -Wundef -Werror ${{env.CXXFLAGS}}
        run: |
          cmake -S . -B build_${{matrix.build_type}}/ \
                -DBUILD_SHARED_LIBS=${{matrix.lib == 'shared'}} \
                -DCMAKE_BUILD_TYPE=${{matrix.build_type}} \
                -DCMAKE_CXX_EXTENSIONS=OFF \
                -DCMAKE_CXX_STANDARD=${{matrix.std}} \
                -DCMAKE_CXX_STANDARD_REQUIRED=ON \
                -DCMAKE_INSTALL_PREFIX:PATH=./install \
                -DWITH_CUSTOM_PREFIX=${{matrix.extra == 'custom-prefix'}} \
                -G Ninja \
                -Werror

      - name: Build
        run: |
          cmake --build build_${{matrix.build_type}}/ --config ${{matrix.build_type}}

      - name: Test
        env:
          CTEST_OUTPUT_ON_FAILURE: 1
        run: |
          cmake --build build_${{matrix.build_type}}/ --config ${{matrix.build_type}} \
                --target test

      - name: Install
        run: |
          cmake --build build_${{matrix.build_type}}/ \
                --config ${{matrix.build_type}} \
                --target install

      - name: Generate Coverage
        if: matrix.build_type == 'Debug'
        run: |
          lcov --directory . --capture --output-file coverage.info
          lcov --remove coverage.info \
            '*/install/include/*' \
            '*/msys64/mingw32/*' \
            '*/msys64/mingw64/*' \
            '*/src/*_unittest.cc' \
            '*/src/googletest.h' \
            '*/src/mock-log.h' \
            --output-file coverage.info

          for file in src/glog/*.h.in; do
            name=$(basename ${file})
            name_we=${name%.h.in}
            sed -i "s|build_${{matrix.build_type}}/glog/${name_we}.h\$|${file}|g" coverage.info
          done

          lcov --list coverage.info

      - name: Upload Coverage to Codecov
        if: matrix.build_type == 'Debug'
        uses: codecov/codecov-action@v2
        with:
          token: ${{ secrets.CODECOV_TOKEN }}
          fail_ci_if_error: true
          verbose: true