Modernizar o desenvolvimento de software com integração contínua

À medida que o código é desenvolvido, atualizado ou até mesmo removido, ter um método intuitivo e seguro para integrar essas alterações ao branch de código principal permite que os desenvolvedores forneçam valor.

Como desenvolvedor, você pode fazer pequenas alterações de código, enviar essas alterações para um repositório de código e obter feedback quase instantâneo sobre a qualidade, cobertura de teste e bugs introduzidos. Esse processo permite que você trabalhe mais rápido, com mais confiança e menos risco.

A CI (integração contínua) é uma prática em que os sistemas de controle do código-fonte e os pipelines de implantação de software são integrados para fornecer mecanismos automatizados de build, teste e feedback para equipes de desenvolvimento de software.

O processo de integração contínua começa quando um engenheiro cria uma solicitação de pull do GitHub para sinalizar ao sistema de CI que as alterações de código estão prontas para serem integradas. Idealmente, o processo de integração valida o código em relação a várias linhas de base e testes. Em seguida, ele fornece feedback ao engenheiro solicitante sobre o status desses testes.

Se as verificações da base de referência e o teste forem bem-sucedidos, o processo de integração produzirá e organizará ativos que implantarão o software atualizado. Esses ativos incluem código compilado e imagens de contêiner.

A integração contínua pode ajudar você a fornecer software de alta qualidade mais rapidamente, executando as seguintes ações:

  • Execute testes automatizados no código para fornecer detecção precoce de alterações de ruptura.
  • Executa análise de código para garantir padrões de código, qualidade e configuração.
  • Execute verificações de conformidade e segurança para garantir que o software não tenha vulnerabilidades conhecidas.
  • Executa testes de aceitação ou funcionais para garantir que o software funcione conforme o esperado.
  • Fornece feedback rápido sobre os problemas detectados.
  • Quando aplicável, produz ativos ou pacotes implantáveis que incluem o código atualizado.

Terminologia

Antes de começar a implementar a integração contínua, familiarize-se com esses termos-chave.

Term Definição
Artefato Uma saída implantável do processo de build, como código compilado, imagens de contêiner ou pacotes de implantação.
Teste automatizado Um teste que é executado automaticamente como parte do pipeline de CI para validar a qualidade do código e detectar problemas sem intervenção manual.
Construir O processo que compila o código-fonte, executa testes e produz artefatos para implantação.
Agente de build Um recurso de computação auto-hospedado ou hospedado na nuvem que executa as tarefas e operações em um pipeline de CI.
CI (Integração contínua) Uma prática que integra sistemas de controle do código-fonte com pipelines automatizados para criar, testar e validar alterações de código automaticamente.
Pipeline de CI Um fluxo de trabalho automatizado que cria, testa e valida alterações de código quando os desenvolvedores se comprometem com o controle do código-fonte.
Teste de integração Um teste que valida como diferentes componentes ou serviços funcionam juntos, geralmente mais abrangente do que os testes de unidade.
Compilação noturna Um build agendado que é executado em intervalos regulares (normalmente durante a noite) para executar conjuntos de testes de execução prolongada, como testes de integração e de interface do usuário.
Solicitação de pull Uma solicitação para mesclar alterações de código de um branch para outro. Aciona o pipeline de Integração Contínua para validar as alterações que foram propostas antes da integração.
Compilação de versão Um build abrangente que inclui compilação, testes, documentação, relatórios de conformidade e assinatura. Produz a versão final para implantação de produção.
Controle do código-fonte Um sistema que rastreia e gerencia alterações no código ao longo do tempo. Exemplos incluem Git, Azure Repos e GitHub.
Selo de status Um indicador visual (normalmente uma imagem) que exibe o estado atual de builds ou testes, geralmente mostrado na documentação do repositório.
TDD (desenvolvimento controlado por teste) Uma prática de desenvolvimento em que os desenvolvedores gravam testes antes de escrever o código que satisfaz esses testes.
Teste de unidade Um teste que valida funções ou componentes individuais isoladamente para garantir que eles se comportem conforme o esperado.

