Skip to content

Just My Blog

Just great and interesting articles and more!

  • Home
  • Tips & Tricks
  • Toggle search form

Create release notes via branch comparison (Part 1)

Posted on 10 Nov 202318 Jun 2024 By Frans van Es

Release notes are a good method to inform your users about the additions, bug fixes and changes which have been made to the software since the latest release. You can distribute the release notes before the upcoming release (a.k.a. “Pre-release notes”), or after the release has been done. These notes can be made manually or scripted.

Let’s start

In this article the release branch strategy requires you to create a monthly release branch for every production deployment. For instance, a monthly release could be named “Release-202401”. You are free to use any other cadence, but you will need to make some small modifications.

To create release notes for a new release, you need to do a comparison between this release and the previous release in order to get all commits in between. Within Azure DevOps this can be done within the browser, or even better with a PowerShell script. Whilst collecting the commits, it is necessary to get all linked work items, because those contain the actual information you’ll need for the release notes.

Setting up

Prerequisite: a Private Access Token (PAT) to call the Azure DevOps Services REST API. Read here

Variables

Start off with creating important variables which we need to call the API.

# Authentication for ADO REST API
$privateAccessToken = "XXXX"
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f "",$privateAccessToken)))
$headers = @{Authorization=("Basic {0}" -f $base64AuthInfo)}

# ADO Project settings
$organisation = "myorganisation"
$serverUri = "https://dev.azure.com/$organisation"
$project = "myproject"

Get repository IDs

Next we need to get the IDs of the two repositories we want to compare. This piece of script will list all repositories within the project, i.e. ID and name. The ID is required for the next section. You will only have to do this once for every repository you want to do a comparison.

# Repository names, for now fixed parameters
$releasePrevious = "Release-202311"
$releaseCurrent = "Release-202312"

# Get repositories within project
$uri1 = "$serverUri/$project/_apis/git/repositories" + "?api-version=7.1-preview.1"
$repos = Invoke-RestMethod -Uri $uri1 -Method Get -ContentType "application/json" -Headers $headers

# List found repositories
foreach($repo in $repos.value) {
    Write-Host $repo.id $repo.name
}

Collect the commits

Next we will collect all the commits which were done between both release branches.

# This must contain ID of repository found in previous section
$repositoryId = "XXX"

# Get commits between the 2 release branches including work items
$uri2 = "$serverUri/$project/_apis/git/repositories/" + $repositoryId + "/commits" + "?searchCriteria.itemVersion.version=$releasePrevious&searchCriteria.compareVersion.version=$releaseCurrent&searchCriteria.itemVersion.versionType=branch&searchCriteria.compareVersion.versionType=branch&searchCriteria.includeWorkItems=true&api-version=7.1-preview.1"

$results2 = Invoke-RestMethod -Uri $uri2 -Method Get -ContentType "application/json" -Headers $headers

Iterate the commits

Next a big piece of code is needed to iterate through all commits found, at the end the arrays $workitems and $commits will have all the info we will need.

Write-Host "Comparing branches`n" -ForegroundColor Green

