# DevOps Engineer

Especialista em CI/CD, pipelines e automação de deploy.

## Responsabilidades

1. **Criar pipelines** de CI/CD para build e deploy
2. **Automatizar releases** para múltiplos ambientes
3. **Configurar testes** automatizados no pipeline
4. **Gerenciar ambientes** e variáveis

## Triggers

Keywords: `pipeline`, `ci/cd`, `deploy`, `release`, `azure devops`, `github actions`, `build`, `automation`

## Azure Pipelines (Azure DevOps)

### Pipeline YAML Completo

```yaml
# azure-pipelines.yml
trigger:
  branches:
    include:
      - main
      - develop
  paths:
    exclude:
      - '**/*.md'
      - '.gitignore'

pr:
  branches:
    include:
      - main
      - develop

variables:
  buildConfiguration: 'Release'
  dotnetVersion: '9.0.x'
  azureSubscription: 'Azure-Service-Connection'

stages:
  # Build Stage
  - stage: Build
    displayName: 'Build & Test'
    jobs:
      - job: BuildJob
        displayName: 'Build .NET App'
        pool:
          vmImage: 'ubuntu-latest'
        steps:
          - task: UseDotNet@2
            displayName: 'Install .NET SDK'
            inputs:
              version: '$(dotnetVersion)'

          - task: DotNetCoreCLI@2
            displayName: 'Restore packages'
            inputs:
              command: 'restore'
              projects: '**/*.csproj'

          - task: DotNetCoreCLI@2
            displayName: 'Build'
            inputs:
              command: 'build'
              projects: '**/*.csproj'
              arguments: '--configuration $(buildConfiguration) --no-restore'

          - task: DotNetCoreCLI@2
            displayName: 'Run Tests'
            inputs:
              command: 'test'
              projects: '**/tests/**/*.csproj'
              arguments: '--configuration $(buildConfiguration) --collect:"XPlat Code Coverage"'

          - task: PublishCodeCoverageResults@1
            displayName: 'Publish Coverage'
            inputs:
              codeCoverageTool: 'Cobertura'
              summaryFileLocation: '$(Agent.TempDirectory)/**/coverage.cobertura.xml'

          - task: DotNetCoreCLI@2
            displayName: 'Publish'
            inputs:
              command: 'publish'
              publishWebProjects: true
              arguments: '--configuration $(buildConfiguration) --output $(Build.ArtifactStagingDirectory)'

          - task: PublishBuildArtifacts@1
            displayName: 'Publish Artifacts'
            inputs:
              pathToPublish: '$(Build.ArtifactStagingDirectory)'
              artifactName: 'drop'

  # Deploy to Dev
  - stage: DeployDev
    displayName: 'Deploy to Dev'
    dependsOn: Build
    condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/develop'))
    jobs:
      - deployment: DeployToDev
        displayName: 'Deploy to Development'
        environment: 'development'
        pool:
          vmImage: 'ubuntu-latest'
        strategy:
          runOnce:
            deploy:
              steps:
                - task: AzureWebApp@1
                  displayName: 'Deploy to Container App'
                  inputs:
                    azureSubscription: '$(azureSubscription)'
                    appType: 'webAppContainer'
                    appName: 'myapp-dev'
                    deployToSlotOrASE: false

  # Deploy to Production
  - stage: DeployProd
    displayName: 'Deploy to Production'
    dependsOn: Build
    condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
    jobs:
      - deployment: DeployToProd
        displayName: 'Deploy to Production'
        environment: 'production'
        pool:
          vmImage: 'ubuntu-latest'
        strategy:
          runOnce:
            deploy:
              steps:
                - task: AzureWebApp@1
                  displayName: 'Deploy to Container App'
                  inputs:
                    azureSubscription: '$(azureSubscription)'
                    appType: 'webAppContainer'
                    appName: 'myapp-prod'
                    deployToSlotOrASE: true
                    slotName: 'staging'

                - task: AzureAppServiceManage@0
                  displayName: 'Swap Slots'
                  inputs:
                    azureSubscription: '$(azureSubscription)'
                    action: 'Swap Slots'
                    webAppName: 'myapp-prod'
                    sourceSlot: 'staging'
                    targetSlot: 'production'
```

### Pipeline com Docker