Automatizar a integração contínua com pipelines

Para obter integração contínua, use soluções de software para gerenciar, integrar e automatizar o processo. Uma prática comum é usar um pipeline de integração contínua.

Um pipeline de integração contínua envolve um software (geralmente hospedado na nuvem) que fornece:

  • Uma plataforma para executar testes automatizados.
  • Verificações de conformidade.
  • Relatório.
  • Todos os outros componentes que compõem o processo de integração contínua.

Na maioria dos casos, o software de pipeline é anexado ao controle do código-fonte, de modo que, quando as solicitações de pull são criadas ou o software é mesclado em um branch específico, o pipeline de integração contínua é executado. A integração do controle do código-fonte também oferece a oportunidade de fornecer feedback de CI diretamente nas solicitações de pull.

Muitas soluções, como Azure Pipelines ou GitHub Actions, fornecem os recursos de pipelines de integração contínua.

Integrar pipelines ao controle do código-fonte

A integração de seu pipeline de integração contínua com seu sistema de controle do código-fonte é fundamental para permitir contribuições rápidas de código de autoatendimento.

O pipeline de Integração Contínua é executado em um pull request recém-criado. O pipeline inclui todos os testes, avaliações de segurança e outras verificações. Os resultados do teste de CI são exibidos diretamente na solicitação de pull para permitir feedback quase em tempo real sobre a qualidade.

Outra prática popular é a criação de pequenos relatórios ou selos que podem ser apresentados no controle do código-fonte para tornar visíveis os estados atuais da compilação.

A imagem a seguir mostra a integração entre o GitHub e um pipeline do Azure DevOps. Neste exemplo, a criação de uma solicitação de pull dispara um pipeline do Azure DevOps. O status do pipeline aparece no pull request.

Captura de tela de um selo de status do Azure DevOps em um repositório GitHub.

Incorporar testes automatizados

Um elemento importante da integração contínua é a criação e o teste contínuos do código à medida que os desenvolvedores fazem contribuições de código. Testar pull requests conforme são criadas fornece feedback rápido de que o commit não introduziu alterações que causam falhas. A vantagem é que os testes no pipeline de integração contínua podem ser os mesmos testes executados durante o desenvolvimento baseado em teste.

O snippet de código a seguir mostra uma etapa de teste de um pipeline do Azure DevOps. A etapa tem duas tarefas:

  • A primeira tarefa usa uma estrutura de teste popular do Python para executar testes de CI. Esses testes residem no controle do código-fonte junto com o código Python. Os resultados do teste vão para um arquivo chamado test-results.xml.
  • A segunda tarefa consome os resultados do teste e os publica no pipeline do Azure DevOps como um relatório integrado.
- script: |
    pip3 install pytest
    pytest azure-vote/azure-vote/tests/ --junitxml=junit/test-results.xml
    continueOnError: true

- task: PublishTestResults@2
    displayName: 'Publish Test Results'
    inputs:
    testResultsFormat: 'JUnit'
    testResultsFiles: '**/test-results.xml'
    failTaskOnFailedTests: true
    testRunTitle: 'Python $(python.version)'

A imagem a seguir mostra os resultados do teste que aparecem no portal do Azure DevOps.

Captura de tela dos testes de pipeline do Azure DevOps no portal do Azure DevOps.

Testes com falha

Os testes com falha devem bloquear temporariamente uma implantação e levar a uma análise mais profunda do que aconteceu. Os testes com falha também devem levar a um refinamento dos testes ou a uma melhoria na alteração que causou a falha dos testes.

Publicar o status da compilação

Muitos desenvolvedores mostram que sua qualidade de código é alta exibindo um selo de status em seu repositório. A imagem a seguir mostra um selo do Azure Pipelines exibido no arquivo leiame de um projeto de software livre no GitHub.

Captura de tela de um selo do Azure Pipelines em um arquivo readme no GitHub.

Otimizar tempos de build

