tasks/dotnet.tasks.ps1

# Control flags
$CleanBuild = $false
$EnableCoverage = $true

# Options
$SolutionToBuild = $false
$ProjectsToPublish = @()
$NuSpecFilesToPackage = @()

$SkipSolutionPackages = $false
$SkipProjectPublishPackages = $false
$SkipNuspecPackages = $false

$FoldersToClean = @("bin", "obj", "TestResults", "_codeCoverage", "_packages")
$ReportGeneratorToolVersion = "4.8.3"
$TestReportTypes = "Cobertura"
$DotNetTestLogger = "console;verbosity=$LogLevel"

# NuGet Publishing Options
$NugetPublishSource = "$here/_local-nuget-feed"
$NugetPublishSymbolSource = $NugetPublishSource
$NugetPublishSkipDuplicates = $true
# By default the build will publish all NuGet packages it finds with the current version number
$NugetPackageNamesToPublishGlob = "*"
# Uses a non-interpolated string to ensure lazy evaluation of the GitVersion variable
$NugetPackagesToPublishGlobSuffix = '.$(($script:GitVersion).SemVer).nupkg'


# Synopsis: Clean .NET solution
task CleanSolution -If {$CleanBuild -and $SolutionToBuild} {
    exec { 
        dotnet clean $SolutionToBuild `
                     --configuration $Configuration `
                     --verbosity $LogLevel
    }

    # Delete output folders
    Write-Build White "Deleting output folders..."
    $FoldersToClean | ForEach-Object {
        Get-ChildItem -Path (Split-Path -Parent $SolutionToBuild) `
                      -Filter $_ `
                      -Recurse `
            | Where-Object { $_.PSIsContainer }
    } | Remove-Item -Recurse -Force
}

# Synopsis: Build .NET solution
task BuildSolution -If {$SolutionToBuild} Version,CleanSolution,RestorePackages,{
    exec { 
        dotnet build $SolutionToBuild `
                     --no-restore `
                     --configuration $Configuration `
                     /p:Version="$(($script:GitVersion).SemVer)" `
                     /p:EndjinRepositoryUrl="$BuildRepositoryUri" `
                     --verbosity $LogLevel
    }
}

# Synopsis: Restore .NET Solution Packages
task RestorePackages -If {$SolutionToBuild} CleanSolution,{
    exec { 
        dotnet restore $SolutionToBuild `
                       --verbosity $LogLevel
    }
}

# Synopsis: Build .NET solution packages
task BuildSolutionPackages -If {!$SkipSolutionPackages -and $SolutionToBuild} Version,{
    exec { 
        dotnet pack $SolutionToBuild `
                    --configuration $Configuration `
                    --no-build `
                    --no-restore `
                    --output $PackagesDir `
                    /p:EndjinRepositoryUrl="$BuildRepositoryUri" `
                    /p:PackageVersion="$(($script:GitVersion).SemVer)" `
                    --verbosity $LogLevel
    }
}

# Synopsis: Run .NET solution tests
task RunTests -If {!$SkipTests -and $SolutionToBuild} {
    if ($script:IsAzureDevOps) {
        Write-Build Green "Configuring Azure Pipelines test logger"
        $DotNetTestLogger = "AzurePipelines"
    }
    elseif ($script:IsGitHubActions) {
        Write-Build Green "Configuring GitHub Actions test logger"
        $DotNetTestLogger = "GitHubActions"
    }

    exec { 
        dotnet test $SolutionToBuild `
                    --configuration $Configuration `
                    --no-build `
                    --no-restore `
                    /p:CollectCoverage="$EnableCoverage" `
                    /p:CoverletOutputFormat=cobertura `
                    /p:ExcludeByFile="$($ExcludeFilesFromCodeCoverage.Replace(",","%2C"))" `
                    --verbosity $LogLevel `
                    --logger $DotNetTestLogger `
                    --test-adapter-path $PSScriptRoot/../bin
    }
}

# Synopsis: Generate test report file
task GenerateTestReport -If {!$SkipTests -and !$SkipTestReport -and $SolutionToBuild} {
    Install-DotNetTool -Name "dotnet-reportgenerator-globaltool" -Version $ReportGeneratorToolVersion
    exec {
        reportgenerator "-reports:$SourcesDir/**/**/coverage.cobertura.xml" `
                        "-targetdir:$CoverageDir" `
                        "-reporttypes:$TestReportTypes"
    }
}

# Synopsis: Build publish packages for selected projects
task BuildProjectPublishPackages -If {!$SkipProjectPublishPackages -and $ProjectsToPublish} Version,{
    foreach ($project in $ProjectsToPublish) {
        Write-Build Green "Publishing Project: $project"
        exec { 
            dotnet publish $project `
                        --nologo `
                        --configuration $Configuration `
                        --no-build `
                        --no-restore `
                        /p:EndjinRepositoryUrl="$BuildRepositoryUri" `
                        /p:PackageVersion="$(($script:GitVersion).SemVer)" `
                        --verbosity $LogLevel
        }
    }
}

