Getting Started with TFS Release Management

Sage McEnery
Modern Stack
Published in
27 min readMay 10, 2017

For many shops, Jenkins is the go-to tool for all your teams Build and Release needs. Without a second thought, many of us instinctively reach for Jenkins when we want to build our Projects and Solutions. Without a shadow of a doubt, Jenkins is a super easy and extremely flexible tool. Further, with its extensive suite of Plug-Ins, practically all of your Build and Release needs can be accomplished using Jenkins.

That said, if you work in a Microsoft only shop, it seems only prudent that we should at least consider the tools Microsoft provides to help us with our Build and Release needs.

If you are using TFS 2015 or higher, then that tool is Release Management (not to be confused with the discipline). In TFS 2013, Release Management was something that you had to pay for via an elevated subscription to MSDN. I may be wrong, but it seems that starting with TFS 2015, Release Management is now included in TFS 2015 out of the box.

Great! Lets give it a whirl.

At first blush, getting started with Release Management is anything but easy. If you are coming to Release Management from Jenkins, getting started can actually be quite off-putting. So off-putting in fact, that I wouldn’t be surprised if people just went back to working in Jenkins and moved on with their lives.

Speaking from experience, the biggest issue with Release Management was simply getting started. Getting things setup correctly is not intuitive and requires a bit of hoping back and forth between different parts of TFS. Additionally, TFS uses some concepts that are disparate when coming from Jenkins, which only adds to the confusion. Without any context it may not be clear immediately how these concepts actually relate to each other.

Having said that, once Release Management is configured it is actually very easy to use. Further, in a purely Microsoft based shop, the benefits are quite clear and evident. If you are already using TFS for your Source Control, the integration is seamless (as one would expect). If you are also using TFS for your Work Item tracking, the visibility Release Management provides is borderline unmatched.

All things considered, while it may be uncomfortable for people to even consider leaving Jenkins, we should at least explore alternative possibilities.

With that, we have a lot of ground to cover so lets get started!

Documentation

We have to start with the documentation. Over the last few years the documentation for Release Management has indeed gotten better, to a point. I remember the days when documentation on Microsoft’s site usually entailed an article that was quite long in its length. A few years ago though Microsoft seem’s to have committed to a new format for their documentation. Documentation is now broken up into smaller pieces and then linked together to form a sort of chain. In theory this might make it easier to digest, especially considering the average Americans short attention span. In reality though, I think this contributes to the confusion of getting started with a tool like Release Management.

Take a look at the Product Page as an example;

Where Should I Start? I feel like there are at least 2–3 options for me here.

Get Started for free just takes me to a signup\in page for Visual Studio Online. That doesn’t help me. I do want to Automate my Deployments, maybe I should start there? Or… maybe I should start with the Documentation?

It doesn’t actually matter, either option is a non-starter.

Documentation dumps me on a screen with so many links to Concepts, I am still left wondering where to start.

Get Started makes sense, right?

Nope…. just links to more concepts.

No… to actually start setting up Release Management, we would have to dig into the Concepts section. Even then, we have to know which concepts actually matter & in what order we need to consider them.

I started with the documentation because I think it adds to the problem. Release Management, to a degree, has a conversion problem. Release Management needs to convert Jenkins users and get them using this product. To do that, it really does need to be as easy as possible to setup, learn and fully utilize. Out of the gate though, it seems to miss some of these targets.

Core difference between Jenkins & Release Management

For many people using Jenkins, a Job is responsible for Building & Releasing code. When first getting started with Jenkins, this setup makes perfect sense and for many people it gets the job done. Granted, Build & Release are two very different concerns & some people would even argue that this type of setup is just wrong. Personally though, this is Information Technology. “Right” is what works for you in your given situation. “Better” is another story altogether. Besides, Jenkins’ flexibility does not force you to conform to a particular setup or configuration.

Release Management, on the other hand, does pretty much force you to separate these two concerns. In fact, Build and Release are two different tabs within the UI.

Jenkins, out of the box, performs all work on a single server\node. The node hosting the UI is the same node that performs the Build operations as well as the activities needed to release the code that has been built. Of course you can add slaves as needed to scale Jenkins, but this is not necessary and again, Jenkins does not force your hand.