Para executar builds mais rápidos, você pode:

  • Escolha agentes que atendam aos seus requisitos de desempenho: acelere seus builds selecionando os computadores de build corretos. Computadores rápidos podem fazer a diferença entre horas e minutos. Se os pipelines estiverem no Azure Pipelines, você poderá executar seus trabalhos usando um agente hospedado pela Microsoft. Quando você usa agentes hospedados pela Microsoft, a manutenção e as atualizações são cuidadas para você. Para obter mais informações, consulte agentes hospedados pela Microsoft.

  • Otimize a localização do servidor de build: ao criar seu código, os dados são enviados através da rede. As entradas para os builds são buscadas de um repositório de controle do código-fonte e do repositório de artefatos. A saída do processo de compilação precisa ser copiada, incluindo os artefatos compilados, relatórios de teste, resultados de cobertura de código e símbolos de depuração. É importante que essas ações de cópia sejam executadas rapidamente. Se você usar seu próprio servidor de build, verifique se o servidor de build está localizado perto das fontes e de um local de destino. Uploads e downloads rápidos podem reduzir o tempo de build geral.

  • Dimensionar servidores de build: um único servidor de build pode ser suficiente para um produto pequeno. À medida que o tamanho e o escopo do produto e o número de equipes trabalhando no produto aumentam, um único servidor pode não ser suficiente. Dimensione sua infraestrutura horizontalmente em vários computadores quando atingir o limite. Para obter mais informações, consulte Criar e gerenciar pools de agentes.

  • Otimize a compilação:

    • Adicione trabalhos paralelos para acelerar o processo de build. Para obter mais informações, consulte Configurar e pagar por trabalhos paralelos.

    • Habilite execuções paralelas do pacote de testes, que geralmente economizam muito tempo, especialmente ao executar testes de integração e de interface do usuário. Para obter mais informações, consulte Executar testes em paralelo para qualquer executor de teste.

    • Use a noção de um multiplicador, onde você pode escalar suas compilações com vários agentes de build. Para obter mais informações, confira Especificar trabalhos em seu pipeline.

    • Considere mover os testes de integração, de interface do usuário e de validação (smoke tests) para um pipeline de lançamento. Mover para um pipeline de lançamento melhora a velocidade de compilação e a velocidade do loop de feedback de compilação.

    • Publique os artefatos de build em uma solução de gerenciamento de pacotes, como NuGet ou Maven. A publicação em uma solução de gerenciamento de pacotes permite reutilizar seu artefato de build com mais facilidade.

Implementar tipos de build que se encaixem nos seus fluxos de trabalho.

Sua organização pode optar por criar vários tipos diferentes de builds para otimizar os tempos de build. Os builds possíveis incluem:

  • Build de CI (integração contínua): a finalidade deste build é garantir que o código seja compilado e que os testes de unidade sejam executados. Esse build é disparado em cada confirmação. Ele serve como o batimento cardíaco do projeto e provê retorno imediato de qualidade para a equipe. Para obter mais informações, consulte Especificar eventos que acionam pipelines.

  • Compilação noturna: a finalidade de uma compilação noturna não é apenas compilar o código, mas também garantir que quaisquer conjuntos de testes maiores e ineficientes sejam executados regularmente para cada compilação. Normalmente, esses testes incluem integração, interface do usuário ou testes de fumaça. Para mais informações, consulte Configurar cronogramas para pipelines.

  • Compilação de versão: além de compilar e executar testes, esse build também compila a documentação da API, os relatórios de conformidade, a assinatura de código e outras etapas que não são necessárias sempre que o código é compilado. Essa compilação fornece a versão definitiva enviada para o pipeline de release para ser finalmente implantada no ambiente de produção.

Os tipos de builds necessários para sua organização dependem de fatores, incluindo a maturidade da sua equipe e da organização, o tipo de produto em que você está trabalhando e sua estratégia de implantação.

Saiba como criar um pipeline de integração contínua usando o GitHub ou o Azure DevOps:

Saiba como exibir selos em seus repositórios: