Maintaining up-to-date dependencies can be a tedious task, often requiring significant concentration. When tackling such tasks, I aim to seamlessly integrate them into the regular workflow to make them more manageable. Considering this approach, it's evident that examining outdated NuGet packages during a pull request phase is a smart strategy!
We're going to set up a YAML pipeline that tracks our outdated dependencies using
dotnet-outdated
) within a pull request on Azure DevOps. This
pipeline will be triggered automatically when a pull request is opened.
While we'll be creating a pipeline for Azure DevOps, you can also draw inspiration from this blog post for platforms like GitHub or others.
Please note that dotnet-outdated
isn't compatible with .NET Framework projects. For more details about this tool,
refer to its GitHub repository.
YAML pipeline
The YAML pipeline is installing the dotnet-outdated
tool, creates an output to JSON file, read that file and create a
comment in the open pull request.
We start with the basics of a YAML pipeline. We need to set this pipeline a branch validation within Azure Devops, so the
trigger is going to be none. We are using powershell (pswh
) step for installing and executing dotnet-outdated
.
trigger: none
steps:
- pwsh: |
# ...
We need to install the dotnet-outdated
and let it analyze our solution. We give arguments with it to output the results
to a JSON file. If the analyzing is finished and there is no file found, there are no outdated dependencies so we can
exit the script.
trigger: none
steps:
- pwsh: |
$solutionName = "ChangeThis.sln"
# Install the tool
dotnet tool install dotnet-outdated-tool
# Analyzing solution and save output to a JSON file
dotnet outdated "$solutionName" --output "outdated-packages.json"
# No file? No outdated dependencies!
if (!(Test-Path "./outdated-packages.json"))
{
Write-Host "All dependencies are up to date!"
return 0;
}
#...
If there are outdated packages, we are gonna read the output file, remove all duplicates and create a markdown table for it.
#...
# Read the output file to a powershell structure which we can use to create a markdown table
$output = Get-Content -Path "./outdated-packages.json" | ConvertFrom-Json
$outdated = @();
foreach ($project in $output.Projects) {
foreach ($framework in $project.TargetFrameworks) {
foreach ($dependency in $framework.Dependencies) {
$outdated += $dependency
}
}
}
# Remove duplicates by Name (this is a trade-off to keep things simple)
$outdated = $outdated | Sort-Object -Property Name -Unique
# Create markdown table for the pull request comment
$markdownTable = "| Name | Resolved Version | Latest Version | Upgrade Severity |`n"
$markdownTable += "| --- | --- | --- | --- |`n"
foreach ($dependency in $outdated) {
$markdownTable += "| $($dependency.Name) | $($dependency.ResolvedVersion) | $($dependency.LatestVersion) | $($dependency.UpgradeSeverity) |`n"
}
#...
After creating the markdown table we can create a pull request comment by using the Azure Devops API. We are using predefined variables for the organization URL, project name, repository name and access token.
# ...
# Creating pull request comment
$body = @"
{
"comments": [
{
"parentCommentId": 0,
"content": "$markdownTable",
"commentType": 1
}
],
"status": 1
}
"@
Invoke-RestMethod `
-Uri "$(System.TeamFoundationCollectionUri)$(System.TeamProject)/_apis/git/repositories/$(Build.Repository.Name)/$(System.PullRequest.PullRequestId)/threads?api-version=5.1" `
-Method POST -Headers @{Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"} `
-Body $Body `
-ContentType "application/json; charset=utf-8"
displayName: Check outdated packages
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
For creating pull request comments, the Build Service user should have permission to contribute to pull requests. You can change those permissions in the security settings of the repository.
And that's it! That's the pipeline which creates a pull request comment when there are outdated dependencies in your solution.
If you don't know how to setup a pipeline for your pull request, you check check-out this blog post: Run the CI Pipeline during a Pull Request.
Complete YAML
trigger: none
steps:
- pwsh: |
$solutionName = "ChangeThis.sln"
# Install the tool
dotnet tool install dotnet-outdated-tool
# Analyzing solution and save output to a JSON file
dotnet outdated "$solutionName" --output "outdated-packages.json"
# No file? No outdated dependencies!
if (!(Test-Path "./outdated-packages.json"))
{
Write-Host "All dependencies are up to date!"
return 0;
}
# Read the output file to a powershell structure which we can use to create a markdown table
$output = Get-Content -Path "./outdated-packages.json" | ConvertFrom-Json
$outdated = @();
foreach ($project in $output.Projects) {
foreach ($framework in $project.TargetFrameworks) {
foreach ($dependency in $framework.Dependencies) {
$outdated += $dependency
}
}
}
# Remove duplicates by Name (this is a trade-off to keep things simple)
$outdated = $outdated | Sort-Object -Property Name -Unique
# Create markdown table for the pull request comment
$markdownTable = "| Name | Resolved Version | Latest Version | Upgrade Severity |`n"
$markdownTable += "| --- | --- | --- | --- |`n"
foreach ($dependency in $outdated) {
$markdownTable += "| $($dependency.Name) | $($dependency.ResolvedVersion) | $($dependency.LatestVersion) | $($dependency.UpgradeSeverity) |`n"
}
# Creating pull request comment
$body = @"
{
"comments": [
{
"parentCommentId": 0,
"content": "$markdownTable",
"commentType": 1
}
],
"status": 1
}
"@
Invoke-RestMethod `
-Uri "$(System.TeamFoundationCollectionUri)$(System.TeamProject)/_apis/git/repositories/$(Build.Repository.Name)/$(System.PullRequest.PullRequestId)/threads?api-version=5.1" `
-Method POST -Headers @{Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"} `
-Body $Body `
-ContentType "application/json; charset=utf-8"
displayName: Check outdated packages
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)