"Hübsche" kontinuierliche Integration für Python

116

Dies ist eine etwas vergebliche Frage, aber die Ausgabe von BuildBot ist nicht besonders schön anzusehen.

Zum Beispiel im Vergleich zu ..

..und andere, BuildBot sieht eher .. archaisch aus

Ich spiele derzeit mit Hudson, aber es ist sehr Java-zentriert (obwohl ich mit diesem Handbuch die Einrichtung einfacher fand als mit BuildBot und mehr Informationen produzierte).

Grundsätzlich gilt: Gibt es Continuous Integration-Systeme für Python, die viele glänzende Grafiken und ähnliches erzeugen?


Update: Seit dieser Zeit hat das Jenkins-Projekt Hudson als Community-Version des Pakets ersetzt. Die ursprünglichen Autoren sind ebenfalls zu diesem Projekt übergegangen. Jenkins ist jetzt ein Standardpaket für Ubuntu / Debian, RedHat / Fedora / CentOS und andere. Das folgende Update ist noch im Wesentlichen korrekt. Der Ausgangspunkt dafür ist bei Jenkins anders.

Update: Nachdem ich ein paar Alternativen ausprobiert habe, denke ich, dass ich bei Hudson bleiben werde. Integrität war nett und einfach, aber ziemlich begrenzt. Ich denke, Buildbot ist besser geeignet, um zahlreiche Build-Slaves zu haben, als alles, was auf einem einzelnen Computer läuft, wie ich es verwendet habe.

Das Einrichten von Hudson für ein Python-Projekt war ziemlich einfach:

  • Laden Sie Hudson von http://hudson-ci.org/ herunter.
  • Führen Sie es mit java -jar hudson.war
  • Öffnen Sie die Weboberfläche unter der Standardadresse von http://localhost:8080
  • Gehen Sie zu Hudson verwalten, Plugins, klicken Sie auf "Aktualisieren" oder ähnliches
  • Installieren Sie das Git-Plugin (ich musste den gitPfad in den globalen Hudson- Einstellungen festlegen )
  • Erstellen Sie ein neues Projekt, geben Sie das Repository, die SCM-Abfrageintervalle usw. ein
  • Installieren Sie nosetestsüber, easy_installfalls dies noch nicht geschehen ist
  • Fügen Sie im Schritt a build hinzu nosetests --with-xunit --verbose
  • Aktivieren Sie "JUnit-Testergebnisbericht veröffentlichen" und setzen Sie "Testbericht-XMLs" auf **/nosetests.xml

Das ist alles was benötigt wird. Sie können E-Mail-Benachrichtigungen einrichten, und die Plugins sind einen Blick wert. Einige, die ich derzeit für Python-Projekte verwende:

  • SLOCCount-Plugin zum Zählen von Codezeilen (und grafische Darstellung!) - Sie müssen sloccount separat installieren
  • Verstöße zum Parsen der PyLint-Ausgabe (Sie können Warnschwellenwerte festlegen und die Anzahl der Verstöße für jeden Build grafisch darstellen).
  • Cobertura kann die Ausgabe von Coverage.py analysieren. Nosetest kann Abdeckung sammeln , während die Tests ausgeführt wird , unter Verwendung nosetests --with-coverage(dies schreibt die Ausgabe an **/coverage.xml)
dbr
quelle
Gute Frage, ich beschäftige mich gerade mit ähnlichen Dingen. Wenn Sie einen Weg gehen, können Sie Ihre Erfahrungen mit dem Rest von uns teilen?
André
3
Ich weiß nicht, ob es verfügbar war, als Sie dies geschrieben haben: Verwenden Sie das Chuck Norris-Plugin für Hudson, um die Kontrolle über Ihre Inhalte weiter zu verbessern!
Johannes Charra
8
Update für 2011/2012 : Diejenigen, die Hudson in Betracht ziehen, sollten Jenkins verwenden , die Open-Source-Fortsetzung des Hudson-Projekts (Hudson wird jetzt von Oracle kontrolliert )
Mindthief

Antworten:

41

Vielleicht möchten Sie Nose und das Xunit-Ausgabe-Plugin ausprobieren . Mit diesem Befehl können Sie Ihre Komponententests und Abdeckungsprüfungen ausführen lassen:

nosetests --with-xunit --enable-cover

Dies ist hilfreich, wenn Sie die Jenkins-Route einschlagen oder einen anderen CI-Server verwenden möchten, der JUnit-Testberichte unterstützt.

Ebenso können Sie die Ausgabe von Pylint mit dem Plugin für Verstöße für Jenkins erfassen

Jason Baker
quelle
4
Nose enthält jetzt standardmäßig das xunit-Plugin -nosetests --with-xunit
dbr
3
Wie führt man dann das Auditing von Pylint aus durch? Wenn ich das nosetests --with-xunit --enable-auditbekomme, bekomme ichnosetests: error: no such option: --enable-audit
Adam Parkin
2
Modernisierte Antwort, das NoseXUnit-Zeug ist jetzt eingebaut und von dem Unglücklichen umbenannt --with-nosexunitin --with-xunit.
dbr
10

Ich weiß nicht, ob es funktionieren würde: Bitten wird von den Leuten gemacht, die Trac schreiben und ist in Trac integriert. Apache Gump ist das von Apache verwendete CI-Tool. Es ist in Python geschrieben.

Edomaur
quelle
9

