Pipeline com SonarQubeCloud + Slack

João ChiroliJoão Chiroli
6 min read

Laboratório 3 – SonarQubeCloud + ESLint + Prettier e Slack

  • Análise estática com SonarQube/SonarCloud

  • Integração de ESLint + Prettier na pipeline

  • Bloquear PRs com cobertura < 50%

  • Notificações no Teams/Slack

  • Tópicos cobertos: SAST, Code Smells, Cobertura de testes, Notificações

Pré requisitos

1️⃣ Step 1: Ponto de partida azure-pipelines.yml

  • Iremos criar uma variável para workingDirectory: '$(Build.SourcesDirectory)/assessment-cc-sre-kubernetes-sr-01/codebase/rdicidr-0.1.0' deixando assim a pipeline mais clean

  • E vamos comentar todo o stage 2 porque não iremos utiliza-lo agora

trigger:
  branches:
    include:
    -  main

pr:
  branches:
    include:
    -  main

variables:
  workingDirectory: '$(Build.SourcesDirectory)/assessment-cc-sre-kubernetes-sr-01/codebase/rdicidr-0.1.0'


stages:

# 1️⃣ Instala, Valida e Publica o Código

  - stage: InstallAndValidate
    displayName: Install And Validate
    pool: 
      vmImage: 'ubuntu-latest'
    jobs:
    - job: InstallAndValidate
      displayName: 'InstallAndValidate'
      steps:
      - checkout: self
        displayName: 'Checkout code'

      - task: UseNode@1
        inputs:
          version: '15.x'
        displayName: 'Install Node.js'

      - script: npm ci
        workingDirectory: '$(workingDirectory)'
        displayName: 'Install dependencies with ci'

      - script: npm run lint
        workingDirectory: '$(workingDirectory)'
        displayName: 'Linter (ESLint)'      

      - script: |
          npm install --save-dev prettier
          npm run prettier
        workingDirectory: '$(workingDirectory)'
        displayName: 'Formatter (Prettier)'
        continueOnError: 'true'

      - script: npm test 
        workingDirectory: '$(workingDirectory)'
        displayName: 'Run Tests with Coverage'

      - task: PublishPipelineArtifact@1
        inputs:
          targetPath: '$(workingDirectory)'
          artifact: 'validated-source'
          publishLocation: 'pipeline'
        displayName: 'Validated Source'


# # 2️⃣ Builda e publica a imagem no Acr

#   - stage: BuildAndPackage
#     displayName: Build And Package
#     dependsOn: InstallAndValidate
#     condition: succeeded()
#     pool: 
#       vmImage: 'ubuntu-latest'
#     jobs:
#     - job: BuildAndPackage
#       displayName: 'BuildAndPackage'
#       steps:
#       - task: DownloadPipelineArtifact@2
#         inputs:
#           artifactName: 'validated-source'
#           targetPath: '$(Pipeline.Workspace)/validated-source'

#       - task: AzureCLI@2
#         inputs:
#           azureSubscription: 'projeto-user-arm'
#           scriptType: 'bash'
#           scriptLocation: 'inlineScript'
#           inlineScript: | 
#             az acr login --name acrplaygroundproject         
#             docker build -t acrplaygroundproject.azurecr.io/playgroundgapp:$(Build.BuildId) $(Pipeline.Workspace)/validated-source
#             docker push acrplaygroundproject.azurecr.io/playgroundgapp:$(Build.BuildId)
#         displayName: 'Build and Push Docker Image'