Release Management does kind of force your hand. We need to decide, ahead of time, where we are going to perform the activities we need to perform.

In short, the biggest difference between Jenkins and Release Management boils down to one simple statement. Jenkins lets you make decisions on the fly whereas Release Management kind of requires you to think about the bigger picture up front.

Planning the Setup

Knowing that Release Management requires us to think of the bigger picture, we can get ready to start setting things up as needed.

To be successful, I found it helpful to think about Release Management in the following way;

The TFS Server stores our Code and our Work. TFS contains a product called Release Management and that product is concerned with Building code and Releasing Code.

To Build the Code, we need to have servers with the necessary tools. These may include tools such as; MSBuild, Visual Studio, NodeJS, Java, etc.

To Release the Code, we need to have servers that have access to the places where we deploy our code. These places are usually the different environments that you have such as; Dev, QA, Int, Prod.

If we were to consider an environment where there is a clear demarcation point (boundary) between these different environments, we might end up with a visualization like this;

Maybe you have different data-centers or vLans that cannot talk to each other. Whatever your situation is, the important thing is that you are thinking ahead of time about HOW you are going to move code between all applicable locations.

The reason this needs to be thought about and considered is because one of the first things you are going to want to configure in Release Management is the Agents.

Define and Configure Agents

Open the TFS UI in a web browser and click the Cog icon.

Do note that if you are currently in a Project\Collection in TFS, the Cog Icon will take you to the Project Management screen. This is not the correct screen to be on.

Wrong Screen! This is the Project Management Screen. Nothing on here says “Agents”

If you are on this screen, you might be inclined to click “DefaultCollection” (assuming you went with the default during install). Doing this will result in the following Management Options;

Note the tab is titled “Agent Queues”

If you click “Control panel” though, you will be presented with the following Management Options.

Note the tab is titled “Agent Pools”

Server level administration is the highest level of administration you can perform and this is where we are going to start.

Click “Agent pools”

There are two activities we are going to want to perform on this tab. The first is the downloading of the “Agent” itself. This is an application that will be ran on every server we define that addresses either one of our two concerns; Build & Release. Lets go ahead and click that link so the download begins.

The other thing we are going to do in the meantime is create our Agent Pools. When I first encountered this screen and was initially learning Release Management, I created a separate pool for each environment I planned to support.

As I got more comfortable with Release Management though I realized not only was this somewhat incorrect, it was also unnecessary. Remember earlier I mentioned about Boundaries? In my environment, Dev, QA & INT are all in the same domain and data center. Stage is our beta environment where users can preview new code and features. Production is actually split between two physical data centers.

With that lesson learned, and for the sake of this article, we are going to create two Pools; BUILD-SERVERS and RELEASE-DEV-QA-INT. Underscores are not allowed, otherwise I would have used them.

It is worth mentioning that you can perform this step from the Agent Queues screen found in the Collection Management Screen. I thought it made sense to show the creation of the pool at the highest level in TFS as it helps to connect the two concepts. Agent Pools are server-wide concepts whereas Agent Queues are scoped to a collection.

Big deal! Now I have this Agent Pool, but there is nothing in it. Nothing in the UI seems to let me add an Agent, so whats next?

Remember that Agent we downloaded earlier? Its time we put that to use. Copy the Zip File off your computer to one of the servers you plan to use for Building or Releasing code. In fact, do what you need to do to get the contents of that Zip File on every server you plan on using as part of your Build\Release cycle.

Extract the contents to a directory that works for you and fire up a Command Prompt. CD into the folder you just extracted and run “ConfigureAgent.cmd”

The questions are you going to be asked are as follows;

  1. Enter the name for the agent: (Default value is fine)
  2. Enter the URL for the Team Foundation Server: ( Server URL, not a Collection level URL)
  3. Configure the Agent against which Agent Pool: ( one of the pools we created earlier )
  4. Enter a path to work folder for this Agent: ( default is fine )
  5. Would you like to install the agent as a Windows Server: ( You bet ya! )
  6. Enter the name of a User Account to use for the Service: ( a Domain level account if this Agent is going to perform Release activities ).
  7. Enter the Password:

Once you are done answering questions, provided they were answered correctly, you should get the Configuration successful message.

