Bump the nuget group across 1 directory with 7 updates #1887
Workflow file for this run
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: Build, test and package | |
on: | |
workflow_dispatch: | |
push: | |
branches: [ main ] | |
paths-ignore: | |
- "**.md" | |
pull_request: | |
branches: [ main ] | |
schedule: | |
- cron: '0 0 * * 0' # Once a week: "At 00:00 on Sunday." | |
defaults: | |
run: | |
shell: pwsh | |
jobs: | |
main: | |
name: Build, test and package | |
permissions: | |
contents: read | |
strategy: | |
fail-fast: false # don't fail if one of the matrix jobs fails. Example: try to run the windows matrix even if the ubuntu matrix fails. | |
matrix: | |
os: [ubuntu-latest, windows-latest] | |
runs-on: ${{ matrix.os }} | |
env: | |
SLN_FILEPATH: ${{github.workspace}}/DotNet.Sdk.Extensions.sln | |
EXTENSIONS_BIN_FOLDER : ${{ github.workspace }}/src/DotNet.Sdk.Extensions/bin/Release | |
TESTING_EXTENSIONS_BIN_FOLDER : ${{ github.workspace }}/src/DotNet.Sdk.Extensions.Testing/bin/Release | |
TEST_RESULTS_ARTIFACT_NAME: test-results-${{ matrix.os }} | |
CODE_COVERAGE_ARTIFACT_NAME: code-coverage-report-${{ matrix.os }} | |
NUGET_ARTIFACT_NAME : nuget-packages-and-symbols | |
steps: | |
- name: Dump github context for debug purposes | |
env: | |
GITHUB_CONTEXT: ${{ toJSON(github) }} | |
run: $env:GITHUB_CONTEXT | |
- name: Checkout repository | |
uses: actions/checkout@v4 | |
- name: Setup .NET | |
uses: actions/setup-dotnet@v4 | |
with: | |
dotnet-version: | | |
6.0.x | |
7.0.x | |
global-json-file: global.json | |
- name: Cache/Restore NuGets | |
uses: actions/cache@v4 | |
with: | |
path: | |
~/.nuget/packages | |
key: ${{ runner.os }}-nuget | |
restore-keys: | | |
${{ runner.os }}-nuget- | |
- name: Install reportgenerator dotnet tool | |
run: dotnet tool install --global dotnet-reportgenerator-globaltool | |
- name: Restore dependencies | |
run: dotnet restore ${{ env.SLN_FILEPATH }} -warnaserror | |
- name: Build | |
run: dotnet build ${{ env.SLN_FILEPATH }} -c Release -warnaserror --no-restore --no-incremental | |
- name: Test and code coverage | |
id: dotnet-test | |
env: | |
# default is 90 seconds. Increasing this because sometimes running on Windows I get: | |
# "vstest.console process failed to connect to testhost process after 90 seconds. This may occur due to machine slowness, | |
# please set environment variable VSTEST_CONNECTION_TIMEOUT to increase timeout." | |
# Don't know why this occurs though | |
VSTEST_CONNECTION_TIMEOUT: 270 | |
run: | | |
$os = $PSVersionTable.OS | |
$testResultsDir = $(Join-Path -Path (Get-Location) -ChildPath "tests/${{ matrix.os }}/test-results") | |
$testCoverageDir = $(Join-Path -Path (Get-Location) -ChildPath "tests/${{ matrix.os }}/coverage-results/") | |
$testCoverageFile = $(Join-Path -Path $testCoverageDir -ChildPath "coverage.net8.0.opencover.xml") | |
Write-Output "test-results-dir=$testResultsDir" >> $env:GITHUB_OUTPUT | |
Write-Output "test-coverage-dir=$testCoverageDir" >> $env:GITHUB_OUTPUT | |
Write-Output "test-coverage-file=$testCoverageFile" >> $env:GITHUB_OUTPUT | |
Write-Output "::group::Test output directories." | |
Write-Output "test-results-dir is set to $testResultsDir" | |
Write-Output "test-coverage-dir is set to $testCoverageDir" | |
Write-Output "test-coverage-file is set to $testCoverageFile" | |
Write-Output "::endgroup::" | |
$downloadArtifactMessage = "You can inspect the test results by downloading the workflow artifact named: ${{ env.TEST_RESULTS_ARTIFACT_NAME }}." | |
$frameworkMonikers = @('net6.0','net7.0','net8.0') | |
foreach($frameworkMoniker in $frameworkMonikers) | |
{ | |
Write-Output "::group::Running dotnet test for target framework $frameworkMoniker." | |
$testCoverageMergeFile = $(Join-Path -Path $testCoverageDir -ChildPath "coverage.$frameworkMoniker.json") | |
dotnet test ${{ env.SLN_FILEPATH }} ` | |
-c Release ` | |
--no-build ` | |
--framework $frameworkMoniker ` | |
--logger "trx;LogFilePrefix=framework" ` | |
--logger GitHubActions ` | |
--logger "liquid.custom;Template=${{github.workspace}}/tests/liquid-test-logger-template.md;runnerOS=${{ matrix.os }};os=$os;LogFilePrefix=framework" ` | |
--results-directory "$testResultsDir" ` | |
/p:CollectCoverage=true ` | |
/p:CoverletOutput="$testCoverageDir" ` | |
/p:MergeWith="$testCoverageMergeFile" ` | |
/p:CoverletOutputFormat="json%2copencover" ` | |
-m:1 ` | |
-- RunConfiguration.TreatNoTestsAsError=true # this must be the last parameter and there must be a space between the -- and the RunConfiguration.TreatNoTestsAsError. See https://github.com/microsoft/vstest/pull/2610#issuecomment-942113882 | |
Write-Output "::endgroup::" | |
if($LASTEXITCODE -ne 0) | |
{ | |
Write-Output "::error title=Tests (${{ matrix.os }})::Tests failed on ${{ matrix.os }}. $downloadArtifactMessage" | |
Exit 1 | |
} | |
} | |
Write-Output "::notice title=Tests (${{ matrix.os }})::Tests passed on ${{ matrix.os }}. $downloadArtifactMessage" | |
- name: Set run even if tests fail conditions | |
id: even-if-tests-fail | |
if: always() | |
run: | | |
# Some of the steps below provide feedback on the test run and I want to run them even if | |
# some of the previous steps failed. For that I need: | |
# - the 'always()' condition: without it the step only runs if the job is successful, it's like the 'if' condition on any step always has a hidden '&& success()' clause. | |
# - the '(steps.<step-id>.conclusion == 'success' || steps.<step-id>.conclusion == 'failure')' condition: to run the steps only if the <step-id> step has ran, regardless | |
# if it failed or not. It won't run if the <step-id> step has been skipped or cancelled. | |
# | |
# As such, the output from this step is meant to be used on the 'if' property of steps as follows: | |
# if: steps.even-if-tests-fail.outputs.condition == 'true' && always() | |
$condition = '${{ (steps.dotnet-test.conclusion == 'success' || steps.dotnet-test.conclusion == 'failure') }}' | |
Write-Output "condition=$condition" >> $env:GITHUB_OUTPUT | |
Write-Output "condition is set to $condition" | |
- name: Upload opencover test coverage file to artifacts | |
if: matrix.os == 'ubuntu-latest' | |
uses: actions/upload-artifact@v4 | |
with: | |
name: opencover-test-coverage-file | |
path: ${{ steps.dotnet-test.outputs.test-coverage-file }} | |
- name: Generate code coverage report | |
id: code-coverage-report-generator | |
if: steps.even-if-tests-fail.outputs.condition == 'true' && always() | |
run: | | |
$testCoverageReportDir = $(Join-Path -Path ${{ steps.dotnet-test.outputs.test-coverage-dir }} -ChildPath "report") | |
Write-Output "test-coverage-report-dir=$testCoverageReportDir" >> $env:GITHUB_OUTPUT | |
reportgenerator ` | |
"-reports:${{ steps.dotnet-test.outputs.test-coverage-file }}" ` | |
"-targetdir:$testCoverageReportDir" ` | |
-reportTypes:htmlInline | |
- name: Upload code coverage report to artifacts | |
if: steps.even-if-tests-fail.outputs.condition == 'true' && always() | |
uses: actions/upload-artifact@v4 | |
with: | |
name: ${{ env.CODE_COVERAGE_ARTIFACT_NAME }} | |
path: ${{ steps.code-coverage-report-generator.outputs.test-coverage-report-dir }} | |
- name: Rename test results files | |
if: steps.even-if-tests-fail.outputs.condition == 'true' && always() | |
run: | | |
# I have another workflow that will get all test result markdown files and add them as comments to a Pull Request. | |
# If I don't rename the test results file there is an edge case that will cause the test results comments on the Pull Request to be incorrect. | |
# | |
# The edge case is when this job is re-run. When the job is re-run, it will upload the test results artifact multiple times. | |
# The artifacts work as a share so if the files have the same name they get overwritten, if not they get added to the existing artifact. | |
# By default, all the test results files will be unique due to a timestamp being part of their name so when re-running the job I will get the test results | |
# from ALL runs in the artifact with name env.TEST_RESULTS_ARTIFACT_NAME. | |
# Then when the workflow to add the test results to the Pull Request runs it will get ALL the markdown files in the env.TEST_RESULTS_ARTIFACT_NAME and | |
# add them as a Pull Request. The end result being I will have more test results showing on the PR than intended. Only the test results from the last run should be displayed | |
# on the Pull Request. | |
# | |
# By running this step, I make sure the test result filenames are deterministic so that on job reruns I will only get the latest test results on the the artifact with name env.TEST_RESULTS_ARTIFACT_NAME. | |
# Example: | |
# As of writing this I have 2 test projects and after running tests I will have one markdown file and one trx file per test project and framework. Let's consider the files for .net7.0: | |
# - one md and trx file for DotNet.Sdk.Extensions.Tests.csproj and another md and trx file for DotNet.Sdk.Extensions.Testing.Tests.csproj. Which for this example let's assume would be named: | |
# - framework_net7.0_20230226152259.md | |
# - framework_net7.0_20230226152312.md | |
# - framework_net7.0_20230226152259.trx | |
# - framework_net7.0_20230226152312.trx | |
# | |
# The filenames contain only the framework and a timestamp. Unfortunately the assembly name is not part of the filename so it's not possible to know which test project the file belongs without viewing its content. | |
# After renaming we would have the following filenames: | |
# - framework_net7.0_0.md | |
# - framework_net7.0_1.md | |
# - framework_net7.0_0.trx | |
# - framework_net7.0_1.trx | |
# | |
# This way when re-running the job the test result filenames are deterministic and will always override existing files in the artifact with name env.TEST_RESULTS_ARTIFACT_NAME. | |
# This does mean that the artifact with name env.TEST_RESULTS_ARTIFACT_NAME will always only contain the test results from the latest run. | |
# | |
$testResultsDir = '${{ steps.dotnet-test.outputs.test-results-dir }}' | |
# rename test result files for all frameworks | |
$frameworkFilters = @('framework_net6.0*','framework_net7.0*','framework_net8.0*') | |
foreach($frameworkFilter in $frameworkFilters) | |
{ | |
# for each framework group the files by extension. There will be .md and .trx file groups | |
$frameworkFiles = Get-ChildItem -Path $testResultsDir -Recurse -Filter $frameworkFilter | Group-Object -Property Extension | |
foreach($extensionFilesGroup in $frameworkFiles) | |
{ | |
# rename all the files in each group by adding a deterministic suffix. Since the count of the files in each group does not change | |
# between workflow runs we can use that as a deterministic suffix. | |
for ($i = 0; $i -lt $extensionFilesGroup.Count; $i++) | |
{ | |
$file = $extensionFilesGroup.Group[$i] | |
$extension = $file.Extension | |
$frameworkPrefix = $frameworkFilter -replace '\*', '' | |
$newFilename = "$frameworkPrefix`_$i$extension" | |
Write-Output "Renaming $file to $newFilename" | |
Rename-Item -Path $file -NewName "$newFilename" | |
} | |
} | |
} | |
- name: Upload test results to artifacts | |
if: steps.even-if-tests-fail.outputs.condition == 'true' && always() | |
uses: actions/upload-artifact@v4 | |
with: | |
name: ${{ env.TEST_RESULTS_ARTIFACT_NAME }} | |
path: ${{ steps.dotnet-test.outputs.test-results-dir }} | |
- name: Package DotNet.Sdk.Extensions | |
if: matrix.os == 'ubuntu-latest' # this job is on a matrix run but I only want to build the NuGet once | |
run: dotnet pack src/DotNet.Sdk.Extensions/DotNet.Sdk.Extensions.csproj -c Release --no-build | |
- name: Package DotNet.Sdk.Extensions.Testing | |
if: matrix.os == 'ubuntu-latest' # this job is on a matrix run but I only want to build the NuGet once | |
run: dotnet pack src/DotNet.Sdk.Extensions.Testing/DotNet.Sdk.Extensions.Testing.csproj -c Release --no-build | |
- name: Upload NuGets and symbols to artifacts | |
id: upload-nuget-artifacts | |
uses: actions/upload-artifact@v4 | |
if: matrix.os == 'ubuntu-latest' # this job is on a matrix run but I only want to upload NuGets as artifacts once | |
with: | |
name: ${{ env.NUGET_ARTIFACT_NAME }} | |
path: | | |
${{ env.EXTENSIONS_BIN_FOLDER }}/*.nupkg | |
${{ env.EXTENSIONS_BIN_FOLDER }}/*.snupkg | |
${{ env.TESTING_EXTENSIONS_BIN_FOLDER }}/*.nupkg | |
${{ env.TESTING_EXTENSIONS_BIN_FOLDER }}/*.snupkg | |
- name: Log artifacts info | |
if: matrix.os == 'ubuntu-latest' # this job is on a matrix run but I only want to log this messages to the build summary once | |
run: | | |
Write-Output "::notice title=Code coverage report::You can download the code coverage report from the workflow artifact named: ${{ env.CODE_COVERAGE_ARTIFACT_NAME }}." | |
Write-Output "::notice title=NuGets::You can download the NuGet packages and symbols from the workflow artifact named: ${{ env.NUGET_ARTIFACT_NAME }}." |