2️⃣Step 2: Adicionando o SonarQubeCloud na pipeline e alterando Dockerfile

  • Nessa step além de colocar o sonarqube na nossa pipeline iremos:

    • Comentar o ruin build

    • O Sonar pra funcionar corretamente é preciso acrescentar 3 tasks novas:

      • task:SonarCloudPrepare@3 precisa estar no começo da pipeline

      • task:SonarCloudAnalyze@3 e task:SonarCloudPublish@3 devem estar na fase final da pipeline

    • Vamos acresentar o parâmetro fetchDepth: 0 logo após do parâmetro steps:

      •   jobs:
              - job: InstallAndValidate
                displayName: 'InstallAndValidate'
                steps:
                - checkout: self
                  fetchDepth: 0 
                  displayName: 'Checkout code'
        
    • Também vamos ajustar a task de testes para que, ao executá-lo, seja gerado um arquivo de cobertura (coverage). Esse arquivo será enviado ao SonarQube para análise dos dados. Além disso, definiremos um limiar mínimo (threshold) de cobertura para garantir a qualidade do código.

  • Nessa etapa também iremos alterar o Dockerfile que está na raiz do projeto, iremos fazer o build usando o Dockerfile e não na pipeline como foi feito nos últimos laboratórios, agora ele terá a seguinte estrutura:

    •   FROM node:15 AS builder
        WORKDIR /app
        COPY . .
        RUN npm ci --ignore-scripts && npm run build
      
        FROM node:15
        WORKDIR /app
        COPY --from=builder /app .
        RUN npm ci --ignore-scripts --omit=dev 
        EXPOSE 3000
        CMD ["npm", "start"]
      
  • Como ficou o azure-pipelines.yml:

    ```yaml trigger: branches: include:

    • main

      pr: branches: include:

    • main

      variables: workingDirectory: '$(Build.SourcesDirectory)/assessment-cc-sre-kubernetes-sr-01/codebase/rdicidr-0.1.0'

stages:

1️⃣ Instala, Valida e Publica o Código

  • stage: InstallAndValidate displayName: Install And Validate pool: vmImage: 'ubuntu-latest' jobs:

    • job: InstallAndValidate displayName: 'InstallAndValidate' steps:

      • checkout: self fetchDepth: 0 displayName: 'Checkout code'

      • task: UseNode@1 inputs: version: '15.x' displayName: 'Install Node.js'

      • task: SonarCloudPrepare@3 inputs: SonarQube: 'projeto-user-sonar' organization: 'joaochiroli123' scannerMode: 'cli' configMode: 'manual' cliProjectKey: 'joaochiroli123_Projeto-Pessoal' cliProjectName: 'Projeto Pessoal' cliSources: '.' extraProperties: | extraProperties: | sonar.qualitygate.wait=true
        sonar.javascript.lcov.reportPaths=$(workingDirectory)/coverage/lcov.info

      • script: npm ci workingDirectory: '$(workingDirectory)' displayName: 'Install dependencies with ci'

      • script: npm run lint workingDirectory: '$(workingDirectory)' displayName: 'Linter (ESLint)'

      • script: | npm install --save-dev prettier npm run prettier workingDirectory: '$(workingDirectory)' displayName: 'Formatter (Prettier)' continueOnError: 'true'

  • script: npm test -- --coverage --watchAll=false --coverageThreshold='{"global":{"lines":50}}' workingDirectory: '$(workingDirectory)' displayName: 'Run Tests with Coverage' env: CI: true
  • task: PublishCodeCoverageResults@2 inputs: codeCoverageTool: 'Clover' summaryFileLocation: '$(workingDirectory)/coverage/clover.xml' reportDirectory: '$(workingDirectory)/coverage'
  • task: SonarCloudAnalyze@3 inputs: jdkversion: 'JAVA_HOME_17_X64'
  • task: SonarCloudPublish@3 inputs: pollingTimeoutSec: '300'

  • task: PublishPipelineArtifact@1 inputs: targetPath: '$(workingDirectory)' artifact: 'validated-source' publishLocation: 'pipeline' displayName: 'Validated Source' ```

    • Após a execução da pipeline podemos verficar no SonarQube que algumas métricas já começam a aparecer