# Synopsis: Publish any built NuGet packages
task PublishSolutionPackages -If {!$SkipSolutionPackages -and $SolutionToBuild -and $NugetPackageNamesToPublishGlob} Version,{

    # Force the wildcard expression to be evaluated now that GitVersion has been run
    $evaluatedNugetPackagesToPublishGlob = Invoke-Expression "`"$($NugetPackageNamesToPublishGlob)$($NugetPackagesToPublishGlobSuffix)`""
    Write-Verbose "EvaluatedNugetPackagesToPublishGlob: $evaluatedNugetPackagesToPublishGlob"
    $nugetPackagesToPublish = Get-ChildItem -Path "$here/_packages" -Filter $evaluatedNugetPackagesToPublishGlob
    Write-Verbose "NugetPackagesToPublish: $nugetPackagesToPublish"

    # Derive the NuGet API key to use - this also makes it easier to mask later on
    # NOTE: Where NuGet auth has been setup beforehand (e.g. via a SOURCE), an API key still needs to be specified but it can be any value
    $nugetApiKey = $env:NUGET_API_KEY ? $env:NUGET_API_KEY : "no-key"

    # Setup the 'dotnet nuget push' command-line parameters that will be the same for each package
    $nugetPushArgs = @(
        "-s"
        $NugetPublishSource
        "-ss"
        $NugetPublishSymbolSource
        "--api-key"
        $nugetApiKey
    )

    if ($NugetPublishSkipDuplicates) {
        $nugetPushArgs += @(
            "--skip-duplicate"
        )
    }

    foreach ($nugetPackage in $nugetPackagesToPublish) {

        Write-Build Green "Publishing package: $nugetPackage"
        # Ensure any NuGet API key is masked in the debug logging
        Write-Verbose ("dotnet nuget push $nugetPackage $nugetPushArgs".Replace($nugetApiKey, "*****"))
        exec {
            & dotnet nuget push $nugetPackage $nugetPushArgs
        }
    }
}

# Synopsis: Build any .nuspec based NuGet Packages
task BuildNuSpecPackages -If {!$SkipNuspecPackages -and $SolutionToBuild -and $NuspecFilesToPackage} Version,{

    foreach ($nuspec in $NuSpecFilesToPackage) {

        # Assumes a convention that the .nuspec file is alongside the .csproj file with a matching name
        $nuspecFilePath = (Resolve-Path (Join-Path $here $nuspec)).Path
        $projectFilePath = $nuspecFilePath.Replace(".nuspec", ".csproj")

        Write-Build Green "Packaging NuSpec: $nuspecFilePath [Project=$projectFilePath]"

        $packArgs = @(
            "--nologo"
            $projectFilePath
            "--configuration"
            $Configuration
            "--no-build"
            "--no-restore"
            "--output"
            $PackagesDir
            # this property needs to be overridden as its default value should be 'false', to ensure that the project
            # is not built without using the .nuspec file
            "-p:IsPackable=true"
            "-p:NuspecFile=$nuspecFilePath"
            "-p:NuspecProperties=version=`"$(($script:GitVersion).SemVer)`""
            "--verbosity"
            $LogLevel
        )
        Write-Verbose "dotnet pack $packArgs"
        exec {
            & dotnet pack $packArgs
        }
    }
}