Back-End

3 ago, 2010

Integração contínua com Buildbot

Publicidade

Os dias de “cowboy coding” já se passaram em muitas organizações, substituídos por um renovado interesse na geração de softwares de qualidade. O teste de Integração contínua (CI) é um componente vital na prática de técnicas de programação ágil que leva ao software de alta qualidade. Conheça a teoria e a prática do teste de CI explorando o Buildbot, um sistema de CI de software livre baseado em Python.

A Integração contínua (CI) é um processo de desenvolvimento de software que promove os seguintes princípios:

  • Manter um repositório de fonte isolada
  • Automatizar a construção
  • Tornar sua construção capaz de se autotestar
  • Todos se cometem todos os dias
  • Todo cometimento deve construir a linha principal em uma máquina de integração
  • Manter a construção rápida
  • Testar em um clone do ambiente de produção
  • Facilitar para que todos obtenham o mais recente executável
  • Todos podem ver o que está acontecendo
  • Automatizar a implementação

Amplamente popularizado por Martin Fowler, a ideia básica da CI é testar e construir continuamente seu software em cada ramificação e também quando o código é mesclado no tronco. Isso leva a um aumento geral na integridade da base do código e também a um aumento na comunicação com os membros da equipe e a uma oportunidade de obter feedback sobre a qualidade geral do seu código. Frequentemente, as pessoas usam esse ciclo para gerar relatórios de cobertura do código e outras estatísticas.

O Buildbot, como outros sistemas de CI, ajuda a automatizar esse ciclo de registro, construção e teste. Os escravos do Buildbot geralmente são executados em plataformas como Win32, Solaris, Intelx64 etc. 

O sistema pode enviar uma notificação por e-mail quando uma construção falha e manter um controle de todas as construções em execução, para que o desenvolvedor possa obter uma visão panorâmica de todo o processo. Finalmente, as pessoas frequentemente utilizam o ciclo automatizado para gerar métricas sobre a qualidade do seu software a qualquer momento. Ao final deste artigo, vamos tratar das métricas e por que faz sentido executá-las em um sistema de CI.

Introdução ao Buildbot

Antes de entrarmos nos elementos básicos do Buildbot, vamos dar uma olhada na sua arquitetura. Como mostra a Figura 1, existem essencialmente três camadas na parte superior do processo de construção. Há uma camada de controle de versão que se anexa a notificações de um sistema de controle de versão.

Existe também uma camada de construção que realiza a comunicação a partir do mestre de construção e retorna os resultados da construção. Finalmente, há a camada de notificação, que frequentemente é configurada para enviar e-mails, ou uma mensagem IRC, quando a construção falha ou para que uma página da Web exiba os resultados coletados das construções com o passar do tempo.

Figura 1. Visão geral da arquitetura do Buildbot

Um dos outros principais recursos da arquitetura do Buildbot é a dependência da biblioteca Twisted baseada em Python para identificar comunicação assíncrona entre mestres e escravos. Essa arquitetura baseada em retorno de chamada permite um loop de feedback mestre/escravo muito simples, embora robusto. Encontre mais detalhes sobre a biblioteca Twisted na seção Recursos ao final deste artigo.

Se você ainda não tiver ouvido falar sobre Buildbot, algumas pesquisas no Google revelarão uma grande coleção de mestres e escravos associados a grandes e pequenos projetos de software livre. Um escravo, que mencionei brevemente antes, é literalmente uma máquina escrava controlada pelo servidor Buildbot mestre.

Normalmente, um escravo é um dentre vários escravos e cada um é executado em uma plataforma de testes diferente. Esse é um importante conceito no mundo do servidor Buildbot. Por exemplo, é possível que você esteja na lista de e-mails de um projeto de software aberto e ouça alguém dizer, “Alguém quer oferecer uma máquina virtual para um escravo Windows”?

O projeto de linguagem Python usa uma grande coleção de escravos Buildbot para testar e construir continuamente a versão mais recente de Python em quantas plataformas for possível. A Figura 2 mostra uma grande variedade de máquinas executando esses escravos de construção do tronco Python, bem como testes. Com os recentes avanços em virtualização, atualmente é comum pedir a membros da sua comunidade de desenvolvimento que hospedem o escravo Buildbot, ou que simplesmente executem várias máquinas virtuais que emulam diferentes configurações de hardware.

Figura 2. Buildbot Python; consulte a figura ampliada