```yaml
# azure-pipelines-docker.yml
trigger:
  - main

variables:
  dockerRegistryServiceConnection: 'acr-connection'
  containerRegistry: 'myacr.azurecr.io'
  imageRepository: 'myapp'
  dockerfilePath: 'Dockerfile'
  tag: '$(Build.BuildId)'

stages:
  - stage: Build
    jobs:
      - job: BuildAndPush
        pool:
          vmImage: 'ubuntu-latest'
        steps:
          - task: Docker@2
            displayName: 'Build and push image'
            inputs:
              containerRegistry: '$(dockerRegistryServiceConnection)'
              repository: '$(imageRepository)'
              command: 'buildAndPush'
              Dockerfile: '$(dockerfilePath)'
              tags: |
                $(tag)
                latest

  - stage: DeployDev
    dependsOn: Build
    jobs:
      - deployment: Deploy
        environment: 'development'
        strategy:
          runOnce:
            deploy:
              steps:
                - task: AzureCLI@2
                  displayName: 'Update Container App'
                  inputs:
                    azureSubscription: 'Azure-Connection'
                    scriptType: 'bash'
                    scriptLocation: 'inlineScript'
                    inlineScript: |
                      az containerapp update \
                        --name myapp-dev \
                        --resource-group rg-myapp-dev \
                        --image $(containerRegistry)/$(imageRepository):$(tag)
```

## GitHub Actions

### Workflow Completo

```yaml
# .github/workflows/ci-cd.yml
name: CI/CD

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

env:
  DOTNET_VERSION: '9.0.x'
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup .NET
        uses: actions/setup-dotnet@v4
        with:
          dotnet-version: ${{ env.DOTNET_VERSION }}

      - name: Restore
        run: dotnet restore

      - name: Build
        run: dotnet build --configuration Release --no-restore

      - name: Test
        run: dotnet test --configuration Release --no-build --verbosity normal

      - name: Publish
        run: dotnet publish src/Web/Web.csproj -c Release -o ./publish

      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: app
          path: ./publish

  docker:
    needs: build
    runs-on: ubuntu-latest
    if: github.event_name == 'push'
    permissions:
      contents: read
      packages: write
    steps:
      - uses: actions/checkout@v4

      - name: Log in to Container Registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Build and push
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: |
            ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
            ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest

  deploy-dev:
    needs: docker
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/develop'
    environment: development
    steps:
      - name: Azure Login
        uses: azure/login@v2
        with:
          creds: ${{ secrets.AZURE_CREDENTIALS }}

      - name: Deploy to Container App
        uses: azure/container-apps-deploy-action@v1
        with:
          resourceGroup: rg-myapp-dev
          containerAppName: myapp-dev
          imageToDeploy: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}

  deploy-prod:
    needs: docker
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    environment: production
    steps:
      - name: Azure Login
        uses: azure/login@v2
        with:
          creds: ${{ secrets.AZURE_CREDENTIALS }}

      - name: Deploy to Container App
        uses: azure/container-apps-deploy-action@v1
        with:
          resourceGroup: rg-myapp-prod
          containerAppName: myapp-prod
          imageToDeploy: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
```

## Dockerfile

```dockerfile
# Dockerfile
FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base
WORKDIR /app
EXPOSE 8080

FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
WORKDIR /src

# Copy csproj and restore
COPY ["src/Web/Web.csproj", "src/Web/"]
COPY ["src/Application/Application.csproj", "src/Application/"]
COPY ["src/Domain/Domain.csproj", "src/Domain/"]
COPY ["src/Infrastructure/Infrastructure.csproj", "src/Infrastructure/"]
RUN dotnet restore "src/Web/Web.csproj"

# Copy everything and build
COPY . .
RUN dotnet build "src/Web/Web.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "src/Web/Web.csproj" -c Release -o /app/publish /p:UseAppHost=false

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .

# Non-root user
USER $APP_UID

ENTRYPOINT ["dotnet", "Web.dll"]
```

## Variáveis e Secrets

### Azure DevOps

```yaml
# Variable Groups
variables:
  - group: 'MyApp-Dev-Variables'  # Link to variable group

# Pipeline variables with secrets
variables:
  - name: 'SqlPassword'
    value: '$(SQL_PASSWORD)'  # From variable group or pipeline variables
```

### GitHub Actions

```yaml
# Using secrets
env:
  CONNECTION_STRING: ${{ secrets.CONNECTION_STRING }}

# Using environments
jobs:
  deploy:
    environment: production
    env:
      API_KEY: ${{ secrets.API_KEY }}  # Environment-specific secret
```

## Documentação de Referência

- [Azure Pipelines](https://learn.microsoft.com/en-us/azure/devops/pipelines/)
- [GitHub Actions](https://docs.github.com/en/actions)
- [YAML Schema](https://learn.microsoft.com/en-us/azure/devops/pipelines/yaml-schema/)
- [Container Apps Deploy](https://learn.microsoft.com/en-us/azure/container-apps/github-actions)

## Checklist de Pipeline

- [ ] Trigger configurado (branches, paths)
- [ ] Build com restore, build, test
- [ ] Publicação de artifacts
- [ ] Code coverage publicado
- [ ] Deploy para dev automático
- [ ] Deploy para prod com approval
- [ ] Secrets no Key Vault ou variable groups
- [ ] Dockerfile otimizado (multi-stage)
- [ ] Health check após deploy

---

*MORPH-SPEC by Polymorphism Tech*
