Integrazione "graziosa" continua per Python


116

Questa è una domanda leggermente .. vana, ma l'output di BuildBot non è particolarmente bello da vedere ..

Ad esempio, rispetto a ..

..e altri, BuildBot sembra piuttosto .. arcaico

Attualmente sto giocando con Hudson, ma è molto incentrato su Java (anche se con questa guida ho trovato più facile da configurare rispetto a BuildBot e ho prodotto maggiori informazioni)

Fondamentalmente: esistono sistemi di integrazione continua mirati a Python, che producono molti grafici brillanti e simili?


Aggiornamento: da questa volta il progetto Jenkins ha sostituito Hudson come versione comunitaria del pacchetto. Anche gli autori originali sono passati a questo progetto. Jenkins è ora un pacchetto standard su Ubuntu / Debian, RedHat / Fedora / CentOS e altri. Il seguente aggiornamento è ancora sostanzialmente corretto. Il punto di partenza per farlo con Jenkins è diverso.

Aggiornamento: dopo aver provato alcune alternative, penso che rimarrò con Hudson. L'integrità era piacevole e semplice, ma piuttosto limitata. Penso che Buildbot sia più adatto ad avere numerosi build-slave, piuttosto che tutto in esecuzione su una singola macchina come lo stavo usando.

Impostare Hudson per un progetto Python è stato piuttosto semplice:

  • Scarica Hudson da http://hudson-ci.org/
  • Eseguilo con java -jar hudson.war
  • Apri l'interfaccia web con l'indirizzo predefinito di http://localhost:8080
  • Vai a Gestisci Hudson, Plugin, fai clic su "Aggiorna" o simile
  • Installa il plugin Git (ho dovuto impostare il gitpercorso nelle preferenze globali di Hudson)
  • Crea un nuovo progetto, inserisci il repository, gli intervalli di polling SCM e così via
  • Installa noseteststramite easy_installse non lo è già
  • Nella fase di creazione, aggiungi nosetests --with-xunit --verbose
  • Seleziona "Pubblica rapporto dei risultati del test JUnit" e imposta "XML del rapporto di prova" su **/nosetests.xml

