Skip to main content
skill CX Codex

ci-cd · codewithmukesh — Claude Code skill: what it does, how to install

Generates CI/CD YAML pipelines for .NET projects. Useful when configuring GitHub Actions or Azure DevOps with build, test, format, and deployment stages.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add codewithmukesh/dotnet-claude-kit --skill ci-cd -a claude-code
Open on GitHub

What ci-cd does

This skill provides workflow patterns and rules for .NET continuous integration. It constructs pipelines for GitHub Actions and Azure DevOps, covering dependency restoration, Release builds, formatting checks with dotnet format --verify-no-changes, and test execution with TRX artifact reporting. In GitHub Actions workflows, it also configures a PostgreSQL 18 service container for integration tests.

The skill enforces building a single artifact that promotes across environments instead of compiling separate configurations for staging and production. It includes workflows for packaging and pushing libraries to NuGet via dotnet nuget push, as well as publishing Docker images to GitHub Container Registry (ghcr.io) triggered by Git version tags.

Plaintext secrets inside workflow YAML are explicitly flagged as bad practice. When targeting Azure DevOps instead of GitHub Actions, service containers require separate Docker tasks or pipeline service connections rather than a simple services block.

What it helps with

  • configure GitHub Actions workflows for .NET builds and tests
  • set up Azure DevOps pipelines with dotnet format checks
  • publish versioned Docker images to GitHub Container Registry
  • pack and release libraries to the NuGet gallery

Example prompts for the agent

  • Create a GitHub Actions CI pipeline for a .NET 10 web app with PostgreSQL tests
  • Set up an Azure DevOps YAML pipeline that builds and tests our .NET solution
  • Write a workflow to pack and push my library to NuGet on tag push

How to install ci-cd

1Skills CLI (Vercel)

npx skills add codewithmukesh/dotnet-claude-kit --skill ci-cd -a claude-code

2Manually: put the files in place

~/.claude/skills/ci-cd/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/ci-cd/

Step by step, with commands for each platform: How to install skills in Claude Code: five ways

Questions about ci-cd

How to install ci-cd in Claude Code?

Run npx skills add codewithmukesh/dotnet-claude-kit --skill ci-cd -a claude-code. The file will be installed to ~/.claude/skills/ci-cd/SKILL.md.

What does the ci-cd skill do?

It teaches the agent how to generate structured CI/CD YAML pipelines for .NET applications. It covers builds, testing, formatting checks, Docker container image pushes, and NuGet publishing for GitHub Actions and Azure DevOps.

How does integration testing differ between GitHub Actions and Azure DevOps here?

GitHub Actions uses native services definitions to spin up a PostgreSQL 18 container alongside the runner. Azure DevOps lacks that exact directive, so the workflow requires a dedicated Docker task or pipeline service connection.

Source text

SKILL.md · MIT
---
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

1. **Pipeline as code** — YAML pipelines committed to the repo. No click-ops in the UI.
2. **Fast feedback** — Build and test on every push. Cache NuGet packages. Fail fast.
3. **Build once, deploy many** — Build the artifact once, promote it through environments (dev → staging → production).
4. **Never skip tests** — Tests gate the pipeline. No deployment without passing tests.

## Patterns

### GitHub Actions — Build + Test

```yaml
# .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

```yaml
# .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:

```yaml
# 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

```yaml
# 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

```yaml
# 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

```yaml
# 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

```yaml
# 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 |

© codewithmukesh · MIT · codewithmukesh/dotnet-claude-kit

Similar skills

Everything for DevOps and infrastructure →

ci-cd by other authors comes first.

From the same set46

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor