ci-cd
codewithmukesh/dotnet-claude-kit
CI/CD pipelines for .NET with GitHub Actions and Azure DevOps YAML workflows.
What is ci-cd?
Set up automated build, test, publish, and deploy pipelines for .NET applications using GitHub Actions or Azure DevOps. Use this skill when configuring continuous integration, automated testing, deployment workflows, or when working with pipeline-as-code patterns.
- GitHub Actions workflows for build, test, and format checking on every push
- Azure DevOps YAML pipelines with equivalent build and test stages
- Docker image building and publishing to container registries
- NuGet package packing and publishing workflows
- Service integration (PostgreSQL) for integration testing in CI
- Test result artifact collection and reporting
How to install ci-cd
npx skills add https://github.com/codewithmukesh/dotnet-claude-kit --skill ci-cdHow to use ci-cd
- 1.Choose GitHub Actions or Azure DevOps based on your repository platform
- 2.Copy the appropriate workflow YAML file (.github/workflows/ci.yml for GitHub Actions or azure-pipelines.yml for Azure DevOps) to your repository root
- 3.Configure environment variables (e.g., DOTNET_VERSION) to match your project requirements
- 4.Add any required secrets (e.g., NUGET_API_KEY, GITHUB_TOKEN) to your repository settings
- 5.Commit and push to trigger the pipeline on your main branch or pull requests
Use cases
- Setting up automated CI/CD for a .NET application on GitHub or Azure DevOps
- Publishing Docker images to a container registry on version tags
- Building and publishing NuGet packages to nuget.org
- Running integration tests against a PostgreSQL database in CI
- Enforcing code formatting checks before allowing merges
- Backend developers building .NET applications
- DevOps engineers setting up CI/CD pipelines
- Open source maintainers using GitHub
- Enterprise teams using Azure DevOps
- Teams deploying .NET services via Docker
ci-cd FAQ
No. Build once in Release configuration and deploy the same artifact to dev, staging, and production with different configuration values.
Use Azure DevOps Pipelines with azure-pipelines.yml. The flow is identical (restore → build → format → test), but task syntax differs (UseDotNet@2 instead of actions/setup-dotnet@v5).
Add a Pack step (dotnet pack) and Push step (dotnet nuget push) triggered on version tags, using a NUGET_API_KEY secret for authentication.
Yes. Define a service (e.g., PostgreSQL) in your workflow, pass connection strings via environment variables, and run tests against the service container.
Never. Use GitHub Secrets or Azure DevOps secret variables and reference them with ${{ secrets.NAME }} or $(SecretVariable) syntax.
Full instructions (SKILL.md)
Source of truth, from codewithmukesh/dotnet-claude-kit.
name: ci-cd description: > CI/CD pipelines for .NET applications. Covers GitHub Actions and Azure DevOps YAML pipelines with build, test, publish, and deploy stages. Load this skill when setting up continuous integration, automated testing, deployment workflows, or when the user mentions "CI/CD", "pipeline", "GitHub Actions", "Azure DevOps", "workflow", "deploy", "build pipeline", "publish", "NuGet push", "release", or "continuous integration".
CI/CD
Core Principles
- Pipeline as code — YAML pipelines committed to the repo. No click-ops in the UI.
- Fast feedback — Build and test on every push. Cache NuGet packages. Fail fast.
- Build once, deploy many — Build the artifact once, promote it through environments (dev → staging → production).
- Never skip tests — Tests gate the pipeline. No deployment without passing tests.
Patterns
GitHub Actions — Build + Test
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
env:
DOTNET_VERSION: '10.0.x'
DOTNET_NOLOGO: true
DOTNET_CLI_TELEMETRY_OPTOUT: true
jobs:
build-and-test:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:18
env:
POSTGRES_DB: testdb
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v5
- name: Setup .NET
uses: actions/setup-dotnet@v5
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
- name: Restore
run: dotnet restore
- name: Build
run: dotnet build --no-restore --configuration Release
- name: Format check
run: dotnet format --verify-no-changes --no-restore
- name: Test
run: dotnet test --no-build --configuration Release --logger trx --results-directory TestResults
env:
ConnectionStrings__Default: "Host=localhost;Database=testdb;Username=postgres;Password=postgres"
- name: Publish test results
uses: actions/upload-artifact@v5
if: always()
with:
name: test-results
path: TestResults/*.trx
GitHub Actions — Build + Publish Docker Image
# .github/workflows/publish.yml
name: Publish
on:
push:
tags: ['v*']
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v5
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract version from tag
id: version
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: |
ghcr.io/${{ github.repository }}:${{ steps.version.outputs.VERSION }}
ghcr.io/${{ github.repository }}:latest
Azure DevOps — Build + Test
Same restore → build → format → test flow as GitHub Actions. Key differences:
# azure-pipelines.yml
trigger:
branches:
include: [main]
paths:
exclude: ['*.md', docs/]
pool:
vmImage: 'ubuntu-latest' # vs runs-on: ubuntu-latest
variables:
dotnetVersion: '10.0.x'
# Key task differences from GitHub Actions:
# Setup .NET: task: UseDotNet@2 (inputs: version: $(dotnetVersion))
# Test results: task: PublishTestResults@2 (testResultsFormat: VSTest)
# Steps use `script:` + `displayName:` instead of `- name:` + `run:`
# Services (e.g., Postgres) require a separate Docker task or pipeline service connection
NuGet Package Publishing
# Part of GitHub Actions workflow
- name: Pack
run: dotnet pack src/MyLibrary -c Release -o ./nupkg --no-build
- name: Push to NuGet
run: dotnet nuget push ./nupkg/*.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json
Anti-patterns
Don't Build Different Artifacts per Environment
# BAD — building separately for each environment
- script: dotnet publish -c Debug # for dev
- script: dotnet publish -c Release # for prod
# GOOD — build once, deploy everywhere
- script: dotnet publish -c Release -o ./publish
# Then deploy the same ./publish artifact to dev, staging, prod
Don't Skip Format Checks in CI
# BAD — no format enforcement
steps:
- run: dotnet build
- run: dotnet test
# GOOD — format check catches style issues early
steps:
- run: dotnet build
- run: dotnet format --verify-no-changes
- run: dotnet test
Don't Hardcode Secrets in Pipelines
# BAD — secret in pipeline YAML
env:
DB_PASSWORD: "my-secret-password"
# GOOD — use pipeline secrets
env:
DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
Decision Guide
| Scenario | Recommendation |
|---|---|
| Open source project | GitHub Actions |
| Enterprise with Azure | Azure DevOps Pipelines |
| Docker deployment | Multi-stage build in CI, push to container registry |
| NuGet library | Build → Test → Pack → Push on tag |
| Database migrations | Run in CI test stage, script for production |
| Environment promotion | Same artifact, different configuration |
Related skills
More from codewithmukesh/dotnet-claude-kit and the wider catalog.

clean-architecture
4-layer .NET architecture with dependency inversion, domain-driven design, and use-case handlers.

code-review
MCP-powered multi-dimensional code review for .NET projects with blast-radius prioritization

configuration
Options pattern, secrets management, and environment-based configuration for .NET 10 applications.

container-publish
Containerize .NET 10 apps without writing a Dockerfile using SDK-native publishing.

convention-learner
Detect and enforce project-specific coding conventions by analyzing existing codebase patterns.

ddd
Domain-Driven Design tactical patterns for .NET: aggregates, value objects, domain events, and repositories.