È tutto ciò che serve. Puoi configurare le notifiche e-mail e vale la pena dare un'occhiata ai plugin . Alcuni che sto attualmente utilizzando per i progetti Python:

  • Plugin SLOCCount per contare le righe di codice (e rappresentarlo graficamente!) - Devi installare sloccount separatamente
  • Violazioni per analizzare l'output di PyLint (è possibile impostare soglie di avviso, rappresentare graficamente il numero di violazioni su ciascuna build)
  • Cobertura può analizzare l'output di coverage.py. Nosetest può raccogliere copertura durante l'esecuzione dei test, utilizzando nosetests --with-coverage(questo scrive l'output in **/coverage.xml)

Ottima domanda, sto esaminando cose simili proprio ora. Se segui una strada, puoi condividere la tua esperienza con il resto di noi?
André

3
Non so se fosse disponibile quando hai scritto questo: usa il plugin Chuck Norris per Hudson per migliorare ulteriormente il controllo sulle tue cose!
Johannes Charra

8
Aggiornamento per il 2011/2012 : coloro che considerano Hudson dovrebbero utilizzare Jenkins , la continuazione open source del progetto Hudson (Hudson è ora controllato da Oracle )
mindthief

Risposte:


41

Potresti voler controllare Nose e il plug-in di output di Xunit . Puoi fare in modo che esegua i tuoi unit test e controlli di copertura con questo comando:

nosetests --with-xunit --enable-cover

Ciò sarà utile se si desidera seguire la rotta Jenkins o se si desidera utilizzare un altro server CI con supporto per i rapporti di test JUnit.

Allo stesso modo puoi catturare l'output di pylint usando il plug-in violazioni per Jenkins


4
Nose ora include il plug-in xunit per impostazione predefinita -nosetests --with-xunit
dbr

3
Allora come si esegue l'auditing da Pylint? Quando nosetests --with-xunit --enable-auditricevonosetests: error: no such option: --enable-audit
Adam Parkin

2
Risposta modernizzata, la roba NoseXUnit è ora incorporata e rinominata dallo sfortunato-quando-downcased --with-nosexunita --with-xunit.
dbr

10

Non so se funzionerebbe: Bitten è fatto dai ragazzi che scrivono Trac ed è integrato con Trac. Apache Gump è lo strumento CI utilizzato da Apache. È scritto in Python.


9

Abbiamo avuto un grande successo con TeamCity come nostro server CI e usando il naso come nostro test runner. Il plug-in di Teamcity per nosetest ti dà il conteggio pass / fail, display leggibile per i test falliti (che possono essere inviati tramite posta elettronica). Puoi anche vedere i dettagli degli errori di test mentre lo stack è in esecuzione.

Se ovviamente supporta cose come l'esecuzione su più macchine, ed è molto più semplice da configurare e mantenere rispetto a buildbot.



6

Anche Atlassian's Bamboo merita sicuramente una visita. L'intera suite Atlassian (JIRA, Confluence, FishEye, ecc.) È piuttosto dolce.


6

Immagino che questo thread sia piuttosto vecchio, ma ecco la mia opinione su Hudson:

Ho deciso di andare con pip e creare un repo (il doloroso da far funzionare ma un bel cestino per le uova), su cui hudson si carica automaticamente con test di successo. Ecco il mio script approssimativo e pronto per l'uso con uno script di esecuzione di configurazione hudson come: /var/lib/hudson/venv/main/bin/hudson_script.py -w $ WORKSPACE -p my.package -v $ BUILD_NUMBER, basta inserire ** / coverage.xml, pylint.txt e nosetests.xml nei bit di configurazione:

#!/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 si tratta di distribuire cose, puoi fare qualcosa come:

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

E poi le persone possono sviluppare cose usando:

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

Questa roba presuppone che tu abbia una struttura repo per pacchetto con setup.py e dipendenze tutte impostate, quindi puoi semplicemente controllare il tronco ed eseguire questa roba su di esso.

Spero che questo aiuti qualcuno.

------aggiornare---------

Ho aggiunto epydoc che si adatta molto bene a hudson. Basta aggiungere javadoc alla tua configurazione con la cartella html

Nota che pip non supporta correttamente il flag -E in questi giorni, quindi devi creare il tuo venv separatamente


Questa risposta è molto utile e contiene molti dettagli per quanto riguarda gli interni di Python CI, qualcosa che non otterrai gratuitamente da Jenkins o altro. Grazie!
maksimov


3

Se stai prendendo in considerazione una soluzione CI ospitata e stai facendo open source, dovresti esaminare anche Travis CI : ha un'ottima integrazione con GitHub. Sebbene sia iniziato come uno strumento Ruby, hanno aggiunto il supporto per Python qualche tempo fa.




1

binstar di continuum ora è in grado di attivare build da github e può compilare per linux, osx e windows ( 32/64 ). la cosa bella è che ti permette davvero di accoppiare strettamente distribuzione e integrazione continua. Questo è attraversare le T e punteggiare le I dell'Integrazione. Il sito, il flusso di lavoro e gli strumenti sono davvero raffinati e AFAIK conda è il modo più robusto e pitonico per distribuire moduli Python complessi, in cui è necessario avvolgere e distribuire librerie C / C ++ / Fotran.


0

Abbiamo usato un bel po 'di morsi. È carino e si integra bene con Trac, ma è una seccatura da personalizzare se si dispone di un flusso di lavoro non standard. Inoltre, non ci sono tanti plugin quanti sono gli strumenti più popolari. Attualmente stiamo valutando Hudson come sostituto.


0

Controlla rultor.com . Come spiega questo articolo , utilizza Docker per ogni build. Grazie a ciò, puoi configurare quello che vuoi all'interno della tua immagine Docker, incluso Python.


0

Piccolo disclaimer, in realtà ho dovuto creare una soluzione come questa per un client che desiderava un modo per testare e distribuire automaticamente qualsiasi codice su un push git e gestire i ticket di emissione tramite note git. Questo ha portato anche al mio lavoro sul progetto AIMS .

Si potrebbe facilmente solo impostare un sistema nodo di nudo che ha un utente costruire e gestire la loro costruzione attraverso make(1), expect(1), crontab(1)/ systemd.unit(5)e incrontab(1). Si potrebbe anche fare un ulteriore passo avanti e utilizzare ansible e celery per build distribuite con un archivio di file gridfs / nfs.

Tuttavia, non mi aspetterei che nessun altro oltre a un ragazzo UNIX di Graybeard o un ingegnere / architetto a livello di Principio arrivasse davvero a questo punto. È solo una bella idea e una potenziale esperienza di apprendimento poiché un server di compilazione non è altro che un modo per eseguire arbitrariamente attività programmate in modo automatizzato.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.