54

I've been working on a C# application and wanted to try the GitLab CI out. All I can see is Ruby and can't find any information on how to build a C# application using it.

When I run the test settings, I make the commit, but I don't have my build.

Enter image description here

How should I make a simple build? Which command could I use for that? I don't mind if I get a failed build (but a build).

2

6 Answers 6

54

I just wanted to share my .gitlab-ci.yml complete with unit testing. You will have to adjust your nuget and possibly other paths. This is for a single project in a solution of the same name.

variables:
  PROJECT_NAME: "ProjectNameGoesHere"
before_script:
  - echo "starting build for %PROJECT_NAME%"
  - echo "Restoring NuGet Packages..."
  - d:\tools\nuget restore "%PROJECT_NAME%.sln"
stages:
  - build
  - test
build:
  stage: build
  script:
  - echo "Release build..."
  - '"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\msbuild.exe" /consoleloggerparameters:ErrorsOnly /maxcpucount /nologo /property:Configuration=Release /verbosity:quiet "%PROJECT_NAME%.sln"'
  artifacts:
    untracked: true
test:
  stage: test
  script:
  - echo "starting tests"
  - cd %PROJECT_NAME%Tests/bin/Release
  - '"C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\MSTest.exe" /testcontainer:%PROJECT_NAME%Tests.dll'
  dependencies:
  - build
6
  • 4
    For those reading this comment, you have FIRST to configure your machine to be the runner. Follow the guide of Prasanth Louis below, and especially the link gitlab.com/gitlab-org/gitlab-ci-multi-runner/blob/master/docs/… (because there were updates). Only then you can use this .gitlab-ci.yml. Commented Dec 2, 2016 at 6:31
  • 1
    @corentin Thank you for including this. Yes and you will need visual studio installed on your build machine as I believe MSTest is part of it.
    – Jeff
    Commented Dec 6, 2016 at 19:07
  • 4
    Please consider submitting your example to the GitLab CI Yml project. Commented Jan 27, 2017 at 19:21
  • my project build successfully but removes all untracked files, including needed bin/ folders for testing.. something strange with artifacts: untracked: true?
    – fiorebat
    Commented Sep 3, 2018 at 15:43
  • 1
    @fiorebat If they are not tracked by git they should be added as per docs.gitlab.com/ee/ci/yaml/#artifacts-untracked If you are checking in dll files to git then you will have to tweak this or ask yourself why you are not pulling them from nugget.
    – Jeff
    Commented Sep 4, 2018 at 15:34
24

In order to build a C# application you should have a Windows runner (with shell executor) configured for a project in GitLab CI.

Your .gitlab-ci.yml file should look something like that:

stages:
  - build

job:
  stage: build
  script:
  - echo "Restoring NuGet Packages..."
  - '"c:\nuget\nuget.exe" restore "MySolution.sln"'
  - ''
  - echo "Release build..."
  - C:\Windows\Microsoft.NET\Framework64\v4.0.30319\msbuild.exe /consoleloggerparameters:ErrorsOnly /maxcpucount /nologo /property:Configuration=Release /verbosity:quiet "MySolution.sln"
  tags:
  except:
  - tags

On a Windows machine you need the following tools:

  • Runner installed
  • Git, added to PATH
  • Latest nuget.exe at C:\nuget (or somewhere else. Just make sure you got the path right in the .gitlab-ci.yml file)
7
  • I'm sorry, what do you mean with 'git, added to PATH'? Commented Dec 1, 2015 at 13:30
  • 2
    Got it, it's for Windows to know where git is located so the git can be executed as shell. Commented Dec 1, 2015 at 14:04
  • 2
    Your path to msbuild doesn't work if there is a space in it.
    – Jeremy
    Commented Dec 8, 2015 at 19:47
  • @grisha On gitlab.com there's not a shared windows runner available. The shared runner on gitlab.com has Docker, but Docker doesn't support (yet) windows containers.* Do you know of plans of Gitlab supporting a windows shared runner? *) Yes, Docker does support windows containers in a weird way, but only if Docker client runs on a windows machine, which to a certain extent defies the purpose.
    – gijswijs
    Commented May 29, 2016 at 18:52
  • @gijswijs There is installation instructions for windows available here. There are links to x86 and amd64 runners. Hope it helps.
    – Grisha
    Commented Jun 14, 2016 at 6:43
