New Azure Functions SDK and VSTS - how to build your functions?

With recent release of Visual Studio 2017 15.3 we're given the possibility to use Azure Functions SDK, which is now fully integrated with IDE. This improves development greatly as we no longer have to maintain function.json by ourselves and are able to run function locally using in-built runtime. How about integrating new features into existing CI/CD pipeline? Well, there're some gotchas, fortunately you can easily configure things so everything runs smoothly.

Building a function project

When you create a new function project in VS you're given the options to easily add new functions with a boilerplate code. If you investigate .csproj file(last time I wrote about building Azure Functions using VSTS it was a .funproj file), you'll realize, that it differs greatly compared to legacy .csproj files:

/
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net461</TargetFramework>
  </PropertyGroup>
  <ItemGroup>    
    <PackageReference Include="Microsoft.NET.Sdk.Functions" Version="1.0.0" />
  </ItemGroup>
  <ItemGroup>
    <Reference Include="Microsoft.CSharp" />
  </ItemGroup>
  <ItemGroup>
    <None Update="host.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
    <None Update="local.settings.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
  </ItemGroup>
</Project>

Considering new structure you can imagine, that it's going to give us some troubles. If you try to build it in VSTS, you'll get following error:

/
Error MSB4066: The attribute "Version" in element <PackageReference> is unrecognized.

Apparently using a default agent queue won't work here - agents don't have proper targets, which are required to build a project(if you build a project locally, you can find those targets in C:\Users\{USER}\.nuget\packages\microsoft.net.sdk.functions\1.0.0\build\netstandard1.0\Microsoft.NET.Sdk.Functions.Build.targets). It'd possible to just import them and run on a default agent, still this looks like a workaround. However, there's an easier solution - during scheduling of your build you can choose a different queue:

Let's try to build our project once more...

/
 Error MSB4041: The default XML namespace of the project must be the MSBuild XML namespace. If the project is authored in the MSBuild 2003 format, please add xmlns="http://schemas.microsoft.com/developer/msbuild/2003" to the <Project> element. If the project has been authored in the old 1.0 or 1.2 format, please convert it to MSBuild 2003 format.

There's still a problem - MSBuild is not able to determine what kind of XML is this. To fix this you can just modify <Project> node to following:

/
<Project Sdk="Microsoft.NET.Sdk" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

Now your project should build correctly:

When working on this solution I found, that some people tried to build new Azure Functions projects using dotnet build step in VSTS - unfortunately this didn't work for me. Let me know if you found another way of integrating new version of .csproj with VSTS!

Running additional VSTS agents in Azure

When working in a smaller team or on a small project, you usually aim to reduce costs of your development pipeline. This is also true for huge projects, but there we're talking about bigger budget and money. When working with a free VSTS subscription, you're limited to only 1 hosted pipeline(and 4 hours / month) to run your builds and release. To be honest - it's nothing when you have real CI/CD set up and working. However, if you consider a fact, that you also have 1 private pipeline, it's possible to mitigate this problem.

Hosting your own agent

VSTS allows you to host and connect your own agents running on your machines. It's a great way to take advantage of a private pipeline when hitting a limit of 4 hours and allows you to have a backup when you need more builds and releases in a short period. To use an agent you need two things:

  • a machine which will host it
  • an installer

A good idea to get a machine is to use your existing Azure subscription(especially when you have MSDN/BizSpark) and create a VM, which can be started and stopped easily. Another thing are capabilities of your machine, which have to match requirements for your build(e.g. MSBuild, Grunt, gulp and so on). 

Get agent screen will help to both determine what is needed to install it and how to do it

Because of capabilities, using different(you can choose from Windows/OSX/Linux) agents can be easier or more difficult. In the future I will show you how to set up e.g. Linux agent, for now we'll focus on the Windows one.

The easiest way is to create a Visual Studio VM from the marketplace in Azure Portal. That way you will have most components needed for a build already installed and configured. 

Usinga Visual Studio virtual machine will ease whole process a lot

To get an installer you have to go to Agent queues screen in VSTS and click the Download button. As present in a one from the screens above, information needed to install and configure it are already there so I won't reinvent a wheel and just ask you to go through it by yourself.

Configuration

Configuration of your agent is pretty straightforward. When you enter following command:

/
C:\your_agent_directory> .\config.cmd

You'll be asked a couple of questions regarding your VSTS account, a name for an agent, agent pool and a method of authentication. The easiest way to authenticate is to use PAT(Personal Access Token) which can be generated here: https://{your_account}.visualstudio.com/_details/security/tokens.

Once you've configured your agent, you can run it with a .\run.cmd command. If everything's all rights, when you go once more to the Agent queues screen, you'll see your build agent available in the selected agent pool:

Building and releasing on your agent

So far so good - we have additional build agent, which can be used in our private pipeline. But what we have to do to schedule a build and a release? 

Builds

Go to the Builds screen. When you click on the Queue new build... button, you will be asked to select a couple options related to a build. The one we're interested in is Queue. Just selected the one which have your build agent configured and click Ok. Your build should start though you've used all available minutes from the hosted pipeline.

Selecting a different queue will allow you to use a different pipeline

Releases

Releases are a bit tricky. When triggering a release you have no option to specify a queue. To do so you have to go to a specific release definition and find Run on agent link above release steps. When you click on it, it will show you another screen, when you can find Deployment queue list, from which your private pipeline can be selected.

Somehow hidden Run on agent screen allow you to run your releases on your own agent

Summary

In above solution you have to consider costs generated by using a VM to perform builds and releases. Currently you can buy another hosted pipeline for 40$ so it's two times less than a minimum VM needed for a Visual Studio. On the other hand, you can automate it so it works only in your work hours = saving some money. If you have an available subscription like BizSpark, you can save even more money. Both solutions are viable but as you can see, starting another build agent is a very easy task, and can help you when you either want to control usage of your pipelines or to build something, what couldn't be built by a hosted agent.