all Technical posts

Using the Hip F# FAKE Build DSL Within DevOps Systems

DevOps systems are a great way to streamline development and automate necessary checks to make sure that the application is behaving like it's supposed to do. However, local development should not be forgotten.

DevOps Systems

As a big fan of automation and DevOps, it’s great to see as much in the Continuous Integration (CI) pipeline as possible when pushing new changes. With package restoring, compilation, unit/integration testing, packaging, deployment, documentation previews and code-scanning, it’s mostly a matter of staying under the ’10min’ rule for the pipeline, while still being able to do as much automation as possible.

What I’ve seen is that this pipeline is sometimes the only place new steps are introduced without thinking about local development. Besides DevOps, I’m also a big fan of test- and type-driven development, which means fast test cycles and continuously testing your code. For example, when you set up Docker integration tests, this usually only lives in the YAML build template and so is not directly available as quickly. This is especially when these Docker tests span multiple images that need to run. Setting this up and tearing it down might take a while. Therefore, you have to push all of the necessary changes each time to test a certain piece of code. The test cycle in this case would be higher than a few minutes as you’d have to switch contexts and verify DevOps test results.

This post will take a look at how we can change this. All of the code samples in this post are available in a dedicated GitHub repository.

F# FAKE DSL Usefulness

A great build tool to automate project development is F# FAKE. In simple F# code, one can quickly define a strong and useful set of relational build steps that run all the things a YAML template in a DevOps would do. The only thing missing with the YAML template is that it would be great to be able to run it locally. This file is more than just a set of build steps and contains things like the build image and parallelization, which is not really useful for local development. Here’s where FAKE comes into play.

As far as I can see it, YAML is for remote building and FAKE is for local building. But what if those two worlds could collide?
In this example, we will be using the following F# FAKE build script. For more information on F# FAKE, I refer you to their amazing getting started page.

Integrate with GitHub Actions

GitHub actions are great for the quick and easy setup of required checks and scheduled runs. The direct built-in capabilities make this especially useful. Integrating a .NET build is fairly easy. The default provided YAML is already helping a lot. Integrating F# FAKE only requires two things: installing F# FAKE and running the target.

The resulting GitHub action looks like this. Since F# FAKE is available as a .NET tool, initiating it is fairly easy.

Integrate with Azure DevOps

Setting up a YAML file to run on Azure DevOps can be a bit harder. Azure DevOps allows stages which are beautifully shown in the GitHub checks on open pull requests. These stages are usually the same stages you see in F# FAKE build scripts: restore, compile, test, deploy. The difference here is that each stage could run on a different machine and even a different image. The trick is to call the F# FAKE build script only for a given target, without the previous dependent targets. This is the same kind of functionality as the --no-build and/or --no-dependencies command-line switches within .NET CLI.

The following sample shows this clearly. Look especially at the testing stage where the build script is called with the --single-target switch. This makes sure that we only run the test target, as the previous targets were already run. Also notice that the test results generated by the build script are used to publish the test results in the Azure DevOps UI, making the results visually available.

Improvements and Maintenance

Adding F# FAKE to your development process is quite easy to do. An even easier way to manage your .NET tools in source control is to make use of the local tool installation option with a tools manifest file (dotnet-tools.json). This will make managing tools easier across members of your team, as one only has to run dotnet tool restore on their machine. The samples don’t make use of this because it would make the installation process a bit harder to understand.

Another improvement is to make use of the F# YAML config type provider. Since one will usually store configuration data like the .NET SDK version, library name, build image and other informational data in a YAML file, it would be useful for the F# FAKE build script to make use of that same file.

The sample below used this YAML build config:

To use the Project: Library setting in your F# FAKE build script, one has to add the FSharp.Configuration package to the F# FAKE nugets and load the YAML config file:

This way, the configuration data will only be stored at one place, and both the DevOps systems as your local F# FAKE build script will use it. A single place for the truth.

Conclusion

This post looked at the possibility of combining the wildly used DevOps systems with the flexibility of F# FAKE. Both worlds often live by themselves, but they could really help each other to make DevOps and automation an even greater and more fun place to work in.

Thanks for reading!
Stijn

Subscribe to our RSS feed

Thanks, we've sent the link to your inbox

Invalid email address

Submit

Your download should start shortly!

Stay in Touch - Subscribe to Our Newsletter

Keep up to date with industry trends, events and the latest customer stories

Invalid email address

Submit

Great you’re on the list!