When I'm aboard a DevOps transformation, I have several goals when it comes to PROCESS and PRODUCTs.

UPDATED 2019.03.13 - Update tracked issues and update latest template.

As always, I frown at complexity and encourage the use of pull requests , which enforce a pre-merge build, unit testing, security scanning, and a candid review by a pair of humanoid eyes. It’s about continuously learning, adapting, improving, sharing knowledge, and raising the quality bar. Quality in, quality out!

My top goal, however, is keeping the pipelines simple.

My top goal!

Azure DevOps offers a variety of features that enable goals, such as artifact filters and gates. In a recent prototype I evaluated three new extensions, that are going to knock the socks off our pipelines and allow us to create a “wow” moment for our hard working system engineers.

GitVersion allows us to looks at our Git history during a build, work out the semantic version of the changes, and flow the version through the build and release pipeline. It makes simplifies the versioning of builds, releases, and makes it easy to pinpoint from which code base a release has emerged from.

The two other extensions have been developed by a fellow ALM | DevOps Ranger, Richard Fennel.

The cross-platform Generate Release Notes based on Release Comparison extension generates a release notes markdown file using the same API calls as the Azure DevOps Pipeline Release UI. It uses a template that allows you to generate professionally looking and detailed release notes.

We are using tags to identify work items that define the release overview and work items that describe the new features.

Here is the template I am using in my sandbox:

# RELEASENOTES

**Release Name** :  ${releaseDetails.releaseDefinition.name}
**Release Number** : ${releaseDetails.name}
**Release Completed** : ${releaseDetails.modifiedOn}
**Compared Release Number** : ${compareReleaseDetails.name}
**Build Number** - $(Build.BuildNumber) 
**Build Id** - $(Build.DefinitionId) 
**Build Source Branch** - $(Build.SourceBranchName) 
**Build Type** - $(Build.Type) 

### DESCRIPTION
@@WILOOP:RN-OVERVIEW@@
${widetail.fields['System.Description']}
@@WILOOP:RN-OVERVIEW@@

### FEATURES
@@WILOOP:RN-FEATURES@@
${widetail.fields['System.Description']}
@@WILOOP:RN-FEATURES@@

### Associated work items
@@WILOOP@@
* **${widetail.fields['System.WorkItemType']} #${widetail.id}** Assigned by: ${widetail.fields['System.AssignedTo']} - ${widetail.fields['System.Title']}
@@WILOOP@@

### Associated commits
@@CSLOOP@@
* **ID ${csdetail.id} ** ${csdetail.message}
@@CSLOOP@@

Here is a template example from our latest pipeline:

**SAMPLE TEMPLATE**

[[_TOC_]]

# Release Notes

|         | RELEASE | BUILD |
|---------|---------|-------|
| Definition Name | ${releaseDetails.releaseDefinition.name} | ${releaseDetails.artifacts[0].definitionReference.definition.name} |
| Definition ID | ${releaseDetails.releaseDefinition.id} | ${releaseDetails.artifacts[0].definitionReference.definition.id} |
| Current Name | ${releaseDetails.name} |  ${releaseDetails.artifacts[0].definitionReference.version.name} |
| URL | ${releaseDetails._links.web.href} | ${releaseDetails.artifacts[0].definitionReference.artifactSourceVersionUrl.id} |
| Completed | ${releaseDetails.modifiedOn} | N/A |
| Compared with | ${compareReleaseDetails.name} | N/A |
| Source Branch | N/A | ${releaseDetails.artifacts[0].definitionReference.branch.name} |

## Technical Description
@@WILOOP:Release Notes:RN-TECH-SUMMARY@@
${widetail.fields['System.Description']}
@@WILOOP:Release Notes:RN-TECH-SUMMARY@@

## Business Description
@@WILOOP:Release Notes:RN-BUSINESS-BLURB@@
${widetail.fields['System.Description']}
@@WILOOP:Release Notes:RN-BUSINESS-BLURB@@

## Dependencies
@@WILOOP:Release Notes:RN-DEPENDENIES@@
${widetail.fields['System.Description']}
@@WILOOP:Release Notes:RN-DEPENDENIES@@

## Known Issues
@@WILOOP:Release Notes:RN-KNOWN-ISSUES@@
${widetail.fields['System.Description']}
@@WILOOP:Release Notes:RN-KNOWN-ISSUES@@

## Technical Debt
@@WILOOP:Release Notes:RN-TECH-DEBT@@
${widetail.fields['System.Description']}
@@WILOOP:Release Notes:RN-TECH-DEBT@@

## Fallback Plan
@@WILOOP:Release Notes:RN-FALLBACK-PLAN@@
${widetail.fields['System.Description']}
@@WILOOP:Release Notes:RN-FALLBACK-PLAN@@

---

## Associated Artifacts

### Associated work items
@@WILOOP@@
* #${widetail.id}
@@WILOOP@@

### Associated commits
@@CSLOOP@@
* **ID ${csdetail.id} ** ${csdetail.message}
@@CSLOOP@@

The Git based WIKI Updater extension takes the generated release notes and injects them into our git based Wiki.

Here is our sample wiki, with the auto-generated release notes.

Two extensions that are simple to implement, with powerful features you must evaluate in your pipelines.

Tracked issues:
- ( OPEN) Re-run of release pipeline results in loss of release notes information
-  (😊 CLOSED) $(Build.*) variables are not replaced when using a file based template

THANK YOU Richard, for delivering these two extensions to the marketplace and listening to my wish lists and issues with great patience 😊