Head back over to TFS and you should now see the Agent listed in the Pool you configured it in. Agents will show up here automatically as you add them and provided everything is setup correctly, they should go Green within a few seconds.

Agent Pool with 2 servers

You will obviously repeat these steps to install the Agents on additional servers. Since we had been running Jenkins for years, I installed an Agent on the same server to perform our Build tasks and made it a member of the BUILD-SERVERS agent pool.

Depending on the work an Agent is configured to perform, its impact on each server you have it installed can be negligible. Agents can be found in the Task Manager as follows;

Agents run as VsoAgent.exe and VsoAgentService.exe

If you want to Delete the service from a machine you have installed it on, find the service in the Services snap-in, Stop the Service, Open its Properties dialog and copy the full name of the service. Open a Command Prompt and enter “SC DELETE [what you copied]”

Deleting an existing agent using the command line

You can run ConfigureAgent.cmd again if you just want to change some of the settings for the Agent.

We are done. Having installed our Agents we can now actually start doing something with Release Management. All things considered, this process is actually pretty easy to complete. It probably took you longer to read this section then it will to configure your agents. While this process does seem quite manual, the ConfigureAgent.cmd does accept parameters so you can easily script out the creation of these Agents.

Building your source code

Once you have your Agents setup, the process for creating a Build is actually pretty quick and easy. You may have already poked around the Build and Release tabs before in an effort to explore this product. Of course, if you did that without having the Agents fully configured, you might not have gotten very far.

Builds are defined at the Project level, so make sure you have navigated to a Project in TFS. Once you have, the Build and Release tabs are available.

Click the + sign button to begin. Note on the resulting dialog that there are two types of Templates available; Build and Deployment. The Build tab is selected by default and this is where we are going to work. Lets choose “Empty” & Click Next to proceed.

Depending on your setup in TFS, the options on this dialog are somewhat limited. The Repository dropdown is limited to the root of the Repository you have scoped to the Project you are working in. In Jenkins we can define the exact Repository path we want to build and one might expect that you can do the same thing here. That is obviously not the case here (at least that I have seen) and seems like a real limitation. In fact, I would go so far as to say this dialog is kind of crappy from the perspective of the Repository dropdown.

We are going to check the Continuous Integration box since that is our ultimate goal. We can also see that the Agent Queues we created earlier are present. Since we decided to separate our Queues based on concern, we will choose BUILD-SERVERS from the drop down and click Create.

Sweet! Now I have a new screen with a bunch of other tabs and things I need to configure. Since the purpose of this article is to go through the basic steps needed to get going with Release Management, we will only focus on the most basic settings for now.

First thing first, lets save this template & get rid of that “New Empty definition 1” label since it is meaningless. Click the Save button and you will get a dialog that allows you to give this definition a meaningful name.

Now that that is done, lets move on. We know we want to Build something, so lets add a Build Step. This will open the Tasks dialog where we can browse the library of Tasks available within Release Management. We are going to choose the Visual Studio Build step.

Click the Add button to add the chosen Task to your Definition. If this is the first time you have seen this dialog, take a moment to look around at all the other tasks that you can use in your Definition. Close the dialog when you are ready.

Now we just have to tell Release Management what we want to build. The Step configuration screen makes it pretty clear that it wants to build a Solution file, so lets tell it which solution file we want to build. Click the Ellipses button next to the Solution text box.

Awesome! This dialog lets us actually browse around our Repository. Use this dialog to navigate to the Solution file you want to build. Click the Solution file you want and press OK.

Now that that is done, we should be good to go. Lets click Save and build this b….!

After clicking Save, the “Queue build” button will become enabled. Click this button to get the show on the road.

This will take you to the Build screen;

Be patient! This is your first Build so expect things to be a bit slow. After a few seconds ( or minutes ), you should start to get some Console output.

Whoa! Wait a minute here! This thing is downloading all the source code in the repository even though I specified a distinct Solution file for it to build. What gives?

Remember the crappy Repository dropdown I mentioned when we first configured the Build Definition? Yeah, that thing is to blame. Lets cancel this job since it isn’t doing what we would prefer it to do. Once it cancels, click the Definition name in the top left corner of the Build pane. This will take you to the screen where you can see all the Build jobs that have occurred for this Build Definition. Next to the Build Definition name, click the Edit link.

