Integración continua "bonita" para Python

116

Esta es una pregunta un poco ... vana, pero la salida de BuildBot no es particularmente agradable de ver ...

Por ejemplo, comparado con ..

..y otros, BuildBot parece bastante .. arcaico

Actualmente estoy jugando con Hudson, pero está muy centrado en Java (aunque con esta guía , me pareció más fácil de configurar que BuildBot y obtuve más información)

Básicamente: ¿existe algún sistema de Integración Continua dirigido a Python, que produzca muchos gráficos brillantes y similares?


Actualización: Desde entonces, el proyecto Jenkins ha reemplazado a Hudson como la versión comunitaria del paquete. Los autores originales también se han trasladado a este proyecto. Jenkins es ahora un paquete estándar en Ubuntu / Debian, RedHat / Fedora / CentOS y otros. La siguiente actualización sigue siendo esencialmente correcta. El punto de partida para hacer esto con Jenkins es diferente.

Actualización: después de probar algunas alternativas, creo que me quedaré con Hudson. La integridad era agradable y simple, pero bastante limitada. Creo que Buildbot se adapta mejor a tener numerosos esclavos de compilación, en lugar de que todo se ejecute en una sola máquina como yo lo estaba usando.

Configurar Hudson para un proyecto de Python fue bastante simple:

  • Descarga Hudson desde http://hudson-ci.org/
  • Ejecutarlo con java -jar hudson.war
  • Abra la interfaz web en la dirección predeterminada de http://localhost:8080
  • Vaya a Administrar Hudson, Complementos, haga clic en "Actualizar" o similar
  • Instale el complemento de Git (tuve que establecer la gitruta en las preferencias globales de Hudson)
  • Cree un nuevo proyecto, ingrese al repositorio, intervalos de sondeo de SCM, etc.
  • Instalar nosetestsvía easy_installsi aún no lo está
  • En el paso de compilación, agregue nosetests --with-xunit --verbose
  • Marque "Publicar informe de resultado de prueba JUnit" y configure "XML de informe de prueba" en **/nosetests.xml

Eso es todo lo que se requiere. Puede configurar notificaciones por correo electrónico y vale la pena echar un vistazo a los complementos . Algunos que estoy usando actualmente para proyectos de Python:

  • Complemento SLOCCount para contar líneas de código (¡y graficarlo!) - debe instalar sloccount por separado
  • Violaciones para analizar la salida de PyLint (puede configurar umbrales de advertencia, graficar la cantidad de violaciones en cada compilación)
  • Cobertura puede analizar la salida de cover.py. Nosetest puede recopilar cobertura mientras realiza sus pruebas, utilizandonosetests --with-coverage (esto escribe la salida en **/coverage.xml)
dbr
fuente
Gran pregunta, estoy investigando cosas similares en este momento. Si sigue una ruta, ¿puede compartir su experiencia con el resto de nosotros?
André
3
No sé si estaba disponible cuando escribiste esto: ¡Usa el complemento Chuck Norris para Hudson para mejorar aún más el control sobre tus cosas!
Johannes Charra
8
Actualización para 2011/2012 : Aquellos que estén considerando que Hudson deberían usar Jenkins , la continuación de código abierto del proyecto Hudson (Hudson ahora está controlado por Oracle )
mindthief

Respuestas:

41

Es posible que desee consultar Nose y el complemento de salida Xunit . Puede hacer que ejecute sus pruebas unitarias y verificaciones de cobertura con este comando:

nosetests --with-xunit --enable-cover

Eso será útil si desea seguir la ruta de Jenkins o si desea utilizar otro servidor CI que sea compatible con los informes de prueba de JUnit.

De manera similar, puede capturar la salida de pylint utilizando el complemento de violaciones para Jenkins

Jason Baker
fuente
4
Nose ahora incluye el complemento xunit por defecto -nosetests --with-xunit
dbr
3
Entonces, ¿cómo se ejecuta la auditoría desde Pylint? Cuando lo nosetests --with-xunit --enable-auditconsiganosetests: error: no such option: --enable-audit
Adam Parkin
2
Respuesta modernizada, las cosas de NoseXUnit ahora están integradas y se renombran de desafortunado cuando se reducen --with-nosexunita --with-xunit.
2013
10

No sé si funcionaría: Bitten está hecho por los chicos que escriben Trac y está integrado con Trac. Apache Gump es la herramienta CI utilizada por Apache. Está escrito en Python.

edomaur
fuente
9

