In this blog post, I’ll demonstrate how to create an Azure DevOps YAML pipeline that automatically generates a new wiki page for each production release that lists the solved work items since the last release.
But first let’s take a look at the why. Why would you want to have automatically generated release notes if you already have an overview of work items per sprint / iteration? Usually because releases and deployments to production environment may do not always take place after each sprint but sometimes after several sprints. Furthermore a consistent structure is guaranteed.
Preconditions and assumptions
Next, be aware of the following preconditions and assumptions.
- The Azure DevOps project is of type
Agileor of a type that extends typeAgile Boards,ReposandPipelinesare enabled on the Azure DevOps project- Git is used as version control system
- Work items (user stories and/or tasks) are linked in pull requests
- A project wiki (not a code wiki!) is already initialized on Azure DevOps project
- The user that sets up and configures the automated release notes generation is in role
Project Administrator
Generate Release Notes (Crossplatform) extension
The release notes file which will be added as a sub page to the Azure DevOps project wiki, is created using the Generate Release Notes (Crossplatform) Azure DevOps extension from Visual Studio Marketplace.
A big thank you at this point to Richard Fennell, the author of the extension!
Implement release notes YAML pipeline
And now let’s dig into the effective solution – the Azure DevOps YAML pipeline itself which will be triggered on every commit to branch main / master as illustrated here.