Back on the Build Definition editor, we are going to go to the Repository tab.

The problem is that by default, the Mappings are set to the root of the Repository that the project is bound to. Clicking the Ellipses button next to the “Map” type mapping allows us to limit the scope of the Source Code we want this Build Definition to concern itself with.

That looks better!

Before we leave though, there is one other thing we want to look at and change. This isn’t the only place that the crappy Repository Dropdown creates an issue. Remember how we checked that Continuous Integration checkbox? Lets click the Triggers tab real quick…

Yup… that doesn’t look good. Even though we are building a Solution that is below the root of our Repository, the trigger is going to fire if any code changes are committed ANYWHERE in the Repository. Lets click the Ellipses and Scope the trigger accordingly as well.

That looks better too. Once we click the Save button again, we can then re-queue a Build and see that things are now working closer to how we expect them to.

That’s looking a lot better now. We can see that the first runs were indeed scoped to the root of the Repository, where as the last two runs were correctly scoped to the Branch we want to build. It is obviously always going to be most efficient to limit the scope of the source code you are interacting with whenever possible.

Further, we can see that we now have some Green Builds! Awesome, now we can move on to Releasing the code we just Built.

Release — Deploying your Code

It took us a while to get here, didn’t it? Truthfully, it will take you longer to read this article then it will to get Release Management actually working. Its been a long trip to this point and I thank you for sticking with me as we work through this process. The reward for your patience should be a quick and easy configuration of Release Management though, so hopefully it is all worth it.

Now that we have Builds completing in TFS, we are ready to define a Release Template. Lets proceed to the Release Tab and click the green + sign to create a new Release Template.

Since we are not working with Azure here, lets choose the Empty template at the bottom of the dialog. Clicking the OK button will present us with the following window.

One of the first things we are going to want to do on this screen is give the Release Definition a meaningful name. Once you do that, lets Save the Definition and get that out of the way.

The next thing we are going to want to do is link this Release Definition to a Build definition using the link highlighted in the screenshot above. This can also be accomplished by going to the Artifacts tab in a Release Definition.

Linking to an Artifact Source will present you with the following dialog.

The Type dropdown is used to tell Release Management where the Release Definition Artifacts can be found. The two options are; Build: which means they come from TFS, & Jenkins: which means the Artifacts come from builds you have configured in Jenkins. To use Jenkins Artifacts, some additional configuration is going to be required which I will not cover in this article.

Since we are using TFS to Build our Solutions, we will choose that option to proceed. Once you do that, you can then choose the Build Definition from the Source drop down.

Oops. It looks like something is wrong. We know we got our Build working and returning a happy green checkbox, so what gives. The key phrase that points us in the right direction is the underlined segment of the sentence. While we do have a Build completing successfully, the Build is not publishing any Artifacts so Release Management has nothing to work with.

Lets go ahead and click the Link button, then Save the Release Definition.

Now that we are done with that, we will need to go modify the Build Definition and make it Publish Artifacts that Release Management can work with. While on the Artifacts tab we can click the name of the Build Definition shown to go and manage it. This will open a new window to a screen showing all Completed Builds for the linked Artifact Source. Click the Edit button in the top left of this screen to edit the Build Definition.

Once you are on the Build Definition management screen, click the “Add build step…” button.

In the Add Tasks dialog window; choose the Utility category, scroll down towards the bottom, and then press the Add button next to the Publish Build Artifacts task. Press the Close button on the dialog once you are done.

Do note that there are 2 Publish Artifacts Tasks in this dialog. The one we chose will publish artifacts from within the directory of the Source Code folder being built. The Copy and Publish Build Artifacts task would be used if your build process produces artifacts in a folder outside the source code folder. Consider the following directory structure;

The MSBuild job marked (1) would warrant us using the “Copy and Publish Build Artifacts” task since the green arrows indicate the build produces artifacts in a directory above the solution file. The MSBuild job marked (2) would warrant us using the “Publish Build Artifacts” task since the CompiledCode folder is underneath the ProjectFiles folder which contains the Solution we are building.

Back to the task at hand.

