trigger:
- main

pr:
- main

variables:
  # Turn this Powershell console into a developer powershell console.
  # https://intellitect.com/enter-vsdevshell-powershell/
  PWSH_DEV: |
    $installPath = &"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -latest -property installationpath
    $devShellLoadedSuccess = $false
    if (Test-Path -Path ../where_is_devshell/here.txt -PathType leaf) {
      $tryDevShell = Get-Item -Path ../where_is_devshell/here.txt | Get-Content -Head 1
      if (Test-Path -Path $tryDevShell) {
        try {
          Import-Module $tryDevShell
          $devShell = $tryDevShell
          $devShellLoadedSuccess = $true
          Write-Output "Successfully loaded DevShell.dll from $tryDevShell"
        }
        catch {
          Write-Output "##[warning]While trying to load the devShell module from $tryDevShell"
          Write-Output $_
        }
      }
    }
    if (-not $devShellLoadedSuccess) {
      Write-Output "Locating DevShell.dll in visual studio installation, please hold on ..."
      $devShell = &"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -latest -find **\Microsoft.VisualStudio.DevShell.dll
      Write-Output "Found DevShell.dll at $devShell"
      try {
        mkdir ../where_is_devshell/
        $devShell | out-file -filepath ../where_is_devshell/here.txt
      }
      catch {
        Write-Output "##[warning]Couldn't cache $devShell in ../where_is_devshell/here.txt :("
        Write-Output $_
      }
      Import-Module $devShell
    }
    Enter-VsDevShell -VsInstallPath $installPath -SkipAutomaticLocation -DevCmdArguments "-arch=amd64"
  RAKUDO_CHECKOUT_TYPE: main
  NQP_CHECKOUT_TYPE: main
  MOAR_CHECKOUT_TYPE: "rev-$(Build.SourceVersion)-selfrepo"
  INSTALL_DIR: install

stages:
- stage: Test
  jobs:
    # Keep the job and matrix entry names as short as possible as the webinterface
    # leaves little space for the name.
    - job: T
      strategy:
       matrix:
         # The Windows job names start with '_' so they are lexicographically first. They usually
         # take the longest to run, so this way we get better pipelining among all the jobs.
         A_Win_MVM:
           IMAGE_NAME: 'windows-2022'
           RAKUDO_OPTIONS: ''
           NQP_OPTIONS: '--backends=moar'
           MOAR_OPTIONS: ''
         A_Win_MVM_reloc:
           IMAGE_NAME: 'windows-2022'
           RELOCATABLE: 'yes'
           RAKUDO_OPTIONS: '--relocatable'
           NQP_OPTIONS: '--backends=moar --relocatable'
           MOAR_OPTIONS: '--relocatable'

         Mac_MVM:
           IMAGE_NAME: 'macOS-14'
           RAKUDO_OPTIONS: ''
           NQP_OPTIONS: '--backends=moar'
           MOAR_OPTIONS: ''
         Mac_MVM_reloc:
           IMAGE_NAME: 'macOS-14'
           RELOCATABLE: 'yes'
           RAKUDO_OPTIONS: '--relocatable'
           NQP_OPTIONS: '--backends=moar --relocatable'
           MOAR_OPTIONS: '--relocatable'
         Mac_MVM_no_C11_atomics:
           IMAGE_NAME: 'macOS-14'
           RAKUDO_OPTIONS: ''
           NQP_OPTIONS: '--backends=moar'
           MOAR_OPTIONS: '--no-c11-atomics'

         Lin_MVM:
           IMAGE_NAME: 'ubuntu-24.04'
           RAKUDO_OPTIONS: ''
           NQP_OPTIONS: '--backends=moar'
           MOAR_OPTIONS: '--debug=3'
           CHECK_LEAKS: 'yes'
         Lin_MVM_reloc:
           IMAGE_NAME: 'ubuntu-24.04'
           RELOCATABLE: 'yes'
           RAKUDO_OPTIONS: '--relocatable'
           NQP_OPTIONS: '--backends=moar --relocatable'
           MOAR_OPTIONS: '--relocatable --debug=3'
           CHECK_LEAKS: 'yes'

         MVM_gcc_njit:
           IMAGE_NAME: 'ubuntu-24.04'
           RAKUDO_OPTIONS: ''
           NQP_OPTIONS: '--backends=moar'
           MOAR_OPTIONS: '--no-jit --cc=gcc --debug=3'
           CHECK_LEAKS: 'yes'
         MVM_gcc:
           IMAGE_NAME: 'ubuntu-24.04'
           RAKUDO_OPTIONS: ''
           NQP_OPTIONS: '--backends=moar'
           MOAR_OPTIONS: '--cc=gcc --debug=3'
           CHECK_LEAKS: 'yes'
         MVM_clang_njit:
           IMAGE_NAME: 'ubuntu-24.04'
           RAKUDO_OPTIONS: ''
           NQP_OPTIONS: '--backends=moar'
           MOAR_OPTIONS: '--no-jit --cc=clang --debug=3'
           CHECK_LEAKS: 'yes'
         MVM_clang:
           IMAGE_NAME: 'ubuntu-24.04'
           RAKUDO_OPTIONS: ''
           NQP_OPTIONS: '--backends=moar'
           MOAR_OPTIONS: '--cc=clang --debug=3'
           CHECK_LEAKS: 'yes'
         MVM_gcc_njit_libffi:
           IMAGE_NAME: 'ubuntu-24.04'
           RAKUDO_OPTIONS: ''
           NQP_OPTIONS: '--backends=moar'
           MOAR_OPTIONS: '--has-libffi --no-jit --cc=gcc --debug=3'
           CHECK_LEAKS: 'yes'
         MVM_gcc_libffi:
           IMAGE_NAME: 'ubuntu-24.04'
           RAKUDO_OPTIONS: ''
           NQP_OPTIONS: '--backends=moar'
           MOAR_OPTIONS: '--has-libffi --cc=gcc --debug=3'
           CHECK_LEAKS: 'yes'
         MVM_clang_njit_libffi:
           IMAGE_NAME: 'ubuntu-24.04'
           RAKUDO_OPTIONS: ''
           NQP_OPTIONS: '--backends=moar'
           MOAR_OPTIONS: '--has-libffi --no-jit --cc=clang --debug=3'
           CHECK_LEAKS: 'yes'
         MVM_clang_libffi:
           IMAGE_NAME: 'ubuntu-24.04'
           RAKUDO_OPTIONS: ''
           NQP_OPTIONS: '--backends=moar'
           MOAR_OPTIONS: '--has-libffi --cc=clang --debug=3'
           CHECK_LEAKS: 'yes'