The release notes pipeline presented in this blog post consists of the following three parts.
- pipeline file
- job file(s)
- template file
First, create a new YAML pipeline file in the git repository (i.e. deploy\pipelines\release-notes-pipeline.yml).
name: $(Date:yyyyMMdd)$(Rev:.r) # defines the format of the build number
trigger:
branches:
include:
- main # trigger on commits to branch 'main'
variables:
- name: "isMainBranch"
value: $[eq(variables['Build.SourceBranch'], 'refs/heads/main')]
pool:
vmImage: "windows-latest"
stages:
- stage: Prod
displayName: "Release Notes and git tag for stage Production"
condition: eq(variables.isMainBranch, true) # ensure conditional execution of stage
jobs:
- template: jobs-generate-release-notes.yml
- template: jobs-create-git-tag.yml
Next, create the jobs file which is responsible for generating the release notes in the git repository.
deploy\pipelines\jobs-generate-release-notes.yml
jobs:
- job: GenerateReleaseNotes
displayName: "Generate Release Notes"
steps:
- task: XplatGenerateReleaseNotes@4 # version 4 is the latest one
inputs:
outputfile: "$(Build.ArtifactStagingDirectory)/releasenotes.md"
templateLocation: "File" # File means the template is loaded from the path specified under 'templatefile'
templatefile: "deploy/pipelines/release-notes-template.md"
checkStage: true # generate release notes since last successful release
stopOnRedeploy: true
dumpPayloadToConsole: false
dumpPayloadToFile: false
replaceFile: True
getParentsAndChildren: True # get parents and children of linked work items which will be accessible in the template
getAllParents: true # get all parents of linked work items which will be accessible in the template
getIndirectPullRequests: False
stopOnError: False
emptySetText: "No items found" # text to be returned if no work items found
- task: PublishBuildArtifacts@1
inputs:
PathtoPublish: "$(Build.ArtifactStagingDirectory)/releasenotes.md" # path to publish release notes to
ArtifactName: "release-notes"
publishLocation: "Container"
- bash: az devops configure --defaults organization=$(System.TeamFoundationCollectionUri) project=$(System.TeamProject) --use-git-aliases true
displayName: "Set default Azure DevOps organization and project"
- bash: az devops wiki page create --path 'Release Notes/$(Build.BuildNumber)' --wiki 'BFU.wiki' --file-path '$(Build.ArtifactStagingDirectory)/releasenotes.md'
displayName: "Create wiki page for release notes"
env:
AZURE_DEVOPS_EXT_PAT: $(System.AccessToken)
For having a consistent git history, a git tag gets created in the following jobs file.
NOTE
In general I prefer to version releases according to semantic versioning (SemVer). However, in this example I used the current date and the revision number for simplicity.
deploy\pipelines\jobs-create-git-tag.yml
jobs:
- job: CreateGitTag
displayName: "Create git tag"
steps:
- checkout: self
persistCredentials: true
clean: true
- script: |
git config --global user.name "Azure DevOps"
git config --global user.email "AZ_DEVOPS_ORG_NAME@YOURDOMAIN"
git tag -a $(Build.BuildNumber) -m $(Build.BuildNumber)
git push origin $(Build.BuildNumber)
Last but not least, add a handlebars template (file of type markdown) to the repository that defines the output.
deploy\pipelines\release-notes-template.md
# Release Notes
**Year:** {{year}}
**Stage:** {{currentStage.identifier}}
**Date & Time:** {{buildDetails.startTime}}
**Version:** {{buildDetails.buildNumber}}
## Features
{{#if this.relatedWorkItems}}
{{#forEach this.relatedWorkItems}}
{{#if (eq this.fields.[System.WorkItemType] 'User Story')}}
- #{{this.id}}
{{/if}}
{{/forEach}}
{{else}}
None
{{/if}}
## Bugfixes
{{#if this.relatedWorkItems}}
{{#forEach this.relatedWorkItems}}
{{#if (eq this.fields.[System.WorkItemType] 'Bug')}}
- #{{this.id}}
{{/if}}
{{/forEach}}
{{else}}
None
{{/if}}
Useful handlebars helpers can be found here.
Import release notes pipeline in Azure DevOps
After the before mentioned files got committed and pushed to the repository, the pipeline needs to be imported in Azure DevOps.
- Open the Azure DevOps project in a browser
- Navigate to
Pipelines - Click
New Pipelinebutton (top right) - Select
Azure Repos Git
- Select the repository that contains the pipeline (YAML) files
- In configure step select
Existing Azure Pipelines YAML file
Note: depending on the content of your repo you may have to click onShow morebutton to see the option
- Select the branch that contains the YAML files (i.e.
develop) - The choose the release notes pipeline file as
Path - Click
Continue - Click on the down arrow right to the
Runbutton and then clickSave - [OPTIONAL] Click the three dots on the top right corner and then click
Rename/moveto rename the pipeline
Authorize build service
To make the release notes pipeline work, the following permissions have to be granted to the build service.
- Navigate to the project wiki
- Click on the three dots
- Select
Wiki security
- Select the project specific build service
- Set
ContributetoAllow
- Open
Project settings(bottom left) - Navigate to
Repositories - Select the repository that contains the YAML pipeline
- Switch to tab
Security - Select the project specific build service
- Ensure
Contributeis set toAllowfor the project specific build service
That’s it, the release notes pipeline is now ready and will run on the next commit to main branch.
Local Testing
To speed up and especially to simplify development of the pipeline task and its templates, there is a tool for local testing provided in the repository of the extension.
It’s pretty straight forward to set up local testing.
- Clone the GitHub repository of the Az DevOps extension
- Navigate to the cloned repository (
~\AzurePipelines\Extensions\XplatGenerateReleaseNotes\V3\testconsole) - Create a handlebars template
- Create/adjust settings file
- Create a Personal Access Token (PAT) in Azure DevOps
- Run the following command
GenerateReleaseNotesConsoleTester.js --filename build-settings.json --pat AZ_DEVOPS_PAT_HERE
For debugging and troubleshooting purposes, you can dump the whole payload/data to the output file by setting "dumpPayloadToFile": "true" in build-settings.json and by adding {{json propertyToDump}} to your handlebars template.
UPDATE 02.07.2024
If your pipeline run fails with the following error message, check if Protect access to repositories in YAML pipelines setting is enabled (see Project settings > Pipelines > Settings).

ERROR: Repository associated with wiki ID 'WIKI_ID' does not exist or you do not have permissions for the operation you are attempting.
##[error]Bash exited with code '1'.
Either disable the setting, if feasible or add resources and uses to the pipeline as stated here.

Leave a comment