Integração contínua “bonita” para Python

116

Esta é uma pergunta ligeiramente ... vã, mas a saída do BuildBot não é particularmente agradável de se olhar ..

Por exemplo, em comparação com ..

..e outros, BuildBot parece bastante .. arcaico

No momento estou jogando com Hudson, mas é muito centrado em Java (embora com este guia , achei mais fácil de configurar do que BuildBot e produziu mais informações)

Basicamente: existe algum sistema de integração contínua voltado para python, que produz muitos gráficos brilhantes e similares?


Atualização: desde então, o projeto Jenkins substituiu Hudson como a versão da comunidade do pacote. Os autores originais também mudaram para este projeto. Jenkins agora é um pacote padrão no Ubuntu / Debian, RedHat / Fedora / CentOS e outros. A atualização a seguir ainda está essencialmente correta. O ponto de partida para fazer isso com Jenkins é diferente.

Atualização: depois de tentar algumas alternativas, acho que vou ficar com Hudson. A integridade era boa e simples, mas bastante limitada. Acho que o Buildbot é mais adequado para ter vários build-slaves, em vez de tudo rodando em uma única máquina como eu estava usando.

Configurar o Hudson para um projeto Python foi muito simples:

  • Baixe o Hudson em http://hudson-ci.org/
  • Execute com java -jar hudson.war
  • Abra a interface da web no endereço padrão de http://localhost:8080
  • Vá para Gerenciar Hudson, Plugins, clique em "Atualizar" ou similar
  • Instale o plugin Git (tive que definir o gitcaminho nas preferências globais do Hudson)
  • Crie um novo projeto, entre no repositório, intervalos de sondagem SCM e assim por diante
  • Instale nosetestsvia easy_installse ainda não estiver
  • Na etapa de construção, adicione nosetests --with-xunit --verbose
  • Marque "Publicar relatório de resultado de teste JUnit" e defina "XMLs de relatório de teste" para **/nosetests.xml

Isso é tudo o que é necessário. Você pode configurar notificações por e-mail e vale a pena dar uma olhada nos plug-ins . Alguns que estou usando atualmente para projetos Python:

  • Plugin SLOCCount para contar linhas de código (e representá-lo graficamente!) - você precisa instalar o sloccount separadamente
  • Violações para analisar a saída PyLint (você pode configurar limites de aviso, representar graficamente o número de violações em cada compilação)
  • Cobertura pode analisar a saída de cover.py. Nosetest pode obter cobertura durante a execução de seus testes, usando nosetests --with-coverage(isso grava a saída em **/coverage.xml)
dbr
fonte
Ótima pergunta, estou investigando coisas semelhantes agora. Se você seguir um caminho, pode compartilhar sua experiência com o resto de nós?
André
3
Não sei se ele estava disponível quando você escreveu isto: use o plugin Chuck Norris para Hudson para aumentar ainda mais o controle sobre suas coisas!
Johannes Charra
8
Atualização para 2011/2012 : Aqueles que consideram Hudson devem usar Jenkins , a continuação de código aberto do projeto Hudson (Hudson agora é controlado pela Oracle )
ladrão de mente

Respostas:

41

Você pode querer verificar o Nose e o plug-in de saída Xunit . Você pode fazer com que ele execute seus testes de unidade e verificações de cobertura com este comando:

nosetests --with-xunit --enable-cover

Isso será útil se você quiser seguir a rota do Jenkins ou se quiser usar outro servidor de CI que tenha suporte para relatórios de teste JUnit.

Da mesma forma, você pode capturar a saída do pylint usando o plugin de violações do Jenkins

Jason Baker
fonte
4
O Nose agora inclui o plugin xunit por padrão -nosetests --with-xunit
dbr
3
Então, como se executa a auditoria do Pylint? Quando eu nosetests --with-xunit --enable-auditchegarnosetests: error: no such option: --enable-audit
Adam Parkin
2
Resposta modernizada, o material do NoseXUnit agora está integrado e renomeado de infeliz quando rebaixado --with-nosexunitpara --with-xunit.
dbr
10

Não sei se daria certo: Bitten é feito pelos caras que escrevem Trac e está integrado ao Trac. Apache Gump é a ferramenta CI usada pelo Apache. Está escrito em Python.