#         MVM_gcc_mingw:
#           IMAGE_NAME: 'windows-2022'
#           RAKUDO_OPTIONS: ''
#           NQP_OPTIONS: '--backends=moar'
#           MOAR_OPTIONS: '--os=mingw32'
#         MVM_coverage:
#           IMAGE_NAME: 'ubuntu-24.04'
#           RAKUDO_OPTIONS: ''
#           NQP_OPTIONS: '--backends=moar'
#           MOAR_OPTIONS: '--compiler=clang --coverage --optimize=0 --debug=3 --cc=clang'
#           COVERAGE: 'yes'

         MVM_gcc_malloc:
           IMAGE_NAME: 'ubuntu-24.04'
           RAKUDO_OPTIONS: ''
           NQP_OPTIONS: '--backends=moar'
           MOAR_OPTIONS: '--cc=gcc --debug=3 --no-mimalloc'
           CHECK_LEAKS: 'yes'
         MVM_clang_malloc:
           IMAGE_NAME: 'ubuntu-24.04'
           RAKUDO_OPTIONS: ''
           NQP_OPTIONS: '--backends=moar'
           MOAR_OPTIONS: '--cc=clang --debug=3 --no-mimalloc'
           CHECK_LEAKS: 'yes'
         MVM_gcc_no_c11_atomics:
           IMAGE_NAME: 'ubuntu-24.04'
           RAKUDO_OPTIONS: ''
           NQP_OPTIONS: '--backends=moar'
           MOAR_OPTIONS: '--cc=gcc --debug=3 --no-c11-atomics'
           CHECK_LEAKS: 'yes'
         MVM_clang_no_c11_atomics:
           IMAGE_NAME: 'ubuntu-24.04'
           RAKUDO_OPTIONS: ''
           NQP_OPTIONS: '--backends=moar'
           MOAR_OPTIONS: '--cc=clang --debug=3 --no-c11-atomics'
           CHECK_LEAKS: 'yes'

         # Backwards compatability jobs, using the oldest OS version that azure pipelines support
         MVM_Ub_22_gcc:
           IMAGE_NAME: 'ubuntu-22.04'
           RAKUDO_OPTIONS: ''
           NQP_OPTIONS: '--backends=moar'
           MOAR_OPTIONS: '--cc=gcc --debug=3'
         MVM_Ub_22_clang:
           IMAGE_NAME: 'ubuntu-22.04'
           RAKUDO_OPTIONS: ''
           NQP_OPTIONS: '--backends=moar'
           MOAR_OPTIONS: '--cc=clang --debug=3'

      pool:
        vmImage: $(IMAGE_NAME)
      workspace:
        clean: all
      timeoutInMinutes: 180
      steps:

        - pwsh: |
            # Windows has a maximum PATH variable length of 2048 (depending on
            # how it's accessed). The length of PATH in AzureCI is already
            # really tight. We'll run into the limit when we add Java and the
            # MS BuildTools to the path.
            # To work around this, we remove a bunch of stuff we won't need
            # from PATH here.
            $shortened_path = "$(PATH)" -replace ';[^;]*(SeleniumWebDrivers|SQL Server|Mercurial|Amazon|mysql|\\sbt\\|NSIS|Windows Performance Toolkit|php|Subversion)[^;]*(?=(;|$))', ''
            echo "##vso[task.setvariable variable=PATH]$shortened_path"
          displayName: "Shorten PATH on Windows"
          condition: eq( variables['Agent.OS'], 'Windows_NT' )

        - task: Cache@2
          displayName: "load cached location of devshell dll"
          inputs:
            key: '"where is devshell on" | "$(IMAGE_NAME)"'
            path: ../where_is_devshell/
          condition: eq( variables['Agent.OS'], 'Windows_NT' )

        - script: |
            sudo apt-get update
            sudo apt-get install libzstd-dev valgrind
            # The loop with libc-bin and glibc-tools are because catchsegv moved packages with Ubuntu 20.04 and again with 22.04
            for pkg in libc-bin glibc-tools
            do
              sudo apt-get install -qy $pkg || true
            done
          condition: and(succeeded(), eq( variables['Agent.OS'], 'Linux' ))
          displayName: Install libzstd-dev and valgrind

        - checkout: self
          path: selfrepo
          displayName: Checkout script repo

        - script: perl selfrepo/tools/build/checkout-repos-for-test.pl $(RAKUDO_CHECKOUT_TYPE) $(NQP_CHECKOUT_TYPE) $(MOAR_CHECKOUT_TYPE)
          workingDirectory: $(Pipeline.Workspace)
          displayName: Checkout repositories

        # Build MoarVM
        - script: |
            perl Configure.pl --prefix=../$(INSTALL_DIR) $(MOAR_OPTIONS)
            make -j2 install
          workingDirectory: '$(Pipeline.Workspace)/MoarVM'
          condition: and(succeeded(), ne( variables['Agent.OS'], 'Windows_NT' ))
          displayName: Build MoarVM
        - pwsh: |
            ${{ variables.PWSH_DEV }}
            perl Configure.pl --prefix=..\$(INSTALL_DIR) $(MOAR_OPTIONS)
            gmake -j2 install
          failOnStderr: false
          workingDirectory: '$(Pipeline.Workspace)/MoarVM'
          condition: and(succeeded(), eq( variables['Agent.OS'], 'Windows_NT' ), contains( variables['MOAR_OPTIONS'], 'mingw32' ))
          displayName: Build MoarVM (Windows, MinGW)
        - pwsh: |
            ${{ variables.PWSH_DEV }}
            perl Configure.pl --prefix=..\$(INSTALL_DIR) $(MOAR_OPTIONS)
            set CL=/MP
            nmake install
          failOnStderr: false
          workingDirectory: '$(Pipeline.Workspace)/MoarVM'
          condition: and(succeeded(), eq( variables['Agent.OS'], 'Windows_NT' ), not(contains( variables['MOAR_OPTIONS'], 'mingw32' )))
          displayName: Build MoarVM (Windows, MSVC)

        # Build NQP
        - pwsh: |
            ${{ variables.PWSH_DEV }}
            perl Configure.pl --prefix=../$(INSTALL_DIR) $(NQP_OPTIONS) --make-install
          workingDirectory: '$(Pipeline.Workspace)/nqp'
          condition: and(succeeded(), eq( variables['Agent.OS'], 'Windows_NT' ) )
          displayName: Build NQP (Windows)
        - script: |
            export SEGFAULT_SIGNALS="all"
            CATCHSEGV=$(which catchsegv)
            $CATCHSEGV perl Configure.pl --prefix=../$(INSTALL_DIR) $(NQP_OPTIONS) --make-install
          workingDirectory: '$(Pipeline.Workspace)/nqp'
          condition: and(succeeded(), ne( variables['Agent.OS'], 'Windows_NT' ) )
          displayName: Build NQP

        # Build Rakudo
        - pwsh: |
            ${{ variables.PWSH_DEV }}
            perl Configure.pl --prefix=../$(INSTALL_DIR) $(RAKUDO_OPTIONS) --make-install
          workingDirectory: '$(Pipeline.Workspace)/rakudo'
          condition: and(succeeded(), eq( variables['Agent.OS'], 'Windows_NT' ) )
          displayName: Build Rakudo (Windows)
        - script: |
            export SEGFAULT_SIGNALS="all"
            CATCHSEGV=$(which catchsegv)
            $CATCHSEGV perl Configure.pl --prefix=../$(INSTALL_DIR) $(RAKUDO_OPTIONS) --make-install
          workingDirectory: '$(Pipeline.Workspace)/rakudo'
          condition: and(succeeded(), ne( variables['Agent.OS'], 'Windows_NT' ) )
          displayName: Build Rakudo

        # TODO: Should use "install moved" instead of "install-moved". But `prove` currently fails with an executable path that contains a space.
        - pwsh: |
            mv $(INSTALL_DIR) $(INSTALL_DIR)-moved
            echo "##vso[task.setvariable variable=INSTALL_DIR]$(INSTALL_DIR)-moved"
          workingDirectory: $(Pipeline.Workspace)
          condition: and(succeeded(), eq( variables['RELOCATABLE'], 'yes' ) )
          displayName: Move installation

        # Test NQP
        - script: prove -j2 -r -e ../$(INSTALL_DIR)/bin/nqp t/nqp t/hll t/qregex t/p5regex t/qast t/moar t/serialization t/nativecall t/concurrency
          workingDirectory: '$(Pipeline.Workspace)/nqp'
          condition: and(succeeded(), eq( variables['Agent.OS'], 'Windows_NT' ) )
          displayName: Test NQP (Windows)
        - script: |
            export SEGFAULT_SIGNALS="all"
            CATCHSEGV=$(which catchsegv)
            $CATCHSEGV prove -j2 -r -e ../$(INSTALL_DIR)/bin/nqp t/nqp t/hll t/qregex t/p5regex t/qast t/moar t/serialization t/nativecall t/concurrency
          workingDirectory: '$(Pipeline.Workspace)/nqp'
          condition: and(succeeded(), ne( variables['Agent.OS'], 'Windows_NT' ) )
          displayName: Test NQP

        # Test Rakudo
        - pwsh: |
            ${{ variables.PWSH_DEV }}
            $install_path = Resolve-Path ../$(INSTALL_DIR)/bin/
            prove -j2 -e "$($install_path.Path)raku" -vlr t
          workingDirectory: '$(Pipeline.Workspace)/rakudo'
          condition: and(succeeded(), eq( variables['Agent.OS'], 'Windows_NT' ) )
          displayName: Test Rakudo (Windows)
        - script: |
            export SEGFAULT_SIGNALS="all"
            CATCHSEGV=$(which catchsegv)
            $CATCHSEGV prove -j2 -e ../$(INSTALL_DIR)/bin/raku -vlr t
          workingDirectory: '$(Pipeline.Workspace)/rakudo'
          condition: and(succeeded(), ne( variables['Agent.OS'], 'Windows_NT' ) )
          displayName: Test Rakudo

        - publish: $(Pipeline.Workspace)/$(INSTALL_DIR)
          condition: and(succeeded(), eq( variables['RELOCATABLE'], 'yes' ))
          displayName: Publish build artifact

#        - script: |
#            git clone --depth 1 'https://github.com/samcv/MoarVM-cover.git' &&
#            cp -v MoarVM-cover/html-cover.sh . &&
#            cp -v MoarVM-cover/nqp-profile ../nqp/ &&
#            cp -v MoarVM-cover/merge-profraw.sh ../nqp/ &&
#            ./html-cover.sh 2
#          condition: and(succeeded(), eq( variables['COVERAGE'], 'yes' ))
#          displayName: Create coverage report

        - script: |
            valgrind --leak-check=full ../$(INSTALL_DIR)/bin/raku --full-cleanup -e '' 2>valgrind.log
            cat valgrind.log
            grep 'in use at exit: 0 bytes in 0 blocks' valgrind.log
          condition: and(succeeded(), eq( variables['CHECK_LEAKS'], 'yes' ), ne( variables['COVERAGE'], 'yes' ), eq( variables['Agent.OS'], 'Linux' ))
          displayName: Check for memory leaks