The Publish Artifact task configuration is somewhat straightforward. The Path to Publish field might cause you the most frustration depending on your particular needs and the types of artifacts your build process generates. This field is expecting a path which is relative to the root of the Source Code mapping you defined in the previous Build Step. If you wanted to publish everything as an Artifact for example, you would put “**” in this field. Consult Microsoft’s documentation for examples of the types of patterns you can use.

Artifact Name is just a plain text field where you give your build artifact a meaningful name. The value you enter here will be shown when working with a Release in Release Management, as we will soon see.

Artifact Type has two options; Server and File Share. Using Server will store the Build Artifacts on your TFS Server and all Release targets will then download the artifacts from that location. You would use File Share if you want the Build Process to copy the artifacts to a centralized File Share server so all release targets can download them from there. Choosing File Share will reveal an additional textbox where you can set the Path where Build Artifacts will be copied to.

My Solution has about 20 Projects in it and the Build process generates all kinds of files. The only Artifacts that I actually care to publish are contained in a subfolder. I simply set Path to Publish to the name of the folder that has the stuff I care about.

This is how my Publish Artifact screen looks when I am done.

Happy day! We should be done now. Save the Build Definition and Queue a build. Wait for it to finish and confirm that everything is still Green. If your build fails now, chances are that the Path to Publish value is incorrect. Check your logs and you should be able to figure out what went wrong;

A failed build where the Path to Publish value is incorrect.

Once your build is Green, its time to head back to the Release tab to wrap up our Release Definition and test it.

Previously we had opted to Link the Artifact source even though TFS was telling us that the Build did not produce any Artifacts.

If we were to delete the Artifact link;

and go to the Link the Artifact Source dialog now, we would see the following;

This tells us that Release Management is linked up to our Build Definition correctly.

With the Artifacts portion of our Release Definition configured correctly, we can move on to define the places those artifacts get deployed to. Let’s click the Environments tab in our Release Definition.

The Default Environment is created by TFS by…. default. Lets just delete that. We could edit it, but that’s no fun.

Its time to think back to our planning phase, in particular, our Environments;

We know we plan to support 4 total environments. Now the first response might be to quickly click the “Add Environments” button and pop all our environments onto the screen at once. Of course, there is nothing stopping you from doing that either. However, if you did do this, you will undeniably find yourself duplicating yourself very quickly and most likely just deleting the additional environments anyway.

Instead, we are going to want to focus on fully configuring the Release for one environment first and testing it thoroughly.

That said, let’s go ahead and add a new environment, choosing Empty from the bottom of the list.

The screen above will show up once you click OK. I have already renamed the environment “DEVELOPMENT”. The Context Menu above is shown when you click the […] button in the top right corner of an environment. We will take a quick peek at some of these options in a bit, but notice the “Clone environment” option. This is partly why I said earlier that we wouldn’t want to just click & add all our environments at once.

Getting back to the task at hand, we need to configure the tasks involved with getting our compiled project code deployed to the target servers. To do that, we will click the Add Tasks button in the second pane.

As you can see from the screenshot above there are numerous tasks which we can use, most of which are Azure related. It is also worth mentioning that we aren’t actually limited to ONLY using the tasks available under the Deploy category, we could use tasks from other categories as well. For our purposes, we will be using the Windows Machine File Copy task.

Clicking the Add button, then Close, will result in the following screen;

Clicking the ellipses button next to source will allow us to quickly navigate through the Build Artifacts available to Release Management.

Be sure to select the Artifact underneath the Build folder.

Let us fill out the rest of the boxes for a quick moment before we continue.

Now that we have completed configuring this task, we can save and run it if we want. Before we do though, lets take a moment to ponder what we are looking at here. The first thing that should stand out like a sore thumb is the fact that the user credentials are sitting there in plain text visible to anyone who comes to this screen. Needless to say, this is less then desirable. Further, the entries in the Machines field are (in my case) only appropriate for my Dev environment. Aside for the Source and Destination field, everything else configured here is… lacking in some way.

Lets save the Release Definition real quick and look at the whole screen.

I guess that looks okay. Lets add another environment real quick.

Oh.. wait a second, the new environment doesn’t have any tasks associated with it. I would need to Add and Configure my Tasks for the QA environment manually now. While our example only has 1 single Task assigned to it, you can easily imagine how cumbersome this would be if you had a more complex release process. The point here really is; fully configure one release pipeline first, then do a Clone Environment when setting up each additional Environment. Lets delete the environment and finish up our DEVELOPMENT environment’s release pipeline.