edomauro
fonte
9

Tivemos grande sucesso com o TeamCity como nosso servidor de CI e usando o nose como nosso executor de teste. O plugin Teamcity para nosetests dá a você a contagem de aprovação / reprovação, exibição legível para teste reprovado (que pode ser enviado por e-mail). Você pode até ver os detalhes das falhas de teste enquanto a pilha está em execução.

É claro que oferece suporte a coisas como execução em várias máquinas e é muito mais simples de configurar e manter do que o buildbot.

Kozyarchuk
fonte
6

O Bambu Atlassian também vale a pena conferir. Toda a suíte Atlassian (JIRA, Confluence, FishEye, etc) é muito doce.

Russ
fonte
6

Acho que este tópico é bastante antigo, mas aqui está minha opinião sobre ele com hudson:

Decidi ir com o pip e configurar um repo (o doloroso para trabalhar, mas de aparência agradável), para o qual o hudson auto carrega com testes bem-sucedidos. Aqui está meu script bruto e pronto para uso com um script de execução de configuração hudson como: /var/lib/hudson/venv/main/bin/hudson_script.py -w $ WORKSPACE -p my.package -v $ BUILD_NUMBER, basta inserir ** / cobertura.xml, pylint.txt e nosetests.xml nos bits de configuração:

#!/var/lib/hudson/venv/main/bin/python
import os
import re
import subprocess
import logging
import optparse

logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s %(levelname)s %(message)s')

#venvDir = "/var/lib/hudson/venv/main/bin/"

UPLOAD_REPO = "http://ldndev01:3442"

def call_command(command, cwd, ignore_error_code=False):
    try:
        logging.info("Running: %s" % command)
        status = subprocess.call(command, cwd=cwd, shell=True)
        if not ignore_error_code and status != 0:
            raise Exception("Last command failed")

        return status

    except:
        logging.exception("Could not run command %s" % command)
        raise

def main():
    usage = "usage: %prog [options]"
    parser = optparse.OptionParser(usage)
    parser.add_option("-w", "--workspace", dest="workspace",
                      help="workspace folder for the job")
    parser.add_option("-p", "--package", dest="package",
                      help="the package name i.e., back_office.reconciler")
    parser.add_option("-v", "--build_number", dest="build_number",
                      help="the build number, which will get put at the end of the package version")
    options, args = parser.parse_args()

    if not options.workspace or not options.package:
        raise Exception("Need both args, do --help for info")

    venvDir = options.package + "_venv/"

    #find out if venv is there
    if not os.path.exists(venvDir):
        #make it
        call_command("virtualenv %s --no-site-packages" % venvDir,
                     options.workspace)

    #install the venv/make sure its there plus install the local package
    call_command("%sbin/pip install -e ./ --extra-index %s" % (venvDir, UPLOAD_REPO),
                 options.workspace)

    #make sure pylint, nose and coverage are installed
    call_command("%sbin/pip install nose pylint coverage epydoc" % venvDir,
                 options.workspace)

    #make sure we have an __init__.py
    #this shouldn't be needed if the packages are set up correctly
    #modules = options.package.split(".")
    #if len(modules) > 1: 
    #    call_command("touch '%s/__init__.py'" % modules[0], 
    #                 options.workspace)
    #do the nosetests
    test_status = call_command("%sbin/nosetests %s --with-xunit --with-coverage --cover-package %s --cover-erase" % (venvDir,
                                                                                     options.package.replace(".", "/"),
                                                                                     options.package),
                 options.workspace, True)
    #produce coverage report -i for ignore weird missing file errors
    call_command("%sbin/coverage xml -i" % venvDir,
                 options.workspace)
    #move it so that the code coverage plugin can find it
    call_command("mv coverage.xml %s" % (options.package.replace(".", "/")),
                 options.workspace)
    #run pylint
    call_command("%sbin/pylint --rcfile ~/pylint.rc -f parseable %s > pylint.txt" % (venvDir, 
                                                                                     options.package),
                 options.workspace, True)

    #remove old dists so we only have the newest at the end
    call_command("rm -rfv %s" % (options.workspace + "/dist"),
                 options.workspace)

    #if the build passes upload the result to the egg_basket
    if test_status == 0:
        logging.info("Success - uploading egg")
        upload_bit = "upload -r %s/upload" % UPLOAD_REPO
    else:
        logging.info("Failure - not uploading egg")
        upload_bit = ""

    #create egg
    call_command("%sbin/python setup.py egg_info --tag-build=.0.%s --tag-svn-revision --tag-date sdist %s" % (venvDir,
                                                                                                              options.build_number,
                                                                                                              upload_bit),
                 options.workspace)

    call_command("%sbin/epydoc --html --graph all %s" % (venvDir, options.package),
                 options.workspace)

    logging.info("Complete")

