name: Build
on:
  push: {}
  pull_request: {}
  schedule:
    - cron: "0 5 * * MON"
  workflow_dispatch: {}

concurrency:
  group: ${{ github.repository }}-${{ github.head_ref || github.run_id }}-build
  cancel-in-progress: true

jobs:
  ubuntu:
    name: "Ubuntu"
    needs: clang-format
    strategy:
      matrix:
        os: [ubuntu-22.04]
        compiler: [gcc, clang]
        build_type: ["", Release, Debug, RelWithDebInfo]
        exclude:
          - compiler: clang
            build_type: RelWithDebInfo
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0
      - name: Install GCC
        if: ${{ matrix.compiler == 'gcc' }}
        run: |
          sudo apt-get install g++
      - name: Install clang
        if: ${{ matrix.compiler == 'clang' }}
        run: |
          sudo apt-get install clang
          export CC=$(which clang)
          export CXX=$(which clang++)
      - name: Install dependencies
        run: |
          sudo apt-get update
          sudo apt-get install \
            cmake \
            ninja-build \
            python3 \
            python3-pip \
            gettext \
            qtbase5-dev \
            libqt5svg5-dev \
            libkf5archive-dev \
            liblua5.3-dev \
            libsqlite3-dev \
            libsdl2-mixer-dev \
            python3-sphinx
          pip install -r docs/requirements.txt
      - name: Configure
        run: |
          cmake . -B build -G Ninja \
            -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} \
            -DCMAKE_INSTALL_PREFIX=/usr
      - name: Build
        run: |
          cmake --build build
      - name: Install
        run: |
          DESTDIR=$PWD/build/install cmake --build build --target install
      - name: Package
        run: |
          cmake --build build --target package
      - name: Upload package
        uses: softprops/action-gh-release@v1
        if: |
          startsWith(github.ref, 'refs/tags/')
            && matrix.compiler == 'gcc'
            && matrix.build_type == 'Release'
        with:
          files: |
            build/Linux-x86_64/freeciv21_*_amd64.deb
            build/Linux-x86_64/freeciv21_*_amd64.deb.sha256

  flagstest:
    name: "Additional compile flags in Ubuntu"
    needs: clang-format
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0
      - name: Install GCC
        run: |
          sudo apt-get install g++
      - name: Install dependencies
        run: |
          sudo apt-get update
          sudo apt-get install \
            cmake \
            ninja-build \
            python3 \
            gettext \
            qtbase5-dev \
            libqt5svg5-dev \
            libkf5archive-dev \
            liblua5.3-dev \
            libsqlite3-dev \
            libsdl2-mixer-dev
      - name: Configure
        run: |
            cmake . -B build -G Ninja --preset "DistroRelease"
      - name: Build
        run: |
          cmake --build build

  windows:
    name: "Windows MSYS2 (gcc)"
    runs-on: windows-latest
    needs: clang-format
    defaults:
      run:
        shell: msys2 {0}
    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0
      - uses: msys2/setup-msys2@v2
        with:
          msystem: MINGW64
          update: true
          install: |
            git
            mingw-w64-x86_64-cmake
            mingw-w64-x86_64-ninja
            mingw-w64-x86_64-nsis
            mingw-w64-x86_64-gcc
            mingw-w64-x86_64-libunwind
            mingw-w64-x86_64-readline
            mingw-w64-x86_64-lua
            mingw-w64-x86_64-SDL2_mixer
            mingw-w64-x86_64-qt5
            mingw-w64-x86_64-qt5-svg
            mingw-w64-x86_64-karchive-qt5
      - name: Configure
        run: |
          export PATH=/mingw64/bin:${PATH}
          export MSYSTEM=MINGW64
          export PKG_CONFIG_PATH=${PKG_CONFIG_PATH}:/mingw64/lib/pkgconfig:/mingw64/share/pkgconfig
          cmake . -B build -G Ninja \
           -DCMAKE_INSTALL_PREFIX=$PWD/build/install \
           -DCMAKE_BUILD_TYPE=Release
      - name: Build
        run: |
          cmake --build build
      - name: Install
        run: |
          cmake --build build --target install
      - name: Package
        run: |
          cmake --build build --target package
      - name: Upload package
        uses: softprops/action-gh-release@v1
        if: startsWith(github.ref, 'refs/tags/')
        with:
          files: |
            build/Windows-x86_64/Freeciv21-*-Windows-x86_64.exe
            build/Windows-x86_64/Freeciv21-*-Windows-x86_64.exe.sha256
      - name: Upload a build
        uses: actions/upload-artifact@v3
        with:
          name: Windows-exe
          path: build/Windows-x86_64/Freeciv21-*.exe

  windows_clang_msvc:
    name: "Windows Clang"
    runs-on: windows-latest
    needs: clang-format
    if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
    env:
      VCPKG_ROOT: C:/vcpkg
      VCPKG_DEFAULT_BINARY_CACHE: ${{github.workspace}}/vcpkg/bincache
    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0
      - name: "Create dir: '${{env.VCPKG_DEFAULT_BINARY_CACHE}}'"
        run: mkdir -p $VCPKG_DEFAULT_BINARY_CACHE
        shell: bash
      - name: Restore vcpkg and its artifacts.
        uses: actions/cache@v3
        with:
          path: ${{env.VCPKG_DEFAULT_BINARY_CACHE}}/*
          key: ${{hashFiles('vcpkg.json')}}
      - name: Show content of workspace after cache has been restored
        run: find $RUNNER_WORKSPACE
        shell: bash
      - name: Enable Developer Command Prompt
        uses: ilammy/msvc-dev-cmd@v1
      - name: Configure
        run: cmake -S . -B build -G "Visual Studio 17 2022" \
         -DCMAKE_BUILD_TYPE=Debug -DVCPKG_BUILD_TYPE=debug \
         -DVCPKG_TARGET_ARCHITECTURE=x64 -DFREECIV_USE_VCPKG=ON \
         -DCMAKE_TOOLCHAIN_FILE="${{env.VCPKG_ROOT}}/scripts/buildsystems/vcpkg.cmake" -A x64 -T ClangCL
      - name: Building
        run: cmake --build build --config Debug

  os_x:
    name: "macOS"
    runs-on: macos-latest
    needs: clang-format
    env:
      MACOSX_DEPLOYMENT_TARGET: 10.15
      VCPKG_BUILD_TYPE: release
    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0
      - name: Install build tools
        run: |
          brew update
          brew install \
            cmake \
            ninja \
            gettext \
            create-dmg
          brew link gettext --force
      - uses: actions/setup-python@v4  # Workaround for #2069
        with:
          python-version: '3.11'
      - uses: lukka/run-vcpkg@v10
        name: Install dependencies
        with:
          vcpkgGitCommitId: 23ceb9cbf9b6d32f485cf039547b70102a6ef9d8
      - name: Build
        uses: lukka/run-cmake@v10
        with:
          configurePreset: 'fullrelease-macos'
          buildPreset: 'fullrelease-macos'
      - name: Split Branch Name
        env:
          BRANCH: ${{github.ref_name}}
        id: split
        run: echo "fragment=${BRANCH##*/}" >> $GITHUB_OUTPUT
      - name: Create App Bundle
        run: |
          mkdir -p Freeciv21.app/Contents/MacOS Freeciv21.app/Contents/Resources
          cp dist/Info.plist Freeciv21.app/Contents/
          cp -r .install/share/freeciv21/* Freeciv21.app/Contents/Resources
          cp .install/bin/freeciv21-* Freeciv21.app/Contents/MacOS
          mkdir client.iconset
          cp data/icons/16x16/freeciv21-client.png client.iconset/icon_16x16.png
          cp data/icons/32x32/freeciv21-client.png client.iconset/icon_16x16@2x.png
          cp data/icons/32x32/freeciv21-client.png client.iconset/icon_32x32.png
          cp data/icons/64x64/freeciv21-client.png client.iconset/icon_32x32@2x.png
          cp data/icons/128x128/freeciv21-client.png client.iconset/icon_128x128.png
          iconutil -c icns client.iconset
          cp client.icns Freeciv21.app/Contents/Resources
          mkdir staging
          mv Freeciv21.app staging
          create-dmg \
            --hdiutil-verbose \
            --volname "Freeciv21 Installer" \
            --volicon "client.icns" \
            --window-pos 200 120 \
            --window-size 800 400 \
            --icon-size 100 \
            --icon "Freeciv21.app" 200 190 \
            --hide-extension "Freeciv21.app" \
            --app-drop-link 600 185 \
            "Freeciv21-${{steps.split.outputs.fragment}}.dmg" \
            "staging/"
          shasum -a 256 Freeciv21-${{steps.split.outputs.fragment}}.dmg > Freeciv21-${{steps.split.outputs.fragment}}.dmg.sha256
      - name: Upload package
        uses: softprops/action-gh-release@v1
        if: startsWith(github.ref, 'refs/tags/')
        with:
          files: |
            Freeciv21-*.dmg
            Freeciv21-*.dmg.sha256
      - name: Upload a build
        uses: actions/upload-artifact@v3
        with:
          name: macOS-dmg
          path: Freeciv21-*.dmg

  fedora:
    runs-on: ubuntu-latest
    if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
    container: fedora:latest
    steps:
      - name: Install dependencies
        run: |
          sudo dnf install -y \
            git \
            cmake \
            ninja-build \
            python \
            gettext \
            qt5-qtbase-devel \
            qt5-qtsvg-devel \
            kf5-karchive-devel \
            lua-devel \
            sqlite-devel \
            SDL2_mixer-devel \
            readline-devel \
            zlib-devel \
            libunwind-devel \
            elfutils-libs
      - uses: actions/checkout@v3
      - name: Configure
        run: |
          cmake . -B build -G Ninja \
            -DCMAKE_BUILD_TYPE=RelWithDebInfo \
            -DCMAKE_INSTALL_PREFIX=/usr
      - name: Build
        run: |
          cmake --build build
      - name: Install
        run: |
          DESTDIR=$PWD/build/install cmake --build build --target install

  nix:
    runs-on: ubuntu-latest
    if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
    steps:
      - name: checkout
        uses: actions/checkout@v3
      - uses: cachix/install-nix-action@v19
      - run: nix flake check
      # TODO: We can add the build to a cache for others (see cachix.org)
      # It's free for FOSS.
      - run: nix build .#freeciv21

  wasm:
    name: "WebAssembly"
    runs-on: ubuntu-latest
    needs: clang-format
    env:
      QT_VERSION: v5.15.8-lts-lgpl
    steps:
      - uses: actions/checkout@v3
      - name: Cache Qt build
        id: qtcache
        uses: actions/cache@v3
        with:
          path: ~/qt
          key: qt-wasm-${{ env.QT_VERSION }}-svg-socket-v2
      - name: Install build tools
        run: |
          sudo apt-get update
          sudo apt-get install \
            cmake \
            ninja-build \
            clang \
            python3 \
            gettext
      - uses: actions/checkout@v3
        name: Checkout emsdk
        with:
          repository: emscripten-core/emsdk
          path: emsdk
      - name: Install emsdk
        run: |
          cd emsdk
          ./emsdk install latest
          ./emsdk activate latest
          touch prime.c
          source emsdk_env.sh
          emcc -sUSE_ZLIB=1 -sUSE_SDL=2 -sUSE_SDL_MIXER=2 prime.c -o prime.o
          ln -s libSDL2_mixer_ogg.a upstream/emscripten/cache/sysroot/lib/wasm32-emscripten/libSDL2_mixer.a
      - name: Install lua
        run: |
          source emsdk/emsdk_env.sh
          wget https://www.lua.org/ftp/lua-5.4.3.tar.gz
          tar xf lua-5.4.3.tar.gz
          cp dist/wasm/lua.CMakeLists.txt lua-5.4.3/CMakeLists.txt
          cd lua-5.4.3
          emcmake cmake .
          emmake make install
      - uses: actions/checkout@v3
        if: steps.qtcache.outputs.cache-hit != 'true'
        name: Checkout qtbase
        with:
          repository: qt/qtbase
          ref: ${{ env.QT_VERSION }}
          path: qtbase
      - name: Build Qt
        if: steps.qtcache.outputs.cache-hit != 'true'
        run: |
          source emsdk/emsdk_env.sh
          cd qtbase
          git config --global user.email "root@example.com"
          git config --global user.name "root"
          git fetch origin 76d12eea2252c5e537dff15b103bdc1f925cf760
          git cherry-pick 76d12eea2252c5e537dff15b103bdc1f925cf760
          ./configure -xplatform wasm-emscripten -opensource -confirm-license -prefix ~/qt -nomake examples
          make install
      - uses: actions/checkout@v3
        if: steps.qtcache.outputs.cache-hit != 'true'
        name: Checkout qtsvg
        with:
          repository: qt/qtsvg
          ref: ${{ env.QT_VERSION }}
          path: qtsvg
      - name: Build QtSvg
        if: steps.qtcache.outputs.cache-hit != 'true'
        run: |
          source emsdk/emsdk_env.sh
          cd qtsvg
          ~/qt/bin/qmake
          make install
      - uses: actions/checkout@v3
        name: Checkout zstd
        with:
          repository: facebook/zstd
          ref: v1.5.0
          path: zstd
      - name: Build zstd
        run: |
          source emsdk/emsdk_env.sh
          cd zstd
          mkdir bld
          emcmake cmake build/cmake -DZSTD_BUILD_PROGRAMS=0 -DZSTD_BUILD_SHARED=0
          emmake make install
      - uses: actions/checkout@v3
        name: Checkout extra-cmake-modules
        with:
          repository: KDE/extra-cmake-modules
          ref: v5.96.0
          path: ecm
      - name: Install ecm
        run: |
          cd ecm
          cmake .
          sudo make install
      - uses: actions/checkout@v3
        name: Checkout karchive
        with:
          repository: KDE/karchive
          ref: v5.96.0
          path: karchive
      - name: Install karchive
        run: |
          source emsdk/emsdk_env.sh
          cd karchive
          git apply ../dist/wasm/karchive.diff
          emcmake cmake . \
            -DECM_DIR=/usr/local/share/ECM/cmake -DBUILD_TESTING=0 \
            -DQt5Core_DIR=$HOME/qt/lib/cmake/Qt5Core \
            -DKF_IGNORE_PLATFORM_CHECK=1 \
            -DCMAKE_INSTALL_PREFIX=../emsdk/upstream/emscripten/cache/sysroot
          emmake make install
      - name: Build Freeciv
        run: |
          source emsdk/emsdk_env.sh
          ls $HOME/qt/lib/cmake/Qt5
          emcmake cmake . \
            -DCMAKE_BUILD_TYPE=Release \
            -DQt5_DIR=$HOME/qt/lib/cmake/Qt5 \
            -DQt5Svg_DIR=$HOME/qt/lib/cmake/Qt5Svg \
            -DQt5Gui_DIR=$HOME/qt/lib/cmake/Qt5Gui \
            -DQt5Core_DIR=$HOME/qt/lib/cmake/Qt5Core \
            -DQt5Network_DIR=$HOME/qt/lib/cmake/Qt5Network \
            -DFREECIV_ENABLE_SERVER=0 \
            -DLUA_MATH_LIBRARY=emsdk/upstream/emscripten/cache/sysroot/lib/wasm32-emscripten/libc.a \
            -DQt5Widgets_DIR=$HOME/qt/lib/cmake/Qt5Widgets \
            -DQt5EventDispatcherSupport_DIR=$HOME/qt/lib/cmake/Qt5EventDispatcherSupport \
            -DQt5FontDatabaseSupport_DIR=$HOME/qt/lib/cmake/Qt5FontDatabaseSupport \
            -DQt5EglSupport_DIR=$HOME/qt/lib/cmake/Qt5EglSupport \
            -DFREECIV_ENABLE_FCMP_CLI=0 -DFREECIV_ENABLE_FCMP_QT=0 \
            -DFREECIV_BUILD_LIBSERVER=0 -DFREECIV_ENABLE_RULEUP=0 \
            -DFREECIV_ENABLE_RULEDIT=0 -DFREECIV_ENABLE_CIVMANUAL=0 \
            -DKF5Archive_DIR=../emsdk/upstream/emscripten/cache/sysroot/lib/cmake \
            -DCAN_UNWIND_STACK=0
          VERBOSE=1 emmake make
      - name: Debug
        if: failure()
        run: |
          cat common/networking/CMakeFiles/networking.dir/includes_CXX.rsp
          cat CMakeCache.txt
      - uses: actions/upload-artifact@v3
        if: failure()
        with:
          name: cmakecache
          path: CMakeCache.txt
      - name: Archive production artifacts
        uses: actions/upload-artifact@v3
        with:
          name: wasm-client
          path: freeciv21-client.*

  clang-format:
    name: clang-format Code Formatter
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
      with:
        fetch-depth: 0
    - name: Run clang-format style check for C/C++
      uses: jidicula/clang-format-action@v4.11.0
      with:
        clang-format-version: '11'
        exclude-regex: 'dependencies'