name: CI_build

on: [push, pull_request]
env:
  PYTHON_ALLOW_CACHE: true
  PYTHON_DIR_CACHE: D:\.cache\python

jobs:
  before_build:

    runs-on: windows-latest
    outputs:
      result: ${{ steps.filter.outputs.result }}
      matrix: ${{ steps.filter.outputs.matrix }}
      title: ${{ steps.filter.outputs.title }}
      python: ${{ steps.filter.outputs.python }}

    steps:
    - name: Checkout repo
      uses: actions/checkout@v4
      with:
        fetch-depth: ${{ github.event_name == 'pull_request' && 2 || 0 }}

    - name: Commit filtering
      id: filter
      run: |
        $allowMaster = $true
        $folders_onejob = "PowerEditor/(Test|(installer/(filesForTesting|functionList)))/"
        $folders_nowork = "\.github/ISSUE_TEMPLATE"
        $files_nowork = "md|txt|log|ini"
        $files_needwork = "CMakeLists\.txt"

        $matrix_all = 'matrix={"build_configuration": ["Release", "Debug"], "build_platform": ["x64", "Win32", "ARM64"]}'
        $matrix_onejob = 'matrix={"build_configuration": ["Debug"], "build_platform": ["Win32"]}'
        Write-Output $matrix_all >> $env:GITHUB_OUTPUT

        $isPush = "${{github.event_name }}" -eq "push" ? $true : $false
        $isMaster = $isPush -and $${{ github.ref_name == github.event.repository.master_branch }}

        $commit_message = $isPush ? (git show -s --format=%B) : (git log -1 --no-merges --pretty=%B)
        $commit_title = ($commit_message -split "[\r\n]+")[0]
        Write-Output "title=$commit_title" >> $env:GITHUB_OUTPUT
        $files_modified = @(git diff --name-only HEAD~1)
        $files_needwork_all = @($files_modified | Where-Object {$_ -notmatch "\.(xml|$files_nowork)$|$folders_nowork|$folders_onejob" -or $_ -match "($files_needwork)$"})

        if ($allowMaster -or !$isMaster) {
            if ($commit_title -match "\[force all\]") {
              Write-Output "Run standard jobs"
            }
            elseif ($commit_title -match "\[force one\]") {
              Write-Output "Run only one Win32/Debug job"
              Write-Output "result=ONEJOB" >> $env:GITHUB_OUTPUT
              Write-Output $matrix_onejob >> $env:GITHUB_OUTPUT
            }
            elseif (($files_modified.length -gt 0 -and $files_needwork_all.length -eq 0) -or $commit_title -match "\[force (xml|none)\]") {
                if (@($files_modified | Where-Object {$_ -notmatch "\.($files_nowork)$|$folders_nowork"}).length -eq 0 -or $commit_title -match "\[force none\]") {
                    Write-Output "Changed files on this commit don't require any additional tasks.`n"
                    Write-Output "result=OK" >> $env:GITHUB_OUTPUT
                    Write-Output "PYTHON_ALLOW_CACHE=false" >> $env:GITHUB_ENV
                    Exit
                }
                else {
                    Write-Output "Run only XML validation step"
                    if (@($files_modified | Where-Object {$_ -match $folders_onejob}).length -eq 0) {
                        Write-Output "result=XML" >> $env:GITHUB_OUTPUT
                    }
                    else {
                      Write-Output "Run only one Win32/Debug job"
                      Write-Output "result=ONEJOB" >> $env:GITHUB_OUTPUT
                      Write-Output $matrix_onejob >> $env:GITHUB_OUTPUT
                    }

                }
            }
            else {
              Write-Output "Run standard jobs"
            }
        }
        else {
          Write-Output "Run standard jobs"
        }

        if ($commit_title -match "\[force nopythoncache\]") {
          $env:PYTHON_ALLOW_CACHE = "false"
          Write-Output "PYTHON_ALLOW_CACHE=false" >> $env:GITHUB_ENV
        }
        if ($Env:PYTHON_ALLOW_CACHE -eq "true") {
          $python = ((python -V) -split " ")[1]
          $requests = (Invoke-RestMethod https://pypi.org/pypi/requests/json).info.version
          $rfc3987 = (Invoke-RestMethod https://pypi.org/pypi/rfc3987/json).info.version
          $pywin32 = (Invoke-RestMethod https://pypi.org/pypi/pywin32/json).info.version
          $lxml = (Invoke-RestMethod https://pypi.org/pypi/lxml/json).info.version
          $key = "${{ runner.os }}-python_$python-requests_$requests-rfc3987_$rfc3987-pywin32_$pywin32-lxml_$lxml"
          Write-Output "python=$key" >> $env:GITHUB_OUTPUT
        }

    - name: (cache) Lookup Python modules
      if: env.PYTHON_ALLOW_CACHE == 'true'
      uses: actions/cache/restore@v4
      id: cache-lookup
      with:
        path: ${{ env.PYTHON_DIR_CACHE }}
        key: ${{ steps.filter.outputs.python }}
        lookup-only: true

    - name: (cache) Restore Python modules
      if: env.PYTHON_ALLOW_CACHE == 'true' && steps.filter.outputs.result == 'XML' && steps.cache-lookup.outputs.cache-hit == 'true'
      uses: actions/cache/restore@v4
      with:
        path: ${{ env.PYTHON_DIR_CACHE }}
        key: ${{ steps.filter.outputs.python }}

    - name: (cache) Install Python modules
      if: env.PYTHON_ALLOW_CACHE == 'true' && steps.cache-lookup.outputs.cache-hit != 'true'
      run: |
        python -m pip install --target ${{ env.PYTHON_DIR_CACHE }} requests rfc3987 pywin32 lxml

    - name: (cache) Save Python modules
      if: env.PYTHON_ALLOW_CACHE == 'true' && steps.cache-lookup.outputs.cache-hit != 'true' && github.event_name == 'push'
      uses: actions/cache/save@v4
      with:
        path: ${{ env.PYTHON_DIR_CACHE }}
        key: ${{ steps.filter.outputs.python }}

    - name: XML validation
      if: steps.filter.outputs.result == 'XML'
      run: |
        if ($Env:PYTHON_ALLOW_CACHE -eq "true" -and (Test-Path -Path ${{ env.PYTHON_DIR_CACHE }})) {
          $Env:PYTHONPATH = "${{ env.PYTHON_DIR_CACHE }}"
        }
        else {
          python -m pip install requests rfc3987 pywin32 lxml
        }
        python PowerEditor\Test\xmlValidator\validator_xml.py
        if ($LastExitCode -eq 0) {
            Write-Output "`nAll XML files are valid.`n"

        }
        else {
            Write-Output "`nSome XML files are invalid.`n"
            $host.SetShouldExit($LastExitCode)
        }

  build_windows:

    runs-on: windows-latest
    needs: before_build
    if: needs.before_build.outputs.result == '' || needs.before_build.outputs.result == 'ONEJOB'
    strategy:
      fail-fast: false
      matrix: ${{ fromJSON(needs.before_build.outputs.matrix) }}

    steps:
    - name: Checkout repo
      uses: actions/checkout@v4

    - name: Add msbuild to PATH
      uses: microsoft/setup-msbuild@v2

    - name: Modify resource.h N++ version to avoid confusion
      working-directory: PowerEditor\src\
      run: |
           $content = Get-Content -Path 'resource.h'
           $newContent = $content -replace 'TEXT\(\"Notepad\+\+ v.*\"\)', 'TEXT("Notepad++ GH_BUILD")'
           $newContent | Set-Content -Path 'resource.h'

    - name: MSBuild of n++ exe
      working-directory: PowerEditor\visual.net\
      run: msbuild notepadPlus.sln /m /p:configuration="${{ matrix.build_configuration }}" /p:platform="${{ matrix.build_platform }}" /p:PlatformToolset="v143"

    - name: Archive artifacts for x64 / Release
      if: matrix.build_platform == 'x64' && matrix.build_configuration == 'Release'
      uses: actions/upload-artifact@v4
      with:
          name: Notepad++.MSVC.${{ matrix.build_platform}}.${{ matrix.build_configuration}}
          path: PowerEditor\bin64\Notepad++.exe

    - name: Archive artifacts for Win32 / Release
      if: matrix.build_platform == 'Win32' && matrix.build_configuration == 'Release'
      uses: actions/upload-artifact@v4
      with:
          name: Notepad++.MSVC.${{ matrix.build_platform}}.${{ matrix.build_configuration}}
          path: PowerEditor\bin\Notepad++.exe

    - name: Archive artifacts for ARM64 / Release
      if: matrix.build_platform == 'ARM64' && matrix.build_configuration == 'Release'
      uses: actions/upload-artifact@v4
      with:
          name: Notepad++.MSVC.${{ matrix.build_platform}}.${{ matrix.build_configuration}}
          path: PowerEditor\binarm64\Notepad++.exe

    - name: Archive artifacts for ARM64|x64 / Debug
      if: (matrix.build_platform == 'ARM64' || matrix.build_platform == 'x64') && matrix.build_configuration == 'Debug'
      uses: actions/upload-artifact@v4
      with:
          name: Notepad++.MSVC.${{ matrix.build_platform}}.${{ matrix.build_configuration}}
          path: PowerEditor\visual.net\${{ matrix.build_platform}}\${{ matrix.build_configuration}}\Notepad++.exe

    - name: Archive artifacts for Win32 / Debug
      if: matrix.build_platform == 'Win32' && matrix.build_configuration == 'Debug'
      uses: actions/upload-artifact@v4
      with:
          name: Notepad++.MSVC.${{ matrix.build_platform}}.${{ matrix.build_configuration}}
          path: PowerEditor\visual.net\${{ matrix.build_configuration}}\Notepad++.exe

    - name: (cache) Restore Python modules for Win32 / Debug
      if: matrix.build_platform == 'Win32' && matrix.build_configuration == 'Debug' && env.PYTHON_ALLOW_CACHE == 'true' && contains(needs.before_build.outputs.title, '[force nopythoncache]') != true
      uses: actions/cache/restore@v4
      with:
        path: ${{ env.PYTHON_DIR_CACHE }}
        key: ${{ needs.before_build.outputs.python }}

    - name: Run xml validation test for Win32 / Debug only
      if: matrix.build_platform == 'Win32' && matrix.build_configuration == 'Debug'
      working-directory: .\
      run: |
           if ($Env:PYTHON_ALLOW_CACHE -eq "true" -and $${{ !contains(needs.before_build.outputs.title, '[force nopythoncache]') }} -and (Test-Path -Path ${{ env.PYTHON_DIR_CACHE }})) {
             $Env:PYTHONPATH = "${{ env.PYTHON_DIR_CACHE }}"
           }
           else {
             python -m pip install requests rfc3987 pywin32 lxml
           }
           python PowerEditor\Test\xmlValidator\validator_xml.py


    - name: Run FunctionList and UrlDetection Tests for Win32 / Debug only
      if: matrix.build_platform == 'Win32' && matrix.build_configuration == 'Debug'
      working-directory: .\
      run: |
           Copy-Item "PowerEditor\visual.net\Debug\Notepad++.exe" -Destination "PowerEditor\bin"
           Copy-Item "PowerEditor\src\langs.model.xml" -Destination "PowerEditor\bin"
           Copy-Item "PowerEditor\src\stylers.model.xml" -Destination "PowerEditor\bin"
           Copy-Item "PowerEditor\src\shortcuts.xml" -Destination "PowerEditor\bin"
           Copy-Item "PowerEditor\src\contextMenu.xml" -Destination "PowerEditor\bin"
           Copy-Item "PowerEditor\installer\functionList" -Destination "PowerEditor\bin" -Recurse

           Copy-Item "PowerEditor\installer\filesForTesting\regexGlobalTest.xml" -Destination "PowerEditor\bin\functionList"
           Copy-Item "PowerEditor\installer\filesForTesting\overrideMap.xml" -Destination "PowerEditor\bin\functionList"

           cd .\PowerEditor\Test\FunctionList\
           .\unitTestLauncher.ps1
           if ($LastExitCode -ne 0) { $host.SetShouldExit($LastExitCode) }

           cd ..\UrlDetection
           .\verifyUrlDetection.ps1


  # build_windows_clang:

    # runs-on: windows-latest
    #needs: before_build
    #if: needs.before_build.outputs.result == ''
    # strategy:
      # matrix:
        # build_configuration: [Release]
        # build_platform: [x64]

    # steps:
    # - name: Checkout repo
      # uses: actions/checkout@v4

    # - name: Add msbuild to PATH
      # uses: microsoft/setup-msbuild@v2

    # - name: Modify resource.h N++ version to avoid confusion
      # working-directory: PowerEditor\src\
      # run: |
           # $content = Get-Content -Path 'resource.h'
           # $newContent = $content -replace 'TEXT\(\"Notepad\+\+ v.*\"\)', 'TEXT("Notepad++ GH_BUILD")'
           # $newContent | Set-Content -Path 'resource.h'

    # - name: MSBuild of n++ exe
      # working-directory: PowerEditor\visual.net\
      # run: msbuild notepadPlus.sln /m /p:configuration="${{ matrix.build_configuration }}" /p:platform="${{ matrix.build_platform }}" /p:PlatformToolset="ClangCL"


  build_windows_cmake:

    runs-on: windows-latest
    needs: before_build
    if: needs.before_build.outputs.result == ''
    strategy:
      matrix:
        include:
          - build_configuration: Release
            build_platform: x64
            arch: amd64

    steps:
    - name: Checkout repo
      uses: actions/checkout@v4

    - name: Add msbuild to PATH
      uses: microsoft/setup-msbuild@v2

    - name: Modify resource.h N++ version to avoid confusion
      working-directory: PowerEditor\src\
      run: |
           $content = Get-Content -Path 'resource.h'
           $newContent = $content -replace 'TEXT\(\"Notepad\+\+ v.*\"\)', 'TEXT("Notepad++ GH_BUILD")'
           $newContent | Set-Content -Path 'resource.h'

    - name: Add nmake to PATH
      uses: ilammy/msvc-dev-cmd@v1
      with:
        arch: ${{ matrix.arch }}

    - name: build scintilla
      working-directory: scintilla/win32/
      run: |
           nmake -f scintilla.mak

    - name: build lexilla
      working-directory: lexilla/src/
      run: |
           nmake -f lexilla.mak

    - name: generate cmake
      working-directory: PowerEditor/src
      run: |
           mkdir _build
           cd _build
           cmake -G "Visual Studio 17 2022" -A ${{ matrix.build_platform }} -T "v143" ..

    - name: build cmake
      working-directory: PowerEditor/src
      run: |
           cd _build
           cmake --build . --config ${{ matrix.build_configuration }}

  build_windows_msys2:

    runs-on: windows-latest
    needs: before_build
    if: needs.before_build.outputs.result == ''
    strategy:
      fail-fast: false
      matrix:
        build_configuration: [Release, Debug]
        build_platform: [x86_64, i686]

    steps:
    - name: Checkout repo
      uses: actions/checkout@v4

    - name: Modify resource.h N++ version to avoid confusion
      working-directory: PowerEditor\src\
      shell: pwsh
      run: |
           $content = Get-Content -Path 'resource.h'
           $newContent = $content -replace 'TEXT\(\"Notepad\+\+ v.*\"\)', 'TEXT("Notepad++ GH_BUILD")'
           $newContent | Set-Content -Path 'resource.h'

    - name: Make n++ exe
      working-directory: .\
      run: |
        Write-host "${{ matrix.build_platform }}"
        Write-host "${{ matrix.build_configuration }}"
        $Env:Path = 'C:\msys64\usr\bin' + [IO.Path]::PathSeparator + $Env:Path
        if ( $${{ matrix.build_platform == 'i686'}} ) {$Env:MSYSTEM = 'MINGW32'}
        if ( $${{ matrix.build_platform == 'i686'}} ) {$Env:Path = 'C:\msys64\mingw32\bin' + [IO.Path]::PathSeparator + $Env:Path}
        if ( $${{ matrix.build_platform == 'x86_64'}} ) {$Env:MSYSTEM = 'MINGW64'}
        if ( $${{ matrix.build_platform == 'x86_64'}} ) {$Env:Path = 'C:\msys64\mingw64\bin' + [IO.Path]::PathSeparator + $Env:Path}
        if ( $${{ matrix.build_configuration == 'Debug'}} ) {$Env:DEBUG = '1'}
        bash -lc "pacman --noconfirm -Syuu"
        bash -lc "pacman --noconfirm -Syuu"
        if ( $${{ matrix.build_platform == 'i686'}} ) {bash -lc "pacman --noconfirm -S mingw-w64-i686-gcc mingw-w64-i686-make"}
        if ( $${{ matrix.build_platform == 'x86_64'}} ) {bash -lc "pacman --noconfirm -S mingw-w64-x86_64-gcc mingw-w64-x86_64-make"}
        Write-Output "Tools version:"
        Write-Output (((gcc --version) | select-object -first 1) + " " + (gcc -dumpmachine))
        Write-Output (mingw32-make --version) | select-object -first 1
        Write-Output (sh --version) | select-object -first 1
        mingw32-make -f PowerEditor\gcc\makefile

    - name: Archive artifacts for ${{ matrix.build_platform}} / Release
      if: matrix.build_configuration == 'Release'
      uses: actions/upload-artifact@v4
      with:
          name: Notepad++.GCC.${{ matrix.build_platform}}.${{ matrix.build_configuration}}
          path: bin.${{ matrix.build_platform}}\notepad++.exe

    - name: Archive artifacts for ${{ matrix.build_platform}} / Debug
      if: matrix.build_configuration == 'Debug'
      uses: actions/upload-artifact@v4
      with:
          name: Notepad++.GCC.${{ matrix.build_platform}}.${{ matrix.build_configuration}}
          path: bin.${{ matrix.build_platform}}-debug\notepad++.exe