Outro usuário do Buildbot muito conhecido é o projeto do navegador Google Chrome. A Figura 3 mostra uma versão altamente customizada do Buildbot, que melhora significativamente a aparência e os recursos da interface do usuário do Buildbot. Felizmente, o Google transformou essas melhorias em software livre para o Buildbot. Ao final do artigo, consulte a seção Recursos a seguir, é possível obter a fonte e a construção dessa versão customizada.

Figura 3. Buildbot aprimorado pelo Google Chrome; veja a figura ampliada

A construção dessa configuração específica está fora do escopo deste artigo, mas recomendo que você dê uma olhada por conta própria. Agora, vamos fazer com que o servidor mestre Buildbot seja executado rapidamente.

Configurando o Buildbot em cinco minutos

Essas etapas foram executadas no Ubuntu 8.10, mas devem funcionar na maioria das distribuições Linux:

  1. Faça o download do ez_setup.py:
    wget http://peak.telecommunity.com/dist/ez_setup.py
  2. Instale o easy_install:
    sudo python ez_setup.py
  3. Instale o pacote Twisted Python com apt-get:
    sudo apt-get install python-Twisted
  4. Siga esta “receita” do collective.buildbot:
    sudo easy_install collective.buildbot

Neste momento, começarão a aparecer várias coisas como o download e
a instalação automáticos de um grupo pacotes. Quando isso for concluído,
você estará pronto para criar um Buildbot! Se a instalação ocorrer
corretamente, digite na linha de comando do shell:

$ paster create -t buildbot my.project
$ cd my.project

Já está quase acabando, é sério, mas antes de terminar, deixe-me
apontar algumas armadilhas que podem enganá-lo quando você configurar o
Buildbot pela primeira vez. Dentro do seu arquivo
my.project/master.cfg, você verá algo como:

Listagem 1. Conteúdo de master.cfg

[buildout] master-parts = master passing.project 
# uncomment this to enable polling
poller [master] recipe = collective.buildbot:master
project-name = passing.project
project # allow to force build with the web interface allow-force = true
# internal port port = 9051 # http port wport = 9081 # buildbot url.
change this if you use a
virtualhost url = http://localhost:9081/ # static files public-html =
${buildout:directory}/public_html slaves = localhost
NaOaPSWb [passing.project]
recipe = collective.buildbot:project slave-names = localhost
vcs = hg repositories =
/home/ngift/myhgrepo
# notifications mail-host = localhost email-notification-sender
= buildbot@cortese email-notification-recipient = super@example.com
# run test each
hour periodic-scheduler=60
# cron build cron-scheduler = 0 8 * * *
# You can change the sequences to build / test your app
# default options should work for most buildout based
projects build-sequence =
# /usr/bin/python2.5 bootstrap.py -c project.cfg
# /usr/bin/python2.5 bin/buildout -c project.cfg test-sequence =
nosetests # zope.testing require exit with status
# bin/test --exit-with-status
[poller] recipe = collective.buildbot:poller
# don't forget to check this # since
it's generated from the paster template it may be a
wrong url repositories = /home/ngift/myhgrepo
#user = h4x0r #password = passwd poll-interval = 120

As coisas mais importantes que devem ser verificadas inicialmente são:

  • você tem o repositório de controle de origem apropriado
  • você deixou build-sequence em branco inicialmente
  •  seu test-sequence, “nose” no meu caso, passará nos testes quando o código for depurado no repositório fornecido.

Caso você tenha outras dúvidas, procure collective.buildbot no guia de Recursos e obtenha um link. Depois que seu arquivo de configuração tiver sido configurado, basta executar os dois comandos a seguir:

$ python bootstrap.py
$ ./bin/buildout

Quando você executar o comando buildout, obterá algumas saídas que serão semelhantes a isto:

Listagem 2. Saída do comando buildout

{673} > ./bin/buildout Unused options for buildout: 'master-parts'.
Installing master. New python executable in /home/ngift/my.project Installing
setuptools............done. [output suppressed for space]

Quando esse comando terminar, a instalação do Buildbot estará concluída e você estará pronto para fazer as coisas funcionarem. Inicie ambos os daemons do Buildbot executando os seguintes comandos a partir do shell:

$ ./bin/master start $ ./bin/yourhostname start

Em seguida, se você apontar um navegador para a URL definida no arquivo master.cfg que, por padrão, é http://localhost:9081/, verá seu Buildbot novinho. No início, ele não fará muitas coisas. No entanto, se você fornecer a ele um script de construção e um executor de testes, ele irá depurar, construir e testar seu código automaticamente. Depois você deverá buscar algumas opções de configuração, mas o trabalho duro em si já está feito.

Gerando relatórios de métricas de código

