We can all agree that tracking the progress of a project enhances productivity and is an effective way to keep everyone involved of its progress. When it comes to managing your project in Azure DevOps (formerly VSTS) or GitHub, you have all of your artifacts in one place: code, CI/CD pipelines, releases, work items, and more. In cases where there’s a larger project with a larger team, the rate at which pull requests and work items are created, opened, and closed will increase significantly between each release. Imagine a large user base that wanted to stay updated on these changes and updates through release notes. They’ll want to know if that pesky bug that was introduced in the last version got fixed this time, or if that feature they’re excited about finally made it out of beta.
Release notes tend to map directly to items that a team is tracking internally; I’d expect a work item on a bug high severity to make it into the release documentation. However, putting together release notes can be quite a challenge and very time consuming. When it’s time to ship new software updates, someone must manually go back in time to the last release, gather the relevant information, and compile it into a document to share with users. How do we keep the release information current and accurate for end users?
It’d be nice to automate the process of extracting information from completed work items and merged pull requests to create a document that outlines changes in a new release. This was the inspiration of the Release Notes Generator. With Azure Functions and Azure Blob Storage, the generator creates a markdown file every time a new release is created in Azure DevOps. In this post, we’ll walk through how the generator works, and use a sample DevOps project as an example for the generator. If you’d like a GitHub version, see the GitHub release notes generator sister post.
Overview of an Azure DevOps Project’s Work Items
View of Rendered Markdown version of release notes in VS Code with Markdown All in One Extension
The generator is an Azure Function app; Functions allow you to only pay for the time your code is running, so I’m only paying for the time it takes my code that generates notes to execute. With an HTTP triggered function, a webhook is configured in Azure DevOps to send an HTTP request to the function to kick off the notes generation process. Webhook configuration simply requires you to copy the url of the function that you’d like to send the endpoint to. An added benefit of using Azure Functions is that you can get started locally on your machine using or the . You can create, debug, test, and deploy your function app all from the comfort of your own computer without even needing an Azure Subscription. You can test HTTP triggered functions locally with a tool like ngrok.
Local development of HTTP triggered function in Visual Studio
Out of all of Azure’s storage account offerings, blob storage is suited for serving and storing unstructured data objects like textual files, including the markdown representation of the release notes. The blob storage structure is similar to common file systems where objects, named blobs, are organized and stored in containers. This way, the release notes have a dedicated location inside a “releases” container. You can manage a storage account on your computer with the Azure Storage Explorer.
Release notes blobs in the releases container in Azure Storage Explorer
The release function uses the Azure Storage API to create a file and append text and links to a file. Interacting with blobs and blob containers through the API requires minimal setup; you just need the associated storage account connection string to get started.
Creating a new release file with Azure Storage API
Azure Functions are a quick and straightforward way to enhance your workflows with Azure DevOps webhooks. The release notes generator sample code is a good start if you’re interested in exploring the serverless possibilities that work for you. The sample includes instructions on how to run it in Visual Studio. Once you’ve got your own generator up and running, be sure to visit the docs and samples to see what else you can do.