„Ładna” ciągła integracja dla Pythona

116

To jest trochę ... próżne pytanie, ale wyjście BuildBota nie jest szczególnie przyjemne.

Na przykład w porównaniu z ...

.. a inne, BuildBot wygląda raczej ... archaicznie

Obecnie gram z Hudsonem, ale jest on bardzo skoncentrowany na Javie (chociaż dzięki temu przewodnikowi łatwiej było skonfigurować niż BuildBot i wygenerowałem więcej informacji)

Zasadniczo: czy istnieją systemy ciągłej integracji skierowane do Pythona, które generują wiele błyszczących wykresów i tym podobnych?


Aktualizacja: Od tego czasu projekt Jenkins zastąpił Hudson jako społeczną wersję pakietu. Pierwotni autorzy również przenieśli się do tego projektu. Jenkins jest teraz standardowym pakietem w systemach Ubuntu / Debian, RedHat / Fedora / CentOS i innych. Następująca aktualizacja jest nadal zasadniczo poprawna. Punkt wyjścia do zrobienia tego z Jenkinsem jest inny.

Aktualizacja: po wypróbowaniu kilku alternatyw, myślę, że zostanę przy Hudsonie. Uczciwość była miła i prosta, ale dość ograniczona. Myślę, że Buildbot lepiej nadaje się do posiadania wielu niewolników kompilacji, niż wszystkiego, co działa na jednej maszynie, tak jak ja jej używałem .

Konfiguracja Hudsona dla projektu w Pythonie była całkiem prosta:

  • Pobierz Hudson z http://hudson-ci.org/
  • Uruchom to z java -jar hudson.war
  • Otwórz interfejs sieciowy pod domyślnym adresem http://localhost:8080
  • Przejdź do Manage Hudson, Plugins, kliknij „Update” lub podobną
  • Zainstaluj wtyczkę Git (musiałem ustawić gitścieżkę w globalnych preferencjach Hudson)
  • Utwórz nowy projekt, wprowadź repozytorium, okresy odpytywania SCM i tak dalej
  • Zainstaluj nosetestsprzez, easy_installjeśli jeszcze nie jest
  • Na etapie kompilacji dodaj nosetests --with-xunit --verbose
  • Zaznacz opcję „Publikuj raport wyników testu JUnit” i ustaw „Pliki XML raportu testowego” na **/nosetests.xml

To wszystko, czego potrzeba. Możesz ustawić powiadomienia e-mail, a wtyczki są warte obejrzenia. Kilka, których obecnie używam w projektach Pythona:

  • Wtyczka SLOCCount do liczenia linii kodu (i tworzenia wykresów!) - musisz zainstalować sloccount osobno
  • Naruszenia dotyczące analizowania danych wyjściowych PyLint (można ustawić progi ostrzegawcze, wykreślić liczbę naruszeń dla każdej kompilacji)
  • Cobertura może przeanalizować wyjście Cover.py. Nosetest może uzyskać pokrycie podczas przeprowadzania testów, używając nosetests --with-coverage(to zapisuje dane wyjściowe **/coverage.xml)
dbr
źródło
Świetne pytanie, szukam teraz podobnych rzeczy. Jeśli wybierzesz jedną trasę, czy możesz podzielić się swoim doświadczeniem z resztą z nas?
André
3
Nie wiem, czy była dostępna, kiedy pisałeś to: użyj wtyczki Chuck Norris dla Hudson, aby jeszcze bardziej zwiększyć kontrolę nad swoimi rzeczami!
Johannes Charra
8
Aktualizacja na rok 2011/2012 : Ci, którzy uważają, że Hudson powinni używać Jenkinsa , będącego kontynuacją projektu Hudson o otwartym kodzie źródłowym (Hudson jest teraz kontrolowany przez Oracle )
złodziej umysłów

Odpowiedzi:

41

Możesz sprawdzić Nose i wtyczkę wyjściową Xunit . Możesz uruchomić testy jednostkowe i sprawdzanie pokrycia za pomocą tego polecenia:

nosetests --with-xunit --enable-cover

Będzie to pomocne, jeśli chcesz skorzystać z trasy Jenkins lub jeśli chcesz użyć innego serwera CI, który obsługuje raportowanie testów JUnit.

Podobnie możesz przechwycić dane wyjściowe pylinta za pomocą wtyczki naruszeń dla Jenkinsa

Jason Baker
źródło
4
Nos zawiera teraz domyślnie wtyczkę xunit -nosetests --with-xunit
dbr
3
Jak więc przeprowadzić audyt z Pylint? Kiedy nosetests --with-xunit --enable-auditdostanęnosetests: error: no such option: --enable-audit
Adam Parkin
2
Unowocześniona odpowiedź, elementy NoseXUnit są teraz wbudowane i przemianowane z niefortunnego-kiedy-zmniejszono --with-nosexunitna --with-xunit.
dbr,
10

Nie wiem, czy to wystarczy: Bitten zostało stworzone przez ludzi, którzy piszą Traca i jest zintegrowane z Trac. Apache Gump to narzędzie CI używane przez Apache. Jest napisany w Pythonie.

edomaur
źródło
9