if __name__ == "__main__":
    main()

Quando se trata de implantar coisas, você pode fazer algo como:

pip -E /location/of/my/venv/ install my_package==X.Y.Z --extra-index http://my_repo

E então as pessoas podem desenvolver coisas usando:

pip -E /location/of/my/venv/ install -e ./ --extra-index http://my_repo

Isso pressupõe que você tenha uma estrutura de repositório por pacote com um setup.py e dependências configuradas, então você pode apenas verificar o tronco e executar essas coisas nele.

Espero que isso ajude alguém.

------atualizar---------

Eu adicionei o epydoc que se encaixa muito bem com o hudson. Basta adicionar javadoc à sua configuração com a pasta html

Observe que pip não suporta o sinalizador -E corretamente atualmente, então você deve criar seu venv separadamente

Nick Holden
fonte
Essa resposta é muito útil e tem muitos detalhes em relação à parte interna do Python CI, algo que você não obterá de graça no Jenkins ou qualquer outra coisa. Obrigado!
maksimov
3

Se você está considerando uma solução de CI hospedada e usando código aberto, você também deve dar uma olhada no Travis CI - ele tem uma integração muito boa com o GitHub. Embora tenha começado como uma ferramenta Ruby, eles adicionaram suporte a Python há algum tempo.

Alex Dupuy
fonte
2

O sinal é outra opção. Você pode saber mais sobre ele e assistir um vídeo também aqui .

Diego Carrion
fonte
2

Eu consideraria o CircleCi - ele tem um ótimo suporte para Python e uma saída muito bonita.

Paul Biggar
fonte
1

O binstar do continuum agora é capaz de acionar compilações do github e pode compilar para linux, osx e windows (32/64). o interessante é que ele realmente permite que você combine distribuição e integração contínua. Isso é cruzar os t's e pontuar os es da integração. O site, o fluxo de trabalho e as ferramentas são realmente polidos e AFAIK conda é a maneira mais robusta e pythônica de distribuir módulos python complexos, onde você precisa empacotar e distribuir bibliotecas C / C ++ / Fotran.

Jelle
fonte
0

Temos usado bastante mordida. É bonito e se integra bem com o Trac, mas é um saco personalizá-lo se você tiver algum fluxo de trabalho fora do padrão. Além disso, simplesmente não existem tantos plug-ins quanto para as ferramentas mais populares. Atualmente estamos avaliando o Hudson como um substituto.

Allen
fonte
0

Verifique rultor.com . Como este artigo explica, ele usa o Docker para cada construção. Graças a isso, você pode configurar o que quiser dentro de sua imagem Docker, incluindo Python.

Yegor256
fonte
0

Uma pequena isenção de responsabilidade, eu realmente tive que construir uma solução como essa para um cliente que queria uma maneira de testar e implantar automaticamente qualquer código em um git push, além de gerenciar os tickets de problema por meio de notas git. Isso também levou ao meu trabalho no projeto AIMS .

Pode-se facilmente apenas configurar um sistema de nó nu que tem um usuário construir e gerenciar sua construção através make(1), expect(1), crontab(1)/ systemd.unit(5)e incrontab(1). Pode-se até ir um passo além e usar ansible e celery para compilações distribuídas com um armazenamento de arquivo gridfs / nfs.

Embora, eu não espere que ninguém além de um cara do UNIX Graybeard ou engenheiro / arquiteto de nível Princípio vá realmente tão longe. Isso é uma boa ideia e uma potencial experiência de aprendizado, já que um servidor de construção nada mais é do que uma maneira de executar tarefas com script de maneira arbitrária de maneira automatizada.

Dwight Spencer
fonte