Microsoft Windows application
You can build and test a Microsoft Windows application using a Windows platform on Harness Cloud or a self-hosted Kubernetes cluster build infrastructure.
This guide assumes you've created a Harness CI pipeline. For more information about creating pipelines, go to the CI pipeline creation overview and the Harness Cloud pipeline tutorial.
If you don't have a Harness account yet, you can create one for free at app.harness.io.
Specify architecture
- Harness Cloud
- Self-hosted
stages:
- stage:
name: build
identifier: build
type: CI
spec:
cloneCodebase: true
platform:
os: Windows
arch: Amd64
runtime:
type: Cloud
spec: {}
There are several self-hosted build infrastructure options. This example uses a Kubernetes cluster build infrastructure. For instructions and important information, go to Run Windows builds in a Kubernetes cluster build infrastructure.
stages:
- stage:
name: build
identifier: build
description: ""
type: CI
spec:
cloneCodebase: true
infrastructure:
type: KubernetesDirect
spec:
connectorRef: YOUR_K8S_CLUSTER_CONNECTOR_ID
namespace: YOUR_K8S_NAMESPACE
automountServiceAccountToken: true
nodeSelector:
kubernetes.io/os: windows
os: Windows
Install dependencies
- Harness Cloud
- Self-hosted
Harness Cloud runners include pre-installed libraries and tools, and you can use Run steps to install additional dependencies or additional versions. For details about pre-installed tools and versions, go to Platforms and image specifications.
- step:
type: Run
identifier: dependencies
name: Dependencies
spec:
shell: Powershell
command: |-
dotnet add package Newtonsoft.json --version 12.0.1
You can use Run steps to install dependencies.
- step:
type: Run
identifier: dependencies
name: Dependencies
spec:
connectorRef: account.harnessImage
image: mcr.microsoft.com/dotnet/sdk:7.0
shell: Powershell
command: |-
dotnet add package Newtonsoft.json --version 12.0.1
Cache dependencies
Add caching to your Build (CI
) stage.
- Harness Cloud
- Self-hosted
Cache your Windows app dependencies with Cache Intelligence. Add caching to your stage.spec
and specify the paths
to cache:
- stage:
spec:
caching:
enabled: true
key: cache-{{ checksum "packages.lock.json" }}
paths:
- C:\%LocalAppData%\NuGet\Cache
sharedPaths:
- C:\%LocalAppData%\NuGet\Cache
With self-hosted build infrastructures, you can:
YAML example: Save and restore cache steps
Here's an example of a pipeline with Save Cache to S3 and Restore Cache from S3 steps.
steps:
- step:
type: RestoreCacheS3
name: Restore Cache From S3
identifier: Restore_Cache_From_S3
spec:
connectorRef: YOUR_AWS_CONNECTOR_ID
region: us-east-1
bucket: YOUR_S3_BUCKET
key: cache-{{ checksum "packages.lock.json" }}
archiveFormat: Tar
- step:
type: Run
...
- step:
type: BuildAndPushDockerRegistry
...
- step:
type: SaveCacheS3
name: Save Cache to S3
identifier: Save_Cache_to_S3
spec:
connectorRef: YOUR_AWS_CONNECTOR_ID
region: us-east-1
bucket: YOUR_S3_BUCKET
key: cache-{{ checksum "packages.lock.json" }}
sourcePaths:
- C:\%LocalAppData%\NuGet\Cache
archiveFormat: Tar
Build and run tests
Add Run steps to build and run your tests.
- Harness Cloud
- Self-hosted
- step:
type: Run
identifier: build_dotnet_app
name: Build DotNet App
spec:
shell: Powershell
command: |-
dotnet restore
dotnet build --no-restore
dotnet test C:\path\to\project.tests.csproj --no-build --verbosity normal
- step:
type: Run
identifier: build_dotnet_app
name: Build DotNet App
spec:
connectorRef: account.harnessImage
image: mcr.microsoft.com/dotnet/sdk:6.0
shell: Powershell
command: |-
dotnet restore
dotnet build --no-restore
dotnet test C:\path\to\project.tests.csproj --no-build --verbosity normal
For some languages, you can leverage Harness' Test Intelligence feature to reduce unit test time.
Visualize test results
You can view test results on the Tests tab of your pipeline executions. Test results must be in JUnit XML format.
For your pipeline to produce test reports, you need to modify the Run step that runs your tests. Make sure the command
generates JUnit XML reports and add the reports
specification.
If your test tool doesn't produce JUnit XML formatted reports by default, you can use a converter to output compatible JUnit XML reports, such as NUnit to JUnit or .NET trx2JUnit.
- Harness Cloud
- Self-hosted
- step:
type: Run
identifier: install_converter
name: install converter
spec:
shell: Powershell
command: |-
dotnet tool install -g trx2junit
export PATH="C:\Users\USER\.dotnet\tools"
- step:
type: Run
identifier: build_dotnet_app
name: Build DotNet App
spec:
shell: Powershell
command: |-
dotnet restore
dotnet build
dotnet test C:\path\to\project.tests.csproj --no-build --verbosity normal
trx2junit results.trx
reports:
type: JUnit
spec:
paths:
- results.xml
- step:
type: Run
identifier: install_converter
name: install converter
spec:
connectorRef: account.harnessImage
image: mcr.microsoft.com/dotnet/sdk:6.0
shell: Powershell
command: |-
dotnet tool install -g trx2junit
export PATH="C:\Users\USER\.dotnet\tools"
- step:
type: Run
identifier: build_dotnet_app
name: Build DotNet App
spec:
connectorRef: account.harnessImage
image: mcr.microsoft.com/dotnet/sdk:6.0
shell: Powershell
command: |-
dotnet restore
dotnet build
dotnet test C:\path\to\project.tests.csproj --no-build --verbosity normal
trx2junit results.trx
reports:
type: JUnit
spec:
paths:
- results.xml
Install Visual Studio
- Harness Cloud
- Self-hosted
Visual Studio 2019 Enterprise is pre-installed on Hosted Cloud runners. For details about all available tools and versions, go to Platforms and image specifications.
You can use a Run step to install a different version or edition of Visual Studio.
- step:
type: Run
identifier: install_vs2022
name: install vs2022
spec:
connectorRef: account.harnessImage
image: mcr.microsoft.com/windows/servercore:ltsc2019
shell: Powershell
command: |-
winget install --id Microsoft.VisualStudio.2022.Enterprise
If not already included on your build machine, you can specify a container image that has the necessary binaries or use a Run step to install Visual Studio.
- step:
type: Run
identifier: install_vs2022
name: install vs2022
spec:
connectorRef: account.harnessImage
image: mcr.microsoft.com/windows/servercore:ltsc2019
shell: Powershell
command: |-
winget install --id Microsoft.VisualStudio.2019.Enterprise
Specify shell
- Harness Cloud
- Self-hosted
In steps that allow you to supply your own commands, such as Run steps and Background steps, you specify the shell
in the step's settings.
- step:
type: Run
identifier: dotnet restore
name: dotnet restore
spec:
shell: Powershell ## Set to Bash, Powershell, Pwsh (PowerShell Core), Python, or Sh.
command: |- ## Enter your script as you would in a command line shell.
dotnet restore
Several shell binaries are pre-installed on Hosted Cloud runners, including Bash and PowerShell. For details about all available tools and versions, go to Platforms and image specifications.
You can also use Run steps to install different shell tools into the build environment, or specify a container image that has the necessary binaries for the command you want to run.
In steps that allow you to supply your own commands, such as Run steps and Background steps, you specify the shell
in the step's settings.
- step:
type: Run
identifier: build_dotnet_app
name: Build DotNet App
spec:
connectorRef: account.harnessImage
image: mcr.microsoft.com/dotnet/sdk:6.0
shell: Powershell ## Set to Bash, Powershell, Pwsh (PowerShell Core), Python, or Sh.
command: |- ## Enter your script as you would in a command line shell.
dotnet restore
You can also use Run steps to install different shell tools into the build environment, or specify a container image that has the necessary binaries for the command you want to run.
Setup .NET SDK
For details about building and testing .NET with Harness CI, including how to setup different versions of the .NET SDK, go to the C# (.NET Core) guide.
Full pipeline examples
The following full pipeline examples are based on the partial examples above.
- Harness Cloud
- Self-hosted
If you copy this example, replace the placeholder values with appropriate values for your code repo connector and repository name. Depending on your project and organization, you may also need to replace projectIdentifier
and orgIdentifier
.
pipeline:
name: default
identifier: default
projectIdentifier: default
orgIdentifier: default
tags: {}
properties:
ci:
codebase:
connectorRef: YOUR_CODE_REPO_CONNECTOR_ID
repoName: YOUR_REPO_NAME
build: <+input>
stages:
- stage:
name: build and test
identifier: build_and_test
type: CI
spec:
cloneCodebase: true
caching:
enabled: true
key: cache-{{ checksum "packages.lock.json" }}
paths:
- C:\%LocalAppData%\NuGet\Cache
execution:
steps:
- step:
type: Run
identifier: dependencies
name: Dependencies
spec:
shell: Powershell
command: |-
dotnet add package Newtonsoft.json --version 12.0.1
- step:
type: Run
identifier: install_converter
name: install converter
spec:
shell: Powershell
command: |-
dotnet tool install -g trx2junit
export PATH="C:\Users\USER\.dotnet\tools"
- step:
type: Run
identifier: build_dotnet_app
name: Build DotNet App
spec:
shell: Powershell
command: |-
dotnet restore
dotnet build
dotnet test C:\path\to\project.tests.csproj --no-build --verbosity normal
trx2junit results.trx
reports:
type: JUnit
spec:
paths:
- results.xml
sharedPaths:
- C:\%LocalAppData%\NuGet\Cache
platform:
os: Windows
arch: Amd64
runtime:
type: Cloud
spec: {}
If you copy this example, replace the placeholder values with appropriate values for your code repo connector, Kubernetes cluster connector, Kubernetes namespace, and repository name. Depending on your project and organization, you may also need to replace projectIdentifier
and orgIdentifier
.
pipeline:
name: default
identifier: default
projectIdentifier: default
orgIdentifier: default
properties:
ci:
codebase:
connectorRef: YOUR_CODE_REPO_CONNECTOR_ID
repoName: YOUR_REPO_NAME
build: <+input>
tags: {}
pipeline:
name: default
identifier: default
projectIdentifier: default
orgIdentifier: default
properties:
ci:
codebase:
connectorRef: YOUR_CODE_REPO_CONNECTOR_ID
repoName: YOUR_REPO_NAME
build: <+input>
tags: {}
stages:
- stage:
name: build and test
identifier: build_and_test
type: CI
spec:
cloneCodebase: true
execution:
steps:
- step:
type: RestoreCacheS3
name: Restore Cache From S3
identifier: Restore_Cache_From_S3
spec:
connectorRef: YOUR_AWS_CONNECTOR_ID
region: us-east-1
bucket: YOUR_S3_BUCKET
key: cache-{{ checksum "packages.lock.json" }}
archiveFormat: Tar
- step:
type: Run
identifier: dependencies
name: Dependencies
spec:
connectorRef: account.harnessImage
image: mcr.microsoft.com/dotnet/sdk:7.0
shell: Powershell
command: |-
dotnet add package Newtonsoft.json --version 12.0.1
- step:
type: Run
identifier: install_converter
name: install converter
spec:
connectorRef: account.harnessImage
image: mcr.microsoft.com/dotnet/sdk:6.0
shell: Powershell
command: |-
dotnet tool install -g trx2junit
export PATH="C:\Users\USER\.dotnet\tools"
- step:
type: Run
identifier: build_dotnet_app
name: Build DotNet App
spec:
connectorRef: account.harnessImage
image: mcr.microsoft.com/dotnet/sdk:6.0
shell: Powershell
command: |-
dotnet restore
dotnet build
dotnet test C:\path\to\project.tests.csproj --no-build --verbosity normal
trx2junit results.trx
reports:
type: JUnit
spec:
paths:
- results.xml
- step:
type: SaveCacheS3
name: Save Cache to S3
identifier: Save_Cache_to_S3
spec:
connectorRef: YOUR_AWS_CONNECTOR_ID
region: us-east-1
bucket: YOUR_S3_BUCKET
key: cache-{{ checksum "packages.lock.json" }}
sourcePaths:
- C:\%LocalAppData%\NuGet\Cache
archiveFormat: Tar
infrastructure:
type: KubernetesDirect
spec:
connectorRef: YOUR_K8S_CLUSTER_CONNECTOR_ID
namespace: YOUR_K8S_NAMESPACE
automountServiceAccountToken: true
nodeSelector:
kubernetes.io/os: windows
os: Windows
Next steps
Now that you have created a pipeline that builds and tests a Windows app, you could:
- Create triggers to automatically run your pipeline.
- Add steps to build and upload artifacts.
- Add a step to build and push an image to a Docker registry.