This week I studied about how release notes can be handled by a team. On the first sight it looks like a lot of additional work but it shouldn't be.

Release notes should be considered a part of the DevOps process and every team member involved in the Sprint deliverables should contribute to the release notes, as who's better to explain a new feature / update / bug,  other than the person who worked on it. In addition this strengthens the sense of ownership on the deliverable.

Release notes can be published in a variety of channels such as a new wiki page on Azure DevOps, Slack or attaching the page to your build results. Also different versions can be created per audience.

Below I will explain an initial PoC on drafting up a release note document using a a DevOps Query which outputs the results on an html. eg my query looks like this

Current sprint done work items

1)  Create a Powershell script for gathering the work items associated with the release and also generate the html file that will be the output. The script below will query the project specified and output the results in an html file. Custom and default fields can be specified as well. Kudos to my colleague Dave for coming up with the script.

[string]$account,  # the name of your DevOps organization
[string]$username, # alternate credentials username
[string]$password, # password
[string]$project, #Project Queried
[string]$reportGuid, #id of ther query being output
[string]$apiVersion = "1.0",
[string]$fileName = ".\ReleaseNotes.html"
Write-Host "Starting generating release notes for " + $buildVersion

$basicAuth = ("{0}:{1}" -f $username,$password)
$basicAuth = [System.Text.Encoding]::UTF8.GetBytes($basicAuth)
$basicAuth = [System.Convert]::ToBase64String($basicAuth)
$headers = @{Authorization=("Basic {0}" -f $basicAuth)}

#=== Get the list of items in this release ===
$reportUrl = "https://" + $account + "" + $project + "/_apis/wit/wiql/" + $reportGuid + "?api-version=" + $apiVersion
Write-Host "Calling to get release items: " $reportUrl
$reportItems = Invoke-RestMethod -Uri $reportUrl -headers $headers -Method Get
$releaseNotes = "<html><title>" + $applicationName + " " + $buildVersion + "</title><body><h1>Release Notes for " + $applicationName + " " + $buildVersion + "</h1>"

#=== Add the details for each item ===
foreach($reportItem in $reportItems.workItems)
  #=== Get the work item details ===
  Write-Host " - Getting release item details: " $reportItem.Url
  $reportItemDetails = Invoke-RestMethod -Uri $reportItem.Url -headers $headers -Method Get
  #=== Add the work items details to the output ===
  $workItemUrl = "https://" + $account + "" + $project + "/_workitems#_a=edit&fullScreen=true&id=" + $reportItemDetails.Id
  $releaseNotes += "<p><a href='" + $workItemUrl + "'>" + $reportItemDetails.fields.'System.WorkItemType' + " " + $reportItemDetails.Id + "</a> " + $reportItemDetails.fields.'System.Title' +"<br/>"
  $releaseNotes += "<b>Description</b><br/>" + $reportItemDetails.fields.'System.Title' + "</p>"

$releaseNotes += "</body></html>"

#=== Write the release notes to the output file === 
Write-Host "Starting to write release notes to: " + $fileName
$releaseNotes | out-file $fileName
Write-Host "Finished writing release notes"

2) The above script includes parameters which will be passed during execution.In order to authenticate against Azure DevOps you can either use a generated PAT (Personal Access Token) or alternate credentials. The former provides more control regarding the permissions while the latter is not recommended for use. To generate a PAT click on your profile.

Values for $account, $project, $reportGuid can be extracted from the aforementioned query's URL.

New Personal Access Token
$account, $project and $reportGuid parameters
./ReleaseNotes.ps1 -account:<name>> -project:<project>> -username:Basic -password:<Personal Access Token> -reportGuid:<report guid> -buildVersion:$(Build.BuildNumber) -applicationName:slothycode -fileName:$(build.stagingDirectory)\ReleaseNotes$(Build.BuildNumber).html
Script execution after PAT has been generated

3) Edit the pipeline and add a new Powershell Task, the task can point to a .ps1 script inside the repository the pipeline is executed against or inline. Predefined variables as the Build Number are passed as well. Notice how the $filename parameter is using the $(build.stagingDirectory) to output the file. This is the directory which is published on the pipeline. Save and queue the pipeline

Should everything done right the output will be similar to

Pipeline Script execution
Release Notes published to the artifact
HTML output

Thanks for reading :)