13

The other answers are good. But I'd like to explain how to install a runner in addition. I use my own local system (Windows), so I chose to run shell. But you could use a Docker image if you'd like.

cd C:\Multi-Runner
gitlab-ci-multi-runner register

Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com )
https://gitlab.com
Please enter the gitlab-ci token for this runner
xxx
Please enter the gitlab-ci description for this runner
my-runner
INFO[0034] fcf5c619 Registering runner... succeeded
Please enter the executor: shell, docker, docker-ssh, ssh?
shell
INFO[0037] Runner registered successfully. Feel free to start it, but if it's
running already the config should be automatically reloaded!

Source: https://gitlab.com/gitlab-org/gitlab-ci-multi-runner/blob/master/docs/install/windows.md

Afterwards, you can use a YAML file a like this:

stages:
    - build
job:
    stage: build
    script: '"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\msbuild.exe" "something.sln"'
1
11

Installing the build runner on a Windows machine helps a lot, and @prasanth-louis has a great example on how to do that.

As for the .gitlab-ci.yml file, you can simplify it even more by using Cake Build:

stages:
    - build
build:
    stage: build
    script:
        - .\build.ps1 -Target Build
    tags:
        - windows

And your build.cake file can look like this (based of the example repository):

#tool nuget:?package=NUnit.ConsoleRunner&version=3.4.0

var target = Argument("target", "Default");
var configuration = Argument("configuration", "Release");

var solution = "./example-project.sln";
var buildDir = Directory("./example-project/bin");

Task("Default")
    .IsDependentOn("Unit-Tests")
    .Does(() =>
{
    Information("Running Default task!");
});

Task("Clean")
    .Does(() =>
{
    CleanDirectory(buildDir);
});

Task("PackageRestore")
    .IsDependentOn("Clean")
    .Does(() =>
{
    Information("Restoring NuGet packages for {0}", solution);
    NuGetRestore(solution);
});

Task("Build")
    .IsDependentOn("PackageRestore")
    .Does(() =>
{
    Information("Restoring NuGet packages for {0}", solution);
    MSBuild(solution, settings => settings.SetConfiguration(configuration));
});

Task("Unit-Tests")
    .IsDependentOn("Build")
    .Does(() =>
{
    NUnit3("./example-project.Tests/**/bin/" + configuration + "/*.Tests.dll");
});

Task("Publish")
    .Does(() =>
{

});

RunTarget(target);
1
  • Cake is definitely the way to go especially if you are transitioning from TeamCity, Jenkins, etc. server that handled a lot of this stuff for you. Commented Jan 19, 2018 at 0:13
6

Here my working .gitlab-ci.yml file for c# application with NUnit as unit test framework and mono as basic image.

Not very fancy but working:

image: mono:latest

stages:
    - build
    - test

variables:
    solution: "Project.sln"
    test: "Project.Test"

before_script:
    - nuget restore

build:
    stage: build
    script:
        - msbuild /p:Configuration=Release $solution

test:
    stage: test
    script:
        - msbuild /p:Configuration=Release $solution
        - mono ./packages/NUnit.ConsoleRunner.3.10.0/tools/nunit3-console.exe ./$test/bin/Release/$test.dll
3

The other answers, while informative, miss a few crucial bits of info:

  • If you are targetting .net core 3.1, .net 5, .net 6 or any newer version then you can build and run your app on linux
  • If you are targetting .net framework (4.8 or below) then you have to build and run your code on a windows machine.

Now Gitlab runs build jobs using runners (aka build agents), that in turn use executors to specifiy the environment in which the build process happens. Runners can run on the Gitlab infrastructure (Saas runners), or can be installed on premise. There are several types of executors: docker, shell, custom, ...

