“How to start?” … Well, I avoided answering this question a long time, until now. I found an approach which fits perfect into Azure DevOps and satisfy my CI / CD workflow.
You know, Real-Life of Microsoft Dynamics 365 Business Central is development, deployment, support, and maintenance together. Therefore all of these processes need access to the right source code.
Source Code Management (SCM)
Some basics: Most of us know “OMA” (Object Manager Advanced). Microsoft Navision developers uses OMA since a long time as SCM. It tracks and manage code changes from C/Side.
Microsoft AL introduced new tools like Visual Studio Code. Source Code is now written externally and stored in textfiles. Furthermore, development happen not longer centralized in one “database”.
Finally, the introduction of industry standard technology is the result of these development process and methodology changes.
This is one reason why git have been appeared in our tool chain and is now the standard SCM for Microsoft Dynamics 365 Business Central.
First of all, you know, Developers now work with an “isolated” copy in their local sandbox. As result, the development process and source code handling is: distributed and isolated.
The project source code is shared with the team as Remote Repository and stored e.g. in Azure DevOps. Each developer work locally with a cloned copy of the Remote Repository, the Local Repository.
[see also: Distributed Git Workflows]
Once I have finished my Work (Gap, Feature or Bug Fix), then I create a Pull Request to integrate my source code changes into a target branch.
[see also: Pull Requests]
Finally, an Azure DevOps Build Agents creates a new Artifact based on the integrated source code (finished work) and so on…
SCM Workflow Requirements
My basic requirements on a SCM workflow within git and Azure DevOps are therefore:
- Changes of Gap / Feature development are tracked in branches
- Artifact / Release creation is based on finished work
After the artifact is successfully created, it will be deployed into test stages (see also: Deployment Stage). Finally, the tested and approved Artifact will be released into Production.
I know, testing is a time consuming process and huge changes invoke lots of tests:
…First of all, as project manager you must align your consultants and key users. Then you need their approval to enter the next stage. If there is a problem and usually there is one then you start from the beginning…
In other words, to decrease the time to production we need fast issues correction of releases. Furthermore all of us know, when a production issues is reported, you need to fix it ASAP.
Therefore we have 2 new important requirements:
- Artifact creation for testing based on Release Source Code
- Hotfix creation based on Production Source Code
Let’s see, what we can do…
All we need is a well defined branching workflow!
Remember, it is necessary for real CI / CD within Azure DevOps and it must provide the right source code for development, testing, support, and maintenance.
At the beginning with Azure DevOps, I focused on Git-Flow. This is a very popular workflow / branching model. Here are some resources I recommend to read:
My branches with this workflow are:
- [master] … contains production source code
- [dev] … includes all finished gaps as Squash Merge from Pull Request
- [feature(s)] … comprises all commits for a gap, the unfinished work
- [release(s)] … handle source code changes and fixes during testing
- [hotfix] … contains bug fixes for production
Releases in Gitflow are managed by branching from [dev]. Finally they will be merged into [master]. Gaps are developed in [feature] branches:
Well, initially I prefered this workflow. But however, Gitflow did not satisfy myself. Pretty soon during first projects I discovered its not handy enough for me. This workflow might have to much overhead.
Let me explain. My biggest issue was the handling of Pull Requests between [dev], [release], and [master] branches in Azure DevOps.
Secondly, [hotfix] or [release-fix] branches increase the complexity a lot:
This is not acceptable for Agile Projects. Each Sprint have a Release. This happens Weekly, Bi-Weekly or Monthly. As a result, I need to spend a lot of effort in SCM.
Furthermore, this workflow is not scalable. Another “Showstopper” appears when you have multiple production sites. Gitflow defines:
[master] branch = Released = Production Source Code.
There is only 1 [master] branch. So how can I serve 2 or more production sites?
My conclusion: There must be a better way!
I started searching and found this promising article:
This workflow have simplified branches:
- [master] … includes all finished gaps as Squash Merge from Pull Requests
- [release(s)] … contains released code for testing as well as production
- [feature(s)] … comprises all commits of unfinished work for gaps
- [hotfix] … similar to a feature, but contains commits of bug fixes
Yes, my first Pain-Point is gone! There is no [dev] branch and Pull Requests are only merged into [master] branch. Another benefit!
My [release] branches are never merged into another branch. They disappear when they are no longer needed:
In addition I can have as many [release] branches as I want. With this, I’m able to manage productive source code for multiple production sites.
My last critic point, was the branching complexity during bug-fixing. What happen with a [hotfix] branch?
Well, a [hotfix] is also simplified and treated like a [feature] branch:
Once I completed a fix, I create a Pull Request and merge the changes back into its source branch. My changes are “Cherry-Picked” into [release] branch.
Another way is to start from production source code in [release]:
The [hotfix] is based on the [release] branch and merged back by Pull Request. All changes are “Cherry-Picked” into [master] and other [release] branches.
Cherry Picks in Azure DevOps
A Cherry Pick starts after we have applied the [hotfix] back into e.g. [master]. Our changes are now a commit on the [master].
My workflow is:
…When I do a cherry pick, then I apply all changes from a single commit to another branch, the Target Branch…
In other words, my source is the Commit where Azure DevOps provide the “Cherry-pick” action:
After execution, Azure DevOps want to create a new branch to merge my cherry pick changes. The requested target branch will be the source branch for the merge.
Finally I need to specify the name of the new branch:
In my example, the new branch [hotfix/fix01] is created from [release/prod-2019-12-01] and contains my production source code. Only the changes from cherry pick commit [c8648eee] are applied as a new commit on [hotfix/fix01].
After all, Azure DevOps wants to create a Pull Request to apply the cherry pick commit [cdcd95c9] changes back to the target branch:
My preferred branching workflow within Azure DevOps is the now:
First of all this workflow fulfill my basic requirements on distributed and isolated feature development. All finished work is integrated and stored in the [master] branch.
Moreover, I can manage the source code in unlimited [release] branches for as many production sites as I want. I can apply hotfixes and cherry picks to each of these releases as well.
And finally, maybe the best part:
[release] branches are only needed, when you have to apply a [hotfix]. A [release] branch can be created on demand. Because each commit still exists on the [master] branch.
Instead of using branches you can use Tags to mark your “release” commits … think about this 😉
OK, I know – this chapter took a while. However, … I’ll try my very best and I’ll continue as fast as possible!
Open topics: “… why I use Universal Packages for my Artifacts and which insights you get from Badges …”
In the meanwhile, I want your feedback! Which branching workflow do you use and how does it satisfy your needs?
Merry Christmas and a Happy New Year!
… Happy Sharing and don’t forget #NeverStopLearning