Um recente desenvolvimento intelectual dos “nerds de testes” é aproveitar o ciclo de integração contínua para gerar também métricas sobre o código de origem. Uma das técnicas mais populares é executar o coletor de testes nosetest com a opção de cobertura. Se você tivesse um projeto chamado “foo”, normalmente executaria:

nosetests –with-coverage –cover-package=example –cover-html \
–cover-html-dir=example_report.html test_example.py

Isso geraria um relatório HTML mostrando todas as linhas de código que não foram cobertas, juntamente com a saída para fluxos padrão, semelhante à listagem abaixo:

Listagem 3. Saída de nosetest

nglep%
nosetests --with-coverage --cover-package=example
--cover-html-dir=example_report.html test_example.py .
Name Stmts Exec Cover Missing
--------------------------------------- example 2 2 100%
----------------------------------------------------------------------
Ran 1 test in
0.004s OK

É possível fazer o download de example.py e test_example.py. A execução desse relatório todas as vezes que o código é revisado fornece ao desenvolvedor e ao gerenciador metadados sobre o que está realmente acontecendo no código. Esse é um exemplo perfeito do motivo pelo qual executar métricas simultaneamente à CI pode ser vantajoso para um projeto.

Outra ferramenta de métrica que fornece metadados sobre seu código é a classificação McCabe da PyMetrics. Nos anos 70, Thomas McCabe surgiu com uma simples e engenhosa observação sobre códigos: quanto mais complexo for um trecho de código, com mais frequência ele irá falhar. Embora isso possa parecer óbvio, infelizmente muitos desenvolvedores parecem não entender a ligação. Ao usar a ferramenta de linha de comando PyMetrics, é possível determinar o número total de ramificações por função.

Geralmente, você deseja manter o número de ramificações inferior a 10 em todos os métodos ou funções que cria, pois independentemente do momento, é difícil manter mais de sete ou oito coisas contextualizadas no cérebro humano. Como ponto de referência, basicamente não é possível testar/manter códigos com classificação superior a 50.

Pessoalmente, vi código com classificação 140 em produção, e o código era muito ruim o que, de fato, valida a teoria de McCabe. Se você puder capturar e sinalizar esse código complexo e frágil no início do processo de desenvolvimento, ele nunca entrará em produção, ainda que todos os testes sejam aprovados.

Conclusão

O principal benefício da integração contínua é a capacidade de otimizar o ciclo de garantia de qualidade com construções automatizadas de software, juntamente com testes e, opcionalmente, métricas de software. Essas construções são acionadas a cada alteração da origem e fornecem feedback instantâneo e relatórios para todo o projeto. Quando a CI é configurada corretamente, ela se torna de fato integrada no processo de produção do código, tanto quanto na criação do código em si.

O Buildbot não é a única alternativa para testes de CI. Dê também uma olhada nas ferramentas Hudson e Bitten. Cada uma delas permite a customização com plug-ins em Python, ainda que Hudson tenha sido escrito em Python. Consulte os recursos a seguir para obter mais informações sobre esses sistemas.

Recursos

Para Aprender:

   Obter produtos e tecnologias:

  • Obtenha a fonte do Buildbot do Google Chrome
  • Para obter alternativas em relação ao Buildbot, confira as ferramentas Hudson e Bitten
  • Saiba mais sobre a estrutura de testes nose
  • O site collective.buildbot oferece uma coleção de receitas “buildout” do Buildbot
  • PyMetrics é uma ferramenta para gerar uma Classificação de Complexidade Ciclomática
  • Avalie os produtos da IBM da forma que melhor lhe convém: Faça o
    download de uma versão de teste de produto, experimente um produto
    on-line, use um produto em um ambiente de nuvem ou passe algumas horas
    no SOA Sandbox aprendendo como implementar Arquitetura Orientada a
    Serviço de forma eficiente

   

Artigo publicado originalmente em developerWorks Brasil, por Noah Gift


Noah Gift é o coautor do livro Python For UNIX and Linux System Administration pela O’Reilly, e também está trabalhando no livro Google App Engine In Action para a Manning. Ele é autor, palestrante, consultor e líder de comunidades, escrevendo para publicações como Red Hat Magazine, O’Reilly e MacTech. O site da sua empresa de consultoria é http://www.giftcs.com, e grande parte de suas obras pode ser encontrada em http://noahgift.com.
Noah tem mestrado em CIS pela Cal State Los Angeles e Bacharelado em Ciências Nutricionais pela Cal Poly San Luis Obispo. Ele é administrador de sistemas certificado pela Apple e pela LPI e trabalhou em empresas como Caltech, Disney Feature Animation, Sony Imageworks, Turner Studios e Weta Digital.