CI/CD with GitHub Actions

Advanced 30 min read Lesson 5 of 5

What is CI/CD?

Continuous Integration (CI) and Continuous Deployment (CD) automate the process of building, testing, and deploying your applications. GitHub Actions provides a powerful platform for implementing CI/CD pipelines.

Key Benefits
  • Automated testing and building
  • Consistent deployment process
  • Faster release cycles
  • Reduced human error
  • Better code quality

GitHub Actions Basics

// Basic workflow structure
name: CI/CD Pipeline

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest
    
    steps:
      - name: Checkout code
        uses: actions/checkout@v3
      
      - name: Setup .NET
        uses: actions/setup-dotnet@v3
        with:
          dotnet-version: '10.0.x'
      
      - name: Restore dependencies
        run: dotnet restore
      
      - name: Build
        run: dotnet build --configuration Release --no-restore
      
      - name: Run tests
        run: dotnet test --configuration Release --no-build
      
      - name: Publish
        run: dotnet publish -c Release -o ./publish

Complete CI/CD Pipeline Example

# .github/workflows/deploy.yml
name: Deploy to Production

on:
  push:
    branches: [ main ]
  workflow_dispatch:  # Manual trigger

env:
  PROJECT_PATH: CSharpMasteryHub
  DOTNET_VERSION: '10.0.x'

jobs:
  test:
    name: Test
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3
      
      - name: Setup .NET
        uses: actions/setup-dotnet@v3
        with:
          dotnet-version: ${{ env.DOTNET_VERSION }}
      
      - name: Restore dependencies
        run: dotnet restore ${{ env.PROJECT_PATH }}
      
      - name: Build
        run: dotnet build ${{ env.PROJECT_PATH }} --configuration Release --no-restore
      
      - name: Run unit tests
        run: dotnet test ${{ env.PROJECT_PATH }}/Tests --configuration Release --no-build --verbosity normal
      
      - name: Run integration tests
        run: dotnet test ${{ env.PROJECT_PATH }}/IntegrationTests --configuration Release --no-build --verbosity normal

  build-and-deploy:
    name: Build and Deploy
    needs: test
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    
    steps:
      - name: Checkout
        uses: actions/checkout@v3
      
      - name: Setup .NET
        uses: actions/setup-dotnet@v3
        with:
          dotnet-version: ${{ env.DOTNET_VERSION }}
      
      - name: Restore dependencies
        run: dotnet restore ${{ env.PROJECT_PATH }}
      
      - name: Build
        run: dotnet build ${{ env.PROJECT_PATH }} --configuration Release --no-restore
      
      - name: Publish
        run: dotnet publish ${{ env.PROJECT_PATH }} -c Release -o ./publish
      
      - name: Upload artifacts
        uses: actions/upload-artifact@v3
        with:
          name: published-app
          path: ./publish
      
      # Deploy to Azure
      - name: Deploy to Azure
        if: github.ref == 'refs/heads/main'
        uses: azure/webapps-deploy@v2
        with:
          app-name: 'csharpmasteryhub'
          publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }}
          package: ./publish
      
      # Deploy to GitHub Pages
      - name: Deploy to GitHub Pages
        if: github.ref == 'refs/heads/main'
        uses: peaceiris/actions-gh-pages@v3
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: ./publish/wwwroot
          force_orphan: true

Environment-Specific Deployment

# .github/workflows/deploy-env.yml
name: Deploy to Environment

on:
  push:
    branches: 
      - dev
      - staging
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest
    
    steps:
      - uses: actions/checkout@v3
      
      - name: Setup .NET
        uses: actions/setup-dotnet@v3
        with:
          dotnet-version: '10.0.x'
      
      - name: Build and Publish
        run: |
          dotnet restore
          dotnet build --configuration Release
          dotnet publish -c Release -o ./publish
      
      - name: Deploy to Development
        if: github.ref == 'refs/heads/dev'
        run: echo "Deploying to development environment"
      
      - name: Deploy to Staging
        if: github.ref == 'refs/heads/staging'
        run: echo "Deploying to staging environment"
      
      - name: Deploy to Production
        if: github.ref == 'refs/heads/main'
        run: echo "Deploying to production environment"

Testing in CI/CD

# Unit test workflow
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Setup .NET
        uses: actions/setup-dotnet@v3
        with:
          dotnet-version: '10.0.x'
      
      - name: Run unit tests
        run: |
          dotnet test Tests/UnitTests --configuration Release
      
      - name: Run integration tests
        run: |
          dotnet test Tests/IntegrationTests --configuration Release
      
      - name: Run code coverage
        run: |
          dotnet test Tests/UnitTests --collect:"XPlat Code Coverage"
      
      - name: Upload coverage reports
        uses: codecov/codecov-action@v3

Security Checks

# Security scanning workflow
jobs:
  security:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Run security scan
        uses: dotnet/security@v1
      
      - name: Scan for vulnerabilities
        run: |
          dotnet restore
          dotnet list package --vulnerable
      
      - name: Run SAST
        uses: github/codeql-action/analyze@v2

Database Migration in CI/CD

# Database migration step
jobs:
  migrate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Setup .NET
        uses: actions/setup-dotnet@v3
        with:
          dotnet-version: '10.0.x'
      
      - name: Install EF Core tools
        run: dotnet tool install --global dotnet-ef
      
      - name: Apply migrations
        run: |
          dotnet ef database update --connection "${{ secrets.DB_CONNECTION_STRING }}"

Complete Workflow with Secrets

# Using GitHub Secrets
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Setup .NET
        uses: actions/setup-dotnet@v3
        with:
          dotnet-version: '10.0.x'
      
      - name: Build and Publish
        run: |
          dotnet restore
          dotnet build --configuration Release
          dotnet publish -c Release -o ./publish
      
      - name: Deploy to Azure
        uses: azure/webapps-deploy@v2
        with:
          app-name: ${{ secrets.AZURE_APP_NAME }}
          publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }}
          package: ./publish
      
      - name: Send notification
        uses: actions/slack@v1
        with:
          channel: '#deployments'
          message: 'Deployment completed successfully!'
          webhook: ${{ secrets.SLACK_WEBHOOK }}
Key Takeaway
  • GitHub Actions provides powerful CI/CD capabilities
  • Automate building, testing, and deployment
  • Use environment-specific configurations
  • Implement security scanning and testing
Exercise

Set up CI/CD for your project:

  1. Create GitHub Actions workflow
  2. Add build and test steps
  3. Configure deployment to free hosting
  4. Set up environment-specific configurations
  5. Add security scanning
  6. Test the complete pipeline
Test Your Knowledge - Take Quiz