Wir haben große Erfolge mit TeamCity als CI-Server und mit Nase als Testläufer erzielt . Mit dem Teamcity-Plugin für Nasentests können Sie die Anzahl der bestandenen / nicht bestandenen, lesbaren Anzeigen für fehlgeschlagene Tests (die per E-Mail gesendet werden können) zählen. Sie können sogar Details zu den Testfehlern anzeigen, während der Stapel ausgeführt wird.

Wenn natürlich Dinge wie das Ausführen auf mehreren Computern unterstützt werden und es viel einfacher einzurichten und zu warten ist als Buildbot.

Kozyarchuk
quelle
6

Atlassians Bambus ist auf jeden Fall einen Besuch wert. Die gesamte Atlassian Suite (JIRA, Confluence, FishEye usw.) ist ziemlich süß.

Russ
quelle
6

Ich denke, dieser Thread ist ziemlich alt, aber hier ist meine Einstellung zu Hudson:

Ich entschied mich für Pip und richtete ein Repo ein (das schmerzhafte, aber gut aussehende Eierkorb), auf das Hudson mit erfolgreichen Tests automatisch hochlädt. Hier ist mein grobes und fertiges Skript zur Verwendung mit einem hudson config-Ausführungsskript wie: /var/lib/hudson/venv/main/bin/hudson_script.py -w $ WORKSPACE -p my.package -v $ BUILD_NUMBER, einfach eingeben ** / cover.xml, pylint.txt und nosetests.xml in den Konfigurationsbits:

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

Wenn Sie Dinge bereitstellen, können Sie Folgendes tun:

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

Und dann können Leute Sachen entwickeln mit:

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

Dieses Zeug setzt voraus, dass Sie eine Repo-Struktur pro Paket mit einer setup.py und Abhängigkeiten haben, die alle eingerichtet sind. Dann können Sie einfach den Trunk auschecken und dieses Zeug darauf ausführen.

Ich hoffe das hilft jemandem.

------aktualisieren---------

Ich habe Epydoc hinzugefügt, das sehr gut zu Hudson passt. Fügen Sie Ihrer Konfiguration einfach javadoc mit dem HTML-Ordner hinzu

Beachten Sie, dass pip das Flag -E heutzutage nicht richtig unterstützt, sodass Sie Ihr venv separat erstellen müssen

Nick Holden
quelle
Diese Antwort ist sehr nützlich und enthält viele Details zu den Interna von Python CI, die Sie von Jenkins oder was auch immer nicht kostenlos erhalten. Vielen Dank!
Maksimov
3

Wenn Sie eine gehostete CI-Lösung in Betracht ziehen und Open Source verwenden, sollten Sie sich auch Travis CI ansehen - es hat eine sehr gute Integration mit GitHub. Während es als Ruby-Tool begann, haben sie vor einiger Zeit Python-Unterstützung hinzugefügt .

Alex Dupuy
quelle
2

Signal ist eine weitere Option. Sie können mehr darüber wissen und sich auch hier ein Video ansehen .

Diego Carrion
quelle
2

Ich würde CircleCi in Betracht ziehen - es hat eine großartige Python-Unterstützung und eine sehr hübsche Ausgabe.

Paul Biggar
quelle
1

Der Binstar von Continuum kann jetzt Builds von Github auslösen und für Linux, OSX und Windows kompilieren (32/64). Das Schöne ist, dass Sie die Verteilung und die kontinuierliche Integration wirklich eng miteinander verbinden können. Das kreuzt die T's und punktiert die I's der Integration. Die Site, der Workflow und die Tools sind wirklich ausgefeilt und AFAIK conda ist die robusteste und pythonischste Methode zum Verteilen komplexer Python-Module, bei denen Sie C / C ++ / Fotran-Bibliotheken umbrechen und verteilen müssen.

Jelle
quelle
0

Wir haben ziemlich viel gebissen. Es ist hübsch und lässt sich gut in Trac integrieren, aber es ist schwierig, es anzupassen, wenn Sie einen nicht standardmäßigen Workflow haben. Außerdem gibt es nicht so viele Plugins wie für die beliebtesten Tools. Derzeit prüfen wir Hudson als Ersatz.

Allen
quelle
0

Überprüfen Sie rultor.com . Wie in diesem Artikel erläutert, wird Docker für jeden Build verwendet. Dank dessen können Sie alles in Ihrem Docker-Image konfigurieren, einschließlich Python.

yegor256
quelle
0

Kleiner Haftungsausschluss, ich musste tatsächlich eine solche Lösung für einen Client entwickeln, der eine Möglichkeit zum automatischen Testen und Bereitstellen von Code auf einem Git-Push sowie zum Verwalten der Issue-Tickets über Git-Notizen wünschte . Dies führte auch zu meiner Arbeit am AIMS-Projekt .

Man könnte leicht nur das Einrichten eines nackten Knoten - System , das einen Build Benutzer hat und verwalten ihre Build durch make(1), expect(1), crontab(1)/ systemd.unit(5), undincrontab(1) . Man könnte sogar noch einen Schritt weiter gehen und Ansible und Sellerie für verteilte Builds mit einem Gridfs / NFS-Dateispeicher verwenden.

Obwohl ich nicht erwarten würde, dass jemand anderes als ein Graybeard UNIX-Typ oder ein Ingenieur / Architekt auf Prinzipienebene tatsächlich so weit geht. Dies ist nur eine gute Idee und eine potenzielle Lernerfahrung, da ein Build-Server nichts anderes als eine Möglichkeit ist, Skriptaufgaben willkürlich auf automatisierte Weise auszuführen.

Dwight Spencer
quelle