# https://cristianadam.eu/20191222/using-github-actions-with-c-plus-plus-and-cmake/
name: CMake Build Matrix

on: [push]

jobs:
  build:
    name: ${{ matrix.config.name }}
    runs-on: ${{ matrix.config.os }}
    strategy:
      fail-fast: false
      matrix:
        config:
        - {
            name: "Windows Latest MSVC", artifact: "Windows-MSVC.tar.xz",
            os: windows-latest,
            build_type: "Release", cc: "cl", cxx: "cl",
            environment_script: "C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/VC/Auxiliary/Build/vcvars64.bat"
          }
        - {
            name: "Windows Latest MinGW", artifact: "Windows-MinGW.tar.xz",
            os: windows-latest,
            build_type: "Release", cc: "gcc", cxx: "g++"
          }
        - {
            name: "Ubuntu Latest GCC", artifact: "Linux.tar.xz",
            os: ubuntu-latest,
            build_type: "Release", cc: "gcc", cxx: "g++"
          }
        - {
            name: "macOS Latest Clang", artifact: "macOS.tar.xz",
            os: macos-latest,
            build_type: "Release", cc: "clang", cxx: "clang++"
          }

    steps:
      - uses: actions/checkout@v1

      # Get latest CMake and ninja
      # https://github.com/marketplace/actions/get-cmake
      - name: Get cmake+ninja
        uses: lukka/get-cmake@latest

      - name: Configure
        shell: cmake -P {0}
        run: |
          set(ENV{CC} ${{ matrix.config.cc }})
          set(ENV{CXX} ${{ matrix.config.cxx }})

          if ("${{ runner.os }}" STREQUAL "Windows" AND NOT "x${{ matrix.config.environment_script }}" STREQUAL "x")
            execute_process(
              COMMAND "${{ matrix.config.environment_script }}" && set
              OUTPUT_FILE environment_script_output.txt
            )
            file(STRINGS environment_script_output.txt output_lines)
            foreach(line IN LISTS output_lines)
              if (line MATCHES "^([a-zA-Z0-9_-]+)=(.*)$")
                set(ENV{${CMAKE_MATCH_1}} "${CMAKE_MATCH_2}")
              endif()
            endforeach()
          endif()

          file(TO_CMAKE_PATH "$ENV{GITHUB_WORKSPACE}/ninja" ninja_program)

          execute_process(
            COMMAND ${{ steps.cmake_and_ninja.outputs.cmake_dir }}/cmake
              -S .
              -B build
              -D CMAKE_BUILD_TYPE=${{ matrix.config.build_type }}
              -G Ninja
              -D CMAKE_MAKE_PROGRAM=${ninja_program}
            RESULT_VARIABLE result
          )
          if (NOT result EQUAL 0)
            message(FATAL_ERROR "Bad exit status")
          endif()


      - name: Build
        shell: cmake -P {0}
        run: |
          set(ENV{NINJA_STATUS} "[%f/%t %o/sec] ")

          if ("${{ runner.os }}" STREQUAL "Windows" AND NOT "x${{ matrix.config.environment_script }}" STREQUAL "x")
            file(STRINGS environment_script_output.txt output_lines)
            foreach(line IN LISTS output_lines)
              if (line MATCHES "^([a-zA-Z0-9_-]+)=(.*)$")
                set(ENV{${CMAKE_MATCH_1}} "${CMAKE_MATCH_2}")
              endif()
            endforeach()
          endif()

          execute_process(
            COMMAND ${{ steps.cmake_and_ninja.outputs.cmake_dir }}/cmake --build build
            RESULT_VARIABLE result
          )
          if (NOT result EQUAL 0)
            message(FATAL_ERROR "Bad exit status")
          endif()


      - name: Run tests
        shell: cmake -P {0}
        run: |
          include(ProcessorCount)
          ProcessorCount(N)

          execute_process(
            COMMAND ${{ steps.cmake_and_ninja.outputs.cmake_dir }}/ctest -j ${N}
            WORKING_DIRECTORY build
            RESULT_VARIABLE result
          )
          if (NOT result EQUAL 0)
            message(FATAL_ERROR "Running tests failed!")
          endif()


      - name: Install Strip
        run: ${{ steps.cmake_and_ninja.outputs.cmake_dir }}/cmake --install build --prefix instdir --strip


      - name: Pack
        working-directory: instdir
        run: ${{ steps.cmake_and_ninja.outputs.cmake_dir }}/cmake -E tar cJfv ../${{ matrix.config.artifact }} .


      - name: Upload
        uses: actions/upload-artifact@v1
        with:
          path: ./${{ matrix.config.artifact }}
          name: ${{ matrix.config.artifact }}

  release:
    if: contains(github.ref, 'tags/v')
    runs-on: ubuntu-latest
    needs: build
    steps:
    - name: Create Release
      id: create_release
      uses: actions/create-release@v1.0.0
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      with:
        tag_name: ${{ github.ref }}
        release_name: Release ${{ github.ref }}
        draft: false
        prerelease: false
    - name: Store Release url
      run: |
        echo "${{ steps.create_release.outputs.upload_url }}" > ./upload_url
    - uses: actions/upload-artifact@v1
      with:
        path: ./upload_url
        name: upload_url

  publish:
    if: contains(github.ref, 'tags/v')
    name: ${{ matrix.config.name }}
    runs-on: ${{ matrix.config.os }}
    strategy:
      fail-fast: false
      matrix:
        config:
        - {name: Windows Latest MSVC, artifact: Windows-MSVC.tar.xz, os: ubuntu-latest}
        - {name: Windows Latest MinGW, artifact: Windows-MinGW.tar.xz, os: ubuntu-latest}
        - {name: Ubuntu Latest GCC, artifact: Linux.tar.xz, os: ubuntu-latest}
        - {name: macOS Latest Clang, artifact: macOS.tar.xz, os: ubuntu-latest}
    needs: release

    steps:
      - name: Download artifact
        uses: actions/download-artifact@v1
        with:
          name: ${{ matrix.config.artifact }}
          path: ./
      - name: Download URL
        uses: actions/download-artifact@v1
        with:
          name: upload_url
          path: ./
      - id: set_upload_url
        run: |
          upload_url=`cat ./upload_url`
          echo ::set-output name=upload_url::$upload_url
      - name: Upload to Release
        id: upload_to_release
        uses: actions/upload-release-asset@v1.0.1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          upload_url: ${{ steps.set_upload_url.outputs.upload_url }}
          asset_path: ./${{ matrix.config.artifact }}
          asset_name: ${{ matrix.config.artifact }}
          asset_content_type: application/x-gtar