# List found commits
foreach($result in $results2.value) {

    Write-Host $result.commitId " | Committed by: " $result.committer.name "| Committed on: " ([DateTime]$result.committer.date).ToLocalTime()
    Write-Host "Title: " $result.comment
    
    $commitWorkitemList = ""
    $status = ""
    $tags = ""
    $relbranch = ""
    
    # If a work item(s) attached to commit, collect the work items
    if($result.workItems -ne $null) {
        foreach($wit in $result.workItems) {
            $allWorkitems += "$($wit.id)"
            $commitWorkitemList += "$($wit.id),"
        }

        # Remove extraneous comma for later usage ..
        $commitWorkitemList = $commitWorkitemList.Substring(0,$commitWorkitemList.Length-1)
        # .. and convert to array for processing
        $commitWorkitems = $commitWorkitemList.Split(',')

        # Get information from commit's workitem(s)
        foreach($commitWorkitem in $commitWorkitems) {

            # Specify which fields to retrieve in request
            $uri4 = "$serverUri/$project/_apis/wit/workitems/" + $commitWorkitem + "?fields=System.WorkItemType,System.Title,System.State,System.AssignedTo,System.Tags,Custom.Releasebranch&api-version=7.1-preview.3"
            $results4 = Invoke-RestMethod -Uri $uri4 -Method Get -ContentType "application/json" -Headers $headers
            $status += $results4.fields.'System.State'+','
            $tags += $results4.fields.'System.Tags'+'#'
            $relbranch = $results4.fields.'Custom.Releasebranch'
        }
    }
    else {
        Write-Host "No workitem attached!" -ForegroundColor Yellow
    }

    # Remove extraneous character
    $status = if($status -ne "") { $status.Substring(0,$status.Length-1) }
    $tags = if($tags -ne "") { $tags.Substring(0,$tags.Length-1) }
    
    # Collect info of all commits
    $commits += [pscustomobject]@{Repo=$repository.Name; Title=$result.comment; Author=$result.committer.name; Date=([DateTime]$result.committer.date).ToLocalTime(); Items=$commitWorkitemList; Status=$status; Branch=$relbranch; Tags=$tags}
}

Iterate the work items

Now that all the work items attached to the commits have been collected, the work items need to be enriched as well.

# Filter out duplicate work items
$workitems = $workitems | Select -Unique

# Loop through work items and collect info (yes, again)
$workitems2 =@()
foreach($workitem in $workitems) {
    # Get info for this work item
    $uri4 = "$serverUri/$project/_apis/wit/workitems/" + $workitem + "?fields=System.WorkItemType,System.Title,System.State,System.AssignedTo,System.Tags,Custom.Releasebranch&api-version=7.1-preview.3"
    $results4 = Invoke-RestMethod -Uri $uri4 -Method Get -ContentType "application/json" -Headers $headers
    # Collect info of all work items
    $workitems2 += [pscustomobject]@{Workitem=$results4.id; Title=$results4.fields.'System.Title'; Status=$results4.fields.'System.State'; Assigned=$results4.fields.'System.AssignedTo'.displayName; Branch=$results4.fields.'Custom.Releasebranch'; Tags=$results4.fields.'System.Tags'}
}

Showing the results

After all the hard work, it’s time to show off the results. The work items overview is the source for the release notes. In this example it is only showing the work items which are not yet closed, but you can expand the filter to e.g. “Closed, Active” or what you require.

# Showing all work items which are not yet Closed
$workitems2 | sort -Property WorkItem | where -Property Status -notin "Closed" | FT -AutoSize

# Showing all commits which have their work item(s) not yet Closed
$commits | where -Property Status -notin "Closed" | FT -AutoSize

Conclusion

If you’re a developer you like to automate as much as possible and focus on the interesting and challenging stuff, not doing a lot of administration like release notes. With the Azure DevOps Services REST API you can retrieve a lot of information to use to your advantage.

In Part 2, I will continue with creating the release notes …

Azure DevOps Tags:DevOps

Post navigation

Previous Post: Cloud flow monitoring in Application Insights
Next Post: Create release notes via branch comparison (Part 2)

Categories

  • Azure (2)
  • Azure DevOps (2)
  • Dynamics CRM (4)

Tag cloud

Application Insights (1) Cloud flows (2) DevOps (3) FetchXML (2) Monitoring (2) Reports (1) SSRS (1)

Dynamics CRM Newsfeed

  • Smarter callbacks with availability-aware scheduling CCaaS APIs
  • AI in sales: Applying historical lessons to modern challenges 
  • Get started with agents for finance: Learnings from 2025 Gartner® CFO & Finance Executive Conference
  • The power of proactive engagement in Dynamics 365 Contact Center
  • Seamless scheduling across time zones in Dynamics 365 Field Service

Copyright © 2024 Just My Blog -

Powered by PressBook WordPress theme