.NET CI/CD Workflows
Generated by dotnet-ci-library, which is composed by all three .NET service archetypes:
dotnet-rest-service-archetypedotnet-grpc-service-archetypedotnet-graphql-service-archetype
The protocol has no effect on the pipeline - all three render the same two workflow files.
Build Workflow
.github/workflows/build.yaml, shown as rendered for a project named billing-service:
name: Build
on:
push:
branches: ["**"]
pull_request:
permissions:
contents: write
id-token: write
env:
IMAGE_NAME: billing-service
APPLICATION_NAME: billing-service
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: p6m-actions/dotnet-setup@v1
- name: Cut Patch Version
if: github.ref_name == 'main'
id: cut-patch
uses: p6m-actions/dotnet-cut-tag@v1
with:
version-level: patch
- name: Build .NET Application
uses: p6m-actions/dotnet-build@v1
with:
run-tests: true
publish-artifacts: ${{ github.ref_name == 'main' }}
# ... shared container build, release and dispatch steps
Step Chain
| # | Step | Scope | Runs on |
|---|---|---|---|
| 1 | Checkout | Shared | Always |
| 2 | .NET setup | .NET | Always |
| 3 | Cut Patch Version | .NET | main |
| 4 | Build .NET Application | .NET | Always |
| 5 | Login to Artifactory Container Registry | Shared | main |
| 6 | Set up Docker Buildx | Shared | Always |
| 7 | Build and Publish Docker Image | Shared | Always |
| 8 | Make Artifacts | Shared | main |
| 9 | Create Github release | Shared | main |
| 10 | Update Application Manifest | Shared | main |
.NET is the only language whose build step takes a branch-dependent input: build artifacts are published as a workflow artifact on main and not on feature branches.
Language-Specific Steps
.NET Setup
- uses: p6m-actions/dotnet-setup@v1
p6m-actions/dotnet-setup installs the .NET SDK and restores NuGet packages with caching.
| Input | Default | Passed by the workflow |
|---|---|---|
dotnet-version | 8.0.x | (default) |
global-json-file | (unset) | (default) |
cache | true | (default) - NuGet package caching |
install-dependencies | true | (default) - runs dotnet restore |
| Output | Description |
|---|---|
dotnet-version | The installed SDK version |
cache-hit | Whether the NuGet cache was restored |
nuget-cache-dir | Path to the NuGet cache |
The workflow does not pin dotnet-version. If your project targets a different SDK, either add a global.json at the repository root (and pass global-json-file) or set dotnet-version explicitly, so CI and the production Dockerfile agree.
Cut Patch Version
- name: Cut Patch Version
if: github.ref_name == 'main'
id: cut-patch
uses: p6m-actions/dotnet-cut-tag@v1
with:
version-level: patch
p6m-actions/dotnet-cut-tag bumps the version in Directory.Build.props, commits, and creates a git tag.
| Input | Required | Value |
|---|---|---|
version-level | No | patch in build.yaml; the dispatch input in cut-tag.yaml |
directory-build-props-path | No | Directory.Build.props (default) |
commit-changes | No | true (default) |
commit-message | No | Bump version to {version} [skip ci] (default) |
skip-push | No | false (default) |
| Output | Description |
|---|---|
version | The new version, e.g. 1.4.2 |
tag | The created git tag |
The action runs p6m-actions/token-exchange@v2 first, which authenticates the push as p6m-ybor[bot] and installs the [skip ci] commit hook. The default commit message also carries [skip ci] explicitly, so the bump is protected twice over.
Build .NET Application
- name: Build .NET Application
uses: p6m-actions/dotnet-build@v1
with:
run-tests: true
publish-artifacts: ${{ github.ref_name == 'main' }}
p6m-actions/dotnet-build restores, builds, optionally tests, and optionally uploads the publish output.
| Input | Default | Value in the workflow |
|---|---|---|
run-tests | true | true (explicit) |
publish-artifacts | false | ${{ github.ref_name == 'main' }} (explicit) |
dotnet-version | 8.0 | (default) |
solution-path | . | (default) |
configuration | Release | (default) |
collect-coverage | false | (default) |
artifact-name | dotnet-build-artifacts | (default) |
verbosity | minimal | (default) |
test-filter | (empty) | (default) - all tests run |
| Output | Description |
|---|---|
build-version | The version of the built application |
test-results | Test execution summary |
coverage-report | Coverage percentage, only when collect-coverage is enabled |
None of these outputs are consumed by the generated workflow - the version that reaches the release and the image tag comes from cut-patch, not from build-version.
publish-artifacts and the container image are independentThe workflow artifact uploaded on main is a convenience for inspecting build output from the Actions UI. The container image is built separately from .platform/docker/prd/Dockerfile and does not consume it.
Cut Tag Workflow
.github/workflows/cut-tag.yaml:
name: Cut Tag
on:
workflow_dispatch:
inputs:
version-level:
description: "Version bump level"
required: true
default: "patch"
type: choice
options:
- patch
- minor
- major
permissions:
id-token: write
contents: write
jobs:
cut-tag:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- uses: p6m-actions/dotnet-setup@v1
- uses: p6m-actions/dotnet-cut-tag@v1
with:
version-level: ${{ inputs.version-level }}
| Input | version-level - patch, minor, or major |
| Outputs | A [skip ci] version bump commit in Directory.Build.props and a git tag, both pushed |
Version File
Directory.Build.props at the repository root is the source of truth, so every project in the solution shares one version:
<Project>
<PropertyGroup>
<Version>1.4.2</Version>
</PropertyGroup>
</Project>
Related
- CI/CD Workflows - the shared steps and the CD handoff
- .NET Actions - the wider .NET action catalog
- .NET Setup Guide - local development environment