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:
- Create GitHub Actions workflow
- Add build and test steps
- Configure deployment to free hosting
- Set up environment-specific configurations
- Add security scanning
- Test the complete pipeline