Python的“漂亮”持续集成

时间:2008-10-22 12:49:55

标签: python jenkins continuous-integration buildbot

这是一个有点虚荣的问题,但BuildBot的输出并不是特别好看......

例如,与..相比。

..和其他人,BuildBot看起来相当......古老

我目前正在玩Hudson,但它是以Java为中心的(尽管使用this guide,我发现它比BuildBot更容易设置,并产生更多信息)

基本上:有没有针对python的持续集成系统,它会产生大量闪亮的图形等等?


更新:从那时起,Jenkins项目取代了Hudson作为该软件包的社区版本。原作者也转到了这个项目。 Jenkins现在是Ubuntu / Debian,RedHat / Fedora / CentOS等标准软件包。以下更新仍然基本正确。使用Jenkins执行此操作的起点不同。

更新: 在尝试了一些替代方案之后,我想我会坚持使用Hudson。 Integrity很简单,但非常有限。我认为Buildbot更适合拥有众多构建从属,而不是像我使用它一样在一台机器上运行。

为一个Python项目设置Hudson非常简单:

  • http://hudson-ci.org/
  • 下载Hudson
  • 使用java -jar hudson.war
  • 运行它
  • 在默认地址http://localhost:8080
  • 上打开网络界面
  • 转到Manage Hudson,插件,点击“更新”或类似
  • 安装Git插件(我必须在Hudson全局首选项中设置git路径)
  • 创建新项目,输入存储库,SCM轮询间隔等
  • 如果nosetests尚未
  • ,请通过easy_install安装nosetests --with-xunit --verbose
  • 在构建步骤中,添加**/nosetests.xml
  • 选中“发布JUnit测试结果报告”并将“测试报告XML”设置为nosetests --with-coverage

这就是所需要的。您可以设置电子邮件通知,the plugins值得一看。我目前正在使用的一些Python项目:

  • SLOCCount plugin计算代码行(并绘制图表!) - 您需要单独安装sloccount
  • Violations解析PyLint输出(您可以设置警告阈值,绘制每个构建的违规数量)
  • Cobertura可以解析coverage.py输出。 Nosetest可以在运行测试时收集覆盖率,使用**/coverage.xml(这会将输出写入{{1}})

14 个答案:

答案 0 :(得分:41)

您可能需要查看Nosethe Xunit output plugin。您可以使用此命令运行单元测试和覆盖检查:

nosetests --with-xunit --enable-cover

如果您想要使用Jenkins路由,或者您想使用另一个支持JUnit测试报告的CI服务器,那将会很有帮助。

同样,您可以使用violations plugin for Jenkins

捕获pylint的输出

答案 1 :(得分:10)

不知道是否会这样做:Bitten是由编写Trac并与Trac集成的人制作的。 Apache Gump是Apache使用的CI工具。它是用Python编写的。

答案 2 :(得分:9)

我们使用TeamCity作为我们的CI服务器并使用nose作为我们的测试运行器取得了巨大成功。 Teamcity plugin for nosetests为您提供计数通过/失败,可读显示失败的测试(可以是E-Mailed)。您甚至可以在堆栈运行时查看测试失败的详细信息。

当然,如果支持在多台机器上运行这样的东西,那么设置和维护比buildbot简单得多。

答案 3 :(得分:8)

Buildbot的瀑布页面可以相当美化。这是一个很好的例子http://build.chromium.org/buildbot/waterfall/waterfall

答案 4 :(得分:6)

我想这个帖子已经很老了,但这是我对哈德森的看法:

我决定选择pip并设置一个回购(痛苦的工作,但看起来很漂亮的eggbasket),哈德森自动上传到成功的测试。这是我的粗略和准备好的脚本,用于hudson配置执行脚本,如:/var/lib/hudson/venv/main/bin/hudson_script.py -w $ WORKSPACE -p my.package -v $ BUILD_NUMBER,刚放入配置位中的** / coverage.xml,pylint.txt和nosetests.xml:

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

在部署内容时,您可以执行以下操作:

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

然后人们可以使用以下方式开发内容:

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

这个东西假设你的每个包都有一个repo结构,并且设置了setup.py和依赖关系,然后你可以检查一下trunk并在其上运行这些东西。

我希望这可以帮助别人。

------更新---------

我添加了epydoc,它非常适合哈德森。只需使用html文件夹

将javadoc添加到您的配置中

请注意,这些天pip不能正确支持-E标志,所以你必须单独创建你的venv

答案 5 :(得分:6)

Atlassian的Bamboo也绝对值得一试。整个Atlassian套房(JIRA,Confluence,FishEye等)非常可爱。

答案 6 :(得分:3)

另一个:Shining Panda是python的托管工具

答案 7 :(得分:3)

如果您正在考虑托管CI解决方案,并且正在开源,那么您也应该考虑Travis CI - 它与GitHub的集成非常好。虽然它最初是作为Ruby工具开始的,但它们前一段时间已经added Python support

答案 8 :(得分:2)

信号是另一种选择。您可以了解更多信息并观看视频here

答案 9 :(得分:2)

我会考虑CircleCi - 它有很棒的Python支持,而且输出非常漂亮。

答案 10 :(得分:1)

continuum' s binstar现在能够从github触发构建,并且可以为linux,osx和windows(32/64)编译。整洁的事情是,它确实允许您密切耦合分布和持续集成。那是越过了t&s并点缀了我的整合。网站,工作流程和工具都非常精致,AFAIK conda是分发复杂python模块的最强大和最方便的方式,你需要包装分发C / C ++ / Fotran库。

答案 11 :(得分:0)

我们使用了很多咬过的东西。它很漂亮并且与Trac很好地集成,但是如果你有任何非标准的工作流程,那么定制它会很痛苦。此外,插件的数量也不如更受欢迎的工具那么多。目前,我们正在评估Hudson作为替代品。

答案 12 :(得分:0)

检查rultor.com。正如this article所解释的那样,它为每个构建使用Docker。多亏了这一点,您可以在Docker镜像中配置您喜欢的任何内容,包括Python。

答案 13 :(得分:0)

小免责声明,我实际上不得不为一个想要在git push上自动测试和部署任何代码的方法的客户构建这样的解决方案,并通过git notes管理问题门票。这也导致我在AIMS project上的工作。

可以轻松地设置一个具有构建用户的裸节点系统,并通过make(1)expect(1)crontab(1) / systemd.unit(5)和{{1 }}。甚至可以更进一步,使用ansible和celery进行分布式构建和gridfs / nfs文件存储。

虽然,我不希望除了Graybeard UNIX人或者原理级工程师/架构师以外的任何人实际上走得这么远。由于构建服务器只是一种以自动方式任意执行脚本任务的方式,因此只是提出了一个好主意和潜在的学习经验。