Hemos tenido un gran éxito con TeamCity como nuestro servidor de CI y usando nose como nuestro corredor de pruebas. El complemento de Teamcity para nosetests le brinda un recuento de pasa / falla, una pantalla legible para la prueba fallida (que se puede enviar por correo electrónico). Incluso puede ver los detalles de las fallas de la prueba mientras se ejecuta la pila.

Si, por supuesto, admite cosas como ejecutarse en varias máquinas, y es mucho más sencillo de configurar y mantener que buildbot.

Kozyarchuk
fuente
6

Definitivamente también vale la pena echarle un vistazo al bambú de Atlassian . Toda la suite de Atlassian (JIRA, Confluence, FishEye, etc.) es bastante dulce.

Russ
fuente
6

Supongo que este hilo es bastante antiguo, pero aquí está mi opinión con hudson:

Decidí ir con pip y configurar un repositorio (lo doloroso de ponerse a trabajar pero la canasta de huevos de aspecto agradable), que hudson carga automáticamente con pruebas exitosas. Aquí está mi script preliminar y listo para usar con un script de ejecución de configuración de hudson como: /var/lib/hudson/venv/main/bin/hudson_script.py -w $ WORKSPACE -p my.package -v $ BUILD_NUMBER, solo póngalo ** /cover.xml, pylint.txt y nosetests.xml en los bits de configuración:

#!/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()

Cuando se trata de implementar cosas, puede hacer algo como:

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

Y luego la gente puede desarrollar cosas usando:

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

Esto supone que tiene una estructura de repositorio por paquete con un setup.py y todas las dependencias configuradas, entonces puede simplemente verificar el tronco y ejecutar estas cosas en él.

Espero que ésto ayude a alguien.

------actualizar---------

Agregué epydoc que encaja muy bien con hudson. Simplemente agregue javadoc a su configuración con la carpeta html

Tenga en cuenta que pip no admite la bandera -E correctamente en estos días, por lo que debe crear su venv por separado

Nick Holden
fuente
Esta respuesta es muy útil y tiene muchos detalles con respecto a los aspectos internos de Python CI, algo que no obtendrá gratis de Jenkins o lo que sea. ¡Gracias!
maksimov
3

Si está considerando una solución de CI alojada y utiliza código abierto, también debería considerar Travis CI, ya que tiene una muy buena integración con GitHub. Si bien comenzó como una herramienta Ruby, hace un tiempo agregaron compatibilidad con Python .

Alex Dupuy
fuente
2

La señal es otra opción. Puedes saber más al respecto y ver un video también aquí .

Diego Carrión
fuente
2

Consideraría CircleCi : tiene una excelente compatibilidad con Python y una salida muy bonita.

Paul Biggar
fuente
1

binstar de continuum ahora puede activar compilaciones desde github y puede compilar para linux, osx y windows (32/64). lo bueno es que realmente le permite acoplar estrechamente la distribución y la integración continua. Eso es cruzar las t y salpicar las I de la integración. El sitio, flujo de trabajo y herramientas están muy pulidos y que yo sepa Conda es la forma más robusta y Pythonic a la distribución de los módulos de Python complejos, en los que necesita para envolver y distribuir bibliotecas de C / C ++ / Fotran.

Jelle
fuente
0

Hemos usado bastante mordido. Es bonito y se integra bien con Trac, pero es un fastidio personalizarlo si tiene un flujo de trabajo no estándar. Además, no hay tantos complementos como los hay para las herramientas más populares. Actualmente estamos evaluando a Hudson como reemplazo.

Allen
fuente
0

Consulte rultor.com . Como explica este artículo , utiliza Docker para cada compilación. Gracias a eso, puede configurar lo que quiera dentro de su imagen de Docker, incluido Python.

yegor256
fuente
0

Pequeño descargo de responsabilidad, de hecho tuve que construir una solución como esta para un cliente que quería una forma de probar e implementar automáticamente cualquier código en un git push además de administrar los tickets de emisión a través de git notes. Esto también me llevó a trabajar en el proyecto AIMS. .

Uno podría fijar fácilmente a un sistema de nodos descubierto que tiene un usuario crear y gestionar su acumulación a través de make(1), expect(1), crontab(1)/ systemd.unit(5), yincrontab(1) . Incluso se podría ir un paso más allá y usar ansible y apio para compilaciones distribuidas con un almacén de archivos gridfs / nfs.

Aunque, no esperaría que nadie más que un chico de Graybeard UNIX o un ingeniero / arquitecto de nivel de Principio llegara tan lejos. Simplemente lo convierte en una buena idea y una experiencia de aprendizaje potencial, ya que un servidor de compilación no es más que una forma de ejecutar arbitrariamente tareas programadas de manera automatizada.

Dwight Spencer
fuente