# cSpell:ignore vsts
# cSpell:ignore parseazuresdkcpp sbom

parameters:
  - name: Artifacts
    type: object
    default: []
  - name: ServiceDirectory
    type: string
    default: not-specified
  - name: TestPipeline
    type: boolean
    default: false
  - name: CoverageEnabled
    type: boolean
    default: true
  - name: CtestRegex
    type: string
    default: .*
  - name: CtestExcludeRegex
    type: string
    default: ''
  - name: BuildReleaseArtifacts
    type: boolean
    default: true
  - name: CoverageReportPath
    type: string
    default: 'sdk/*/*/*cov_xml.xml'
  - name: LineCoverageTarget
    type: number
    default: 95
  - name: BranchCoverageTarget
    type: number
    default: 70
  - name: TestEnv
    type: object
    default: []
  - name: PreTestSteps
    type: stepList
    default: []
  - name: PostTestSteps
    type: stepList
    default: []
  - name: MatrixFile
    type: string
    default: eng/pipelines/templates/stages/platform-matrix.json
  - name: JobName
    type: string
    default: Validate 
  - name: RunMetaJobs
    type: boolean
    default: true

jobs:
  - template: /eng/common/pipelines/templates/jobs/generate-job-matrix.yml
    parameters:
      GenerateJobName: ${{ parameters.JobName }}_generate_matrix
      MatrixConfigs:
        - Name: base
          Path: ${{ parameters.MatrixFile }}
          Selection: all
          GenerateVMJobs: true
      JobTemplatePath: /eng/pipelines/templates/jobs/ci.tests.yml
      OsVmImage: $(LINUXVMIMAGE)
      Pool: $(LINUXPOOL)
      AdditionalParameters:
        DisplayName: ${{ parameters.JobName }}
        Artifacts: ${{ parameters.Artifacts }}
        ServiceDirectory: ${{ parameters.ServiceDirectory }}
        TestPipeline: ${{ parameters.TestPipeline }}
        CtestRegex: ${{ parameters.CtestRegex }}
        CtestExcludeRegex: ${{ parameters.CtestExcludeRegex }}
        CoverageReportPath: ${{ parameters.CoverageReportPath }}
        CoverageEnabled: ${{ parameters.CoverageEnabled }}
        LineCoverageTarget: ${{ parameters.LineCoverageTarget }}
        BranchCoverageTarget: ${{ parameters.BranchCoverageTarget }}
        TestEnv: ${{ parameters.TestEnv }}
        PreTestSteps: ${{ parameters.PreTestSteps }}
        PostTestSteps: ${{ parameters.PostTestSteps }}

  # Disable build for cpp - client
  - ${{ if and(eq(parameters.RunMetaJobs, 'true'), ne(parameters.ServiceDirectory, 'not-specified' )) }}:
    - job: GenerateReleaseArtifacts
      pool:
        name: $(WINDOWSPOOL)
        image: $(WINDOWSVMIMAGE)
        os: windows
      variables:
        apiviewParserVersion: "20240927.5"
        VCPKG_DEFAULT_TRIPLET: 'x64-windows-static'
        Package.EnableSBOMSigning: true
      steps:
        - template: /eng/common/pipelines/templates/steps/set-default-branch.yml
        - template: /eng/common/pipelines/templates/steps/check-spelling.yml
          parameters:
            ContinueOnError: false

        # Install Python on the machine for verify-path-length script.
        - task: UsePythonVersion@0
          displayName: Install Python Version

        # Base Path Length calculated based on Visual Studio's defaults for projects.
        # By default, Visual Studio puts projects in a folder structure like this:
        # C:\Users\<username>\source\repos\<project>. That is 34 characters before project.
        # The default project name for the C++ SDK is azure-sdk-for-cpp. That is 18 additional characters (52).
        # Assuming that the user is building with the default cmake presets, cmake will create a build folder 
        # which is about 25 characters long (x64-static-debug-perftests).
        - template: /eng/common/pipelines/templates/steps/verify-path-length.yml
          parameters:
            SourceDirectory: $(Build.SourcesDirectory)
            BasePathLength: 75

        - template: /eng/common/pipelines/templates/steps/verify-links.yml
          parameters:
            ${{ if eq(variables['Build.Reason'], 'PullRequest') }}:
              Directory: ''
              Urls: (eng/common/scripts/get-markdown-files-from-changed-files.ps1)
            ${{ if ne(variables['Build.Reason'], 'PullRequest') }}:
              Directory: sdk/${{ parameters.ServiceDirectory }}
            CheckLinkGuidance: $true

        - ${{ each artifact in parameters.Artifacts }}:
          - template: /eng/common/pipelines/templates/steps/set-test-pipeline-version.yml
            parameters:
              PackageName: ${{ artifact.Name }}
              ServiceDirectory: ${{ parameters.ServiceDirectory }}
              TestPipeline: ${{ parameters.TestPipeline }}

        - pwsh: |
            $setupFile="doxygen-1.9.7-setup.exe";

            Invoke-WebRequest `
              -MaximumRetryCount 10 `
              -Uri "https://azuresdkartifacts.blob.core.windows.net/tools/doxygen/$setupFile" `
              -OutFile $setupFile `
            | Wait-Process;

            Write-Host "Installing $setupFile..."
            Start-Process -Filepath .\$setupFile -ArgumentList @("/VERYSILENT") -Wait
            Write-Host "Install complete"
            .'C:\Program Files\doxygen\bin\doxygen.exe' --version
          workingDirectory: $(Agent.TempDirectory)
          displayName: Download and Install Doxygen

        - template: /eng/common/pipelines/templates/steps/set-vcpkg-cache-vars.yml

        - script: vcpkg --version
          condition: >-
              and(
              succeeded(),
              not(eq(variables['Agent.OS'], 'Darwin'))
              )
          displayName: vcpkg --version

        - template: /eng/pipelines/templates/steps/cmake-build.yml
          parameters:
            ServiceDirectory: ${{ parameters.ServiceDirectory }}
            Build: false
            GenerateArgs: >-
              -DINSTALL_GTEST=OFF
              -DBUILD_TESTING=OFF
              -DBUILD_TRANSPORT_CURL=OFF
              -DBUILD_DOCUMENTATION=YES

        - pwsh: npm install -g moxygen
          displayName: Install Moxygen to generate markdown for learn.microsoft.com

        - pwsh: |
            Write-Host "Using apiview parser version ${{ variables.apiviewParserVersion }}"
            azcopy copy "https://azuresdkartifacts.blob.core.windows.net/azure-sdk-for-cpp/parseazuresdkcpp/${{ variables.apiviewParserVersion }}/RelWithDebInfo/ParseAzureSdkCpp.exe" "$(System.DefaultWorkingDirectory)/parser/ParseAzureSdkCpp.exe"
            azcopy copy "https://azuresdkartifacts.blob.core.windows.net/azure-sdk-for-cpp/parseazuresdkcpp/${{ variables.apiviewParserVersion }}/RelWithDebInfo/ParseAzureSdkCpp.pdb" "$(System.DefaultWorkingDirectory)/parser/ParseAzureSdkCpp.pdb"
          displayName: Download ApiView Parser.

        - task: Powershell@2
          inputs:
            filePath: $(System.DefaultWorkingDirectory)/eng/scripts/Generate-APIReview-Token-Files.ps1
            arguments: >
              -ArtifactList ('${{ convertToJson(parameters.Artifacts) }}' | ConvertFrom-Json | Select-Object Name)
              -OutPath $(Build.ArtifactStagingDirectory)
              -ParserPath $(System.DefaultWorkingDirectory)/parser/ParseAzureSdkCpp.exe
              -ServicePath $(Build.SourcesDirectory)/sdk/${{ parameters.ServiceDirectory }}
            pwsh: true
            workingDirectory: $(Pipeline.Workspace)
          displayName: Generate APIReview Token Files

        - task: Powershell@2
          inputs:
            filePath: $(Build.SourcesDirectory)/eng/common/scripts/Save-Package-Properties.ps1
            arguments: >
              -ServiceDirectory ${{parameters.ServiceDirectory}}
              -OutDirectory $(Build.ArtifactStagingDirectory)/packages/PackageInfo
            pwsh: true
            workingDirectory: $(Pipeline.Workspace)
          displayName: Dump Package properties

        # Generate package spec JSON files for tagging the repo
        - ${{ each artifact in parameters.Artifacts }}:
            - pwsh: >-
                New-Item
                -ItemType directory
                -Path $(Build.ArtifactStagingDirectory)
                -Name packages/${{ artifact.Name }}
                -Force
              displayName: Create package info artifact location

            - pwsh: |
                $outputPath = Join-Path -Path $(Build.ArtifactStagingDirectory) packages/${{ artifact.Name }}/package-info.json

                $version = eng/scripts/Get-PkgVersion -ServiceDirectory ${{ parameters.ServiceDirectory }} -PackageName ${{ artifact.Path }}
                $outputObject = @{ version = $version.ToString(); name = '${{ artifact.Name }}'; packageName = "${{ artifact.Name }}_$version"; } | ConvertTo-Json

                Set-Content -Path $outputPath -Value $outputObject

                # Set AZURE_SDK_VERSION for use in Doxygen generation
                Write-Host "##vso[task.setvariable variable=AZURE_SDK_VERSION]$version"
              displayName: Create package info JSON file for ${{ artifact.Name }}

            - task: Powershell@2
              inputs:
                targetType: inline
                script: |
                  # If there is no vcpkg directory skip staging the vcpkg port artifacts
                  if (!(Test-Path build/vcpkg/ports/${{ artifact.VcpkgPortName }})) {
                    Write-Host "No vcpkg port directory at build/vcpkg/ports/${{ artifact.VcpkgPortName }}"
                    exit
                  }

                  New-Item `
                    -ItemType Directory `
                    $(Build.ArtifactStagingDirectory)/packages/${{ artifact.Name }}/vcpkg -Force

                  Copy-Item -Recurse `
                    build/vcpkg/ports/${{ artifact.VcpkgPortName }}/. `
                    $(Build.ArtifactStagingDirectory)/packages/${{ artifact.Name }}/vcpkg/port
                pwsh: true
              displayName: Copy vcpkg port files from build for ${{ artifact.Name }}

            - pwsh: |
                $outputPath = Join-Path -Path $(Build.ArtifactStagingDirectory) packages/${{ artifact.Name }}
                $changelogPath = "sdk/${{ parameters.ServiceDirectory }}/${{ artifact.Path }}/CHANGELOG.md"

                if (Test-Path $changeLogPath) {
                  Copy-Item sdk/${{ parameters.ServiceDirectory }}/${{ artifact.Path }}/CHANGELOG.md $outputPath
                } else {
                  Write-Warning "$changeLogPath does not exist"
                }
              displayName: Copy CHANGELOG.md to package artifact for ${{ artifact.Name }}

            - script: cmake --build . --target ${{ artifact.Path }}-docs
              workingDirectory: build
              displayName: Generate docs (${{ artifact.Name }}-docs)
              condition: and(succeeded(), ne('${{parameters.ServiceDirectory}}', 'appconfiguration'))
            
            - pwsh: |
                $docsfileExists = Test-Path -Path "build/sdk/${{ parameters.ServiceDirectory }}/${{ artifact.Path }}/docs/html"
                Write-Output "##vso[task.setvariable variable=DocsFileExists]$docsfileExists"
              displayName: Check if docs exist for ${{ artifact.Name }}

            - template: /eng/common/pipelines/templates/steps/verify-links.yml
              parameters:
                Directory:
                Urls: annotated.html
                CheckLinkGuidance: $false
                Recursive: $true
                WorkingDirectory: build/sdk/${{ parameters.ServiceDirectory }}/${{ artifact.Path }}/docs/html
                condition: and(succeeded(), eq(variables['DocsFileExists'], True))

            - task: PowerShell@2
              inputs:
                targetType: filePath
                filePath: eng/scripts/New-DocsMsArtifact.ps1
                arguments: >-
                  -ServiceDirectory ${{ parameters.ServiceDirectory }}
                  -PackageName ${{ artifact.Name }}
                  -TargetFolder $(Build.ArtifactStagingDirectory)/packages/${{ artifact.Name }}/docs/docs.ms
                ignoreLASTEXITCODE: true
                pwsh: true
              displayName: Generate ${{ artifact.Name }} artifacts for docs.ms

            - task: Powershell@2
              inputs:
                filePath: $(System.DefaultWorkingDirectory)/eng/scripts/Generate-Snippets.ps1
                arguments: >
                 -source_dir $(Build.SourcesDirectory)/sdk/${{parameters.ServiceDirectory}}/${{artifact.Name}}
                 -output_dir $(Build.SourcesDirectory)/sdk/${{parameters.ServiceDirectory}}/${{artifact.Name}}
                 -verify
                pwsh: true
              displayName: Verify Snippets are correct for ${{artifact.Name}}

            - pwsh: |
                New-Item -ItemType directory -Path $(Build.ArtifactStagingDirectory) -Name docs/${{ artifact.Name }}
              displayName: Create doc artifact location

            - task: CopyFiles@2
              inputs:
                sourceFolder: $(Build.ArtifactStagingDirectory)/packages/${{ artifact.Name }}
                contents: package-info.json
                targetFolder: build/sdk/${{ parameters.ServiceDirectory }}/${{ artifact.Path }}/docs/html
              displayName: Copy package-info.json to documentation path

            - task: CopyFiles@2
              inputs:
                sourceFolder: build/sdk/${{ parameters.ServiceDirectory }}/${{ artifact.Path }}/docs/html
                targetFolder: $(Build.ArtifactStagingDirectory)/docs/${{ artifact.Name }}
              displayName: Copy documentation to artifact staging directory

            - task: Powershell@2
              inputs:
                filePath: $(Build.SourcesDirectory)/eng/common/scripts/Verify-ChangeLog.ps1
                arguments: >
                  -ChangeLogLocation sdk/${{ parameters.ServiceDirectory }}/${{ artifact.Path }}/CHANGELOG.md
                  -VersionString (Get-Content build/sdk/${{ parameters.ServiceDirectory }}/${{ artifact.Path }}/docs/html/package-info.json | ConvertFrom-Json).version
                  -ForRelease $true
                pwsh: true
              displayName: Verify CHANGELOG.md contents
              continueOnError: true
              condition: and(succeeded(), eq(variables['VerifyChangeLogForRelease'], 'true'))

        - pwsh: |
            $packageJsonDest = Join-Path -Path $(Build.ArtifactStagingDirectory) PackageInfo
            $packageJsonSource = Join-Path -Path $(Build.ArtifactStagingDirectory) packages/PackageInfo
            mkdir $packageJsonDest
            Copy-Item $packageJsonSource/* $packageJsonDest -Force
          displayName: Copy Package Json
        - template: /eng/common/pipelines/templates/steps/publish-1es-artifact.yml
          parameters:
            ArtifactPath: $(Build.ArtifactStagingDirectory)/packages
            ArtifactName: packages
        - template: /eng/common/pipelines/templates/steps/publish-1es-artifact.yml
          parameters:
            ArtifactPath: $(Build.ArtifactStagingDirectory)/PackageInfo
            ArtifactName: PackageInfo
        
        - task: Powershell@2
          inputs:
            filePath: $(System.DefaultWorkingDirectory)/eng/common/scripts/Create-APIReview.ps1
            arguments: >
              -ArtifactList ('${{ convertToJson(parameters.Artifacts) }}' | ConvertFrom-Json | Select-Object Name)
              -ArtifactPath "$(Build.ArtifactStagingDirectory)/packages"
              -ApiKey "$(azuresdk-apiview-apikey)"
              -SourceBranch $(Build.SourceBranchName)
              -DefaultBranch $(DefaultBranch)
              -BuildId $(Build.BuildId)
              -RepoName "$(Build.Repository.Name)"
            pwsh: true
            workingDirectory: $(Pipeline.Workspace)
          displayName: Create API Review
          condition: >-
            and(
              succeeded(),
              ne(variables['Skip.CreateApiReview'], 'true'),
              ne(variables['Build.Reason'],'PullRequest'),
              eq(variables['System.TeamProject'], 'internal')
            )
        - ${{ if eq(variables['Build.Reason'], 'PullRequest') }}:
          - ${{ each artifact in parameters.Artifacts }}:
            - template: /eng/common/pipelines/templates/steps/detect-api-changes.yml
              parameters:
                ArtifactPath: $(Build.ArtifactStagingDirectory)\packages

        - template: /eng/common/pipelines/templates/steps/publish-1es-artifact.yml
          parameters:
            ArtifactPath: $(Build.ArtifactStagingDirectory)/docs
            ArtifactName: docs
            CustomCondition: eq(variables['DocsFileExists'], True)

        - template: /eng/common/pipelines/templates/steps/eng-common-workflow-enforcer.yml