Odnieśliśmy wielki sukces z TeamCity jako naszym serwerem CI i wykorzystując nos jako nasz testowy biegacz. Wtyczka Teamcity do testów nosetestów zapewnia zliczanie wyniku pozytywnego / negatywnego, czytelny wyświetlacz dla niepowodzenia testu (który można przesłać pocztą elektroniczną). Możesz nawet zobaczyć szczegóły niepowodzeń testów podczas działania stosu.

Jeśli oczywiście obsługuje takie rzeczy, jak działanie na wielu komputerach, i jest znacznie prostsze w konfiguracji i utrzymaniu niż buildbot.

Kozyarchuk
źródło
6

Warto również sprawdzić Bamboo Atlassian . Cały pakiet Atlassian (JIRA, Confluence, FishEye itp.) Jest całkiem fajny.

Russ
źródło
6

Wydaje mi się, że ten wątek jest dość stary, ale oto moje podejście do niego z hudsonem:

Zdecydowałem się pójść z pipem i założyć repozytorium (bolesne, ale ładnie wyglądający koszyk na jajka), do którego Hudson automatycznie przesyła po udanych testach. Oto mój szorstki i gotowy skrypt do użycia ze skryptem wykonywania konfiguracji hudson, takim jak: /var/lib/hudson/venv/main/bin/hudson_script.py -w $ WORKSPACE -p my.package -v $ BUILD_NUMBER, po prostu wstaw ** / zasięg.xml, pylint.txt i nosetests.xml w bitach konfiguracyjnych:

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

Jeśli chodzi o wdrażanie rzeczy, możesz zrobić coś takiego:

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

A potem ludzie mogą tworzyć rzeczy za pomocą:

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

Te rzeczy zakładają, że masz strukturę repozytorium na pakiet z ustawionym plikiem setup.py i zależnościami, a następnie możesz po prostu sprawdzić trunk i uruchomić na nim te rzeczy.

Mam nadzieję, że to komuś pomoże.

------aktualizacja---------

Dodałem epydoc, który bardzo ładnie pasuje do hudson. Po prostu dodaj javadoc do swojej konfiguracji za pomocą folderu html

Zauważ, że pip nie obsługuje obecnie poprawnie flagi -E, więc musisz osobno utworzyć venv

Nick Holden
źródło
Ta odpowiedź jest bardzo przydatna i zawiera wiele szczegółów dotyczących wewnętrznych elementów Python CI, coś, czego nie dostaniesz za darmo od Jenkinsa lub cokolwiek innego. Dzięki!
maksimov
3

Jeśli rozważasz hostowane rozwiązanie CI i robisz open source, powinieneś również przyjrzeć się Travis CI - ma bardzo dobrą integrację z GitHub. Zaczęło się jako narzędzie Ruby, ale jakiś czas temu dodali obsługę Pythona .

Alex Dupuy
źródło
2

Sygnał to kolejna opcja. Możesz dowiedzieć się więcej na ten temat i obejrzeć film również tutaj .

Diego Carrion
źródło
2

Rozważałbym CircleCi - ma świetne wsparcie dla Pythona i bardzo ładne wyjście.

Paul Biggar
źródło
1

Continuum binstar teraz jest w stanie wyzwolić buduje z github i można skompilować dla Linux, OSX i Windows (32/64). fajną rzeczą jest to, że naprawdę pozwala ci na ścisłe połączenie dystrybucji i ciągłej integracji. To przecinanie „t” i kropkowanie „ja” integracji. Witryna, przepływ pracy i narzędzia są naprawdę dopracowane, a AFAIK conda jest najbardziej niezawodnym i pythonowym sposobem dystrybucji złożonych modułów Pythona, w którym trzeba pakować i dystrybuować biblioteki C / C ++ / Fotran.

Jelle
źródło
0

Sporo używaliśmy ugryzienia. Jest ładny i dobrze integruje się z Trac, ale jego dostosowanie jest trudne, jeśli masz niestandardowy przepływ pracy. Poza tym nie ma tak wielu wtyczek, jak dla bardziej popularnych narzędzi. Obecnie oceniamy Hudson jako zamiennik.

Allen
źródło
0

Sprawdź rultor.com . Jak wyjaśniono w tym artykule , używa Dockera do każdej kompilacji. Dzięki temu możesz skonfigurować co tylko zechcesz w swoim obrazie Dockera, w tym w Pythonie.

yegor256
źródło
0

Małe zastrzeżenie, tak naprawdę musiałem zbudować takie rozwiązanie dla klienta, który chciał automatycznie przetestować i wdrożyć dowolny kod w git push oraz zarządzać biletami wydania za pomocą notatek git. To również doprowadziło do mojej pracy nad projektem AIMS .

Można było łatwo po prostu skonfigurować gołego systemu węzła, który ma użytkownikowi budować i zarządzać ich gromadzeniu przez make(1), expect(1), crontab(1)/ systemd.unit(5)i incrontab(1). Można by nawet pójść o krok dalej i użyć ansible i selera do kompilacji rozproszonych z magazynem plików gridfs / nfs.

Chociaż nie spodziewałbym się, że ktokolwiek inny poza Sziwobrodym UNIXem lub inżynierem / architektem poziomu Principle zajdzie tak daleko. To po prostu fajny pomysł i potencjalne doświadczenie edukacyjne, ponieważ serwer kompilacji to nic innego jak sposób na arbitralne wykonywanie zadań skryptowych w sposób zautomatyzowany.

Dwight Spencer
źródło