Back to our Windows Machine File Copy task. In the screenshot below I highlighted 3 pieces of information that are either; subject to change per environment or, things I would want to obscure from users.

To address these, we will now work with the Environment Properties dialog.

On the Variables tab, I have created three separate variables, one for each of the items highlighted above. For the EnvPassword field, I have clicked the little lock icon. Not only does this encrypt this variables value, it will also ensure that this value does not show in any of the Release Logs.

Variables defined and set for the DEVELOPMENT environment

Release Logs, which we will see a little later, can be very verbose and are retained until the Release is deleted. If you have any information you do not want people to see, this icon should be checked before testing a release. For our purposes, we are now done with this dialog. Lets click OK to close out the dialog.

Now that we have our Variables defined, it is time to plug them into our Tasks settings.

Custom Environment Variables entered into Task

With that, we will now Save the Release Definition. Once you are done, you should notice that the Release Icon is now enabled.

Upon clicking Create Release, you will be presented with the following dialog;

This dialog allows me to quickly choose the Build I want to Release, identified by the Build ID. I will choose the latest build to continue. Upon clicking the Create button, the dialog will close and a new little blue bar will show up on the Release Definition screen.

Clicking the Release identifier link will take us to the Release Details screen.

Ultimately, we are just going to click the Deploy button to get the show on the road.

Before we do that though, I want to take a quick moment to point a few things out on this screen. This is the first time we have seen this screen and this is also one of the first screens that shows a pivotal difference between Jenkins and Release Management. Up to this point nothing we have done in Release Management couldn’t be replicated in Jenkins.

Viewing the Commits and Work Items tabs does show a rather significant difference.

Quick access to a complete list of Changesets included in a Release

Without having to dig through logs or anything, we can quickly and easily see what Development Work is contained in this release. This is an obvious benefit that we can freely realize simply by combing our Dev-Build-Release workflows under the umbrella of a single tool-set.

When we click the Deploy button, we will get a condensed version of this information on a single screen.

Once you click Deploy, the dialog will close. Lets head over to the Logs tab now;

Within a few moments you should start to see console output in the blue pane. As your release is progressing, the console window should keep you informed as to status.

As a step is completed, you can click the Step Name in the left hand treeview to views the log messages specific to that step. If the step generated a lot of logging events, you may need to download the logs as zip file.

If any errors occur, the step which generated the error will show as a red X. Clicking the step will allow you to view the logs for the failed step.

You can always revisit any past release and access the logs if you need to.

Viewing the logs for a previously completed Release. Complete Deploy logs are to big to display and require Zip File download.
Zip Contents are nicely organized making the information you seek easy to find

We are done, everything is green and we can see that our release completed successfully. We can click the Release Definition in the left hand pane to quickly see all the Releases that have executed for the selected Definition.

We can now click the Edit button in the header or Edit from the context menu shown when clicking the caret next to the Release Definition name in the left pane.

Now we are ready to begin configuring all of our additional environments. To do so, we will click the […] button next to our DEVELOPMENT environment and choose Clone Environment;

Clone Environment option from the Context Menu

Next, we just click the […] button next to our new QA environment to open the QA environment parameters dialog. Because our Release is based on Variables, all we need to do now is change the ReleaseTargets variable which defines the machines where want our code to be deployed to.

Since our QA environment is “gated”, we do not want anyone to create a release and update our QA environment. We prefer to have people approve the updating of our QA environment. As such, we will click over to the Approvals tab on this dialog;

A Release requiring approval from one of three people.

As you build out each environment in Release Management, you can add different tasks as needed. Here we can see that for my INT integration environment, I am going to configure a web based load test.

In Conclusion

I know this article was long and didn’t even take a deep dive into Release Management. Release Management is actually a big product with a lot of features and functionality in it. Taking the time to explore it all is worth it though, especially if you are a Microsoft shop that is already using TFS for your Source Control and\or Work Item tracking. As with all Microsoft products, the deeply integrated nature of the tools provides a clear benefit in the right situation.

I hope you found this article useful and please do not hesitate to leave your thoughts and comments below.

If you are reading this, Thank You! I appreciate you taking the time to read to this point.

--

--