Our team has over 100 different repositories (applications) with pipelines and release definitions in Azure DevOps. We have many on-premise web servers that share hosting the applications. With this setup we have taken advantage of using Library / Variable Groups to share settings that are reused. In our team we recently “rediscovered” a little gem in how Azure DevOps works with library variables / variable groups, stages and Release scope. I wanted to share as there was confusion in the team that was adding unnecessary pipeline variable setup.
Given a three stage pipeline like dev->test->prod and you need to define a variable:
For a variable that is the same for all stages, use the Release scope. AppSettings.AppName for example in the above snippet doesn’t change for the stage.
For a variable that is different for each stage, define it three times, setting the value differently per the stage.
Straight forward, no fuss. What about variables groups?
Every release definition of ours has variable groups that describe the iis deployment information such as the root folder path for where we “install” the application folder and other IIS information that we have normalized for all the applications on that host (deployment group and/or environment). We also have settings for our single sign on system that all the applications use and it’s settings for the various stages (dev/test/prod).
If the information for each stage does not change then we could pick the Release Scope when we setup the Variable Group. Straight forward, no fuss.
If you are using variable groups scoped to a stage then do you have to declare the variable per stage, three times (dev/test/prod)?
Below, we have hooked up variable groups to each stage (dev/test/prod) for our .Net Core apps logging settings.
So do you create three pipeline variables, one per stage in the pipeline variables? Since the values are different and/or scoped to the stage, this seems like the logical choice and you can but it’s just adding clutter.
You can define them once and use Release for the scope and the variable groups use the scoped value per the stage during the release to each stage*.
* I know someone reading this is saying BUT BUT if the variable name (Logging.LogLevel.Default) in the variable group matches with what is in your settings file you don’t have to reference it at all in pipeline variables. Correct. However, there are times you might have to due to a mismatch or as we have by convention chosen to. You might notice we start our variable reference with a caret ^. This is part of the convention we have adopted. More on that in a later post.
Overriding the Release scope
Now, what if you wanted to override a value for a stage that has a Release based scope?
Add the new pipeline variable, set the stage and set the value to override with. The variable group value for the stage will be overridden with your new value. This is a great option when you are deviating from your convention or need to have a different setting for a while. It’s easy to cleanup. Simply delete the pipeline variable for the stage when done. We use this technique for a 3rd party vendor solution connection string that changes during their upgrade cycles. During the upgrade timeline we override then go back to normal when the upgrade cycle completes.
You can also mark the Release scope variable as “settable at release time” instead of creating a stage variable override like shown above. It is “faster” and if one was doing it for quick troubleshooting, no problem. For deviating from the normal/convention or prolonged usage I prefer an overridden stage variable. The extra information provided by this tells anyone looking at the variables this isn’t “normal”. It’s also less obtuse than having to view the logs of a release to see what the setting was set to at release time when using the “settable at release time” option.
Never, mix the two approaches for the same variable. The overridden stage variable will win which might feel counterintuitive. I’ll explain more on our conventions around variable groups in a later post.