tasks/dotnet.tasks.ps1
# Control flags $CleanBuild = $false $EnableCoverage = $true $SkipTest = $false $SkipTestReport = $false $SkipSolutionPackages = $false $SkipNuspecPackages = $false $SkipProjectPublishPackages = $false # Options $SolutionToBuild = $false $ProjectsToPublish = @() $NuSpecFilesToPackage = @() $SkipSolutionPackages = $false $SkipProjectPublishPackages = $false $SkipNuspecPackages = $false $FoldersToClean = @("bin", "obj", "TestResults", "_codeCoverage", "_packages") $ReportGeneratorToolVersion = "4.8.3" $TestReportTypes = "Cobertura" # Logging Options $DotNetTestLogger = "console;verbosity=$LogLevel" $DotNetFileLoggerVerbosity = "detailed" $DotNetCompileLogFile = "dotnet-build.log" $DotNetCompileFileLoggerProps = "/flp:verbosity=$DotNetFileLoggerVerbosity;logfile=$DotNetCompileLogFile" $DotNetTestLogFile = "dotnet-test.log" $DotNetTestFileLoggerProps = "/flp:verbosity=$DotNetFileLoggerVerbosity;logfile=$DotNetTestLogFile" $DotNetPackageLogFile = "dotnet-package.log" $DotNetPackageFileLoggerProps = "/flp:verbosity=$DotNetFileLoggerVerbosity;logfile=$DotNetPackageLogFile" $DotNetPackageNuSpecLogFile = "dotnet-pacakge-nuspec.log" $DotNetPackageNuSpecFileLoggerProps = "/flp:verbosity=$DotNetFileLoggerVerbosity;logfile=$DotNetPackageNuSpecLogFile;append" $DotNetPublishLogFile = "dotnet-publish.log" $DotNetPublishFileLoggerProps = "/flp:verbosity=$DotNetFileLoggerVerbosity;logfile=$DotNetPublishLogFile;append" # 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,RestorePackages,{ exec { try { dotnet build $SolutionToBuild ` --no-restore ` --configuration $Configuration ` /p:Version="$(($script:GitVersion).SemVer)" ` /p:EndjinRepositoryUrl="$BuildRepositoryUri" ` --verbosity $LogLevel ` $($DotNetCompileFileLoggerProps ? $DotNetCompileFileLoggerProps : "/fl") ` $DotNetCompileFileLoggerProps } finally { if ((Test-Path $DotNetCompileLogFile) -and $IsAzureDevOps) { Write-Host "##vso[artifact.upload artifactname=logs]$(Get-Item $DotNetCompileLogFile)" } } } } # 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 { try { dotnet pack $SolutionToBuild ` --configuration $Configuration ` --no-build ` --no-restore ` --output $PackagesDir ` /p:EndjinRepositoryUrl="$BuildRepositoryUri" ` /p:PackageVersion="$(($script:GitVersion).SemVer)" ` --verbosity $LogLevel ` $($DotNetPackageFileLoggerProps ? $DotNetPackageFileLoggerProps : "/fl") ` $DotNetPackageFileLoggerProps } finally { if ((Test-Path $DotNetPackageLogFile) -and $IsAzureDevOps) { Write-Host "##vso[artifact.upload artifactname=logs]$(Get-Item $DotNetPackageLogFile)" } } } } # Synopsis: Run .NET solution tests task RunTests -If {!$SkipTest -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" } try { 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 ` $($DotNetTestFileLoggerProps ? $DotNetTestFileLoggerProps : "/fl") ` $DotNetTestFileLoggerProps ` } } finally { if ((Test-Path $DotNetTestLogFile) -and $IsAzureDevOps) { Write-Host "##vso[artifact.upload artifactname=logs]$(Get-Item $DotNetTestLogFile)" } } } # Synopsis: Generate test report file task GenerateTestReport -If {!$SkipTest -and !$SkipTestReport -and $SolutionToBuild} { Install-DotNetTool -Name "dotnet-reportgenerator-globaltool" -Version $ReportGeneratorToolVersion $testReportGlob = "$SourcesDir/**/**/coverage.cobertura.xml" if (!(Get-ChildItem -Path $SourceDir -Filter "coverage.cobertura.xml" -Recurse)) { Write-Warning "No code coverage reports found for the file pattern '$testReportGlob' - skipping test report" } else { exec { reportgenerator "-reports:$testReportGlob" ` "-targetdir:$CoverageDir" ` "-reporttypes:$TestReportTypes" } } } # Synopsis: Build publish packages for selected projects task BuildProjectPublishPackages -If {!$SkipProjectPublishPackages -and $ProjectsToPublish} Version,{ # Remove the existing log, since we append to it for each project being published Get-Item $DotNetPublishLogFile -ErrorAction Ignore | Remove-Item -Force try { 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 ` $($DotNetPublishFileLoggerProps ? $DotNetPublishFileLoggerProps : "/fl") ` $DotNetPublishFileLoggerProps } } } finally { if ((Test-Path $DotNetPublishLogFile) -and $IsAzureDevOps) { Write-Host "##vso[artifact.upload artifactname=logs]$(Get-Item $DotNetPublishLogFile)" } } } # 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" ) } # Remove the existing log, since we append to it for each project being packaged via a NuSpec file Get-Item $DotNetPackageNuSpecLogFile -ErrorAction Ignore | Remove-Item -Force try { 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 } } } finally { if ((Test-Path $DotNetPackageNuSpecLogFile) -and $IsAzureDevOps) { Write-Host "##vso[artifact.upload artifactname=logs]$(Get-Item $DotNetPackageNuSpecLogFile)" } } } # 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 $($DotNetPackageNuSpecFileLoggerProps ? $DotNetPackageNuSpecFileLoggerProps : "/fl") $DotNetPackageNuSpecFileLoggerProps ) Write-Verbose "dotnet pack $packArgs" exec { & dotnet pack $packArgs } } } |