3️⃣Step 3: Integração com Slack

  • Após criação da sua conta → Vá em canais e crie um projeto

  • No canto superior direito vá até os 3 pontos → clique em editar configurações

  • Ao abrir Editar configurações → Clique em integrações → Adicionar Apps e procure por Azure Devops Pipelines

    • Agora você precisa interagir com o bot usando /azrepos signin para fazer a conexão entre sua pipeline e o slack

    • Screenshot of Sign in prompt for Slack.

    • Selecione sign in → copie o código que vai aparecer pra você → use este código em enter code

  • Agora é preciso fazer um ajuste nas politicas da organização do Azure Devops para que essa integração realmente funcione então siga os passos abaixo:

    • Entre na sua organização (https://dev.azure.com/{yourorganization}).

    • Selecione Organization settings.

      • Deixe as configurações seguindo esta estrutura:

    • Agora basta executar sua pipeline que seu slack vai começar a receber as notificações:

4️⃣Step 4: Pipeline final azure-pipelines.yml

    trigger:
      branches:
        include:
        -  main

    pr:
      branches:
        include:
        -  main

    variables:
      workingDirectory: '$(Build.SourcesDirectory)/assessment-cc-sre-kubernetes-sr-01/codebase/rdicidr-0.1.0'


    stages:

    # 1️⃣ Instala, Valida e Publica o Código

      - stage: InstallAndValidate
        displayName: Install And Validate
        pool: 
          vmImage: 'ubuntu-latest'
        jobs:
        - job: InstallAndValidate
          displayName: 'InstallAndValidate'
          steps:
          - checkout: self
            fetchDepth: 0 
            displayName: 'Checkout code'

          - task: UseNode@1
            inputs:
              version: '15.x'
            displayName: 'Install Node.js'

          - task: SonarCloudPrepare@3
            inputs:
              SonarQube: 'projeto-user-sonar'
              organization: 'joaochiroli123'
              scannerMode: 'cli'
              configMode: 'manual'
              cliProjectKey: 'joaochiroli123_Projeto-Pessoal'
              cliProjectName: 'Projeto Pessoal'
              cliSources: '.'
              extraProperties: |
                extraProperties: |
                  sonar.qualitygate.wait=true            
                  sonar.javascript.lcov.reportPaths=$(workingDirectory)/coverage/lcov.info

          - script: npm ci
            workingDirectory: '$(workingDirectory)'
            displayName: 'Install dependencies with ci'

          - script: npm run lint
            workingDirectory: '$(workingDirectory)'
            displayName: 'Linter (ESLint)'      

          - script: |
              npm install --save-dev prettier
              npm run prettier
            workingDirectory: '$(workingDirectory)'
            displayName: 'Formatter (Prettier)'
            continueOnError: 'true'


          - script: npm test -- --coverage --watchAll=false  --coverageThreshold='{"global":{"lines":50}}'
            workingDirectory: '$(workingDirectory)'
            displayName: 'Run Tests with Coverage'
            env:
              CI: true


          - task: PublishCodeCoverageResults@2
            inputs:
              codeCoverageTool: 'Clover'
              summaryFileLocation: '$(workingDirectory)/coverage/clover.xml'
              reportDirectory: '$(workingDirectory)/coverage'


          - task: SonarCloudAnalyze@3
            inputs:
              jdkversion: 'JAVA_HOME_17_X64'


          - task: SonarCloudPublish@3
            inputs:
              pollingTimeoutSec: '300'

          - task: PublishPipelineArtifact@1
            inputs:
              targetPath: '$(workingDirectory)'
              artifact: 'validated-source'
              publishLocation: 'pipeline'
            displayName: 'Validated Source'


    # 2️⃣ Builda e publica a imagem no Acr

      - stage: BuildAndPackage
        displayName: Build And Package
        dependsOn: InstallAndValidate
        condition: succeeded()
        pool: 
          vmImage: 'ubuntu-latest'
        jobs:
        - job: BuildAndPackage
          displayName: 'BuildAndPackage'
          steps:
          - task: DownloadPipelineArtifact@2
            inputs:
              artifactName: 'validated-source'
              targetPath: '$(Pipeline.Workspace)/validated-source'

          - task: AzureCLI@2
            inputs:
              azureSubscription: 'projeto-user-arm'
              scriptType: 'bash'
              scriptLocation: 'inlineScript'
              inlineScript: | 
                az acr login --name acrplaygroundproject         
                docker build -t acrplaygroundproject.azurecr.io/playgroundgapp:$(Build.BuildId) $(Pipeline.Workspace)/validated-source
                docker push acrplaygroundproject.azurecr.io/playgroundgapp:$(Build.BuildId)
            displayName: 'Build and Push Docker Image'
0
Subscribe to my newsletter

Read articles from João Chiroli directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

João Chiroli
João Chiroli