name: Build

on: [push, pull_request]

jobs:
  build-client:
    name: client ${{matrix.config.name}}
    runs-on: ${{matrix.config.os}}
    strategy:
      fail-fast: false
      matrix:
        config:
        - name: "windows_x64_msvc"
          os: windows-latest
          generator: "Visual Studio 17 2022"
          arch: "-A x64"
          target: traintastic-client
          jobs: 4
          build_type: Release
          build_deb: false
          defines: ""

        - name: "ubuntu_24.04"
          os: ubuntu-24.04
          generator: "Unix Makefiles"
          arch: ""
          target: traintastic-client
          jobs: 4
          build_type: Release
          build_deb: true
          defines: ""

        - name: "ubuntu_24.04_arm64"
          os: ubuntu-24.04-arm
          generator: "Unix Makefiles"
          arch: ""
          target: traintastic-client
          jobs: 4
          build_type: Release
          build_deb: true
          defines: ""

        - name: "raspberrypios_arm7"
          os: [self-hosted, ARM, RaspberryPi]
          generator: "Unix Makefiles"
          arch: ""
          target: traintastic-client
          jobs: 4
          build_type: Release
          build_deb: true
          defines: "-DCMAKE_CXX_COMPILER_LAUNCHER=ccache"

        - name: "raspberrypios_arm64"
          os: [self-hosted, ARM64, RaspberryPi]
          generator: "Unix Makefiles"
          arch: ""
          target: traintastic-client
          jobs: 4
          build_type: Release
          build_deb: true
          defines: "-DCMAKE_CXX_COMPILER_LAUNCHER=ccache"

        - name: "macos-15-intel"
          os: "macos-15-intel"
          generator: "Unix Makefiles"
          arch: ""
          osx_arch: x86_64
          target: traintastic-client
          jobs: 4
          build_type: Release
          build_deb: false
          defines: ""

        - name: "macos-15-arm64"
          os: "macos-15"
          generator: "Unix Makefiles"
          arch: ""
          osx_arch: arm64
          target: traintastic-client
          jobs: 4
          build_type: Release
          build_deb: false
          defines: ""

    steps:
    - uses: FranzDiebold/github-env-vars-action@v2

    # All:
    - name: Checkout
      uses: actions/checkout@v3
      with:
        submodules: recursive

    # Windows only:
    - name: Install Qt 5
      if: startswith(matrix.config.os, 'windows')
      uses: jurplel/install-qt-action@v4
      with:
        cache: true
        version: 5.15

    # macOS only:
    - name: Install Qt 6.5
      if: startswith(matrix.config.os, 'macos')
      uses: jurplel/install-qt-action@v4
      with:
        cache: true
        modules: qtwebsockets
        version: 6.5.*

    - name: Set CMAKE_OSX_ARCHITECTURES
      if: startswith(matrix.config.os, 'macos')
      uses: actions/github-script@v7
      with:
        script: |
          core.exportVariable('CMAKE_OSX_ARCHITECTURES', '${{matrix.config.osx_arch}}');

    # Ubuntu only:
    - name: apt update
      if: startswith(matrix.config.os, 'ubuntu')
      run: sudo apt update

    # Ubuntu only:
    - name: Install packages
      if: startswith(matrix.config.os, 'ubuntu')
      run: sudo apt install qt6-base-dev qt6-svg-dev qt6-websockets-dev

    # All:
    - name: Create Build Environment
      run: cmake -E make_directory ${{github.workspace}}/client/build

    # All:
    - name: Configure CMake
      shell: bash
      working-directory: ${{github.workspace}}/client/build
      run: cmake $GITHUB_WORKSPACE/client -G "${{matrix.config.generator}}" ${{matrix.config.arch}} -DCMAKE_BUILD_TYPE=${{matrix.config.build_type}} ${{matrix.config.defines}}

    # All:
    - name: Build
      working-directory: ${{github.workspace}}/client/build
      shell: bash
      run: cmake --build . --config ${{matrix.config.build_type}} --target ${{matrix.config.target}} --parallel ${{matrix.config.jobs}}

    # Windows only:
    - name: Run windeployqt
      if: startswith(matrix.config.os, 'windows')
      shell: cmd
      run: |
        call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
        windeployqt --release --no-translations -no-system-d3d-compiler --no-opengl-sw ${{github.workspace}}/client/build/${{matrix.config.build_type}}/traintastic-client.exe

    # Linux only:
    - name: Build debian package
      if: matrix.config.build_deb
      working-directory: ${{github.workspace}}/client/build
      run: cpack

    # Windows only:
    - name: Upload artifact
      if: startswith(matrix.config.os, 'windows')
      uses: actions/upload-artifact@v4
      with:
        name: traintastic-client-windows
        path: ${{github.workspace}}/client/build/${{matrix.config.build_type}}

    # Linux only:
    - name: Upload debian package artifact
      if: matrix.config.build_deb
      uses: actions/upload-artifact@v4
      with:
        name: traintastic-client-deb-${{matrix.config.name}}
        path: ${{github.workspace}}/client/build/*.deb

  build-server:
    name: server ${{matrix.config.name}}
    runs-on: ${{matrix.config.os}}
    env:
      VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite"
    strategy:
      fail-fast: false
      matrix:
        config:
        - name: "windows_x64_clang"
          os: windows-latest
          generator: "Visual Studio 17 2022"
          arch: "-A x64"
          toolset: "-T ClangCL"
          target: ALL_BUILD
          jobs: 4
          build_type: Release
          build_deb: false
          defines: ""
          ccov: false

        - name: "ubuntu_24.04"
          os: ubuntu-24.04
          generator: "Unix Makefiles"
          arch: ""
          toolset: ""
          target: all
          jobs: 4
          build_type: Release
          build_deb: true
          defines: "-DINSTALL_SYSTEMD_SERVICE=ON"
          ccov: false

        - name: "ubuntu_24.04 (debug+ccov)"
          os: ubuntu-24.04
          generator: "Unix Makefiles"
          arch: ""
          toolset: ""
          target: traintastic-server-test
          jobs: 4
          build_type: Debug
          build_deb: false
          defines: "-DCODE_COVERAGE=ON"
          ccov: true

        - name: "ubuntu_24.04_arm64"
          os: ubuntu-24.04-arm
          generator: "Unix Makefiles"
          arch: ""
          toolset: ""
          target: all
          jobs: 4
          build_type: Release
          build_deb: true
          defines: "-DINSTALL_SYSTEMD_SERVICE=ON"
          ccov: false

        - name: "raspberrypios_arm7"
          os: [self-hosted, ARM, RaspberryPi]
          generator: "Unix Makefiles"
          arch: ""
          toolset: ""
          target: all
          jobs: 3
          build_type: Release
          build_deb: true
          defines: "-DINSTALL_SYSTEMD_SERVICE=ON -DCMAKE_CXX_COMPILER_LAUNCHER=ccache"
          ccov: false

        - name: "raspberrypios_arm64"
          os: [self-hosted, ARM64, RaspberryPi]
          generator: "Unix Makefiles"
          arch: ""
          toolset: ""
          target: all
          jobs: 3
          build_type: Release
          build_deb: true
          defines: "-DINSTALL_SYSTEMD_SERVICE=ON -DCMAKE_CXX_COMPILER_LAUNCHER=ccache"
          ccov: false

        - name: "macos-15-intel"
          os: "macos-15-intel"
          generator: "Unix Makefiles"
          arch: ""
          toolset: ""
          target: all
          jobs: 4
          build_type: Release
          build_deb: false
          defines: ""
          ccov: false

        - name: "macos-15-arm64"
          os: "macos-15"
          generator: "Unix Makefiles"
          arch: ""
          toolset: ""
          target: all
          jobs: 4
          build_type: Release
          build_deb: false
          defines: ""
          ccov: false

    steps:
    - uses: FranzDiebold/github-env-vars-action@v2

    # All:
    - name: Checkout
      uses: actions/checkout@v3
      with:
        submodules: recursive

    - name: Export GitHub Actions cache environment variables
      uses: actions/github-script@v7
      with:
        script: |
          core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || '');
          core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '');

    - name: Set VCPKG_ROOT
      if: startswith(matrix.config.os, 'windows') || startswith(matrix.config.os, 'macos')
      uses: actions/github-script@v7
      with:
        script: |
          core.exportVariable('VCPKG_ROOT', process.env.VCPKG_INSTALLATION_ROOT || '');

    - name: Set CMAKE_OSX_ARCHITECTURES
      if: startswith(matrix.config.os, 'macos')
      uses: actions/github-script@v7
      with:
        script: |
          core.exportVariable('CMAKE_OSX_ARCHITECTURES', 'x86_64');

    # Ubuntu only:
    - name: apt update
      if: startswith(matrix.config.os, 'ubuntu')
      run: sudo apt update

    # Ubuntu only:
    - name: Install packages
      if: startswith(matrix.config.os, 'ubuntu')
      run: sudo apt install libboost-program-options-dev libboost-url-dev liblua5.4-dev lcov libarchive-dev clang-tidy libsystemd-dev

    # MacOS only:
    - name: Install brew packages
      if: startswith(matrix.config.os, 'macos')
      run: brew install libarchive lua@5.4

    # All:
    - name: Create Build Environment
      # Some projects don't allow in-source building, so create a separate build directory
      # We'll use this as our working directory for all subsequent commands
      run: cmake -E make_directory ${{github.workspace}}/server/build

    # All:
    - name: Configure CMake
      shell: bash
      working-directory: ${{github.workspace}}/server/build
      # Note the current convention is to use the -S and -B options here to specify source
      # and build directories, but this is only available with CMake 3.13 and higher.
      # The CMake binaries on the Github Actions machines are (as of this writing) 3.12
      run: cmake $GITHUB_WORKSPACE/server -G "${{matrix.config.generator}}" ${{matrix.config.arch}} ${{matrix.config.toolset}} -DCMAKE_BUILD_TYPE=${{matrix.config.build_type}} ${{matrix.config.defines}}

    # All:
    - name: Build
      working-directory: ${{github.workspace}}/server/build
      shell: bash
      # Execute the build.  You can specify a specific target with "--target <NAME>"
      run: cmake --build . --config ${{matrix.config.build_type}} --target ${{matrix.config.target}} --parallel ${{matrix.config.jobs}}

    # mingw only
    #- name: Run tests (mingw)
    #  if: matrix.config.name == 'windows_x64_mingw'
    #  working-directory: ${{github.workspace}}/server/build
    #  run: |
    #    $env:PATH += ';C:\ProgramData\chocolatey\lib\mingw\tools\install\mingw64\bin'
    #    ctest --output-on-failure

    # All:
    - name: Run tests
      if: matrix.config.name != 'windows_x64_mingw'
      working-directory: ${{github.workspace}}/server/build
      run: ctest --output-on-failure

    # Linux only:
    - name: Build debian package
      if: matrix.config.build_deb
      working-directory: ${{github.workspace}}/server/build
      run: cpack

    # Windows only:
    - name: Upload artifact
      if: matrix.config.name == 'windows_x64_clang'
      uses: actions/upload-artifact@v4
      with:
        name: traintastic-server-windows
        path: ${{github.workspace}}/server/build/Release/traintastic-server.exe

    # Linux only:
    - name: Upload debian package artifact
      if: matrix.config.build_deb
      uses: actions/upload-artifact@v4
      with:
        name: traintastic-server-deb-${{matrix.config.name}}
        path: ${{github.workspace}}/server/build/*.deb

    # Code coverage:
    - name: Code coverage
      if: matrix.config.ccov
      working-directory: ${{github.workspace}}/server/build
      run: make ccov

    - name: "Code coverage: upload to coveralls.io"
      if: matrix.config.ccov
      continue-on-error: true
      uses: coverallsapp/github-action@master
      with:
        github-token: ${{secrets.GITHUB_TOKEN}}
        path-to-lcov: ${{github.workspace}}/server/build/ccov/traintastic-server-test.info

    - name: "Code coverage: upload artifact"
      if: matrix.config.ccov
      uses: actions/upload-artifact@v4
      with:
        name: traintastic-server-test-code-coverage
        path: ${{github.workspace}}/server/build/ccov/*

  build-data:
    name: shared data ${{matrix.config.name}}
    runs-on: ${{matrix.config.os}}
    needs: [build-lang, build-manual]
    strategy:
      fail-fast: false
      matrix:
        config:
        - name: "ubuntu_24.04"
          os: ubuntu-24.04
          defines: ""

        - name: "raspberrypios_10"
          os: [self-hosted, ARM64, RaspberryPi]
          defines: ""

    steps:
    - uses: FranzDiebold/github-env-vars-action@v2

    - name: Checkout
      uses: actions/checkout@v3
      with:
        submodules: recursive

    - name: "Download artifact: lang"
      uses: actions/download-artifact@v4
      with:
        name: traintastic-lang
        path: ${{github.workspace}}/shared/translations

    - name: "Download artifact: manual"
      uses: actions/download-artifact@v4
      with:
        name: traintastic-manual
        path: ${{github.workspace}}/manual/output

    - name: Create Build Environment
      run: cmake -E make_directory ${{github.workspace}}/shared/build

    - name: Configure CMake
      shell: bash
      working-directory: ${{github.workspace}}/shared/build
      run: cmake $GITHUB_WORKSPACE/shared ${{matrix.config.defines}}

    - name: Build debian package
      working-directory: ${{github.workspace}}/shared/build
      run: cpack

    - name: Upload debian package artifact
      uses: actions/upload-artifact@v4
      with:
        name: traintastic-data-deb-${{matrix.config.name}}
        path: ${{github.workspace}}/shared/build/*.deb

  build-lang:
    name: language files
    runs-on: ubuntu-latest

    steps:
    - uses: FranzDiebold/github-env-vars-action@v2

    - name: Checkout
      uses: actions/checkout@v3
      with:
        submodules: recursive

    - name: Build language files
      working-directory: ${{github.workspace}}/shared/translations
      run: python3 json2lang.py

    - name: Upload artifact
      uses: actions/upload-artifact@v4
      with:
        name: traintastic-lang
        path: ${{github.workspace}}/shared/translations/*.lang

  build-manual:
    name: manual
    runs-on: ubuntu-latest

    steps:
    - uses: FranzDiebold/github-env-vars-action@v2

    - name: Checkout
      uses: actions/checkout@v3
      with:
        submodules: recursive

    - name: Install python requirements
      working-directory: ${{github.workspace}}/manual
      run: sudo pip3 install -r requirements.txt

    - name: Build manual
      working-directory: ${{github.workspace}}/manual
      run: ./build.py

    - name: Upload artifact
      uses: actions/upload-artifact@v4
      with:
        name: traintastic-manual
        path: ${{github.workspace}}/manual/output/*

  package-innosetup:
    name: package innosetup
    runs-on: windows-2022
    needs: [build-client, build-server, build-lang, build-manual]

    steps:
    - uses: FranzDiebold/github-env-vars-action@v2

    - name: Checkout
      uses: actions/checkout@v3
      with:
        submodules: recursive

    - name: Download artifacts 1/2
      uses: actions/download-artifact@v4
      with:
        name: traintastic-client-windows
        path: ${{github.workspace}}/client/build/Release

    - name: Download artifacts 2/2
      uses: actions/download-artifact@v4
      with:
        name: traintastic-server-windows
        path: ${{github.workspace}}/server/build

    - name: "Download artifact: lang"
      uses: actions/download-artifact@v4
      with:
        name: traintastic-lang
        path: ${{github.workspace}}/shared/translations

    - name: "Download artifact: manual"
      uses: actions/download-artifact@v4
      with:
        name: traintastic-manual
        path: ${{github.workspace}}/manual/output

    - name: Build installer
      shell: cmd
      run: |
        "C:/Program Files (x86)/Inno Setup 6/ISCC.exe" %GITHUB_WORKSPACE%/package/innosetup/traintastic.iss

    - name: Upload artifact
      uses: actions/upload-artifact@v4
      with:
        name: package-innosetup
        path: ${{github.workspace}}/package/innosetup/output

  deploy:
    name: Deploy to website
    if: ${{ github.event_name == 'push' }}
    runs-on: ubuntu-latest
    needs: [package-innosetup, build-server, build-client, build-data, build-manual]

    steps:
    - uses: FranzDiebold/github-env-vars-action@v2

    - name: Download artifacts 1/6
      uses: actions/download-artifact@v4
      with:
        name: package-innosetup
        path: ${{github.workspace}}/dist/${{env.CI_REF_NAME_SLUG}}/${{github.run_number}}

    - name: Download artifacts 2/6
      uses: actions/download-artifact@v4
      with:
        pattern: traintastic-client-deb-*
        merge-multiple: true
        path: ${{github.workspace}}/dist/${{env.CI_REF_NAME_SLUG}}/${{github.run_number}}

    - name: Download artifacts 3/6
      uses: actions/download-artifact@v4
      with:
        pattern: traintastic-server-deb-*
        merge-multiple: true
        path: ${{github.workspace}}/dist/${{env.CI_REF_NAME_SLUG}}/${{github.run_number}}

    - name: Download artifacts 4/6
      uses: actions/download-artifact@v4
      with:
        name: traintastic-server-test-code-coverage
        path: ${{github.workspace}}/dist/${{env.CI_REF_NAME_SLUG}}/${{github.run_number}}/ccov

    - name: Download artifacts 5/6
      uses: actions/download-artifact@v4
      with:
        name: traintastic-manual
        path: ${{github.workspace}}/dist/${{env.CI_REF_NAME_SLUG}}/${{github.run_number}}/manual

    - name: Download artifacts 6/6
      uses: actions/download-artifact@v4
      with:
        pattern: traintastic-data-deb-*
        merge-multiple: true
        path: ${{github.workspace}}/dist/${{env.CI_REF_NAME_SLUG}}/${{github.run_number}}

    - uses: easingthemes/ssh-deploy@v2.2.11
      env:
          SSH_PRIVATE_KEY: ${{secrets.SERVER_SSH_KEY}}
          ARGS: "-rltgoDzvO"
          SOURCE: "dist/*"
          REMOTE_HOST: ${{secrets.REMOTE_HOST}}
          REMOTE_PORT: ${{secrets.REMOTE_PORT}}
          REMOTE_USER: ${{secrets.REMOTE_USER}}
          TARGET: ${{secrets.REMOTE_TARGET}}/traintastic/

  update-readme-contributors:
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/master'
    name: Update contributers in README.md
    steps:
        - name: Update contribute list
          uses: akhilmhdh/contributors-readme-action@v2.3.11
          env:
              GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