Most of the gitlab build scripts that can be found around the internet assume a saas runner with a docker executor running on linux, which is based on a specific docker image. This won't work if you want to build your app on windows. For this, either install your own executor, as several other answers instruct to do, or use a windows saas runner which, although in beta, works fine even for production (we have been doing this for months without trouble). While installing your own runner can be useful, e.g. for debugging purposes, I find this defeats the whole purpose of building your software on a hosted cicd platform (github actions, gitlab ci, ...). For debugging, I prefer to base my build script on shell commands which can be run on your local dev box, which minimizes trial and error and makes installing your own runner superfluous.

To get started with a windows runner, see this exemple script. One or two gotchas that I went through:

  • You cannot choose the VM image of the build machine, it is managed by Gitlab and its content is not documented. This leaves you vulnerable to breaking changes if they decide to change their image.
  • Strangely, at the time of writing, the .net framework 4.8 developer pack is not installed on the windows executor image, but luckily chocolatey is, so if you target net48 you must install it in your before_script section.
  • The provisionning of the build machine is somewhat slower than a linux maching running docker, our builds average 15mn which we find acceptable.

That being said, here is a trimmed example based on our build scripts:

variables:
  MSBUILD_EXE: 'C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\MSBuild\Current\bin\msbuild.exe'
  UPDATE_VERSION: '.\path\to\Update-Version.ps1'
  APP_FOLDER: '.\path\to\Artifacts\_PublishedWebsites\MyApp\'
  
.windows_build_base:
  tags:
    - shared-windows
    - windows
    - windows-1809
  before_script:
    - Set-Variable -Name "time" -Value (date -Format "%H:%m")
    - echo ${time}
    - echo "started by ${GITLAB_USER_NAME}"
    - echo ".NET versions already installed"
    - Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*", "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*" 
      | Where {$_.DisplayName -like '*.NET*' -and $_.DisplayVersion -like '4.*'} 
      | Select-Object DisplayName, DisplayVersion
    - echo "Installing .NET 4.8 Developer Pack"
    - choco install netfx-4.8-devpack -y

stages:
  - build
  - publish

build:
  only:
   - prod
   - test
  extends:
    - .windows_build_base
  stage: build
  script:
    - nuget restore
    - '& "${UPDATE_VERSION}" -srcDir . | Set-Variable -Name VERSION' # capture output of UPDATE_PRODUCTINFO script in variable VERSION
    - echo "VERSION=${VERSION}"
    - Add-Content -Path app_version.env -Value "VERSION=${VERSION}" # store value of VERSION in dotenv file to be passed to dependent stages, as per this workaround https://gitlab.com/gitlab-org/gitlab/-/issues/212629#note_430278657
    - Get-Content app_version.env
    - '& "${MSBUILD_EXE}" /t:solution_path\to\MyApp /p:Configuration=Release /clp:Summary /verbosity:Minimal /p:OutDir=.\Artifacts'
  artifacts:
    expire_in: 1 day
    paths:
      - '${APP_FOLDER}'
    reports:
      dotenv: app_version.env

publish:
   only:
   - prod
   - test
   image: 
     name: octopusdeploy/octo
     entrypoint: [""]
   stage: publish
   dependencies:
    - build
   script:
     - echo "VERSION=$VERSION"
     - octo pack --id="MyApp" --format="zip" --version="$VERSION" --basePath="path/to/Artifacts/_PublishedWebsites/MyApp" --outFolder="/output/"
     - octo push --overwrite-mode="OverwriteExisting" --server="https://mycompany.octopus.app" --space "MyOctoSpace" --package="/output/MyApp.$VERSION.zip"

This script:

  1. Installs .net 4.8 dev pack
  2. Restores nuget packages
  3. Manually updates the software version and passes it between the build and publish stages
  4. Builds the app
  5. Packs and pushes it to octopus deploy
1
  • This is the only answer that explains how to build on windows without the need to install a runner on your own machine or on-prem hardware.
    – Nicolas
    Commented Jan 19, 2023 at 13:40

Not the answer you're looking for? Browse other questions tagged or ask your own question.