Building

This document summarises the build and release process for the Ocelot project. The build scripts are written using Cake (C# Make), with relevant build tasks defined in the ‘build.cake’ file located in the root of the Ocelot project. The scripts are designed to be run by developers locally in a Bash terminal (on any OS), in Command Prompt (CMD) or PowerShell consoles (on Windows OS), or by a CI/CD server (currently GitHub Actions), with minimal logic defined in the build server itself.

The final goal of the build process is to create Ocelot.* NuGet packages (.nupkg files) for redistribution via the NuGet repository or manually. The build process consists of several steps: (1) compilation, (2) testing, (3) creating and publishing NuGet packages, and (4) making an official GitHub release. The build process requires pre-installed .NET SDKs on the build machine (host) for all target framework monikers: TFMs are net8.0 and net9.0 currently. In general, the build process is the same across all environments and tools, with a few differences described below.

In IDE

In an IDE, a DevOps engineer can build the project in Visual Studio IDE or another IDE in Release configuration mode, but the latest .NET 8/9 SDKs must be pre-installed on the local machine. However, this approach is not practical because the generated ‘.nupkg’ files must be uploaded to NuGet manually, and the GitHub release must also be created manually. A better approach is to utilize the ‘build.cake’ script In terminal, which covers all building scenarios.

In terminal

Folder: ./

These are local machine or remote server building scenarios using build scripts, aka ‘build.cake’. In these scenarios, the following two commands should be run in a terminal from the project’s root folder:

dotnet tool restore && dotnet cake  # In Bash terminal
dotnet tool restore; dotnet cake  # In PowerShell terminal

Note: The default target task (“Default”) is “Build”, and output files will be stored in the ./artifacts directory.

To run a desired target task, you need to specify its name:

dotnet tool restore && dotnet cake --target=name  # In Bash terminal
dotnet tool restore; dotnet cake --target=name  # In PowerShell terminal

For example,

  • dotnet cake --target=Build
    

    It runs a local build, performing compilation and testing only.

  • dotnet cake --target=Version
    

    It checks the next version to be tagged in the Git repository during the next release, without performing compilation or testing tasks.

  • dotnet cake --target=CreateReleaseNotes
    

    It generates Release Notes artifacts in the /artifacts/Packages folder using the ReleaseNotes.md template file.

  • dotnet cake --target=Release
    

    It creates a release, consisting of the following steps: compilation, testing, generating release notes, creating .nupkg files, publishing NuGet packages, and finally, making a GitHub release.

Note 1: The building tools for the dotnet tool restore command are configured in the dotnet-tools.json file.

Note 2: Some targets (build tasks) require appropriate environment variables to be defined directly in the terminal session (aka secret tokens).

With Docker

Folder: ./docker

The best way to replicate the CI/CD process and build Ocelot locally is by using the Dockerfile.build file, which can be found in the ‘docker’ folder in the Ocelot root directory. For example, use the following command:

docker build --platform linux/amd64 -f ./docker/Dockerfile.build .

You may need to adjust the platform flag depending on your system.

Note: This approach is somewhat excessive, but it will work if you are a masterful Docker user. 🙂 The Ocelot team has not followed this approach since version 24.0, favoring With CI/CD-based builds and occasionally building In terminal instead.

With CI/CD

Folder: ./.github/workflows
Provider: GitHub Actions
Workflows: PR, Develop, Release
Dashboard: Workflow runs (Actions tab)

The Ocelot project utilizes GitHub Actions as a CI/CD provider, offering seamless integrations with the GitHub ecosystem and APIs. Starting from version 24.0, all pull requests, development commits, and releases are built using GitHub Actions workflows. There are three workflows: one for pull requests (PR), one for the develop branch (Develop), and one for the main branch (Release).

Note: Each workflow has a dedicated status badge in the Ocelot README: the Release Status button and the Development Status button, with the PR status being published directly in a pull request under the “Checks” tab.

The PR workflow will track code coverage using Coveralls. After opening a pull request or submitting a new commit to a pull request, Coveralls will publish a short message with the current code coverage once the top commit is built. Considering that Coveralls retains the entire history but does not fail the build if coverage falls below the threshold, all workflows have a built-in 80% threshold, applied internally within the build-cake job, particularly during the “Cake Build” step-action. If the code coverage of a newly opened pull request drops below the 80% threshold, the ‘build-cake’ job will fail, logging an appropriate message in the “Cake Build” step.

Note 1: There are special code coverage badges in Ocelot README: the Develop Coveralls Status button and the Release Coveralls Status button.

Note 2: The current code coverage of the Ocelot project is around 85-86%. The coverage threshold is subject to change in upcoming releases. All Coveralls builds can be viewed by navigating to the ThreeMammals/Ocelot project on Coveralls.io.

Documentation

Folder: ./docs
Dashboard: Ocelot app project

Documentation building is configured using the ‘.readthedocs.yaml’ integration file, which allows builds to run separately via the Read the Docs publisher. All build artifacts and document sources are located in the ‘docs’ folder. More details on the documentation build process can be found in the README.

Note 1: Documentation builds have a dedicated status badges in Ocelot README: the Develop ReadTheDocs Status button and the Release ReadTheDocs Status button.

Note: Documentation can be easily built locally in a terminal from the ‘docs’ folder by running the make.sh or make.bat scripts. The resulting documentation build files will be located in the ./docs/_build folder, with the HTML documentation specifically written to the ./docs/_build/html folder.

Testing

The tests should run and function correctly as part of the building process using the dotnet test command. You can also run them in Visual Studio IDE within the Test Explorer window. Depending on your build scenario, Ocelot testing can be performed as follows.

In IDE: Simply run tests via the Test Explorer window of Visual Studio IDE.

In terminal: There are two main approaches:

  1. Run the dotnet test command to perform all tests (unit, integration, and acceptance):

    dotnet test -f net8.0 ./Ocelot.sln
    

    Or run tests separately per project:

    dotnet test -f net8.0 ./test/Ocelot.UnitTests/Ocelot.UnitTests.csproj  # Unit tests only
    dotnet test -f net8.0 ./test/Ocelot.IntegrationTests/Ocelot.IntegrationTests.csproj  # Integration tests only
    dotnet test -f net8.0 ./test/Ocelot.AcceptanceTests/Ocelot.AcceptanceTests.csproj  # Acceptance tests only
    
  2. Run dotnet cake command: dotnet cake --target=Tests to perform all tests (unit, integration and acceptance). Or run tests separately per testing project:

    dotnet cake --target=UnitTests # unit tests only
    dotnet cake --target=IntegrationTests # integration tests only
    dotnet cake --target=AcceptanceTests # acceptance tests only
    

With Docker: This approach is not recommended. Instead, perform automated testing With CI/CD or opt for In terminal-based testing, which is a more advanced method.

With CI/CD: In GitHub Actions workflows, the testing process consists of separate testing steps, organized per job:

SSL certificate

To create a certificate for Testing, you can use OpenSSL:

  • Install the openssl package (if you are using Windows, download the binaries here).

  • Generate a private key:

    openssl genrsa 2048 > private.pem
    
  • Generate a self-signed certificate:

    openssl req -x509 -days 1000 -new -key private.pem -out public.pem
    
  • If needed, create a PFX file:

    openssl pkcs12 -export -in public.pem -inkey private.pem -out mycert.pfx