Jenkins-持续集成秘籍-全-

Jenkins 持续集成秘籍(全)

原文:zh.annas-archive.org/md5/B61AA47DB2DCCD9DEF9EF3E145A763A7

译者:飞龙

协议:CC BY-NC-SA 4.0

序言

Jenkins 是一个基于 Java 的持续集成(CI)服务器,支持在软件周期的早期发现缺陷。 由于插件数量迅速增长(目前超过 1,000 个),Jenkins 与许多类型的系统通信,构建和触发各种测试。

CI 涉及对软件进行小改动,然后构建和应用质量保证流程。 缺陷不仅出现在代码中,还出现在命名约定、文档、软件设计方式、构建脚本、将软件部署到服务器的过程等方面。 CI 迫使缺陷早日显现,而不是等待软件完全生产出来。 如果在软件开发生命周期的后期阶段发现了缺陷,那么处理过程将会更加昂贵。 一旦错误逃逸到生产环境中,修复成本将急剧增加。 估计捕捉缺陷的成本早期是后期的 100 到 1,000 倍。 有效地使用 CI 服务器,如 Jenkins,可能是享受假期和不得不加班英雄般拯救一天之间的区别。 而且你可以想象,在我作为一个有着对质量保证的渴望的高级开发人员的日常工作中,我喜欢漫长而乏味的日子,至少是对于关键的生产环境。

Jenkins 可以定期自动构建软件,并根据定义的标准触发测试,拉取结果并基于定义的标准失败。 通过构建失败早期降低成本,增加对所生产软件的信心,并有可能将主观流程转变为开发团队认为是公正的基于指标的进攻性流程。

Jenkins 不仅是一个 CI 服务器,它还是一个充满活力和高度活跃的社区。 开明的自我利益决定了参与。 有许多方法可以做到这一点:

这本书涵盖了什么内容

第一章,维护 Jenkins,描述了常见的维护任务,如备份和监视。 本章中的配方概述了适当维护的方法,进而降低了故障的风险。

第二章,增强安全性,详细介绍如何保护 Jenkins 的安全性以及启用单点登录(SSO)的价值。本章涵盖了许多细节,从为 Jenkins 设置基本安全性,部署企业基础设施(如目录服务)到部署自动测试 OWASP 十大安全性。

第三章,构建软件,审查了 Jenkins 与 Maven 构建的关系以及使用 Groovy 和 Ant 进行少量脚本编写。配方包括检查许可证违规、控制报告创建、运行 Groovy 脚本以及绘制替代度量。

第四章,通过 Jenkins 进行沟通,审查了针对不同目标受众(开发人员、项目经理以及更广泛的公众)的有效沟通策略。Jenkins 是一个有才华的沟通者,通过电子邮件、仪表板和谷歌服务的一大群插件通知您。它通过移动设备对您叫嚷,在您经过大屏幕时辐射信息,并通过 USB 海绵导弹发射器向您射击。

第五章,利用度量改善质量,探讨了源代码度量的使用。为了节省成本和提高质量,您需要尽早在软件生命周期中消除缺陷。Jenkins 测试自动化创建了一张度量的安全网。本章的配方将帮助您构建这个安全网。

第六章,远程测试,详细介绍了建立和运行远程压力测试和功能测试的方法。本章结束时,您将对 Web 应用程序和 Web 服务运行性能和功能测试。包括两种典型的设置方案。第一种是通过 Jenkins 将 WAR 文件部署到应用服务器。第二种是创建多个从节点,准备好将测试工作从主节点转移。

第七章,探索插件,有两个目的。第一个是展示一些有趣的插件。第二是审查插件的工作原理。

附录,增进质量的流程,讨论了本书中的配方如何支持质量流程,并指向其他相关资源。这将帮助您形成一个完整的图景,了解配方如何支持您的质量流程。

本书所需准备的内容

本书假设您已经在运行 Jenkins 实例。

要运行本书提供的配方,您需要以下软件:

推荐:

可选的:

有帮助的:

  • 一个本地的 subversion 或 Git 仓库

  • 首选的操作系统:Linux(Ubuntu)

    注意

    请注意,您可以从 Jenkins GUI (http://localhost:8080/configure) 中安装不同版本的 Maven、Ant 和 Java。您不需要将这些作为操作系统的一部分安装。

安装 Jenkins 有许多方法:作为 Windows 服务安装,使用 Linux 的仓库管理功能(如aptyum),使用 Java Web Start,或直接从 WAR 文件运行。您可以选择您感觉最舒适的方法。但是,您可以从 WAR 文件运行 Jenkins,使用命令行中的 HTTPS,指向自定义目录。如果任何实验出现问题,则可以简单地指向另一个目录并重新开始。

要使用此方法,首先将JENKINS_HOME环境变量设置为您希望 Jenkins 在其中运行的目录。接下来,运行类似以下命令的命令:

Java –jar jenkins.war –httpsPort=8443 –httpPort=-1

Jenkins 将开始在端口8443上通过 https 运行。通过设置httpPort=-1关闭 HTTP 端口,并且终端将显示日志信息。

您可以通过执行以下命令来请求帮助:

Java –jar jenkins.war –help

可以在wiki.jenkins-ci.org/display/JENKINS/Installing+Jenkins找到更广泛的安装说明。

对于在 VirtualBox 中使用 Jenkins 设置虚拟镜像的更高级菜谱描述,您可以使用第一章 维护 Jenkins 中的 使用测试 Jenkins 实例 菜谱。

这本书是为谁准备的

本书适用于 Java 开发人员、软件架构师、技术项目经理、构建管理器以及开发或 QA 工程师。预期具有对软件开发生命周期的基本理解,一些基本的 Web 开发知识以及对基本应用服务器概念的熟悉。还假定具有对 Jenkins 的基本理解。

在本书中,您会发现几个经常出现的标题(准备就绪,如何做,它是如何工作的,还有更多以及另请参见)。

为了清晰地说明如何完成一个菜谱,我们使用以下各节。

准备就绪

本节告诉您可以在菜谱中期待什么,并描述了为菜谱设置任何软件或任何预备设置所需的步骤。

如何做…

本节包含了遵循菜谱所需的步骤。

它是如何工作的…

本节通常包含了对前一节中发生的事情的详细解释。

还有…

本节包含有关菜谱的其他信息,以使读者更加了解菜谱。

另请参见

本节提供了其他有用信息的相关链接。

约定

在本书中,您将找到一些区分不同类型信息的文本样式。 以下是这些样式的一些示例及其含义的解释。

文本中的代码词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟网址、用户输入和 Twitter 用户名显示如下:"然后,特定于工作的配置将存储在子目录中的config.xml中。"

代码块设置如下:

<?xml version='1.0' encoding='UTF-8'?>
<org.jvnet.hudson.plugins.thinbackup.ThinBackupPluginImpl plugin="thinBackup@1.7.4">
<fullBackupSchedule>1 0 * *  7</fullBackupSchedule>
<diffBackupSchedule>1 1 * * *</diffBackupSchedule>
<backupPath>/data/jenkins/backups</backupPath>
<nrMaxStoredFull>61</nrMaxStoredFull>
<excludedFilesRegex></excludedFilesRegex>
<waitForIdle>false</waitForIdle>
<forceQuietModeTimeout>120</forceQuietModeTimeout>
<cleanupDiff>true</cleanupDiff>
<moveOldBackupsToZipFile>true</moveOldBackupsToZipFile>
<backupBuildResults>true</backupBuildResults>
<backupBuildArchive>true</backupBuildArchive>
<backupUserContents>true</backupUserContents>
<backupNextBuildNumber>true</backupNextBuildNumber>
<backupBuildsToKeepOnly>true</backupBuildsToKeepOnly>
</org.jvnet.hudson.plugins.thinbackup.ThinBackupPluginImpl>

当我们希望引起您对代码块的特定部分的注意时,相关行或项目将以粗体显示:

server {
  listen   80;
  server_name  localhost;
  access_log  /var/log/nginx/jenkins _8080_proxypass_access.log;
  error_log  /var/log/nginx/jenkins_8080_proxypass_access.log;
  location / {
    proxy_pass      http://127.0.0.1:7070/;
    include         /etc/nginx/proxy.conf;
  }
}

任何命令行输入或输出都将显示如下:

sudo apt-get install jenkins

新术语重要词汇以粗体显示。 您在屏幕上看到的单词,例如菜单或对话框中的单词,将以此类似的形式显示在文本中:“单击保存。”

注意

警告或重要提示将显示在此框中。

提示

技巧和窍门会显示如此。

读者反馈

我们的读者反馈始终受欢迎。 请告诉我们您对本书的看法——您喜欢或不喜欢的方面。 读者反馈对我们非常重要,因为它帮助我们开发您真正会受益的标题。

要发送给我们一般反馈,只需发送电子邮件至<feedback@packtpub.com>,并在您的消息主题中提及书名。

如果您在某个主题上拥有专业知识,并且对编写或为书籍做贡献感兴趣,请参阅我们的作者指南,网址为 www.packtpub.com/authors

客户支持

现在您是 Packt 书籍的自豪拥有者,我们有一些东西可以帮助您充分利用您的购买。

下载示例代码

您可以从 www.packtpub.com 的帐户中下载您购买的所有 Packt Publishing 书籍的示例代码文件。 如果您在其他地方购买了此书,您可以访问 www.packtpub.com/support 并注册以直接通过电子邮件接收文件。

勘误

虽然我们已经尽了一切努力确保内容的准确性,但错误确实会发生。 如果您在我们的书中发现错误——可能是文本中的错误或代码中的错误——我们将不胜感激您向我们报告。 这样做可以帮助其他读者免受挫折,并帮助我们改进本书的后续版本。 如果您发现任何勘误,请访问 www.packtpub.com/submit-errata,选择您的书籍,单击勘误提交表链接,并输入您的勘误详情。 一旦验证您的勘误,您的提交将被接受,并且勘误将被上传到我们的网站或添加到该标题的错误部分下的任何现有勘误列表中。

要查看先前提交的勘误表,请访问 www.packtpub.com/books/content/support 并在搜索框中输入书名。所需信息将出现在勘误表部分下。

盗版

盗版互联网上的受版权保护的材料是各种媒体持续面临的问题。在 Packt,我们非常重视对我们的版权和许可的保护。如果你在互联网上发现我们作品的任何形式的非法副本,请立即提供给我们位置地址或网站名称,以便我们采取措施解决。

请通过 <copyright@packtpub.com> 联系我们,并附上怀疑盗版材料的链接。

我们感谢您帮助保护我们的作者和我们为您提供有价值内容的能力。

问题

如果你对本书的任何方面有问题,可以通过 <questions@packtpub.com> 联系我们,我们将尽力解决问题。

第一章 维护 Jenkins

在本章中,我们将涵盖以下步骤:

  • 使用测试 Jenkins 实例

  • 备份和恢复

  • 从命令行修改 Jenkins 配置

  • 安装 Nginx

  • 配置 Nginx 作为反向代理

  • 报告总体存储使用情况

  • 通过日志解析故意失败的构建

  • 通过日志解析添加警告存储使用违规的作业

  • 通过 Firefox 与 Jenkins 保持联系

  • 通过 JavaMelody 进行监视

  • 跟踪脚本粘合剂

  • 编写 Jenkins 命令行界面脚本

  • 使用 Groovy 全局修改作业

  • 发出归档需求信号

介绍

Jenkins 功能丰富,通过插件可以大大扩展。Jenkins 与许多外部系统进行通信,其作业与许多不同的技术合作。在一个运行 24 x 7 的丰富环境中维护 Jenkins 是一个挑战。你必须注意细节。添加新作业很容易,而且你不太可能很快删除旧项目。负载增加,密码过期,存储填满。此外,Jenkins 及其插件的改进速度很快。每周都会发布一个新的 Jenkins 小版本,主要是改进,偶尔会有 bug。在复杂环境中保持系统稳定,你需要监视、清理存储、备份、控制你的 Jenkins 脚本,并始终保持清洁和抛光。本章包含最常见任务的步骤。正确的维护可以降低失败的风险,例如:

  • 新插件引发异常: 有很多优秀的插件正在快速版本更改中编写。在这种情况下,你很容易意外添加带有新缺陷的插件新版本。在升级期间曾出现过插件突然不起作用的情况。为了防止插件异常的风险,在发布到关键系统之前考虑使用一个测试 Jenkins 实例。

  • 存储溢出的问题: 如果你保留了包括 war 文件、大量的 JAR 文件或其他类型的二进制文件和源代码在内的构建历史记录,那么你的存储空间会以惊人的速度被消耗掉。存储成本已经大幅降低,但存储使用量意味着更长的备份时间和更多从从节点到主节点的通信。为了最小化磁盘溢出的风险,你需要考虑你的备份和恢复策略,以及作业高级选项中表达的相关构建保留策略。

  • 脚本混乱: 由于作业由各个开发团队编写,所包含脚本的位置和风格各异。这使得你很难跟踪。考虑使用明确定义的脚本位置和通过插件管理的脚本仓库。

  • 资源耗尽: 随着内存消耗或强烈作业数量增加,Jenkins 会变慢。正确的监控和快速反应会减少影响。

  • 由于有机增长而导致工作之间普遍缺乏一致性:Jenkins 安装和使用都很简单。无缝开启插件的能力令人上瘾。Jenkins 在组织内的采用速度可能令人叹为观止。没有一致的政策,你的团队将引入大量插件,并且也会有很多执行相同工作方式的方式。规范提高了工作的一致性和可读性,从而减少了维护工作。

    注意

    本章中的示例旨在解决提到的风险。它们只代表一套方法。如果您有意见或改进意见,请随时通过 <bergsmooth@gmail.com> 联系我,或者最好是向 Jenkins 社区维基添加教程。

Jenkins 社区正在为您努力工作。Jenkins 每周都有小版本发布,并且许多插件偶尔都会有增量改进,因为变化的速度,会引入错误。如果您发现问题,请报告。

提示

加入社区

要添加社区错误报告或修改维基页面,您需要在 wiki.jenkins-ci.org/display/JENKINS/Issue+Tracking 创建一个帐户。

使用测试 Jenkins 实例

持续集成CI)服务器在创建确定性发布周期方面至关重要。如果 CI 存在长期不稳定性,那么在项目计划中达到里程碑的速度将会减慢。增量升级令人上瘾并且大多数情况下很简单,但应该以 Jenkins 的关键角色——软件项目的生命周期为依据来看待。

在将插件发布到您的 Jenkins 生产服务器之前,值得积极部署到一个测试 Jenkins 实例,然后坐下来让系统运行作业。这样可以给你足够的时间来对发现的任何轻微缺陷做出反应。

设置测试实例的方法有很多种。其中一种是使用 Ubuntu 的虚拟图像,并与 主机 服务器(虚拟机运行的服务器)共享工作区。这种方法有很多优点:

  • 保存状态:您可以随时保存运行中虚拟图像的状态,并在以后返回到该运行状态。这对于有高风险失败的短期实验非常有用。

  • 共享图像的能力:您可以在任何可以运行播放器的地方运行虚拟图像。这可能包括您的家庭桌面或一个高级服务器。

  • 使用多种不同操作系统:这对运行具有多种浏览器类型的集成测试或功能测试的节点机器非常有用。

  • 交换工作区:通过将工作区放在虚拟服务器主机外部,您可以测试不同版本级别的操作系统与一个工作区。您还可以测试 Jenkins 的一个版本与具有不同插件组合的不同主机工作区。

    提示

    长期支持版本

    社区通过使用长期支持版本的 Jenkins 来管理核心稳定性,这个版本相对于最新版本来说更加成熟,功能较少。然而,它被认为是升级最稳定的平台(mirrors.jenkins-ci.org/war-stable/latest/jenkins.war)。

测试实例通常比接受和生产系统的规格低。通过让测试实例处于饥饿状态,你可以及早暴露出某些类型的问题,比如内存泄漏。随着你将配置移到生产环境,你希望扩大容量,这可能涉及从虚拟机移动到硬件。

这个教程详细介绍了如何使用 VirtualBox(www.virtualbox.org/),这是一个开源的虚拟图像播放器,带有一个 Ubuntu 镜像(www.ubuntu.com/)。虚拟图像将挂载主机服务器上的一个目录。然后你将 Jenkins 指向挂载的目录。当客户端操作系统重新启动时,Jenkins 将自动运行并对共享目录进行操作。

注意

在整本书中,将使用 Ubuntu 作为示例操作系统引用各个案例。

准备就绪

你需要下载并安装 VirtualBox。你可以在www.virtualbox.org/manual/UserManual.html找到下载最新版本 VirtualBox 的详细说明。在撰写本书时,从 VirtualBox 镜像 SourceForge 网站下载的最新版本是 Ubuntu 11.04。解压缩 Ubuntu 11.04 虚拟图像文件从sourceforge.net/projects/virtualboximage/files/Ubuntu%20Linux/11.04/ubuntu_11.04-x86.7z/download

如果遇到问题,手册是一个很好的起点;特别是,请参考第十二章故障排除,网址为www.virtualbox.org/manual/ch12.html

请注意,在阅读时可能会有更新的图像可用。随时尝试最新版本;很可能这个教程仍然适用。

你会在virtualboxes.org/images/ubuntu-server/找到一系列最新的 Ubuntu 虚拟图像。

提示

安全注意事项

如果你考虑使用他人的操作系统镜像,这是一个不良的安全实践,那么你应该按照wiki.ubuntu.com/Testing/VirtualBox中提到的方法从引导光盘创建一个 Ubuntu 镜像。

如何操作...

  1. 运行 VirtualBox 并点击左上角的新建图标。现在你会看到一个用于安装虚拟图像的向导。

  2. 名称设置为Jenkins_Ubuntu_11.04。操作系统类型将自动更新。点击下一步按钮。

  3. 内存设置为2048 MB,然后点击下一步

    请注意,主机机器需要比其分配给客户镜像的总内存多 1GB RAM。在本例中,你的主机机器需要 3GB RAM。欲了解更多详情,请访问www.oracle.com/us/technologies/virtualization/oraclevm/oracle-vm-virtualbox-ds-1655169.pdf

  4. 选择使用现有硬盘。单击文件夹图标浏览并选择未打包的 VDI 镜像:如何做...

  5. 按下创建按钮。

  6. 点击启动图标启动虚拟镜像:如何做...

  7. 使用用户名和密码Ubuntu reverse登录客户操作系统。

  8. 从终端更改 Ubuntu 用户的密码如下:

    sudo passwd
    
    
  9. 按照pkg.jenkins-ci.org/debian/中的说明安装 Jenkins 存储库。

  10. 根据安全补丁更新操作系统(这可能需要一些时间取决于带宽):

    sudo apt-get update
    sudo apt-get upgrade
    
    
  11. 安装内核的dkms模块:

    sudo apt-get install dkms
    
    

    注意,dkms模块支持安装其他内核模块,例如 VirtualBox 所需的模块。欲了解更多详情,请访问help.ubuntu.com/community/DKMS

  12. 安装 Jenkins:

    sudo apt-get install jenkins
    
    
  13. 安装 VirtualBox 的内核模块:

    sudo /etc/init.d/vboxadd setup
    
    
  14. 使用 VirtualBox 窗口中的设备菜单选项安装客户附件:如何做...

  15. jenkins用户添加到vboxsf组,如下所示:

    sudo gedit /etc/group
    vboxsf:x:1001:Jenkins
    
    
  16. 修改/etc/default/jenkins中的JENKINS_HOME变量,以指向挂载的共享目录:

    sudo gedit /etc/default/jenkins
    JENKINS_HOME=/media/sf_workspacej
    
    
  17. 在主机操作系统上创建名为workspacej的目录。

  18. 在 VirtualBox 中,右键单击 Ubuntu 镜像并选择设置

  19. 文件夹路径字段更新为指向您之前创建的目录。在下面的截屏中,你可以看到该文件夹是在我的home目录下创建的:如何做...

  20. 重新启动 VirtualBox,然后启动 Ubuntu 客户操作系统。

  21. 在客户操作系统上运行 Firefox 并浏览http://localhost:8080。你将看到一个本地运行的 Jenkins 实例,准备用于实验。

它是如何工作的...

首先,你安装了一个 Ubuntu 的虚拟镜像,更改了密码,使其他人更难登录,并更新了客户操作系统的安全补丁。

Jenkins 存储库已添加到客户操作系统中已知存储库的列表。这涉及在本地安装存储库密钥。该密钥用于验证自动下载的软件包属于您同意信任的存储库。一旦信任启用,您可以通过标准软件包管理安装最新版本的 Jenkins,并随后积极更新。

您需要安装一些额外的代码,称为客户端附加组件,以便 VirtualBox 可以从主机共享文件夹。客户端附加组件依赖于动态内核模块支持DKMS)。DKMS 允许将代码的部分动态添加到内核中。当您运行/etc/init.d/vboxadd setup命令时,VirtualBox 通过 DKMS 添加了客户端附加组件模块。

注意

警告:如果您忘记添加 DKMS 模块,则共享文件夹将在没有显示任何错误的情况下失败。

默认的 Jenkins 实例现在需要进行一些重新配置:

  • jenkins用户需要属于vboxsf组,以便具有使用共享文件夹的权限

  • /etc/init.d/jenkins 启动脚本指向/etc/default/jenkins,从而获取特定属性的值,如JENKINS_HOME

接下来,您可以通过 VirtualBox GUI 向宿主操作系统添加共享文件夹,最后重新启动 VirtualBox 和宿主操作系统,以确保系统处于完全配置和正确初始化的状态。

配置 VirtualBox 网络有许多选项。您可以在www.virtualbox.org/manual/ch06.html找到一个很好的介绍。

参见

备份和恢复

对于 Jenkins 的顺利运行来说,一个核心任务是定期备份其主目录(在 Ubuntu 中为/var/lib/jenkins),不一定是所有的工件,但至少是其配置以及插件需要生成报告的测试历史记录。

备份没有意义,除非您可以还原。关于此主题有很多故事。我最喜欢的(我不会提及涉及的著名公司)是在 70 年代初期的某个地方,一家公司购买了一台非常昂贵的软件和磁带备份设备,以备份通过他们的主机收集的所有营销结果。然而,并非所有事情都是自动化的。每晚都需要将一盘磁带移入特定插槽。一个工人被分配了这项任务。一年来,工人专业地完成了这项任务。有一天发生了故障,需要备份。备份无法还原。原因是工人每晚还需要按下录制按钮,但这不是分配给他的任务的一部分。没有定期测试还原过程。失败的是过程,而不是薪水微薄的人。因此,吸取历史教训,本配方描述了备份和还原。

目前,备份有多个插件可用。我选择了 thinBackup 插件(wiki.jenkins-ci.org/display/JENKINS/thinBackup),因为它允许调度。

提示

插件的快速演进和配方的有效性

插件更新频繁,可能每周都需要更新。然而,核心配置改变的可能性不大,但增加额外选项的可能性很大,这会增加你在 GUI 中输入的变量。因此,本书中显示的截图可能与最新版本略有不同,但配方应该保持不变。

准备工作

为 Jenkins 创建一个具有读写权限的目录并安装 thinBackup 插件。

小贴士

把墨菲当朋友

你应该假设本书中的所有配方情况最糟糕:外星人攻击、咖啡泼在主板上、猫吃电缆、电缆吃猫等等。确保你正在使用一个测试 Jenkins 实例。

操作步骤...

  1. 管理 Jenkins页面点击ThinBackup链接:操作步骤...

  2. 点击工具集图标旁边的设置链接。

  3. 按照以下截图中显示的细节添加,其中/data/jenkins/backups是你之前创建的目录的占位符。注意关于使用H语法的警告;这将在稍后解释。操作步骤...

  4. 点击保存

  5. 然后,点击立即备份图标。

  6. 从命令行访问你的备份目录。现在你应该看到一个名为FULL-{timestamp}的额外子目录,其中{timestamp}是创建完整备份所需的秒数。

  7. 点击还原图标。

  8. 将显示一个名为从备份还原的下拉菜单,其中显示了备份的日期。选择刚刚创建的备份,然后点击还原按钮:操作步骤...

  9. 为了保证一致性,重新启动 Jenkins 服务器。

工作原理...

备份调度程序使用 cron 表示法(en.wikipedia.org/wiki/Cron)。1 0 * * 7表示每周的第七天在凌晨 00:01。1 1 * * *意味着差异备份每天只发生一次,在凌晨 1:01。每隔七天,前一次的差异备份将被删除。

还记得配置时的警告吗?将时间符号替换为H允许 Jenkins 选择何时运行 thinBackup 插件。H H * * *将在一天中的随机时间触发作业,从而分散负载。

等待 Jenkins/Hudson 空闲以执行备份是一种安全方法,并帮助 Jenkins 分散负载。建议启用此选项;否则,由于构建锁定文件,备份可能会损坏。

在指定的分钟数后强制 Jenkins 进入安静模式,确保在备份时没有作业在运行。此选项在等待 Jenkins 在特定时间内保持安静后强制进入安静模式。这可以避免备份等待 Jenkins 自然达到安静时刻时出现问题。

差异备份仅包含自上次完整备份以来已修改的文件。插件查看最后修改日期以确定需要备份的文件。如果另一个进程更改了最后修改日期但实际上没有更改文件内容,该过程有时可能会出错。

61 是使用备份创建的目录数。由于我们通过 清理差异备份 选项清理差异,因此在清理最旧的备份之前,我们将达到大约 54 个完整备份,大约一年的存档。

我们选择了备份构建结果,因为我们假设我们是在作业内进行清理。完整存档中不会有太多额外的内容添加。但是,如果配置错误,你应该监视存档的存储使用情况。

清理差异备份可以避免手动进行清理工作。将旧备份移到 ZIP 文件中可以节省空间,但可能会暂时减慢 Jenkins 服务器的速度。

注意

为了安全起见,定期将存档复制到系统之外。

名为备份构建存档备份 'userContent' 文件夹备份下一个构建编号文件的备份选项会增加备份的内容和系统状态。

恢复是返回到恢复菜单并选择日期的问题。额外选项包括恢复构建编号文件和插件(从外部服务器下载以减小备份大小)。

注意

我再次强调,你应该定期进行恢复操作,以避免尴尬。

全面备份是最安全的,因为它们会恢复到一个已知的状态。因此,在完整备份之间不要生成太多差异备份。

这还没完呢…

还有几点给你思考。

检查权限错误

如果有权限问题,插件将悄无声息地失败。要发现这些问题,你需要检查 Jenkins 的日志文件,/var/log/jenkins/jenkins.log(适用于 *NIX 发行版),查看日志级别为 SEVERE 的日志:

SEVERE: Cannot perform a backup. Please be sure jenkins/hudson has write privileges in the configured backup path {0}.

测试排除模式

下面的 Perl 脚本将允许你测试排除模式。只需将 $content 值替换为你的 Jenkins 工作区位置,将 $exclude_pattern 替换为你要测试的模式。以下脚本将打印排除的文件列表:

#!/usr/bin/perl
use File::Find;
my $content = "/var/lib/jenkins";
my $exclude_pattern = '^.*\.(war)|(class)|(jar)$';
find( \&excluded_file_summary, $content );
subexcluded_file_summary {
  if ((-f $File::Find::name)&&( $File::Find::name =~/$exclude_pattern/)){
print "$File::Find::name\n";
  }
}

小贴士

下载示例代码

你可以从你在www.packtpub.com的帐户中下载所有你购买的 Packt Publishing 书籍的示例代码文件。如果你在其他地方购买了这本书,你可以访问www.packtpub.com/support注册,以便直接通过电子邮件接收文件。

你可以在perldoc.perl.org/File/Find.html找到标准 Perl 模块 File::Find 的文档。

对于 $content 提及的每个文件和目录,find(\&excluded_file_summary,$content); 行调用 excluded_file_summary 函数。

排除模式'^.*\.(war)|(class)|(jar)$忽略所有的 WAR、class 和 JAR 文件。

提示

EPIC Perl

如果你是一名偶尔编写 Perl 脚本的 Java 开发人员,请考虑在 Eclipse 中使用 EPIC 插件(www.epic-ide.org/)。

另请参阅

  • 报告整体存储使用示例

  • 添加一个通过日志解析警告存储使用违规的作业示例

从命令行修改 Jenkins 配置

你可能会想知道 Jenkins 工作空间顶层的 XML 文件。这些是配置文件。config.xml 文件是处理默认服务器值的主要文件,但也有特定的文件用于通过 GUI 设置任何插件的值。

工作空间下还有一个jobs子目录。每个单独的作业配置都包含在与作业同名的子目录中。然后,作业特定的配置存储在子目录中的config.xml中。对于users目录也是类似的情况:每个用户一个子目录,其中个人信息存储在config.xml中。

在所有基础设施中的 Jenkins 服务器具有相同的插件和版本级别的受控情况下,您可以在一个测试机器上进行测试,然后将配置文件推送到所有其他机器上。然后,你可以使用命令行界面CLI)或/etc/init.d下的脚本重启 Jenkins 服务器,如下所示:

sudo /etc/init.d/jenkins restart

此示例使你熟悉主要的 XML 配置结构,然后根据 XML 的详细信息提供有关插件 API 的提示。

准备工作

你需要一个启用了安全性并且能够通过登录并通过命令行或通过文本编辑器进行编辑的能力来编辑文件的 Jenkins 服务器。

如何操作...

  1. 在 Jenkins 的顶层目录中,寻找config.xml文件。编辑带有numExecutors的行,将数字2改为3

    <numExecutors>3</numExecutors>
    
  2. 重新启动服务器。你会看到执行器的数量已从默认的两个增加到三个:如何操作...

  3. 插件通过 XML 文件持久保存其配置。为了证明这一点,请查找thinBackup.xml文件。除非你已安装 thinBackup 插件,否则你找不到它。

  4. 再次查看备份和恢复的示例。现在你会找到以下 XML 文件:

    <?xml version='1.0' encoding='UTF-8'?>
    <org.jvnet.hudson.plugins.thinbackup.ThinBackupPluginImpl plugin="thinBackup@1.7.4">
    <fullBackupSchedule>1 0 * *  7</fullBackupSchedule>
    <diffBackupSchedule>1 1 * * *</diffBackupSchedule>
    <backupPath>/data/jenkins/backups</backupPath>
    <nrMaxStoredFull>61</nrMaxStoredFull>
    <excludedFilesRegex></excludedFilesRegex>
    <waitForIdle>false</waitForIdle>
    <forceQuietModeTimeout>120</forceQuietModeTimeout>
    <cleanupDiff>true</cleanupDiff>
    <moveOldBackupsToZipFile>true</moveOldBackupsToZipFile>
    <backupBuildResults>true</backupBuildResults>
    <backupBuildArchive>true</backupBuildArchive>
    <backupUserContents>true</backupUserContents>
    <backupNextBuildNumber>true</backupNextBuildNumber>
    <backupBuildsToKeepOnly>true</backupBuildsToKeepOnly>
    </org.jvnet.hudson.plugins.thinbackup.ThinBackupPluginImpl>
    

工作原理...

Jenkins 使用 XStream (xstream.codehaus.org/) 将其配置持久化为可读的 XML 格式。工作空间中的 XML 文件是插件、任务和各种其他持久化信息的配置文件。config.xml 文件是主配置文件。安全设置和全局配置在这里设置,并反映通过 GUI 进行的更改。插件使用相同的结构,XML 值对应于底层插件类中的成员值。GUI 本身是通过 Jelly 框架 (commons.apache.org/jelly/) 从 XML 创建的。

通过重新启动服务器,您可以确保在初始化阶段捕获到任何配置更改。

注意

还可以从管理 Jenkins页面的存储功能中使用重新加载配置,在不重新启动的情况下加载更新的配置。

还有更多...

这里有几件事情供你考虑。

关闭安全性

当您测试新的安全功能时,很容易将自己锁在 Jenkins 外面。您将无法再次登录。要解决此问题,通过编辑 config.xmluseSecurity 修改为 false,然后重新启动 Jenkins;现在安全功能已关闭。

查找自定义插件扩展的 JavaDoc

下面的代码行是名为 thinBackup.xml 的薄插件配置文件的第一行,提到了信息持久化的类。类名是一个很好的 Google 搜索词。插件可以扩展 Jenkins 的功能,可能会为管理 Groovy 脚本公开有用的方法:

<org.jvnet.hudson.plugins.thinbackup.ThinBackupPluginImpl>

添加垃圾的效果

只要它们被识别为有效的 XML 片段,Jenkins 就能很好地识别无效配置。例如,将以下代码添加到 config.xml 中:

<garbage>yeuchblllllllaaaaaa</garbage>

当您重新加载配置时,您将在管理 Jenkins屏幕的顶部看到这个:

添加垃圾的效果

按下管理按钮将返回到详细的调试信息页面,其中包括调和数据的机会:

添加垃圾的效果

从中可以看出,Jenkins 在阅读不理解的损坏配置时是开发人员友好的。

另见

  • 使用测试 Jenkins 实例 配方

安装 Nginx

此配方描述了安装基本 Nginx 安装所需的步骤。

Nginx(发音为 engine-x)是一个免费的、开源的、高性能的 HTTP 服务器和反向代理,以及 IMAP/POP3 代理服务器。Igor Sysoev 在 2002 年开始开发 Nginx,在 2004 年发布了第一个公开版本。Nginx 以其高性能、稳定性、丰富的功能集、简单的配置和低资源消耗而闻名。

注意

您可以在 wiki.nginx.org/Main 找到 Nginx 社区的 wiki 站点。

在你的 Jenkins 服务器前面放置一个 Nginx 服务器有很多优点:

  • 简单配置: 语法简单直观。配置新服务器的基本细节只需要几行易于阅读的文本。

  • 速度和资源消耗: Nginx 以比竞争对手更快的速度运行,并且资源消耗更少。

  • URL 重写: 强大的配置选项允许你直接管理 Nginx 后面的多个服务器的 URL 命名空间。

  • 抵消 SSL: Nginx 可以负责安全连接,减少组织中所需的证书数量,并降低 Jenkins 服务器的 CPU 负载。

  • 缓存: Nginx 可以缓存 Jenkins 的大部分内容,减少 Jenkins 服务器必须返回的请求数量。

  • 监控: 当 Nginx 部署在多个 Jenkins 服务器前时,其集中日志文件可以作为一个明确的监控点。

准备工作

阅读官方安装说明:wiki.nginx.org/Install

如何操作...

  1. 从终端输入:

    sudo apt-get install nginx
    
    
  2. 浏览至本地主机位置。现在你将看到 Nginx 的欢迎页面:如何操作...

  3. 从终端输入 sudo /etc/init.d/nginx,你将获得以下输出:

    Usage: nginx {start|stop|restart|reload|force-reload|status|configtest|rotate|upgrade}
    
    

    请注意,你不仅可以停止和启动服务器,还可以检查状态并运行配置测试。

  4. 通过输入 sudo /etc/init.d/nginx status 命令检查服务器状态:

    * nginx is running
    
    
  5. 在 gedit 中编辑欢迎页面:

    sudo gedit /usr/share/nginx/html/index.html.
    
    
  6. <body> 标签后,添加 <h1>Welcome to nginx working with Jenkins</h1>

  7. 保存文件。

  8. 浏览至本地主机位置。你将看到一个修改过的欢迎页面:如何操作...

  9. 查看 /etc/nginx/nginx.conf 配置文件,特别是以下几行:

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;
    
  10. 编辑并保存 /etc/nginx/sites-available/default。对于两个 listen 部分,将数字 80 改为 8000

    listen 8000 default_server;
    listen [::]:8000 default_server ipv6only=on;
    

    如果端口 8000 已被另一个服务器使用,则可以随意更改为其他端口号。

  11. 通过终端运行以下命令测试配置:

    sudo /etc/init.d/nginx configtest
    * Testing nginx configuration   [ OK ]
    
    
  12. 从终端重新启动服务器:

    sudo /etc/init.d/nginx restart
    * Restarting nginx nginx
    
    
  13. 浏览至本地主机位置。你将看到无法连接的警告:如何操作...

  14. 浏览至 localhost:8000,你将看到欢迎页面。

工作原理...

你使用 apt 命令以默认设置安装了 Nginx。 /etc/init.d/nginx 命令用于控制服务器。你编辑了欢迎页面,位于 /usr/share/nginx/html/index.html,并重新启动了 Nginx。

主配置文件是 /etc/nginx/nginx.confinclude /etc/nginx/conf.d/*.conf; 行从 /etc/nginx/conf.d 目录中具有 conf 扩展名的任何文件收集配置设置。它还通过 include /etc/nginx/sites-enabled/*; 命令收集 /etc/nginx/sites-enabled 目录中的任何配置文件。

您通过在名为/etc/nginx/sites-available/default的默认配置文件中使用listen指令更改了 Nginx 服务器监听的端口号。为了避免尴尬,我们在部署更改之前测试了配置。您可以通过终端使用/etc/init.d/nginx configtest命令来执行此操作。

提示

支持信息

Nginx HTTP 服务器Packt Publishing出版的书籍详细介绍了 Nginx 的许多方面。您可以在www.packtpub.com/nginx-http-server-for-web-applications/book找到此书。

关于配置的示例章节可在线获取,网址为www.packtpub.com/sites/default/files/0868-chapter-3-basic-nginx-configuration_1.pdf

更多内容……

这里还有一些您需要考虑的要点。

命名日志文件

Nginx 允许您在多个端口上运行多个虚拟主机。为了帮助您维护服务器,建议您将日志文件分开。为此,您需要更改/etc/nginx/nginx.conf中的以下行:

access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;

为他人提供方便。考虑使用一致的命名约定,例如包括主机名和端口号:

access_log /var/log/nginx/HOST_PORT_access.log;
error_log /var/log/nginx/HOST_PORT_error.log;

备份配置

我再次强调一下这一点。备份配置更改对于您的基础设施的平稳运行至关重要。就个人而言,我将所有配置更改备份到版本控制系统中。我可以查看提交日志,准确地了解何时犯了错误或使用了巧妙的调整。但是,版本控制并不总是可行的,因为可能包含诸如密码之类的敏感信息。至少要在本地自动备份配置。

另请参阅

  • 将 Nginx 配置为反向代理配方

配置 Nginx 为反向代理

本文介绍如何将 Nginx 配置为 Jenkins 的反向代理。您将修改日志文件和端口位置,调整缓冲区大小和传递的请求标头。我还会介绍在重新启动 Nginx 之前测试配置的最佳实践。这种最佳实践帮助我避免了许多尴尬的时刻。

准备工作

您需要遵循安装 Nginx配方,并在localhost:8080上运行 Jenkins 实例。

如何做……

  1. 创建/etc/nginx/proxy.conf文件,并添加以下代码:

    proxy_redirect          off;
    proxy_set_header        Host            $host;
    proxy_set_header        X-Real-IP       $remote_addr;
    proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
    client_max_body_size    10m;
    client_body_buffer_size 128k;
    proxy_connect_timeout   90;
    proxy_send_timeout      90;
    proxy_read_timeout      90;
    proxy_buffers           32 4k;
    
  2. 创建/etc/nginx/sites-enabled/jenkins_8080_proxypass文件,并添加以下代码:

    server {
    listen   80;
    server_name  localhost;
    access_log  /var/log/nginx/jenkins _8080_proxypass_access.log;
    error_log  /var/log/nginx/jenkins_8080_proxypass_access.log;
    
    location / {
    proxy_pass      http://127.0.0.1:7070/;
    include         /etc/nginx/proxy.conf;
            }
    }
    
  3. 从终端运行sudo /etc/init.d/nginx configtest。您将看到以下输出:

    * Testing nginx configuration   [ OK ]
    
    
  4. 在终端中,通过运行以下命令重新启动服务器:

    sudo /etc/init.d/nginx restart
    
    
  5. 浏览至本地主机位置。连接将超时,如下面的截图所示:如何做……

  6. 查看访问日志 /var/log/nginx/jenkins _8080_proxypass_access.log。您将看到类似于以下行的行(请注意,499 是状态码):

    127.0.0.1 - - [25/Jun/2014:17:50:50 +0200] "GET / HTTP/1.1" 499 0 "-" "Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:30.0) Gecko/20100101 Firefox/30.0"
    
    
  7. 编辑 /etc/nginx/sites-enabled/jenkins_8080_proxypass,将 7070 更改为 8080

    location / {
    proxy_pass      http://127.0.0.1:8080/;
    include         /etc/nginx/proxy.conf;
            }
    
  8. 测试配置更改:

    sudo /etc/init.d/nginx configtest
    * Testing nginx configuration   [ OK ]
    
    
  9. 从终端运行以下命令重新启动 Nginx 服务器:

    sudo /etc/init.d/nginx restart
    
    
  10. 浏览到本地主机位置。您将看到 Jenkins 的主页面。

工作原理...

Nginx 配置语法的致敬之处在于您只需配置几行即可配置 Nginx。

默认情况下,Nginx 对 /etc/nginx/sites-enabled/ 目录中的文件中的任何配置都会起作用。在本次操作中,您向该目录添加了一个文件;然后,它被添加到 Nginx 的配置设置中,并在下次重启时生效。

配置文件包含一个带有端口和服务器名称 localhostserver 块。您可以在配置中定义多个服务器,它们监听不同的端口并具有不同的服务器名称。但是,在我们的情况下,我们只需要一个服务器:

server {
listen   80;
server_name  localhost;

您还定义了日志文件的位置,如下所示:

access_log  /var/log/nginx/Jenkins_8080_proxypass_access.log;
error_log  /var/log/nginx/jenkins_8080_proxypass_access.log;

Nginx 将请求头中指定的 URI 与服务器块内定义的位置指令的参数进行比较。在本例中,您只有一个指向顶级 / 的位置命令:

location / {

可以配置多个位置。但是,在我们的示例中,只有一个位置将所有请求传递给位于 127.0.0.1:8080 的 Jenkins 服务器:

  proxy_pass      http://127.0.0.1:8080/;

如上所述,当 proxy_pass 指向不存在的位置时,将返回 499 HTTP 状态码。这是 Nginx 特定的标记问题的方式。

注意

注意,proxy_pass 可以同时使用 HTTP 和 HTTPS 协议。

我们加载了第二个配置文件,该文件处理了代理的详细设置。这是有用的,因为您可以在许多服务器配置中重复相同的设置,使详细信息保持集中。这种方法有助于可读性和维护。

include         /etc/nginx/proxy.conf;

注意

Nginx 配置允许您使用嵌入变量,如 $remote_addr 客户端的远程地址。Nginx 参考手册详细介绍了嵌入变量。您可以在 nginx.com/wp-content/uploads/2014/03/nginx-modules-reference-r3.pdf 找到该手册。

proxy.conf 中,您设置了头信息。您将 X-REAL-IPX-Forwarded-For 设置为请求者的远程地址。对于后端服务器和负载均衡器的顺利运行,您需要这两个头信息:

proxy_set_header        X-Real-IP       $remote_addr;
proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;

注意

欲了解更多关于 X-Forwarded-For 的信息,请访问 en.wikipedia.org/wiki/X-Forwarded-For

您还定义了性能相关的其他细节,包括客户端主体的最大大小(10 兆字节)、超时值(90 秒)和内部缓冲区大小(324 千字节):

client_max_body_size    10m;
client_body_buffer_size 128k;
proxy_connect_timeout   90;
proxy_send_timeout      90;
proxy_read_timeout      90;
proxy_buffers           32 4k;

注意

有关 Nginx 作为反向代理服务器的更多信息,请访问 nginx.com/resources/admin-guide/reverse-proxy/

还有更多……

这里还有一些你需要考虑的要点。

测试复杂配置

现代计算机价格便宜而且功能强大。它们能够支持多个测试 Jenkins 和 Nginx 服务器。测试复杂配置的方法有很多。其中一种是在虚拟网络上运行多个虚拟机。另一种是使用不同的环回地址和/或不同的端口(127.0.0.1:8080127.0.0.2:8080等)。这两种方法的优点是可以将网络流量保持在以太网卡上,并保留在计算机本地。

正如前言中所述,您可以通过类似以下命令从命令行运行 Jenkins:

java –jar jenkins.war –httpsport=8443 –httpPort=-1

Jenkins 将开始在端口8443上通过 HTTPS 运行。 -httpPort=-1 关闭了 HTTP 端口。

要选择一个单独的主目录,您首先需要设置 JENKINS_HOME 环境变量。

您将使用以下命令在127.0.0.2的端口80上运行 Jenkins:

sudo –jar jenkins.war  --httpPort=80 --httpListenAddress=127.0.0.2

卸载 SSL

Nginx 的优点之一是你可以让它处理 SSL 请求,然后将它们作为 HTTP 请求传递给多个 Jenkins 服务器。你可以在 wiki.jenkins-ci.org/display/JENKINS/Jenkins+behind+an+nginx+reverse+proxy 找到这个基本配置。

首先,您需要将端口80上的请求重定向到 HTTPS URL。在以下示例中,使用了301状态码:

server {
listen 80;
return 301 https://$host$request_uri;
}

这表示链接已永久移动。这允许重定向被缓存。然后,您将需要在端口443上设置服务器,这是 HTTPS 的标准端口,并加载服务器和其关联密钥的证书:

server {
listen 443;
server_name localhost;

ssl on;
ssl_certificate /etc/nginx/ssl/server.crt;
ssl_certificate_key /etc/nginx/ssl/server.key;

最后,您需要在配置为端口443的服务器中使用 locationproxy_pass 将 HTTP 传递给运行 HTTP 的 Jenkins 服务器:

location / {
proxy_pass              http://127.0.0.1:8080;

提示

尽管它很简单,但已知的配置陷阱是众所周知的,其中一些在 wiki.nginx.org/Pitfalls 中提到。

另请参阅

  • 安装 Nginx 配方

报告整体存储使用情况

组织有各自的方式来处理不断增长的磁盘使用情况。政策从没有政策,依赖于临时人类互动,到拥有最先进的软件和中央报告设施。大多数组织处于这两个极端之间,大部分是临时干预,对于更关键的系统则自动报告一些情况。凭借极小的努力,你可以让 Jenkins 通过 GUI 报告磁盘使用情况,并定期运行触发有用事件的 Groovy 脚本。

该配方突出了磁盘使用插件,并使用该配方来讨论在 Jenkins 工作区中存储归档的成本。

磁盘使用插件与一个早期警告系统结合使用时效果最好,该系统在达到软限制或硬限制时会通知您。通过日志解析来警告存储使用违规的作业添加配方详细说明了解决方案。这个配方表明配置 Jenkins 需要很少的努力。每一步甚至可能看起来都很琐碎。Jenkins 的强大之处在于你可以从一系列简单的步骤和脚本中构建复杂的响应。

准备工作

您需要安装磁盘使用插件。

如何做...

  1. 点击管理 Jenkins页面下的磁盘使用情况链接:如何做...

  2. Jenkins 显示每个项目名称、构建和工作空间磁盘使用情况摘要的页面。点击表格顶部以按文件使用情况对工作空间进行排序:如何做...

工作原理...

在 Jenkins 中添加插件非常简单。问题是您将如何处理这些信息。

在构建中你很容易忘记一个复选框;也许一个高级选项被错误地启用了。高级选项有时可能会有问题,因为它们不直接显示在 GUI 中,所以您需要先点击高级按钮,然后再查看它们。在星期五下午,这可能是一步太远了。

高级选项包括工件保留选项,您需要正确配置以避免磁盘使用过多。在上一个示例中,Sakai Trunk的工作空间为2 GB。这个大小与作业有自己的本地 Maven 存储库有关,如使用私有 Maven 存储库高级选项所定义。你很容易忽略这个选项。在这种情况下,没有什么可以做的,因为 trunk 拉取可能会导致其他项目不稳定的快照 jar。以下截图显示的高级选项包括工件:

工作原理...

查看项目的高级选项后,查看项目的磁盘使用情况,可以帮助您找到不必要的私有存储库。

还有更多...

如果您保留了大量的工件,这表明您使用 Jenkins 的目的失败了。Jenkins 是推动产品通过其生命周期的引擎。例如,当一个作业每天构建快照时,你应该将快照推送到开发人员认为最有用的地方。那不是 Jenkins,而是一个 Maven 存储库或者像 Artifactory (www.jfrog.com/products.php)、Apache Archiva (archiva.apache.org/) 或 Nexus (nexus.sonatype.org/) 这样的存储库管理器。这些存储库管理器与将内容转储到磁盘相比具有显著优势,例如:

  • 通过充当缓存加快构建速度:开发团队往往会处理相似或相同的代码。如果您构建并使用仓库管理器作为镜像,那么仓库管理器将缓存依赖项;当作业 Y 请求相同的构件时,下载将在本地进行。

  • 充当本地共享快照的机制:也许您的一些快照仅用于本地使用。仓库管理器具有限制访问的功能。

  • 用于便捷的构件管理的图形用户界面:所有三个仓库管理器都有直观的 GUI,使您的管理任务尽可能简单。

在考虑到这些因素的情况下,如果您在 Jenkins 中看到构件的积累,而它们比部署到仓库更不可访问和有益,请将其视为需要升级基础设施的信号。

欲了解更多信息,请访问maven.apache.org/repository-management.html

注意

保留策略

Jenkins 可能会消耗大量磁盘空间。在作业配置中,您可以决定是保留构件还是在一段时间后自动删除它们。删除构件的问题是您也将删除任何自动测试的结果。幸运的是,有一个简单的技巧可以避免这种情况。在配置作业时,点击丢弃旧构建,选中高级复选框,并定义保留构件的最大构建数。然后在指定的构建数后删除构件,但日志和结果会被保留。这有一个重要的后果:即使您已经删除了其他占用磁盘更多的构件,您现在也允许报告插件继续显示测试历史。

另请参阅

  • 备份和恢复配方

通过日志解析有意失败的构建

让我们想象一下,您被要求清理没有在其构建过程中运行任何单元测试的代码。代码很多。为了迫使质量的提高,如果您错过了一些残留的缺陷,那么您希望 Jenkins 构建失败。

你需要的是一个灵活的日志解析器,它可以在构建输出中发现的问题失败或警告。救命稻草是,本配方描述了如何配置一个日志解析插件,该插件可以在控制台输出中发现不需要的模式,并在发现模式时失败作业。例如,当没有单元测试时,Maven 会发出警告。

准备工作

您需要按照wiki.jenkins-ci.org/display/JENKINS/Log+Parser+Plugin中提到的安装日志解析器插件。

如何做...

  1. 在 Jenkins 工作空间下创建由 Jenkins 拥有的log_rules目录。

  2. no_tests.rule文件添加到log_rules目录中,内容为一行:

    error /no tests/
    
  3. 创建一个带有在编译过程中产生弃用警告的源代码的作业。在以下示例中,您正在使用来自 Sakai 项目的 CLOG 工具:

    • 作业名称Sakai_CLOG_Test

    • Maven 2/3 项目

    • 源代码管理Git

    • 仓库 URLhttps://source.sakaiproject.org/contrib/clog/trunk

    • 构建

    • Maven 版本3.2.1(或者您当前版本的标签)

    • 目标和选项clean install

  4. 运行构建。它不应该失败。

  5. 如下截图所示,访问 Jenkins 的管理配置页面,并在控制台输出解析部分添加描述和解析规则文件的位置:操作方法...

  6. Sakai_CLOG_Test 作业的后构建操作部分中选中控制台输出(构建日志)解析框。

  7. 选中在错误时标记构建失败复选框:操作方法...

    选择解析规则选择停止无测试

    构建作业,现在它应该失败了。

  8. 单击左侧菜单中的解析的控制台输出链接。现在您将能够看到解析的错误,如下截图所示:操作方法...

工作原理...

全局配置页面允许您添加每个带有一组解析规则的文件。规则使用插件主页(wiki.jenkins-ci.org/display/JENKINS/Log+Parser+Plugin)中提到的正则表达式。

您使用的规则文件由一行组成:error /no tests/

如果在控制台输出中找到无测试模式(区分大小写的测试),则插件会将其视为错误,构建将失败。可以添加更多的测试行。找到的第一个规则胜出。其他级别包括warnok

源代码是从不存在单元测试的 Sakai (www.sakaiproject.org) 区域中拉取的。

规则文件具有独特的.rules扩展名,以防您想在备份期间编写排除规则。

安装插件后,您可以在先前创建的规则文件之间为每个作业选择。

注意

这个插件赋予您周期性扫描明显的语法错误并适应新环境的能力。您应该考虑系统地遍历一系列失败的可疑构建的规则文件,直到完全清理为止。

还有更多...

另外两个常见的日志模式示例可能会出现问题,但通常不会导致构建失败:

  • MD5 校验和:如果 Maven 仓库有一个工件,但没有其关联的 MD5 校验和文件,那么构建将下载该工件,即使它已经有一个副本。幸运的是,该过程将在控制台输出中留下一条warn消息。

  • 启动自定义集成服务失败:当您真正希望构建失败时,这些失败可能会以warninfo级别记录。

另请参阅

  • 添加一个作业以通过日志解析警告存储使用违规情况的步骤

添加一个作业以通过日志解析警告存储使用违规情况

磁盘使用插件不太可能满足您的所有磁盘维护需求。此方案将向您展示如何通过添加自定义 Perl 脚本来加强磁盘监视,以警告磁盘使用违规行为。

脚本将生成两个警报:当磁盘使用量超出可接受水平时生成硬错误,当磁盘接近该限制时生成软警告。然后,日志解析器插件将相应地做出反应。

注意

对于 Jenkins 任务而言,使用 Perl 是典型的,因为 Jenkins 可以很好地适应大多数环境。您可以预期在获取工作时使用 Perl、Bash、Ant、Maven 和全系列的脚本和绑定代码。

准备工作

如果尚未这样做,请在 Jenkins 工作区下创建一个由 Jenkins 拥有的名为log_rules的目录。还要确保 Perl 脚本语言已安装在您的计算机上,并且 Jenkins 可以访问。Perl 默认安装在 Linux 发行版上。ActiveState 为 Mac 和 Windows 提供了一个体面的 Perl 发行版(www.activestate.com/downloads)。

如何操作...

  1. log_rules目录下添加名为disk.rule的文件,并包含以下两行:

    error /HARD_LIMIT/
    warn /SOFT_LIMIT/
    
  2. 访问 Jenkins 的管理配置页面,并将描述DISC_USAGE添加到控制台输出部分。指向解析规则文件的位置。

  3. 将以下名为disk_limits.pl的 Perl 脚本添加到选择的位置,确保 Jenkins 用户可以读取该文件:

    use File::Find;
    my $content = "/var/lib/jenkins";
    if ($#ARGV != 1 ) {
      print "[MISCONFIG ERROR] usage: hard soft (in Bytes)\n";
      exit(-1);
    }
    my $total_bytes=0;
    my $hard_limit=$ARGV[0];
    my $soft_limit=$ARGV[1];
    
    find( \&size_summary, $content );
    
    if ($total_bytes>= $hard_limit){
    print "[HARD_LIMIT ERROR] $total_bytes>= $hard_limit (Bytes)\n";
    }elseif ($total_bytes>= $soft_limit){
    print "[SOFT_LIMIT WARN] $total_bytes>= $soft_limit (Bytes)\n";
    }else{
    print "[SUCCESS] total bytes = $total_bytes\n";
    }
    
    subsize_summary {
      if (-f $File::Find::name){
        $total_bytes+= -s $File::Find::name;
      }
    }
    
  4. 修改$content变量以指向 Jenkins 工作区。

  5. 创建一个自由风格软件项目任务。

  6. 构建部分下,添加构建步骤 / 执行 Shell。对于命令,请添加perl disk_limits.pl 9000000 2000000

  7. 随意更改硬限制和软限制(9000000 2000000)。

  8. 后构建操作中检查控制台输出(构建日志)解析

  9. 勾选在警告时标记构建不稳定复选框。

  10. 勾选在错误时标记构建失败复选框。

  11. 将解析规则文件选择为DISC_USAGE如何操作...

  12. 多次运行构建。

  13. 在左侧的构建历史下,选择趋势链接。您现在可以查看趋势报告,并查看成功和失败的时间线,如以下屏幕截图所示:如何操作...

工作原理...

Perl 脚本期望接收两个命令行输入:硬限制和软限制。硬限制是$content目录下磁盘利用率不应超过的字节值。软限制是一个较小的字节值,触发警告而不是错误。警告给管理员提供了在达到硬限制之前清理的时间。

Perl 脚本遍历 Jenkins 工作区并计算所有文件的大小。对于工作区下的每个文件或目录,脚本调用size_summary方法。

如果硬限制小于内容大小,则脚本会生成日志输出[HARD_LIMIT ERROR]。解析规则将捕获此错误并导致构建失败。如果达到软限制,则脚本将生成输出[SOFT_LIMIT WARN]。插件将根据warn /SOFT_LIMIT/规则检测到这一点,然后发出作业warn信号。

还有更多...

欢迎来到 Jenkins 的奇妙世界。您现在可以利用所有安装的功能。作业可以按计划执行,并在失败时发送电子邮件。您还可以发布推文、添加 Google 日历条目,并触发额外的事件,例如磁盘清理构建等等。您的想象力和 21 世纪的技术基本上是有限的。

另请参阅

  • 备份和恢复配方

通过 Firefox 与 Jenkins 保持联系

如果您是 Jenkins 管理员,则您的角色是密切关注您的基础架构内构建活动的起伏变化。由于非编码原因,构建有时会偶尔冻结或中断。如果构建失败并且这与基础架构问题有关,则您需要迅速收到警告。Jenkins 可以通过多种方式做到这一点。第四章 通过 Jenkins 进行通信,专门介绍了针对不同受众的不同方法。从电子邮件、Twitter 和对话服务器,您可以选择广泛的提示、踢、喊和 ping。我甚至可以想象一个 Google 夏季代码项目,其中一个远程控制的小车移动到睡着的管理员身边,然后吹口哨。

这个配方是你被联系的更愉快的方式之一。你将使用 Firefox 附加组件拉取 Jenkins 的 RSS 源。这样你就可以在日常工作中查看构建过程了。

准备就绪

您需要在计算机上安装 Jenkins,并在至少一个 Jenkins 实例上拥有一个运行作业历史的帐户。您还需要添加 Status-4-Evar 插件,您可以从addons.mozilla.org/zh-CN/firefox/addon/status-4-evar/获取。

以下网址将解释自上一版书籍以来 Firefox 状态栏发生了什么变化support.mozilla.org/zh-CN/kb/what-happened-status-bar

提示

为开发者做广告

如果你喜欢这个附加组件,并希望将来获得更多功能,那么在附加组件作者的网站上捐款几美元是理性的自利行为。

如何做...

  1. 选择浏览器右上角的打开菜单图标:如何操作...

  2. 点击附加组件按钮:如何操作...

  3. 搜索批量(右上角),搜索所有附加组件标题搜索 Jenkins。

  4. 点击安装按钮安装Jenkins 构建监视器

  5. 重新启动 Firefox。

  6. 现在,在 Firefox 的右下角,您会看到一个小的 Jenkins 图标:如何操作...

  7. 右键单击图标。

  8. 选择首选项,然后会出现订阅屏幕。

  9. 为您的 Jenkins 实例添加一个可识别但简短的名称。例如,插件测试服务器

  10. Feed URL 添加 URL,结构如下 http://host:port/rssAll 例如,http://localhost:8080/rssAll如何操作...

  11. 检查启用执行器监控

  12. 单击确定按钮。插件工具栏中会出现一个区域,显示着插件测试服务器的订阅 URL 名称和一个健康图标。如果您将鼠标悬停在名称上,将显示更详细的状态信息:如何操作...

工作原理...

Jenkins 提供了 RSS 订阅以使其状态信息可供各种工具访问。Firefox 插件会轮询配置的订阅,并以易于理解的格式显示信息。

要为特定的关键作业进行配置,您需要使用以下结构:http://host:port/job/job name/rssAll

要仅查看构建失败,请将 rssAll 替换为 rssFailed。要仅查看最后一次构建,请将 rssAll 替换为 rssLatest

还有更多...

这里还有一些需要考虑的事项。

RSS 凭据

如果在您的 Jenkins 实例上启用了安全性,则大多数 RSS 订阅将受到密码保护。要添加密码,您需要修改订阅 URL 为以下结构:

http://username:password@host:port/path

提示

警告

使用此插件的负面方面是在编辑期间显示任何订阅 URL 密码的纯文本。

Firefox 的替代方案

Firefox 可在多个操作系统上运行。这使您可以在这些操作系统上使用一个插件进行通知。然而,缺点是您必须保持 Firefox 浏览器在后台运行。另一种选择是特定于操作系统的通知软件,它会在系统托盘中弹出。这种软件的示例包括用于 Mac OSX 的 CCMenu (ccmenu.org) 或用于 Windows 的 CCTray (en.sourceforge.jp/projects/sfnet_ccnet/releases/)。

另请参阅

  • 第四章中的 使用 Google 日历进行移动演示 配方,通过 Jenkins 进行通信

通过 JavaMelody 进行监控

JavaMelody(code.google.com/p/javamelody/)是一个提供全面监控的开源项目。Jenkins 插件监控 Jenkins 的主实例和节点。该插件提供了大量重要信息。你可以查看主要数量(如 CPU 或内存)1 天、1 周甚至数月的演变图表。演变图表非常适合确定资源消耗大的定期作业。JavaMelody 允许您实时监控资源的渐进性退化。它通过将统计数据导出为 PDF 格式来简化报告的编写。JavaMelody 已经拥有超过 25 个人年的努力,功能丰富。

本文介绍了如何轻松安装监控插件(wiki.jenkins-ci.org/display/Jenkins/Monitoring),然后讨论了故障排除策略及其与生成的指标的关系。

提示

社区合作

如果你觉得这个插件有用,请考虑回馈给插件或核心 JavaMelody 项目。

准备工作

你需要安装监控插件。

如何操作...

  1. 管理 Jenkins页面点击监控 Jenkins 主节点链接。现在你会看到详细的监控信息,如下截图所示:如何操作...

  2. http://host:port/monitoring?resource=help/help.html上阅读在线帮助,其中 host 和 port 指向你的服务器。

  3. 通过访问http://host:port/monitoring/nodes直接查看节点进程的监控。

工作原理...

JavaMelody 的优点是以 Jenkins 用户身份运行,并且可以访问所有相关的指标。它的主要缺点是作为服务器的一部分运行,一旦发生故障就会停止监视。因此,由于这个缺点,你应该将 JavaMelody 视为监控解决方案的一部分,而不是整个解决方案。

还有更多...

监控是全面测试和故障排除的基础。本节探讨了这些问题与插件中提供的测量之间的关系。

使用 JavaMelody 进行故障排除 - 内存

你的 Jenkins 服务器有时可能会出现内存问题,原因是构建过于贪婪、插件泄露或基础架构中的某些隐藏复杂性。JavaMelody 具有广泛的内存测量范围,包括堆转储和内存直方图。

Java 虚拟机将内存分成各种区域,为了清理,它会删除没有对其他对象的引用的对象。当垃圾回收忙碌时,它可能会占用大量 CPU 资源,而且内存越满,垃圾回收就越繁忙。对于外部监控代理来说,这看起来像是一个 CPU 峰值,通常很难追踪到。仅仅因为垃圾收集器管理内存,就认为 Java 中不存在内存泄漏的潜力也是一种错误。许多常见做法,如自定义缓存或调用本地库,都可能导致内存被持有太长时间。

慢慢渗漏的内存泄漏将显示为与内存相关的演化图上的缓缓上升。如果你怀疑有内存泄漏,那么你可以通过执行垃圾收集器链接来强制插件进行完整的垃圾收集。如果不是内存泄漏,那么这个缓缓上升将会突然下降。

内存问题也可能表现为大的 CPU 峰值,因为垃圾收集器拼命尝试清理,但几乎无法清理足够的空间。垃圾收集器还可以在全面寻找不再被引用的对象时暂停应用程序("停止世界"垃圾收集),从而导致网页浏览器请求的响应时间增加。这可以通过统计 http - 1 天中的平均最大时间来观察到。

使用 JavaMelody 进行故障排除 - 痛苦的工作

你应该考虑以下几点:

  • 卸载工作:为了稳定的基础设施,尽可能地从主实例中卸载尽可能多的工作。如果你有定期任务,请将最重的任务在时间上保持分离。时间分离不仅能均匀负载,而且可以通过观察 JavaMelody 的演化图来更容易地找到有问题的构建。还要考虑空间分离;如果某个节点或一组标记的节点显示出问题,那么开始切换作业的机器位置,并通过 http://host:port/monitoring/nodes 查看它们的单独性能特征。

  • 硬件成本低廉:与支付人工小时相比,购买额外的 8 GB 大约相当于一个人小时的努力。

    注意

    一个常见的错误是向服务器添加内存,同时忘记更新初始化脚本以允许 Jenkins 使用更多内存。

  • 审查构建脚本:Javadoc 生成和自定义 Ant 脚本可以分叉 JVM 并在其自己的配置中保留定义的内存。编程错误也可能是问题的原因。不要忘记审查 JavaMelody 关于统计系统错误日志统计 http 系统错误的报告。

  • 不要忘记外部因素:因素包括备份、定期任务、更新 locate 数据库和网络维护。这些将显示为演化图中的周期性模式。

  • 人多势众:结合磁盘使用插件等使用 JavaMelody,以全面了解重要统计信息。每个插件都很容易配置,但它们对您的有用性将比增加额外插件的维护成本增长更快。

另请参阅

  • 第七章, 插件探索中的使用 Groovy 钩子脚本和在启动时触发事件食谱

跟踪脚本粘合剂

如果维护脚本在基础架构中分散,备份和特别是还原将产生负面影响。最好将您的脚本放在一个地方,然后通过节点远程运行它们。考虑将您的脚本放在主 Jenkins 主目录下并备份到 Git 存储库。如果您能在线共享较不敏感的脚本,对社区来说将更好。您的组织将获得好处;然后脚本将得到一些重要的同行审查和改进。有关社区存储库详细信息,请查看http://localhost:8080/scriptler.git/中的支持信息。

在本食谱中,我们将探讨 Scriptler 插件的使用,以在本地管理您的脚本并从在线目录下载有用的脚本。

准备工作

您需要安装 Scriptler 插件(wiki.jenkins-ci.org/display/JENKINS/Scriptler+Plugin)。

如何操作...

  1. Manage Jenkins页面下点击Scriptler链接。您会注意到粗体文本。当前您没有任何可用的脚本;您可以从远程目录导入脚本或创建自己的脚本。

  2. 在左侧点击远程脚本目录链接。

  3. 点击ScriptierWeb选项卡。

  4. 点击getThreadDump的软盘图标。如果脚本不可用,则选择另一个您喜欢的脚本。

  5. 点击Submit按钮。

  6. 您现在已经返回到Scriptler主页面。您会看到三个图标。选择最右边的图标来执行脚本:如何操作...

  7. 您现在位于运行脚本页面。选择一个节点,然后点击运行按钮。

    注意

    如果脚本出现startup failed消息,则请在entry.keyfor之间添加一行,然后脚本将正常运行。

  8. 要编写新的 Groovy 脚本或上传您本地系统上的脚本,请在左侧点击添加新脚本链接。

工作原理...

此插件允许您轻松管理您的 Groovy 脚本,并强制将所有 Jenkins 管理员的代码放在一个标准位置,这样您就可以更轻松地计划备份,并间接共享知识。

该插件创建了一个名为 scriptler 的目录,位于 Jenkins 工作空间下,并将你创建的文件的元信息持久化到 scriptler.xml 文件中。第二个文件名为 scriptlerweb-catalog.xml,提到了可以下载的在线文件列表。

所有本地脚本都包含在子目录 scripts 中。

还有更多...

如果足够多的人使用这个插件,那么在线脚本列表将大大增加生成一个重要的可重用代码库的过程。因此,如果你有有趣的 Groovy 脚本,那就上传吧。你需要在第一次登录时创建一个新账户,以便登录到 scriptlerweb.appspot.com/login.gtpl

上传你的脚本允许人们对其投票,并向你发送反馈。免费的同行评审只会提高你的脚本技能,并在更广泛的社区中增加你的认可度。

另请参阅

  • Scripting the Jenkins CLI 配方

  • 使用 Groovy 对作业进行全局修改 配方

Scripting the Jenkins CLI

Jenkins CLI (wiki.jenkins-ci.org/display/JENKINS/Jenkins+CLI) 允许你在远程服务器上执行多项维护任务。任务包括将 Jenkins 实例上线和下线、触发构建以及运行 Groovy 脚本。这使得对最常见的琐事进行脚本化变得容易。

在这个配方中,你将登录到 Jenkins 实例,运行一个查找大于某个大小的文件的 Groovy 脚本,然后退出登录。该脚本代表了一个典型的维护任务。在审查输出后,你可以运行第二个脚本来删除你想要删除的文件列表。

注意

在撰写本章时,交互式 Groovy shell 无法从 CLI 中工作。这在错误报告中有所提及:issues.jenkins-ci.org/browse/JENKINS-5930

准备工作

http://host/jnlpJars/jenkins-cli.jar下载 CLI JAR 文件。

将以下脚本添加到 Jenkins 控制下的一个目录,并将其命名为 large_files.groovy

root = jenkins.model.Jenkins.instance.getRootDir()
count = 0
size =0
maxsize=1024*1024*32
root.eachFileRecurse() { file ->
count++
size+=file.size();
if (file.size() >maxsize) {
println "Thinking about deleting: ${file.getPath()}"
            // do things to large files here
        }
}
println "Space used ${size/(1024*1024)} MB Number of files ${count}"

如何做...

  1. 从终端运行以下命令,将http://host替换为你服务器的真实地址,例如,http://localhost:8080

    java -jar jenkins-cli.jar -s 
    http://host  login --username username
    
    
  2. 输入你的密码。

  3. 查看在线帮助:

    java -jar jenkins-cli.jar -s 
    http://host   help
    
    
  4. 运行 Groovy 脚本。输出现在将提到所有超大文件:

    java -jar jenkins-cli.jar -s http://host groovy large_files.groovy
    
    
  5. 通过运行以下命令注销:

    java -jar jenkins-cli.jar -s http://host logout.
    
    

工作原理...

CLI 允许你从命令行工作并执行标准任务。将 CLI 包装在诸如 Bash 等的 shell 脚本中,可以让你同时脚本化维护任务和大量 Jenkins 实例。本配方执行了大量维护工作。在这种情况下,它检查 x 个文件以查找超大的构件,节省你可以用在更有趣任务上的时间。

在执行任何命令之前,你需要通过 login 命令进行身份验证。

评审root = jenkins.model.Jenkins.instance.getRootDir()脚本使用 Jenkins 框架获取指向 Jenkins 工作空间的java.io.File

通过maxsize=1024*1024*32设置最大文件大小为 32 MB。

该脚本使用标准的root.eachFileRecurse(){ file -> Groovy 方法访问 Jenkins 工作空间下的每个文件。

注意

你可以在Jenkins 的当前 JavaDoc中找到最新的文档。

还有更多...

此示例中使用的身份验证可以改进。你可以在http://localhost:8080/user/{username}/configure(其中username是你的用户名)下添加你的 SSH 公钥,方法是将其剪切并粘贴到SSH 公钥部分。你可以在wiki.jenkins-ci.org/display/JENKINS/Jenkins+CLI找到详细说明。

在撰写本书时,关键方法存在一些问题。有关更多信息,请访问issues.jenkins-ci.org/browse/JENKINS-10647。尽管安全性较低,但请随时使用在本示例中已被证明稳定运行的方法。

注意

CLI 易于扩展,因此随着时间的推移,CLI 的命令列表会增加。因此,偶尔检查帮助选项非常重要。

另请参阅

  • 使用 Groovy 全局修改作业 示例

  • 编写全局构建报告的脚本 示例

使用 Groovy 全局修改作业

Jenkins 不仅是一个持续集成服务器,而且还是一个具有从脚本控制台中可用的暴露内部结构的丰富框架。你可以通过编程方式迭代作业、插件、节点配置和各种丰富的对象。随着作业数量的增加,你会注意到脚本变得更有价值。例如,想象一下,如果你需要在 100 个作业中增加自定义内存设置。一个 Groovy 脚本可以在几秒钟内完成。

这个示例是一个典型的例子:你将运行一个脚本,该脚本通过所有作业进行迭代。然后,脚本通过作业名称找到一个特定的作业,然后使用一个随机数更新该作业的描述。

准备就绪

使用管理员帐户登录 Jenkins。

操作步骤...

  1. 创建一个名为MyTest的空作业。

  2. 管理 Jenkins页面中,点击脚本控制台链接。

  3. 点击添加新脚本

  4. 将以下脚本剪切并粘贴到脚本文本区域输入:

    import java.util.Random
    Random random = new Random()
    
    hudson.model.Hudson.instance.items.each{ job ->
    println ("Class: ${job.class}")
    println ("Name: ${job.name}")
    println ("Root Dir: ${job.rootDir}")
    println ("URL: ${job.url}")
    println ("Absolute URL: ${job.absoluteUrl}")
    
    if ("MyTest".equals(job.name)){
      println ("Description: ${job.description}")
    job.setDescription("This is a test id: ${random.nextInt(99999999)}")
    }
    }
    
  5. 点击运行按钮。结果应与以下屏幕截图类似:操作步骤...

  6. 再次运行脚本;您会注意到描述中的随机数现在已经改变了。

  7. 复制并运行以下脚本:

    for (slave in hudson.model.Hudson.instance.slaves) {
    println "Slave class: ${slave.class}"
    println "Slave name: ${slave.name}"
    println "Slave URL: ${slave.rootPath}"
    println "Slave URL: ${slave.labelString}\n"
    }
    

    如果您的 Jenkins 主服务器上没有slave实例,则不会返回任何结果。否则,输出将类似于以下屏幕截图:

    操作步骤...

它是如何工作的...

Jenkins 有一个丰富的框架,可以在脚本控制台中使用。第一个脚本遍历其父级为 AbstractItem 的作业 (javadoc.jenkins-ci.org/hudson/model/AbstractItem.html)。第二个脚本遍历 slave 对象的实例 (javadoc.jenkins-ci.org/hudson/slaves/SlaveComputer.html)。

还有更多...

针对硬核的 Java 开发者:如果您不知道如何执行编程任务,那么示例代码的极佳来源是 Jenkins 插件的 Subversion 目录 (svn.jenkins-ci.org/trunk/hudson/plugins/) 和更新更及时的 Github 位置 (github.com/jenkinsci)。

注意

如果您有兴趣捐赠您自己的插件,请查阅wiki.jenkins-ci.org/display/JENKINS/Hosting+Plugins上的信息。

另请参阅

  • Scripting the Jenkins CLI 配方

  • Scripting global build reports 配方

表示需要归档

每个开发团队都是独特的。团队有自己的业务方式。在许多组织中,周期性需要完成一次性任务。例如,每年结束时,对整个文件系统进行全面备份。

本配方详细介绍了一个脚本,该脚本检查任何作业的最后一次成功运行;如果年份与当前年份不同,则在作业描述的开头设置警告。因此,它向您提示现在是执行某些操作的时候,例如归档然后删除。当然,您也可以通过编程方式执行归档。但是,对于高价值的操作,值得强制干预,让 Groovy 脚本引起您的注意。

准备工作

使用管理账户登录 Jenkins。

如何执行...

  1. 管理 Jenkins 页面中,点击 Script Console 链接,然后运行以下脚本:

    Import hudson.model.Run;
    Import java.text.DateFormat;
    
    def warning='<font color=\'red\'>[ARCHIVE]</font> '
    def now=new Date()
    
    for (job in hudson.model.Hudson.instance.items) {
    println "\nName: ${job.name}"
        Run lastSuccessfulBuild = job.getLastSuccessfulBuild()
    if (lastSuccessfulBuild != null) {
    def time = lastSuccessfulBuild.getTimestamp().getTime()
    if (now.year.equals(time.year)){
    println("Project has same year as build");
    }else {
    if (job.description.startsWith(warning)){
    println("Description has already been changed");
    }else{
    job.setDescription("${warning}${job.description}")
            }
         }
       }
    }
    

    任何项目,如果其上次成功构建的年份不同于当前年份,则在其描述的开头添加了以红色显示的 [ARCHIVE] 一词,如下图所示:

    如何执行...

它是如何工作的...

检查代码清单:

  • 定义了一个警告字符串,并将当前日期存储在 now 中。通过 for 语句在 Jenkins 中以编程方式迭代每个作业。

  • Jenkins 有一个用于存储构建运行信息的类。运行时信息通过 job.getLastSuccessfulBuild() 检索,并存储在 lastSuccessfulBuild 实例中。如果没有成功的构建,则 lastSuccessfulBuild 被设置为 null;否则,它具有运行时信息。

  • 检索上次成功构建的时间,然后通过 lastSuccessfulBuild.getTimestamp().getTime() 将其存储在 time 实例中。

当前年份与上次成功构建的年份进行比较,如果它们不同并且警告字符串尚未添加到作业描述的开头,则更新描述。

提示

Javadoc

你会在 javadoc.jenkins-ci.org/hudson/model/Job.html 找到作业 API,并且在 javadoc.jenkins-ci.org/hudson/model/Run.html 找到 Run 信息。

还有更多...

在编写自己的代码之前,你应该审查已经存在的代码。Jenkins 拥有一个庞大、免费可用且开放授权的示例代码库,插件数量达到了 1,000 个并且在不断扩展。尽管在这种情况下使用了标准 API,但值得仔细审查插件代码库。在这个例子中,你会发现部分代码是从 lastsuccessversioncolumn 插件中重用的。(tinyurl.com/pack-jenkins-1)。

提示

如果你在审查插件代码库时发现任何缺陷,请通过补丁和错误报告为社区做出贡献。

另请参阅

  • Scripting the Jenkins CLI 配方

  • 使用 Groovy 全局修改作业 配方

第二章. 增强安全性

在本章中,我们将涵盖以下内容:

  • 测试 OWASP 十大安全问题

  • 通过模糊测试在 Jenkins 中查找 500 错误和 XSS 攻击

  • 通过小型配置更改提高安全性

  • 使用 JCaptcha 防止注册机器人

  • 通过 Groovy 查看 Jenkins 用户

  • 使用审计追踪插件

  • 安装 OpenLDAP

  • 使用脚本领域身份验证进行配置

  • 通过自定义组脚本查看基于项目的矩阵策略

  • 管理 OpenLDAP

  • 配置 LDAP 插件

  • 安装 CAS 服务器

  • 在 Jenkins 中启用 SSO

  • 探索 OWASP Dependency-Check 插件

介绍

在本章中,我们将讨论 Jenkins 的安全性,考虑到 Jenkins 可以存在于多样的基础架构中。我们还将探讨如何扫描 Jenkins 编译时使用的 Java 代码库中已知安全问题。

唯一完全安全的系统是不存在的系统。对于真实服务,你需要注意不同面向攻击的表面。Jenkins 的主要表面是其基于 Web 的图形用户界面及其与从节点和本机操作系统的信任关系。在线服务需要严密关注其安全表面。对于 Jenkins,主要有三个原因:

  • Jenkins 有能力通过其插件或主从拓扑结构与各种基础架构通信

  • 插件周围的代码更改速度很快,可能意外包含与安全相关的缺陷

  • 你需要加固默认安装,使其对外开放

一个平衡因素是,使用 Jenkins 框架的开发人员应用经过验证的技术,例如 XStream(xstream.codehaus.org/)用于配置持久性,Jelly(commons.apache.org/jelly/)用于呈现 GUI。这种使用知名框架最小化了支持代码数量,而使用的代码经过了充分测试,限制了漏洞范围。

另一个积极的方面是 Jenkins 代码是免费供审查的,核心社区保持警惕。贡献代码的任何人不太可能故意添加缺陷或意外的许可证标头。然而,你应该信任但要核实。

本章前半部分致力于 Jenkins 环境。在后半部分,你将看到 Jenkins 如何融入更广泛的基础架构。

轻量级目录访问LDAP)广泛可用,并且是企业目录服务的事实标准。我们将使用 LDAP 进行 Jenkins 的身份验证和授权,然后使用 JASIG 的中央认证服务CAS)进行单点登录SSO)。了解更多,请访问www.jasig.org/cas。CAS 允许您登录一次,然后转到其他服务而无需重新登录。当您希望从 Jenkins 链接到其他受密码保护的服务(例如组织的内部 wiki 或代码浏览器)时,这非常有用。同样重要的是,CAS 可以在幕后连接到多种类型的身份验证提供者,例如 LDAP、数据库、文本文件以及越来越多的其他方法。这使得 Jenkins 间接地可以使用许多登录协议,这些协议已经由其插件提供。

提示

安全公告

Jenkins 相关安全公告有电子邮件列表和 RSS 源。您可以在wiki.jenkins-ci.org/display/JENKINS/Security+Advisories找到公告源的链接。

测试 OWASP 的十大安全问题

本文介绍了使用 OWASP 的渗透测试工具 w3af 对 Jenkins 进行已知安全问题的自动测试。有关更多信息,请访问w3af.sourceforge.net。OWASP 的目的是使应用程序安全可见。2010 年 OWASP 的十大不安全性列表包括以下内容:

  • A2-跨站脚本(XSS):当应用程序将未经转义的输入返回给客户端的浏览器时,可能会发生 XSS 攻击。Jenkins 管理员可以通过作业描述默认执行此操作。

  • A6-安全配置错误:Jenkins 插件赋予您编写自定义身份验证脚本的能力。通过错误的配置很容易出错。

  • A7-不安全的加密存储:Jenkins 有 600 多个插件,每个插件都将其配置存储在单独的 XML 文件中。密码以明文形式存储可能会有罕见的错误。您需要仔细检查。

  • A9-传输层保护不足:Jenkins 默认运行在 HTTP 上。获取受信任的证书可能会很麻烦并涉及额外的成本。您可能会心生诱惑,不实施 TLS,从而使您的数据包处于开放状态。

您会发现 2013 年的 OWASP 十大不安全性与 2010 年版本相比有些变化。最显著的变化是包含了 A9-使用已知弱点组件。如果您的软件依赖于旧库,那么就有机会利用已知弱点进行操纵。

Jenkins 拥有一个由积极、分散和勤奋的社区编写的大量插件。由于代码的大量更改,可能会无意中添加安全缺陷。例如,在配置文件中明文留下密码,或者使用不移除可疑 JavaScript 的不安全渲染。你可以通过手动审查配置文件来找到第一类缺陷。第二类缺陷对更广泛的受众可见,因此更容易被破解。你可以手动攻击新的插件。互联网上有很多有用的备忘单(ha.ckers.org/xss.html)。这种工作很乏味;自动化测试可以覆盖更多内容,并作为 Jenkins 作业的一部分定期安排。

在名为探索 OWASP Dependency-Check 插件的配方中,你将配置 Jenkins,让它基于自动审查你的代码依赖关系来警告你已知的攻击向量。

提示

OWASP 商店

OWASP 每年发布一份关于 Web 应用程序十大最常见安全攻击向量的列表。他们通过 lulu.com 发布此文档和各种书籍。在 Lulu,你可以免费获取 OWASP 文档的 PDF 版本,或者购买廉价的按需打印版本。你可以在官方商店找到它:stores.lulu.com/owasp

准备工作

渗透测试有可能损坏正在运行的应用程序。确保你备份了 Jenkins 工作空间的副本。你可能需要重新安装。同时关闭 Jenkins 中的任何已启用安全性:这样可以让 w3af 自由地漫游安全表面。

从 SourceForge 下载 w3af 的最新版本(w3af.org/download/),并且也下载并阅读 OWASP 的十大已知攻击列表(www.owasp.org/index.php/Category:OWASP_Top_Ten_Project)。

w3af 同时具有 Windows 和 *NIX 安装包;使用您选择的操作系统安装。但是,Windows 安装程序不再受支持,没有安装程序的安装过程很复杂。因此,最好使用工具的 *NIX 版本。

注意

w3af 的 Debian 包比 Linux 的 SourceForge 包老旧且不稳定。因此,不要使用 apt-getyum 安装方法,而是使用从 SourceForge 下载的包。

如何操作...

  1. 要安装 w3af,请按照开发者网站上给出的说明进行操作(w3af.org/download/)。如果 Ubuntu 存在任何无法解决的依赖问题,请退回到 apt-get 安装方法,并安装工具的旧版本,方法如下:

    sudo apt-get install w3af
    
    
  2. 运行 w3af。

  3. 配置文件选项卡下,选择OWASP_TOP10

  4. 目标地址窗口下,填写 http://localhost:8080/,将主机名更改为适合您的环境。

  5. 点击 Start 按钮。现在将进行渗透测试,而 Start 按钮将更改为 Stop。在扫描结束时,Stop 按钮将更改为 Clear操作方法...

  6. 通过选择 Log 标签查看攻击历史记录。

  7. 通过单击 Results 标签查看结果。

  8. 在第一次扫描后,在 Profiles 下选择 full_audit

  9. 点击 Clear 按钮。

  10. Target 地址窗口中键入 http://localhost:8080/

  11. 点击 Start

  12. 等待扫描完成并查看 Results 标签。

它是如何工作的...

w3af 由安全专业人员编写。它是一个可插拔的框架,具有为不同类型的攻击编写的扩展。配置文件定义了您将在渗透测试中使用的插件及其关联的配置。

您首先使用 OWASP_TOP10 配置文件进行攻击,然后再次使用更全面的插件进行攻击。

结果会根据您的设置而变化。根据插件,偶尔会标记出不存在的安全问题。您需要手动验证所提到的任何问题。

在写作时,使用这种方法未发现重大缺陷。然而,该工具指出了缓慢的链接并生成了服务器端异常。这是你想在错误报告中记录的信息类型。

还有更多...

一致地保护您的应用程序需要经验丰富的细节关注。以下是您需要审查的更多内容。

使用 Webgoat 进行目标练习

安全缺陷的前十名列表有时会难以理解。如果你有一些空闲时间,喜欢针对一个故意不安全的应用程序进行实践,那么你应该尝试一下 Webgoat (www.owasp.org/index.php/Category:OWASP_WebGoat_Project)。

Webgoat 配有提示系统和链接到视频教程的文档良好;它几乎没有误解攻击的余地。

更多工具

w3af 是一个强大的工具,但与以下工具一起使用效果更好:

  • Nmap (nmap.org/):一个易于使用、非常流行、屡获殊荣的网络扫描器。

  • Nikto (cirt.net/nikto2):一个 Perl 脚本,快速总结系统详细信息并查找最明显的缺陷。

  • Skipfish (code.google.com/p/skipfish/downloads/list):一个利用大量请求长时间运行的 C 程序。您可以从不同的攻击字典中进行选择。这是一个极好的穷人压力测试;如果您的系统保持稳定,那么您就知道它已经达到了最低的稳定水平。

  • Wapiti (wapiti.sourceforge.net/):一个基于 Python 的脚本,发现可攻击的 URL,然后循环遍历一个邪恶参数列表。

Jenkins 是灵活的,因此可以通过运行作业中的脚本调用各种工具,包括提到的安全工具。

有许多优秀的资源可用于保护本地操作系统,包括 Debian 安全指南(www.debian.org/doc/manuals/securing-debian-howto/);对于 Windows,可以在 MSDN 安全中心下找到相关文章(msdn.microsoft.com/en-us/security/);对于 Mac,可以参考苹果官方的安全指南(www.apple.com/support/security/guides/)。在线服务需要高度关注其安全性。

另请参阅

  • 通过模糊查找 Jenkins 中的 500 错误和 XSS 攻击 配方

  • 通过小配置更改提高安全性 配方

  • 探索 OWASP 依赖检查插件 配方

通过模糊查找 Jenkins 中的 500 错误和 XSS 攻击

该配方描述了如何使用模糊器在您的 Jenkins 服务器中查找服务器端错误和 XSS 攻击。

模糊器会遍历一系列网址,盲目地附加不同的参数,并检查服务器的响应。输入的参数是关于脚本命令的变化,例如 <script>alert("random string");</script>。如果服务器的响应包含脚本的未转义版本,那么就发现了一种攻击向量。

跨站脚本攻击目前是较流行的一种攻击形式(en.wikipedia.org/wiki/Cross-site_scripting)。该攻击涉及将脚本片段注入客户端浏览器,以便脚本以来自受信任网站的方式运行。例如,一旦您已登录应用程序,您的会话 ID 可能存储在 cookie 中。注入的脚本可能会读取 cookie 中的值,然后将信息发送到另一台服务器,以备重用尝试。

一个模糊器会发现攻击目标站点上的链接以及站点网页中存在的表单变量。对于发现的网页,它会基于历史攻击和大量微小变化重复发送输入。如果返回的响应与发送的相同的随机字符串,模糊器就知道它发现了一个恶意网址

要完全与基于 Web 的应用程序的构建流程集成,您需要构建应用程序、部署和运行应用程序、从脚本运行模糊器,并最终使用日志解析来在输出中提到恶意网址时失败构建。对于您希望集成的其他命令行工具,该流程将类似。有关日志解析的更多信息,请参阅第一章 中的 通过日志解析故意失败构建 配方,Maintaining Jenkins

准备工作

备份你的牺牲 Jenkins 服务器并关闭其安全性。预计攻击结束时应用程序将不稳定。

你需要在你的计算机上安装 Python 编程语言。要下载和安装 Wapiti,你需要按照 wapiti.sourceforge.net 上的说明进行操作。

注意

如果你从本地机器攻击本地机器,那么你可以关闭其网络。攻击将留在环回网络驱动程序中,不会有数据包逃逸到互联网。

在这个教程中,方法和命令行选项都是正确的。但是,在阅读时,提到的结果可能不存在。Jenkins 经历了快速的生命周期,开发人员迅速清除错误。

如何操作...

  1. wapiti bin 目录中运行以下命令:

    python wapiti  http://localhost:8080 -m "-all,xss,exec" -x http://localhost:8080/pluginManager/* -v2
    
    
  2. 当命令运行完成时,你将在控制台输出中看到最终报告的位置:

    Report
    ------
    A report has been generated in the file
    ~/.wapiti/generated_report
    ~/.wapiti/generated_report/index.html with a browser to see this report.
    
    
  3. 在网页浏览器中打开报告并进行审阅:如何操作...

  4. 点击内部服务器错误链接。

  5. 对于其中一个名为在 /iconSize 中发现的异常的项目,从cURL 命令行选项卡中复制 URL:如何操作...

  6. 在网页浏览器中打开 URL。现在你会看到一个新生成的 Jenkins 错误报告页面,如下图所示:如何操作...

  7. 运行以下命令:

    python wapiti http://localhost:8080 -m "-all,xss,permanentxss" -x http://localhost:8080/pluginManager/*
    
    
  8. 查看输出以验证 permanentxss 模块是否已运行:

    [*] Loading modules :
    mod_crlf, mod_exec, mod_file, mod_sql, mod_xss, mod_backup, mod_htaccess, mod_blindsql, mod_permanentxss, mod_nikto
    [+] Launching module xss
    [+] Launching module permanentxss
    
    

工作原理...

Wapiti 载入不同的模块。默认情况下,会使用所有模块。你需要进行选择;对于 Ubuntu Linux 的 Version 2.2.1,这会导致 Wapiti 崩溃或超时。

要加载特定模块,请使用 -m 选项。

-m "-all,xss,exec" 语句告诉 Wapiti 忽略所有模块,除了 xssexec 模块。

exec 模块非常擅长在 Jenkins 中找到 500 错误。这主要是由于 Jenkins 无法很好地处理意外输入。这纯粹是一组外观问题。但是,如果开始出现与文件或数据库服务等资源相关的错误,则应提高问题的优先级并发送错误报告。

-x 选项指定要忽略的 URL。在这种情况下,我们不想给插件管理器带来麻烦。如果这样做,它将向一个无辜的外部服务生成大量请求。

Wapiti 爬取网站。如果你不小心,工具可能会跟踪到你不想测试的位置。为了避免尴尬,请小心使用排除 URL 的选项 -x

-v2 选项设置日志的详细程度最高,这样你就可以看到所有攻击。

在 Wapiti 的第二次运行中,你还使用了 permanentxss 模块,有时会发现真正的 XSS 攻击,这取决于开发人员构建功能和清理错误之间的竞争。

注意

穷人版的质量保证

模糊测试器擅长覆盖应用程序的大部分 URL 空间,触发可能会耗费大量时间来查找的错误。考虑在项目的 QA 过程中通过 Jenkins 作业进行自动化。

还有更多...

您在此方法中生成的报告提到的服务器错误比 XSS 攻击要多得多。这是因为许多生成的错误是由于意外的输入导致失败,这些失败只被最后一层错误处理捕获,本例中为错误报告页面。如果您认为错误值得报告,请按照 bug 报告页面上的说明操作。

这里有一些关于堆栈跟踪输出背后含义的指南:

  • java.lang.SecurityException:如果 Jenkins 用户正在进行程序员认为不安全的操作,比如访问 URL,则只有在您登录后才能到达此处。

  • java.lang.IllegalArgumentException:Jenkins 检查了参数的有效范围,参数值超出了该范围。这是故意抛出的异常。

  • java.lang.NumberFormatException:Jenkins 没有检查有效的字符串,然后尝试将一个不符合规范的字符串解析为数字。

  • java.lang.NullPointerException:通常发生在您访问一个没有设置所有参数的 URL 时,Jenkins 期望的参数值不存在。在程序员的语言中:代码期望存在一个不存在的对象,然后尝试调用不存在对象的方法,而不检查对象是否存在。程序员需要添加更多的错误检查。编写一个错误报告。

另请参阅

  • 测试 OWASP 前 10 大安全问题的方法

  • 通过小的配置更改提高安全性的方法

通过小的配置更改提高安全性

此方法描述了修改后的配置,以加强 Jenkins 的默认安全设置。重新配置包括在控制台输出中掩码密码和添加一次性随机数,这使得很难伪造表单输入。这些调整的组合极大地加强了 Jenkins 的安全性。

准备就绪

您将需要安装 Mask Passwords 插件 (wiki.jenkins-ci.org/display/JENKINS/Mask+Passwords+Plugin)。

如何操作...

  1. 创建一个作业。

  2. 单击掩码密码复选框并添加一个变量。

  3. 名称字段中键入MyPassword,在密码字段中键入changeme,如下面的屏幕截图所示:操作步骤...

  4. 执行 shell中键入echo This is MyPassword $MyPassword

  5. 运行作业。

  6. 查看控制台输出操作步骤...

  7. 返回配置全局安全性页面,单击防止跨站点请求伪造攻击,确保选择了默认 Crumb 发行者选项:操作步骤...

工作原理...

屏蔽密码插件将密码从屏幕或控制台中删除,并用 x 替换,从而避免意外阅读。 除非你发现未记录的副作用或需要调试一个任务,否则你应该始终保持该插件打开状态。

注意

你可以在 配置系统自动屏蔽密码参数 部分全局设置参数。

跨站请求伪造(en.wikipedia.org/wiki/Cross-site_request_forgery)的例子,例如,如果你意外地访问了第三方位置;该位置上的脚本尝试使你的浏览器执行一个动作(如删除一个任务),方法是让你的网页浏览器访问 Jenkins 中已知的 URL。 Jenkins 会认为浏览器是在执行你的命令,然后遵循该请求。 一旦开启了 nonce 特性,Jenkins 通过生成一个称为nonce的随机一次性数字来避免 CSRF,在请求的一部分返回。 这个数字不容易被知晓,并且在短时间内失效,限制了重放攻击的风险。

还有更多...

Jenkins 使用起来非常愉快。 这是因为 Jenkins 使得完成工作变得容易,并且可以通过插件与多种基础架构进行通信。 这意味着,在许多组织中,随着服务的有机增长,管理员的数量迅速增加。 在管理员团队习惯于能够添加任意标记的灵活性之前,考虑及早开启 HTML 转义。

考虑偶尔重播 通过模糊测试查找 Jenkins 中的 500 错误和 XSS 攻击 的方法,以验证消除此潜在 XSS 攻击源。

请参阅

  • 测试 OWASP 前十大安全问题 的方法

  • 通过模糊测试查找 Jenkins 中的 500 错误和 XSS 攻击 的方法

使用 JCaptcha 避免注册机器人

CAPTCHA 代表 Completely Automated Public Turing Test to tell Computers and Humans Apart。 最常见的 CAPTCHA 是显示为图形的连续字母和数字,你必须正确输入到文本输入框中。

如果你允许任何人在你的 Jenkins 服务器上注册账号,那么你最不想要的就是机器人(自动化脚本)创建账号,然后将其用于不礼貌的用途。 机器人具有规模经济效应,能够快速扫描互联网而且永远不会感到无聊。 CAPTCHA 是对这些愚蠢攻击的必要防御手段。

机器人的负面目的如下:

  • 对你的服务器执行 拒绝服务 (DOS) 攻击,例如,通过自动创建大量的重型任务

  • 分布式拒绝服务攻击 (DDOS),通过利用多个 Jenkins 服务器发送大量请求来攻击其他服务器

  • 通过注入不需要的广告或指向恶意网站的内容

  • 通过添加永久存储并在用户意外浏览 Jenkins 站点时运行的脚本

    注意

    商业动机导致犯罪分子绕过 CAPTCHA 的行为在法律案例中有着充分的记录。你可以在www.wired.com/2010/10/hacking-captcha/找到其中一个案例。

准备就绪

确保已备份你的 Jenkins 服务器。你将修改其安全设置。很容易出现服务变更错误。

提示

JCaptcha 插件是基于 Java 实现的,你可以在jcaptcha.atlassian.net/wiki/display/general/Home找到。

如何操作...

  1. 以管理员身份登录。

  2. 点击配置全局安全性链接。

  3. 安全领域下选择 Jenkins 自己的用户数据库。

  4. 如下截图所示,选择允许用户注册操作步骤...

  5. 点击保存

  6. 浏览注册位置http://localhost:8080/signup。你会看到类似以下截图的内容:操作步骤...

  7. 管理 Jenkins页面点击管理插件链接。

  8. 选择可用选项卡。

  9. 安装 JCaptcha 插件。

  10. 管理 Jenkins页面下点击配置全局安全性链接。

  11. 安全领域下选择 Jenkins 自己的用户数据库。

  12. 如下截图所示,选择在注册时启用验证码操作步骤...

  13. 点击保存,然后点击注销链接。

  14. 浏览注册位置http://localhost:8080/signup。该页面现在通过 CAPTCHA 进行了防御,如下截图所示:操作步骤...

工作原理...

安装该插件将在注册流程中添加 CAPTCHA 图像。图像需要模式识别才能解读。人类在这方面非常擅长;自动化流程则要差得多,但在不断改善。

还有更多...

这里有几个你可以考虑的要点。

深度防御

防御方法(如 CAPTCHA)与进攻方法(如越来越智能的机器人)之间存在一场竞赛。没有一种解决方案能将风险降至零。最佳实践是考虑采用分层方法。根据你的要求,考虑添加身份验证、限制访问到已知 IP 地址、备份配置、审查日志文件、漏洞测试以及改善站点的一般安全卫生情况。

提示

SANS 研究所撰写了一篇关于深度防御策略的论文www.sans.org/reading-room/whitepapers/basics/defense-in-depth-525

有关机器人的更多信息

安全竞赛仍在继续。机器人变得越来越聪明,脚本小子也更多。以下是关于这场竞赛的一些背景文章:

另请参阅

  • 测试 OWASP 十大安全问题配方

通过 Groovy 查看 Jenkins 用户

Groovy 脚本在主机服务器上作为 Jenkins 用户运行。此处介绍的配方突显了 Jenkins 应用程序和主机服务器的威力和危险性。

准备就绪

以管理员身份登录您的测试 Jenkins 实例。

如何做...

  1. 脚本控制台(http://localhost:8080/script)运行以下脚本:

    def printFile(location) {
    pub = new File(location)
    if (pub.exists()){ 
    println "Location ${location}"
    pub.eachLine{line->println line}
        } else{
    println "${location} does not exist"
        }
    }
    
    printFile("/etc/passwd")
    printFile("/var/lib/jenkins/.ssh/id_rsa")
    printFile("C:/Windows/System32/drivers/etc/hosts")
    
  2. 查看输出。

    对于典型的*NIX 系统,它将类似于以下截图:

    如何做...

    对于 Windows 系统,它将类似于以下截图:

    如何做...

它是如何工作的...

您运行的脚本并不像看起来那么良性。Groovy 脚本可以做任何 Jenkins 用户在主机服务器上以及测试 Jenkins 服务器内具有权限执行的操作。定义了一个方法,该方法读取作为字符串传递的文件的位置。然后脚本打印内容。如果文件不存在,则也会提到。测试了三个位置。您可以轻松添加更详细的位置集。

文件的存在清晰地定义了所使用的操作系统类型和磁盘分区的结构。

/etc/passwd文件通常不包含密码。密码隐藏在一个影子密码文件中,安全地不可见。但是,用户名具有真实的登录帐户(不是/bin/false),以及它们是否具有 shell 脚本,这提示了要尝试通过专注于字典攻击来尝试破解的帐户。

如果为 Jenkins 生成私钥和公钥,则可以节省配置工作量。这允许脚本在用户的许可下运行,而无需密码登录。Jenkins 通常用于控制其从属节点。通过 Groovy 脚本检索密钥代表了更广泛基础架构的进一步危险。

如果任何插件以明文或可解密文本存储密码,则可以捕获插件的 XML 配置文件并进行解析。

您不仅可以读取文件,还可以更改权限并覆盖二进制文件,使攻击更难发现并更具侵略性。

更多信息...

限制风险的最佳方法是限制具有在脚本控制台中运行 Groovy 脚本权限的登录帐户数,并定期审查审计日志。

通过使用基于矩阵的策略,限制管理员帐户变得更加容易,你可以决定每个用户或组的权限。这一策略的一个改进是基于项目的矩阵策略,其中可以选择每个作业的权限。然而,基于项目的矩阵策略在管理方面的成本要高得多。

注意

自 Jenkins 的版本 1.430 以来,矩阵式安全策略暴露了额外的权限,以决定哪个组或用户可以运行 Groovy 脚本。随着时间的推移,预计会增加更多的权限。

另请参阅

  • 使用审计跟踪插件配方

  • 通过自定义组脚本审查项目矩阵策略配方

使用审计跟踪插件

任务可能会失败。如果你能看到最后运行任务的人以及他们做了什么改变,可以加快调试速度。这个配方确保你已经启用了审计,并创建了一组本地审计日志,其中包含大量事件的历史记录,而不是默认定义的小日志大小。

准备工作

安装审计跟踪插件(wiki.jenkins-ci.org/display/JENKINS/Audit+Trail+Plugin)。

如何操作...

  1. 访问配置 Jenkins屏幕(http://localhost:8080/configure)。

  2. 审计跟踪部分,点击添加记录器按钮。

  3. 修改审计跟踪的默认设置以允许长时间的观察。将日志文件大小 MB更改为128日志文件计数更改为40

  4. 点击高级...按钮以审查所有设置。如何操作...

工作原理...

审计插件创建了一个名为审计跟踪的日志记录器(wiki.jenkins-ci.org/display/JENKINS/Logger+Configuration)。你可以访问日志的记录器页面,网址为http://localhost:8080/log/?来查看哪些记录器正在记录。

日志记录器的输出通过 Jenkins 配置屏幕中看到的URL 模式来记录进行过滤。你会发现日志文件格式比大多数日志更易读,以日期时间戳开始,日志中间描述正在发生的事情,并在最后指明操作的用户。看看以下示例:

2011 年 7 月 18 日下午 3:18:51 由用户 Alan 启动的 job/Fulltests_1/ #3

2011 年 7 月 18 日下午 3:19:22 /job/Fulltests_1/configSubmit by Alan

现在清楚地知道谁什么时候做了什么。

注意

考虑将audit.log文件本身放在版本控制系统下。这样做有三个主要原因。首先是在存储故障的情况下。第二个是为了使更难以修改审计日志而不留下证据。最后,这是一个集中收集整个企业的小日志文件的地方。

还有更多...

这里还有一些你应该考虑的东西。

一个补充插件 - JobConfigHistory

一个补充插件,用于跟踪配置更改并在作业内部显示信息,称为 JobConfigHistory 插件 (wiki.jenkins-ci.org/display/JENKINS/JobConfigHistory+Plugin)。该插件的优点是您可以看到谁做了这些关键更改。缺点是它向潜在的完整 GUI 添加了一个图标,为其他功能留下了较少的空间。

缺少审计日志

对于安全官员来说,略微偏执有所帮助。如果您的审计日志突然丢失,那么这很可能是黑客希望掩盖其踪迹的迹象。如果一个文件丢失或审计时间出现间隙,这也是真实的。即使这是由于配置问题或损坏的文件系统引起的,您也应该调查。缺少日志应触发对相关服务器的更广泛审查。至少,审计插件的行为与预期不符。

考虑为这些极具价值的日志添加一个小的报告脚本。例如,考虑修改 第三章中的在 Jenkins 中报告替代代码度量配方,构建软件,以解析日志文件并制作随后以图形显示的度量。这使您可以随着时间查看团队工作的起伏。当然,数据可以伪造,但这需要额外的努力。

注意

减少日志文件篡改风险的一种方法是将日志事件发送到中央远程 syslog 服务器。您可以配置审计追踪插件以与配置系统页面中的 syslog 配合使用。

Swatch

您可以想象一种情况,您不希望某些用户运行 Groovy 脚本,并且希望在发生意外操作时收到电子邮件。如果您想要立即对特定日志模式做出反应且尚未有基础设施,请考虑使用 Swatch,这是一个开源产品,可以在大多数 *NIX 发行版中免费使用。(sourceforge.net/projects/swatch/www.jaxmag.com/itr/online_artikel/psecom,id,766,nodeid,147.html)。

Swatch 是一个 Perl 脚本,定期审查日志。如果发现模式,则通过电子邮件或执行命令做出反应。

另请参阅

  • 通过小的配置更改改善安全性配方

  • 通过 Groovy 查看 Jenkins 用户配方

  • 第三章中的在 Jenkins 中报告替代代码度量配方,构建软件

安装 OpenLDAP

轻量级目录访问协议LDAP)提供了一个非常流行的开放标准目录服务。它在许多组织中用于向世界展示用户信息。LDAP 还用作保存用户密码进行身份验证的中央服务,并且可以包含外部系统可能需要的路由邮件、POSIX 帐户管理以及各种其他信息。Jenkins 可以直接连接到 LDAP 进行身份验证,或间接通过 CAS SSO 服务器(www.jasig.org/cas),后者再使用 LDAP 作为其密码容器。Jenkins 还有一个电子邮件插件(wiki.jenkins-ci.org/display/JENKINS/LDAP+Email+Plugin),它从 LDAP 中提取其路由信息。

因为 LDAP 是一个常见的企业服务,Jenkins 在构建应用程序的测试基础设施时也可能会遇到 LDAP,作为集成测试的一部分。

本教程向您展示如何快速安装一个名为 slapd 的 OpenLDAP 服务器(www.openldap.org/),然后通过 LDAP 数据交换格式LDIF)添加组织、用户和组,LDIF 是一种简单的文本格式,用于存储 LDAP 记录(en.wikipedia.org/wiki/LDAP_Data_Interchange_Format)。

注意

Active Directory 在企业环境中也很流行。Jenkins 有一个用于 Active Directory 的插件(wiki.jenkins-ci.org/display/JENKINS/Active+Directory+plugin)。

准备工作

本教程假定你正在运行一个现代的基于 Debian 的 Linux,比如 Ubuntu。

注意

有关在 Windows 上安装 OpenLDAP 的详细说明,请参阅 www.userbooster.de/en/support/feature-articles/openldap-for-windows-installation.aspx

将以下 LDIF 条目保存到 basic_example.ldif 文件中,并将其放在您的主目录中:

dn: ou=mycompany,dc=nodomain
objectClass: organizationalUnit
ou: mycompany

dn: ou=people,ou=mycompany,dc=nodomain
objectClass: organizationalUnit
ou: people

dn: ou=groups,ou=mycompany,dc=nodomain
objectClass: organizationalUnit
ou: groups

dn: uid=tester1,ou=people,ou=mycompany,dc=nodomain
objectClass: inetOrgPerson
uid: tester1
sn: Tester
cn: I AM A Tester
displayName: tester1 Tester
userPassword: changeme
mail: tester1.tester@dev.null

dn: cn=dev,ou=groups,ou=mycompany,dc=nodomain
objectclass: groupofnames
cn: Development
description: Group for Development projects
member: uid=tester1,ou=people,dc=mycompany,dc=nodomain

如何做...

  1. 通过执行以下命令安装 LDAP 服务器 slapd

    sudo apt-get install slapdldap-utils
    
    
  2. 当询问时,请填写管理员密码。

  3. 从命令行添加 LDIF 记录;然后会要求输入你在第 2 步中使用的管理员密码。执行以下命令:

    ldapadd -x -D cn=admin,dc=nodomain -W -f ./basic_example.ldif
    
    

工作原理...

LDIF 是 LDAP 中记录的文本表达形式。

  • 区别名称dn):这是每个记录的唯一标识符,结构化使对象驻留在组织树结构中。

  • objectClassobjectClass,比如 organizationalUnit,定义了一组必需和可选属性。在 organizationalUnit 的情况下,ou 属性是必需的。这对于捆绑定义目的的属性很有用,比如创建属于一个组织结构的属性或拥有电子邮件帐户。

在示例中,在安装 LDAP 服务器后,我们通过包安装期间创建的管理员帐户(默认dn:cn=admin,dc=nodomain)导入了数据;如果是这种情况,您将需要更改示例第 2 步中-D选项的值。

管理员帐户的默认dn可能会有所不同,这取决于您安装了哪个版本的 slapd。

LDIF 创建了一个具有三个组织单位的组织结构:

  • dn:ou=mycompany,dc=nodomain

  • dn:ou=people,ou=mycompany,dc=nodomain:搜索人员的位置

  • dn:ou=groups,ou=mycompany,dc=nodomain:搜索组的位置

为了测试,创建了一个用户(dn: uid=tester1,ou=people,ou=mycompany,dc=nodomain)。记录必须具有的属性列表由inetOrgPerson对象类定义。

通过groupOfNames对象类创建了一个组(dn: cn=dev,ou=groups,ou=mycompany,dc=nodomain)。通过添加指向用户的dn的成员属性,将用户添加到组中。

Jenkins 查找用户名以及用户所属的组。在 Jenkins 中,您可以根据他们的组信息定义用户可以配置哪些项目。因此,您应考虑添加与您的 Jenkins 作业结构匹配的组,例如开发、验收,以及为那些需要全局权限的人员添加一个组。

更多信息...

这个 LDIF 示例没有涵盖添加objectClass访问控制列表ACLs):

  • objectClass:LDAP 使用objectClass对传入的记录创建请求进行检查。如果记录中不存在所需的属性,或者类型错误,则 LDAP 将拒绝数据。有时需要添加一个新的objectClass;您可以使用图形工具完成此操作。管理 OpenLDAP示例展示了这样一个工具。

  • 访问控制列表:这些定义了哪个用户或哪个组可以做什么。有关这个复杂主题的信息,请访问www.openldap.org/doc/admin24/access-control.html。您还可以从man slapd.access命令行中查看您的 OpenLDAP 服务器的主要入口。

另请参阅

  • 管理 OpenLDAP示例

  • 配置 LDAP 插件示例

使用脚本领域认证进行配置

对于许多企业应用程序,配置发生在用户首次登录时。例如,可以创建带有内容的目录,将用户添加到电子邮件分发列表,修改访问控制列表,或者向市场部门发送电子邮件。

这个示例将向您展示如何使用两个脚本:一个用于通过 LDAP 登录并执行示例配置,另一个用于返回用户所属的组列表。这两个脚本都使用 Perl,这使得代码紧凑。

准备工作

您需要安装 Perl 和Net::LDAP模块。对于 Debian 发行版,您应通过以下命令安装libnet-ldap-perl软件包:

sudo apt-get install libnet-ldap-perl

你还需要安装 Script Realm 插件(wiki.jenkins-ci.org/display/JENKINS/Script+Security+Realm)。

如何做到...

  1. 作为 Jenkins 用户,将以下文件放置在 Jenkins 控制的目录下,并赋予可执行权限。将文件命名为 login.pl。确保 $home 变量指向正确的工作空间:

    #!/usr/bin/perl
    use Net::LDAP;
    use Net::LDAP::Utilqw(ldap_error_text);
    
    my $dn_part="ou=people,ou=mycompany,dc=nodomain";
    my $home="/var/lib/jenkins/userContent";
    my $user=$ENV{'U'};
    my $pass=$ENV{'P'};
    
    my $ldap = Net::LDAP->new("localhost");
    my $result =$ldap->bind("uid=$user,$dn_part", password=>$pass);
    if ($result->code){
    my $message=ldap_error_text($result->code);
    print "dn=$dn\nError Message: $message\n";
    exit(1);
        }
    # Do some provisioning
    unless (-e  "$home/$user.html"){
    open(HTML, ">$home/$user.html");
    print HTML "Hello <b>$user</b> here is some information";
    close(HTML);
    }
    exit(0);
    
  2. 作为 Jenkins 用户,将以下文件放置在 Jenkins 控制的目录下,并赋予可执行权限。将文件命名为 group.pl

    #!/usr/bin/perl
    print "guest,all";
    exit(0);
    
  3. 通过 全局安全配置 屏幕下的 安全领域 子部分配置插件,然后添加以下详细信息:

    • 检查 通过自定义脚本进行身份验证

    • 登录命令/var/lib/Jenkins/login.pl

    • 分组命令/var/lib/Jenkins/group.pl

    • 分组分隔符

  4. 点击 保存 按钮。

  5. 使用用户名 tester1 和密码 changeme 登录。

  6. 访问 http://localhost:8080/userContent/tester1.html 中的配置内容。你会看到以下截图:如何做到...

工作原理...

login.pl 脚本从环境变量 UP 中提取用户名和密码。然后脚本尝试将用户自绑定到计算出的唯一 LDAP 记录。例如,用户 tester1 的专有名称是 uid=tester1, ou=people,ou=mycompany,dc=nodomain

自绑定发生在你搜索自己的 LDAP 记录并同时进行身份验证时。这种方法的优点是允许你的应用程序在不使用全局管理帐户的情况下测试密码的真实性。

如果身份验证失败,则返回退出码 1。如果身份验证成功,则进行配置过程,然后返回退出码 0

如果文件尚不存在,则会创建它。在配置过程中会创建一个简单的 HTML 文件。这只是一个示例;你可以做更多的事情,从发送电子邮件提醒到在整个组织范围内进行完整的帐户配置。

group.pl 脚本简单地返回包括每个用户的两个组,即 guests 和 all。Guest 是仅供访客使用的组。All 是所有用户(包括访客)都属于的组。稍后,如果你想发送关于服务维护的电子邮件,那么你可以使用 LDAP 查询通过 all 组收集电子邮件地址。

还有更多...

根据所使用的模式,LDAP 服务器用于多种目的。你可以路由邮件、创建登录帐户等。这些帐户由常见的认证平台强制执行,如可插拔认证模块PAM),特别是 PAM_LDAPwww.padl.com/OSS/pam_ldap.htmlwww.yolinux.com/TUTORIALS/LDAP_Authentication.html)。

在阿姆斯特丹大学,我们使用自定义架构,以便用户记录具有一个用于倒计时记录的属性。计划任务执行对计数器的 LDAP 搜索,然后将计数器递减一。任务注意到当计数器达到某些数字时,并执行诸如发送电子邮件警告之类的操作。

您可以想象将此方法与自定义登录脚本结合使用。一旦顾问首次登录 Jenkins,他们将在将其 LDAP 记录移至“待忽略”分支之前获得一定的宽限期。

另请参阅

  • 通过自定义组脚本审查基于项目的矩阵策略示例

通过自定义组脚本审查基于项目的矩阵策略

安全最佳实践要求您应该将个别用户的权限限制到他们所需的级别。

本示例探讨了基于项目的矩阵策略。在此策略中,您可以逐个作业地为个别用户或组分配不同的权限。

本示例使用启用了 Script Security 插件的自定义领域脚本,允许您使用任何长度大于五个字符的名称和密码登录,并将测试用户放置在其自己的独特组中。这将允许您测试基于项目的矩阵策略。

使用自定义脚本进行用户认证和定义组,使您的测试 Jenkins 服务器能够连接到各种非标准的身份验证服务。

准备就绪

您需要安装 Script Security Realm 插件 (wiki.jenkins-ci.org/display/JENKINS/Script+Security+Realm) 并且还要安装具有 URI 模块的 Perl (search.cpan.org/dist/URI/URI/Escape.pm)。URI 模块包含在现代 Perl 发行版中,因此在大多数情况下,脚本将直接运行。

操作步骤...

  1. 将以下脚本复制到 Jenkins 工作区的login2.pl文件中:

    #!/usr/bin/perl
    my $user=$ENV{'U'};
    my $pass=$ENV{'P'};
    my $min=5;
    
    if ((length($user) < $min) || (length($pass) < $min)) {
        //Do something here for failed logins
    exit (-1);
    }
    exit(0);
    
  2. 将脚本的所有者和组更改为jenkins,如下所示:

    sudo chown jenkins:jenkins /var/lib/jenkins/login2.pl
    
    
  3. 将以下脚本复制到 Jenkins 工作区的group2.pl文件中:

    #!/usr/bin/perl
    use URI;
    use URI::Escape;
    my $raw_user=$ENV{'U'};
    my $group=uri_escape($raw_user);
    print "grp_$group";
    exit(0);
    
  4. 将脚本的所有者和组更改为jenkins,如下所示:

    sudo chown jenkins:jenkins /var/lib/jenkins/group2.pl
    
    
  5. 全局安全性配置屏幕下的安全域子部分配置插件。

  6. 选择通过自定义脚本进行身份验证单选按钮,并添加以下详细信息:操作步骤...

  7. 选中基于项目的矩阵授权策略复选框。

  8. 添加名为adm_alan的用户并授予完整权限,如下截图所示:操作步骤...

  9. 点击保存按钮。

  10. 尝试以密码少于五个字符登录adm_alan

  11. adm_alan登录,密码大于五个字符即可。

  12. 创建一个名为project_matrix_test且无配置的新作业。

  13. 在作业中选中启用基于项目的安全性复选框。

  14. 添加grp_proj_tester组的完全权限(例如,选中所有复选框):如何做...

  15. 以用户I_cant_see_you身份登录。注意,您无法查看最近创建的作业project_matrix_test

  16. proj_tester身份登录。注意,您现在可以查看和配置project_matrix_test

它是如何工作的...

login2.pl脚本允许任何用户名-密码组合成功登录,只要它至少是$min变量定义的长度。

group2.pl脚本从环境中读取用户名,然后转义名称,以确保以后不会意外运行任何恶意脚本。group2.pl脚本将用户放入grp_username组中。例如,如果proj_tester登录,则属于grp_proj_tester组。

组脚本允许我们以任意用户身份登录并查看用户的权限。在基于项目的矩阵策略中,用户或组的权限在两个级别上定义:

  • 通过 Jenkins 配置页面进行全局设置。这是您应该为系统范围管理定义全局账户的地方。

  • 通过作业配置屏幕的每个项目。全局账户可以获得额外的项目权限,但不能失去权限。

在这个示例中,您以一个行为类似根管理员的全局账户adm_alan登录。然后,您以I_cant_see_you登录;这根本没有额外权限,甚至看不到作业首页。最后,您以proj_tester登录,他属于grp_proj_tester组,具有特定作业的完全权限。

使用每个项目的权限,不仅限制个人用户的权力,还可以确定他们可以查看哪些项目。这个功能对于拥有大量作业的 Jenkins 主服务器特别有用。

还有更多...

还有一些事情您应该考虑。

我自己的自定义安全漏洞

我希望您已经发现了这一点。登录脚本存在一个重大的安全缺陷。由U变量定义的用户名输入未经检查是否有恶意内容。例如,用户名可以如下:

<script>alert('Do something');</script>

稍后,如果任意插件将用户名显示为自定义视图的一部分,那么如果插件没有安全转义,用户名将在最终用户的浏览器中运行。这个例子展示了安全性出错有多容易。最好在可以的时候使用知名且受信任的库。例如,OWASP 的 Java 特定AntiSamy库(www.owasp.org/index.php/Category:OWASP_AntiSamy_Project)在过滤 CSS 或 HTML 片段形式的输入方面表现出色。

对于 Perl,在这个主题上有很多优秀的文章,比如www.perl.com/pub/2002/02/20/css.html

静态代码审查、污点标记和去污点标记

静态代码审查是指读取未运行的代码并查找已知代码缺陷的工具。PMD 和 FindBugs 是很好的示例(fsmsh.com/2804.com)。这些通用工具之一可以检查您的代码以查找安全缺陷。采取的一种方法是如果输入来自外部来源(例如 Internet)或直接来自文件,则将其视为输入污染。要解除污染,必须首先将输入传递给正则表达式,并安全地转义、移除或报告不需要的输入。

另请参阅

  • 使用脚本领域身份验证进行配置教程

OpenLDAP 管理

本教程是 LDAP 管理的快速入门。它详细介绍了如何通过命令行添加或删除用户记录,并强调了使用示例 LDAP 浏览器的方法。这些技能对于维护用于集成测试或 Jenkins 帐户管理的 LDAP 服务器非常有用。

准备工作

要尝试此操作,您需要安装带有Net::LDAP模块的 Perl。例如,对于 Debian 发行版,您应该安装libnet-ldap-perl包(ldap.perl.org)。

您还需要安装 LDAP 浏览器 JExplorer(jxplorer.org/)。

如何做...

  1. 要将用户添加到 LDAP,您需要将以下 LDIF 记录写入名为basic_example.ldif的文件中:

    dn: uid=tester121,ou=people,ou=mycompany,dc=nodomain
    objectClass: inetOrgPerson
    uid: tester121
    sn: Tester
    givenName: Tester121 Tester
    cn: Tester121 Tester
    displayName: Tester121 Tester
    userPassword: changeme
    mail: 121.tester@dev.null
    
  2. 在记录末尾添加一行,并将前一条记录复制到文本文件中,在第二条记录中将数字121替换为122

  3. 运行以下ldapadd命令,并在询问时输入 LDAP 管理员密码。

    ldapadd -x -D cn=admin,dc=nodomain -W -f ./basic_example.ldif
    
    
  4. 运行 Jxplorer,连接以下值:

    • 主机localhost

    • 级别Anonymous

    • 选择Schema选项卡,然后在objectClasses下选择account

    • Table Editor中,您会看到以MAYMUST提及的属性:

    如何做...

  5. 通过选择文件,然后选择断开连接来断开与Anonymous帐户的连接。

  6. 选择文件,然后选择连接,以admin帐户重新连接。添加以下细节:

    • 主机Localhost

    • 级别:用户+密码

    • 用户 DNcn=admin,dc=nodomain

    • 密码:您的密码

  7. Explore选项卡下,选择tester1

  8. Table Editor中,将1021 XT值添加到postalCode中,然后单击提交

  9. 在屏幕顶部选择LDIF菜单选项,然后单击Export Subtree

  10. 单击确定按钮,然后编写要将 LDIF 导出到的文件的名称,然后单击保存

  11. 创建具有以下代码行的可执行脚本并运行它:

    #!/usr/bin/perl
    use Net::LDAP;
    use Net::LDAP::Utilqw(ldap_error_text);
    
    my $number_users=2;
    my $counter=0;
    my $start=100;
    
    my $ldap = Net::LDAP->new("localhost");
    $ldap->bind("cn=admin,dc=nodomain",password=>"your_password");
    
    while ($counter < $number_users){
      $counter++;
        $total=$counter+$start;
    my $dn="uid=tester$total,ou=people,ou=mycompany,dc=nodomain";
    my $result = $ldap->delete($dn); 
    if ($result->code){
    my $message=ldap_error_text($result->code);
    print "dn=$dn\nError Message: $message\n";
        }
    }
    

工作原理...

在这个示例中,你已经执行了一系列任务。 首先,你使用一个 LDIF 文件添加了两个用户。 这对于小组织中的 LDAP 管理员来说是一个典型的事件。 你可以保存 LDIF 文件,然后进行小的修改以添加或删除用户、组等。

接下来,通过 LDAP 浏览器(在本例中是 Jxplorer)匿名查看了目录结构。 Jxplorer 可以在各种操作系统上运行,并且是开源的。 你的操作突显出 LDAP 是一个企业目录服务,即使是匿名用户也能找到其中的内容。 在 Jxplorer 中页面快速渲染的事实突显出 LDAP 是一个读取优化的数据库,能够高效返回搜索结果。

当要呈现的对象数量增加时,使用 LDAP 浏览器通常会更加令人沮丧。 例如,在阿姆斯特丹大学,有超过 60,000 个学生记录在一个分支下。 在这些情况下,你被迫使用命令行工具或者对搜索过滤器非常小心。

能够查看ObjectClass,了解你可能使用的属性以及哪些属性是必须使用的,可以帮助你优化你的记录。

接下来,你以管理员用户绑定(执行某些操作)并操作 tester1 的记录。 对于小组织来说,这是一种高效的管理方式。 将记录导出为 LDIF 文件允许你将该记录用作进一步导入记录的模板。

删除脚本是程序控制的一个示例。 这给了你在通过改变几个变量而实现大规模生成、修改和删除记录时很大的灵活性。 Perl 之所以被选择,是因为它的减少冗长性。 这种类型脚本的使用对于整合测试的配置是很典型的。

在删除脚本中,你会看到要删除的用户数量被设置为 2,测试账号的起始值为 100。 这意味着之前生成的两个记录将被删除,例如tester101tester102

这个脚本首先以管理员账号绑定一次,然后通过使用$counter来计算每个记录的专有名称,循环处理一系列记录。 对每个记录调用删除方法,任何生成的错误都将被打印出来。

还有更多内容...

你应该考虑删除用户的 Perl 脚本,作为整合测试中高效进行 LDAP 服务器配置或清理的示例。 要创建一个添加脚本而不是删除脚本,你可以编写类似的脚本,用以下行代码替换我的$result = $ldap->delete($dn)

my$result=$ldap->add($dn,attrs=>[ @$whatToCreate]);

这里,@$whatTOCreate是一个包含属性和objectClass的哈希。 获取更多示例,请访问search.cpan.org/~gbarr/perl-ldap/lib/Net/LDAP/Examples.pod#OPERATION_-_Adding_a_new_Record

参见

  • 安装 OpenLDAP配方

  • 配置 LDAP 插件配方

配置 LDAP 插件

LDAP 是企业目录服务的标准。 本配方解释了如何将 Jenkins 连接到您的测试 LDAP 服务器。

准备工作

若要尝试此方法,您应首先执行安装 OpenLDAP配方中提到的步骤。

如何实现...

  1. 转到配置全局安全性屏幕并选择启用安全性

  2. 勾选LDAP复选框。

  3. 服务器值添加为127.0.0.1

  4. 单击高级按钮,然后添加以下详细信息:

    • 用户搜索基础ou=people,ou=mycompany,dc=nodomain

    • 用户搜索过滤器uid={0}

    • 组搜索基础ou=groups,ou=mycompany,dc=nodomain

工作原理...

测试 LDAP 服务器支持匿名绑定:您可以在未验证的情况下搜索服务器。 大多数 LDAP 服务器都允许这种方法。 但是,一些服务器配置为执行特定的信息安全策略。 例如,您的策略可能强制要求能够匿名验证用户记录是否存在,但您可能无法检索特定属性,例如他们的电子邮件或邮政地址。

匿名绑定简化了配置;否则,您需要为 LDAP 中具有执行搜索权限的用户添加帐户详细信息。 这个账号拥有强大的 LDAP 权限,绝不能共享,并且可能会在您的安全防线中出现漏洞。

用户搜索过滤器uid={0}用于查找其uid等于用户名的用户。 许多组织更喜欢使用cn而不是uid; 属性的选择是一种品味问题。 您甚至可以想象使用电子邮件属性来唯一标识一个人,只要该属性不能被用户更改。

提示

安全领域

当您登录时,将调用hudson.security.LDAPSecurityRealm类的一个实例。 代码定义在 Groovy 脚本中,您可以在Jenkins.war文件内的WEB-INF/security/LDAPBindSecurityRealm.groovy中找到。

欲了解更多信息,请访问wiki.hudson-ci.org/display/HUDSON/Standard+Security+Setup

有更多内容...

以下是您需要考虑的一些事情。

配置错误与坏凭据之间的区别

首次配置 LDAP 插件时,您的身份验证过程可能由于配置错误而失败。幸运的是,Jenkins 会生成错误消息。 对于 Debian Jenkins 软件包,您可以在/var/log/jenkins/jenkins.log中找到日志文件。 对于作为服务运行的 Windows 版本,您可以通过在 Jenkins 源上过滤来查找相关日志查看器中的事件。

两个主要经常出现的错误如下:

  • 用户搜索基础或组搜索基础的配置错误:相关日志条目将如下所示:

    org.acegisecurity.AuthenticationServiceException: LdapCallback;[LDAP: error code 32 - No Such Object]; nested exception is javax.naming.NameNotFoundException: [LDAP: error code 32 - No Such Object]; remaining name 'ou=people,dc=mycompany ,dc=nodomain'
    
    
  • 凭证错误:如果用户不存在于 LDAP 中,您可能要么输入了错误的密码,要么意外地搜索了 LDAP 树的错误部分。因此,日志错误将以以下文本开头:

    org.acegisecurity.BadCredentialsException: Bad credentials
    
    

搜索

应用程序以多种方式从 LDAP 中检索信息:

  • 匿名获取一般信息:这种方法仅适用于向世界公开的信息。但是,LDAP 服务器也可以将搜索查询限制为特定的 IP 地址。应用程序将取决于您的组织准备披露的属性。如果信息安全政策发生变化,则可能导致应用程序意外中断。

  • 自绑定:应用程序绑定为用户,然后使用该用户的权限进行搜索。这种方法最清晰。但是,在日志记录中并不总是清楚应用程序背后的操作。

  • 使用具有许多权限的特定于应用程序的管理员帐户:该帐户获取您的应用程序所需的所有信息,但如果泄露给错误的人,可能会迅速引起重大问题。

    注意

    如果 LDAP 服务器有账户锁定策略,那么黑客很容易锁定应用程序。

实际上,所选择的方法由企业目录服务的预定义访问控制策略定义。

小贴士

审查插件配置

目前,Jenkins 有超过 600 个插件。虽然偶尔可能会在工作区目录或插件目录中的 XML 配置文件中以纯文本存储密码,但这种情况可能性很小。每次安装需要超级用户账户的新插件时,都应仔细检查相关的配置文件。如果看到纯文本,应编写一个附带补丁的错误报告。

另请参阅

  • 安装 OpenLDAP 配方

  • 管理 OpenLDAP 配方

安装 CAS 服务器

Yale CAS (www.jasig.org/cas) 是一个单点登录服务器。它被设计为校园范围的解决方案,因此易于安装并且相对简单地配置以满足您特定的基础设施需求。CAS 允许您登录一次,然后在不再登录的情况下自动使用许多不同的应用程序。这使得用户在一天中使用的典型 Jenkins 用户的应用程序范围内的互动更加愉快。

Yale CAS 在 Java 和 PHP 中有辅助库,可简化第三方应用程序的集成。

Yale CAS 还具有一个可插拔的处理程序集合的显着优势,该处理程序集合通过一系列后端服务器进行身份验证,例如 LDAP、openid (openid.net/) 和 radius (en.wikipedia.org/wiki/RADIUS)。

在此示例中,您将安装完整版本的 CAS 服务器,从 Tomcat 7 服务器内运行。这个示例比本章中的其他示例更详细,而且很容易配置错误。本示例中提到的修改后的配置文件可从书籍网站下载。

准备工作

从 3.4 系列中下载 Yale CAS (www.apereo.org/cas/download) 并解压缩。本文档是使用版本 3.4.12.1 编写的,但应该可以在 3.4 系列的早期或晚期版本中进行少量修改后运行。

安装 Tomcat 7 (tomcat.apache.org/download-70.cgi)。本文档假定已安装的 Tomcat 服务器最初处于关闭状态。

注意

从 2014 年 6 月起,CAS 4 文档已从 JASIG 网站移至 jasig.github.io/cas/4.0.x/index.html

如何操作...

  1. 在解压缩的 Tomcat 目录中,编辑 conf/server.xml,注释掉端口 8080 的配置信息,如下所示:

    <!--
    <Connector port="8080" protocol="HTTP/1.1"   …..
    -->
    
  2. 在需要启用 SSL 的端口 9443 下面添加以下内容:

    <Connector port="9443"  protocol="org.apache.coyote.http11.Http11Protocol" SSLEnabled="true"
    maxThreads="150" scheme="https" secure="true"
    keystoreFile="${user.home}/.keystore" keystorePass="changeit"
    clientAuth="false" sslProtocol="TLS" />
    
  3. Tomcat 将以哪个用户身份运行,可以通过以下命令创建自签名证书:

    keytool -genkey -alias tomcat -keyalg RSA
    
    

    注意

    如果在你的 PATH 环境变量中找不到 keytool,那么你可能需要填写已安装的 Java 的 bin 目录的完整路径。

  4. 从解压缩的 CAS 服务器根目录下方,复制 modules/cas-server-uber-webapp-3.x.x 文件(其中 x.x 是具体版本号)到 Tomcat Web 应用程序的目录,确保文件重命名为 cas.war

  5. 启动 Tomcat。

  6. 使用用户名等于密码,例如,smile/smile,通过 https://localhost:9443/cas/login 登录。

  7. 停止 Tomcat。

  8. 要么修改 webapps/cas/Web-INF/deployerConfigContext.xml 文件,要么替换为先前从书籍网站下载的示例文件。要进行修改,你需要注释掉 SimpleTestUsernamePasswordAuthenticationHandler 行,如下所示:

    <!--
      <bean class="org.jasig.cas.authentication.handler.support.SimpleTestUsernamePasswordAuthenticationHandler" />
    -->
    
  9. 在注释掉的代码下面,添加 LDAP 的配置信息:

    <bean  class="org.jasig.cas.adaptors.ldap.BindLdapAuthenticationHandler">
    <property name="filter" value="uid=%u" />
    <property name="searchBase" value="ou=people,ou=mycompany,dc=nodomain" />
    <property name="contextSource" ref="contextSource" />
    </bean>
    </list>
    </property>
    </bean>
    
  10. </bean> 后添加额外的 bean 配置,将 password value 替换为你自己的密码:

    <bean id="contextSource" class="org.springframework.ldap.core.support.LdapContextSource">
    <property name="pooled" value="false"/>
    <property name="urls">
    <list>
    <value>ldap://localhost/</value>
    </list>
    </property>
    <property name="userDn" value="cn=admin,dc=nodomain"/>
    <property name="password" value="adminpassword"/>
    <property name="baseEnvironmentProperties">
    <map>
    <entry>
    <key><value>java.naming.security.authentication</value>
    </key>
    <value>simple</value>
    </entry>
    </map>
    </property>
    </bean>
    

    重新启动 Tomcat。

  11. 使用 tester1 帐户通过 https://localhost:9443/cas/login 登录。如果看到类似以下截图的页面,恭喜你;你现在已经运行了 SSO!如何操作...

工作原理...

默认情况下,Tomcat 运行在端口 8080 上,这恰好是 Jenkins 的端口号。要将端口号更改为 9443 并启用 SSL,您必须修改 conf/server.xml。为了让 SSL 正常工作,Tomcat 需要一个带有私有证书的密钥库。使用 ${user.home} 变量指向 Tomcat 用户的主目录,例如,keystoreFile="${user.home}/.keystore" keystorePass="changeit"

您选择的协议是 TLS,这是 SSL 的一个较新且安全的版本。有关更多详细信息,请访问tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html

接下来,生成一个证书并将其放置在 Tomcat 用户的证书存储中,准备供 Tomcat 使用。您的证书存储可能包含许多证书,因此tomcat别名唯一标识证书。

在下载的 CAS 包中,存在两个 CAS WAR 文件。较大的 WAR 文件包含所有认证处理程序的库,包括所需的 LDAP 处理程序。

默认设置允许您使用与用户名相同的密码登录。此设置仅用于演示目的。要替换或串联处理程序,您必须编辑webapps/cas/Web-INF/deployerConfigContext.xml。更多详细信息,请参考wiki.jasig.org/display/CASUM/LDAP

如果在任何时候您遇到配置问题,最好检查的地方是 Tomcat 的主日志,logs/catalina.out。例如,错误的用户名或密码将生成以下错误:

WHO: [username: test]
WHAT: error.authentication.credentials.bad
ACTION: TICKET_GRANTING_TICKET_NOT_CREATED
APPLICATION: CAS
WHEN: Mon Aug 08 21:14:22 CEST 2011
CLIENT IP ADDRESS: 127.0.0.1
SERVER IP ADDRESS: 127.0.0.1

还有更多...

这里有一些您应该考虑的事情。

后端认证

Yale CAS 具有广泛的后端认证处理程序,对于 Java 开发人员来说,撰写自己的处理程序是直截了当的。下表列出了当前的处理程序。请注意,通过使用受支持良好的第三方框架如 JAAS 和 JDBC 实现,您可以连接到比下表中提到的更广泛的服务:

Active Directory 这连接到您的 Windows 基础设施。
JAAS 这实现了标准可插入认证模块PAM)框架的 Java 版本。这允许您引入其他认证机制,如 Kerberos。
LDAP 这连接到您的企业目录服务。
RADIUS 这连接到 RADIUS。
受信任 这用于将一些认证卸载到 Apache 服务器或另一个 CAS 服务器。
通用 一组小型通用处理程序,例如从列表或文件中接受用户的处理程序。
JDBC 这个连接数据库,甚至还有用于电子表格和 LDAP 的驱动程序。
传统 这支持 CAS2 协议。
SPNEGO 简单和受保护的 GSSAPI 协商机制允许 CAS 服务器在后端服务之间协商协议。它潜在地允许在后端服务之间过渡。
X.509 证书 这需要一个可信客户端证书。

使用 ESUP CAS 的另一种安装方法

ESUP 联盟还提供了一个经过重新打包的 CAS 版本,包括额外的易用功能,包括一个即开即用的演示版本。然而,ESUP 版本的 CAS 服务器落后于最新版本。如果您想比较这两个版本,您可以在esup-casgeneric.sourceforge.net/install-esup-cas-quick-start.html找到 ESUP 的安装文档。

注意

ESUP 软件包比此配方更容易安装和配置;但是,它包含的是 CAS 的旧版本。

信任 LDAP SSL

在测试 LDAP 服务器上启用 SSL 可以避免在网络上传送可嗅探的密码,但您需要让 CAS 服务器信任 LDAP 服务器的证书。来自 JASIG WIKI 的相关引用是:

请注意,您的 JVM 需要信任启用 SSL 的 LDAP 服务器的证书,否则 CAS 将拒绝连接到您的 LDAP 服务器。您可以将 LDAP 服务器的证书添加到 JVM 信任存储库 ($JAVA_HOME/jre/lib/security/cacerts) 中来解决此问题。

几个有用的资源

在 JASIG WIKI(wiki.jasig.org/)上有许多有用的 CAS 3.4 系列资源:

另请参阅

  • 在 Jenkins 中启用 SSO 配方

在 Jenkins 中启用 SSO

在这个配方中,您将通过使用 CAS1 插件在 Jenkins 中启用 CAS。为了使 CAS 协议正常工作,您还需要在 Jenkins 和 CAS 服务器之间建立信任关系。Jenkins 插件信任 CAS 服务器的证书。

准备就绪

要尝试此操作,您需要按照 安装 CAS 服务器 配方和 Cas1 插件 (wiki.jenkins-ci.org/display/JENKINS/CAS1+Plugin) 中描述的步骤安装 CAS 服务器。

注意

Cas1 插件在作者尝试过的环境中表现稳定。然而,还有第二个 CAS 插件 (wiki.jenkins-ci.org/display/JENKINS/CAS+Plugin),旨在通过提供新功能与现有功能一起,例如支持 CAS 2.0 协议,来取代 CAS1 插件。

熟悉了这个配方后,考虑尝试使用 CAS 插件。

如何做…

  1. 您需要导出 CAS 服务器的公共证书。通过在 Firefox 网页浏览器中访问 http://localhost:9443 来执行此操作。在地址栏中,您会看到一个锁定的锁图标位于左侧。点击图标;一个安全弹出对话框将出现。

  2. 点击更多信息按钮。

  3. 点击查看证书按钮。

  4. 选择详细信息选项卡。

  5. 点击导出按钮。

  6. 选择公共证书存储的位置。

  7. 按下保存

  8. 按以下方式导入到 Java 的密钥库中:

    sudo keytool -import -alias myprivateroot -keystore ./cacerts -file  location_of_exported certificate
    
    
  9. 要配置您的 CAS 设置,请访问 Jenkins 中的全局安全配置屏幕,位于安全领域部分下。在访问控制下,勾选CAS 协议版本 1复选框,并添加以下详细信息:

    • CAS 服务器 URLhttps://localhost:9443

    • Hudson 主机名localhost:8080

  10. 从 Jenkins 注销。

  11. 登录 Jenkins。您现在将被重定向到 CAS 服务器。

  12. 登录 CAS 服务器。您现在将被重定向回 Jenkins。

工作原理...

CAS 插件无法验证客户端的凭据,除非它信任 CAS 服务器证书。如果证书由知名的受信任机构生成,那么它们的证书很可能已经存在于默认的密钥库(cacerts)中。这是随您的 Java 安装一起预先打包的。然而,在您创建的 CAS 安装配方中,您创建了一个自签名的证书。

CAS 插件的配置细节微不足道。请注意您将角色验证脚本字段留空。这意味着您的基于矩阵的策略将不得不依赖于用户被赋予特定权限,而不是由定制的 CAS 服务器定义的组。

恭喜,您拥有一个可以与许多其他应用程序和身份验证服务无缝配合的工作中的 SSO!

另请参阅

  • 安装 CAS 服务器 配方

探索 OWASP 依赖检查插件

OWASP 依赖检查工具将 Java 程序和 JavaScript 库与 CVE 数据库中已知的威胁进行比较(cve.mitre.org/)。CVE 是约 69,000 个公开已知信息安全漏洞和曝光的词典。这个过程是对 OWASP 十大 A9 - 使用已知的易受攻击组件的自然防御。

CVE 数据库被用作漏洞扫描器报告问题的标准,允许工具用户使用一个通用语言来比较其软件的易受攻击程度。CVE 报告包括描述、问题首次报告位置和估计的危险级别。

注意

依赖检查工具并不总是准确的,因为它需要将库与漏洞联系起来,有时很难准确匹配库签名。因此,您需要根据输出审查和过滤操作。

准备工作

安装 OWASP 依赖检查插件。

如何做...

  1. 点击 管理 Jenkins 页面中的 配置系统 链接。

  2. 查看 OWASP 依赖检查 部分,如以下截图所示:如何操作...

  3. 按下 高级... 按钮,您将得到类似以下截图的内容:如何操作...

  4. 按下 分析器... 按钮,您将得到类似以下截图的内容:如何操作...

  5. 访问 http://localhost:8080/view/All/newJob

  6. 创建一个名为 OWASP 的自由样式作业。

  7. 调用 OWASP 依赖检查分析 添加一个 构建 步骤。

  8. 要扫描的路径 字段中,键入 /var/lib/jenkins/workspace 或您选择的项目的路径。

  9. 确保 生成可选的 HTML 报告 是唯一被选中的复选框。请注意,您未选择 禁用 CPE 自动更新 复选框:如何操作...

  10. 按下 保存

  11. 按下 立即构建 图标。

  12. 作业完成后,请按以下工作区图标:如何操作...

  13. 点击 dependency-check-vulnerabilty.html 链接。根据 Jenkins 工作区内运行的作业,您将看到类似以下截图的报告:如何操作...

工作原理...

安装插件会自动安装 OWASP 依赖检查工具。您可以在工具的主页上找到工具的主页:www.owasp.org/index.php/OWASP_Dependency_Check

工作原理...

通过 Jenkins 界面,您配置了工具查看 Jenkins 主目录下的每个 Java 库 .jar 文件。如果您的 Jenkins 服务器配置了许多作业,扫描将需要一些时间。

禁用 CPE 自动更新 选项未被选中。这是必要的,因为工具首次运行需要从外部 CVE 数据库下载安全信息。如果不允许此操作发生,则报告将不包含任何信息。虽然下载最新的威胁信息需要时间,但这是找到新问题的最安全方法。

更多内容...

在撰写本文时,Jenkins 中的依赖插件选项落后于命令行工具可用的选项。为了让您了解插件中可能的更改,从 www.owasp.org/index.php/OWASP_Dependency_Check 下载命令行工具。

工具下载并解压缩后,按如下方式运行高级帮助:

sh dependency-check.sh –advancedHelp

你的输出将类似于以下截图:

更多内容...

该文本后跟有一组简要的描述,涵盖了所有选项,例如:

-n,--noupdate             Disables the automatic updating of the CPE data.

选项在 Jenkins GUI 配置中反映出来,或将被反映出来。

注意

您可以在 GitHub 上找到该工具的最新代码源(github.com/jeremylong/DependencyCheck)。

另请参阅

  • Chapter 1 中的汇报总体存储使用量配方,维护 Jenkins

  • Chapter 1 中的通过日志解析添加作业以警告存储使用违规配方,维护 Jenkins

第三章 构建软件

本章中,我们将介绍以下内容:

  • 在 Jenkins 中绘制替代代码指标图

  • 通过 Maven 运行 Groovy 脚本

  • 操纵环境变量

  • 通过 Maven 在 Groovy 中运行 Ant

  • 基于 JSP 语法错误使 Jenkins 作业失败

  • 为集成测试配置 Jetty

  • 使用 Rat 查看许可证违规情况

  • 在 Maven 中审查许可证违规

  • 通过构建描述公开信息

  • 通过 groovy-postbuild 插件对生成的数据做出反应

  • 通过 Jenkins API 远程触发作业

  • 自适应站点生成

介绍

本章回顾了 Jenkins 和 Maven 构建之间的关系,还包含了一些使用 Groovy 和 Ant 进行脚本编写的内容。

Jenkins 是灵活性的大师。它在多个平台和技术上表现出色。Jenkins 具有直观的界面和清晰的配置设置。这对完成工作很有帮助。然而,同样重要的是,您清楚地定义 Jenkins 插件与 Maven 构建文件之间的界限。缺乏区分会使您不必要地依赖于 Jenkins。如果您知道您将始终通过 Jenkins 运行构建,则可以放置一些核心工作在 Jenkins 插件中,获得有趣的额外功能。

然而,如果您希望始终能够直接构建、测试和部署,那么您将需要保持pom.xml中的细节。您必须权衡利弊;拥有“功能蔓延”是很容易的。与编写冗长的pom.xml文件相比,UI 更容易配置。提高的可读性会导致较少的与配置相关的缺陷。对于您来说使用 Jenkins 完成大多数常见任务,如传输工件、通信和绘制测试趋势,也更加简单。Jenkins 与 Maven 之间的互动示例是使用 Jenkins Publish Over SSH 插件(wiki.jenkins-ci.org/display/JENKINS/Publish+Over+SSH+Plugin)。您可以配置传输文件或将以下内容添加到pom.xml中:

<build>
<plugins>
  <plugin>
    <artifactId>maven-antrun-plugin</artifactId>
    <configuration>
      <tasks>
        <scp file="${user}:${pass}@${host}:${file.remote}" localTofile="${file.local}"/>
      </tasks>
    </configuration>
    <dependencies>
      <dependency>
        <groupId>ant</groupId>
        <artifactId>ant-jsch</artifactId>
        <version>1.6.5</version>
      </dependency>
      <dependency>
        <groupId>com.jcraft</groupId>
        <artifactId>jsch</artifactId>
        <version>0.1.42</version>
      </dependency>
    </dependencies>
  </plugin>
</plugins>
</build>

记住特定 JAR 和版本的依赖关系,有时使用 Maven 插件会感觉像魔术一样。Jenkins 插件简化了细节。

Maven 使用配置文件,以便您可以在项目中使用不同的配置,例如开发、验收或生产服务器名称。这还允许您更新插件的版本号,从而简化维护工作。有关更多信息,请访问 maven.apache.org/guides/introduction/introduction-to-profiles.html

在本章后面,您将有机会使用 AntBuilder 运行 Groovy 脚本。每种方法都是可行的;使用取决于您的偏好而不是一个明确的选择。

Jenkins 插件可以很好地协同工作。例如,推广构建插件(wiki.jenkins-ci.org/display/JENKINS/Promoted+Builds+Plugin)在构建满足某些条件时发出信号,并在成功构建旁边放置一个图标,如下截图所示:

Introduction

你可以使用此功能来发出信号,例如,通知质量保证团队需要测试构建,或者通知系统管理员收集构件并部署。其他插件也可以通过推广触发(例如,当开发人员使用推广插件签署构建时),包括 SSH 插件。然而,Maven 不知道推广机制。随着 Jenkins 的发展,预计会有更多的插件相互关系。

Jenkins 精通操作的编排。你应该将作业的运行时间最小化,并将较重的作业偏移到节点上。较重的作业往往聚集在文档生成或测试周围。Jenkins 允许你将作业链接在一起,因此作业将与特定的 Maven 目标相结合,例如集成测试(Maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html#Lifecycle_Reference)。在这种情况下,你可以选择编写一些构建文件,也许是一个多模块项目(maven.apache.org/guides/mini/guide-multiple-modules.html),或者是一个更厚的pom.xml文件,其中包含不同的目标,可以在作业之间调用。保持简单傻瓜KISS)倾向于决策朝着一个较大的单一文件。

Jenkins 是一个企业友好的技术中立平台。

Jenkins 是技术中立的,可以将组织、开发团队和软件在生命周期中的位置的项目技术粘合在一起。Jenkins 让你可以运行自己选择的脚本语言,轻松地使用 Git、子版本、CVS 和许多其他版本控制系统拉取源代码。如果 Jenkins 不兼容,开发人员可以通过一点实践编写自己的集成。

在本书中,你将看到涉及到子版本和 GIT 项目。这代表了一个现实的混合。许多人认为 Git 比子版本更加灵活多变。请放心在本书的示例中选择 Git 作为你的存储库。从一开始就设计,Jenkins 使你可以轻松选择不同的版本控制系统。

如果你看一下 2014 年初 Ohoh 的代表性集合中 Git 和子版本的相对使用情况,对于 Git,有 247,103 个存储库(总数的 37%),子版本有 324,895 个存储库(总数的 48%)。

典型企业在使用最现代化的服务时落后于小型组织,因为他们不愿改变工作流程。因此,预计与较小组织相比,这类企业的子版本仓库比例较高。

一个 pom.xml 模板

本章中的配方将包括pom.xml示例。为节省页面空间,只显示必要的细节。您可以从书籍网站下载完整的示例。

这些示例是针对 Maven 3.2.1 进行测试的,尽管这些示例应该与最新版本的 Maven 一起工作。

从主 Jenkins 配置屏幕(http://localhost:8080/configure)下的Maven部分,您将需要安装此版本,并为其提供标签3.2.1

要为 Maven 项目生成基本模板,您有两个选择。您可以通过原型目标(Maven.apache.org/guides/introduction/introduction-to-archetypes.html)创建项目,或者您可以从这里开始一个简单的pom.xml文件:

<project 

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://Maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.berg</groupId>
<artifactId>ch3.builds.xxx</artifactId>
<version>1.0-SNAPSHOT</version>
<name>Template</name>
</project>

模板看起来简单,但只是较大有效pom.xml的一部分。它与 Maven 中隐藏的默认值相结合。要查看扩展版本,您需要运行以下命令:

mvn help:effective-pom

除非另有说明,否则应将配方中提到的片段插入模板中,就在</project>标签之前,根据约定更新您的groupIDartifactIDversion值。有关更多详细信息,请访问maven.apache.org/guides/mini/guide-naming-conventions.html

Maven 变更

Maven 2 已经结束其生命周期(maven.apache.org/maven-2.x-eol.html),开发团队已经停止支持它。您不能指望及时删除新发现的错误。在撰写本书时,Maven 4 正在规划中,尚未发布。

如果您已经安装了作为软件包的 Maven 2,并希望升级到 Maven 3,则需要安装 Maven 软件包。要在不同 Maven 版本之间切换,您需要运行以下 Ubuntu 命令:

sudo update-alternatives --config mvn

设置文件系统 SCM

在前几章中,您使用了将文件复制到工作区的配方。这很容易解释,但受操作系统特定。您还可以通过文件系统 SCM 插件(wiki.jenkins-ci.org/display/JENKINS/File+System+SCM)进行文件复制,因为这是与操作系统无关的。您需要安装该插件,并确保文件具有正确的权限,以便 Jenkins 用户可以复制它们。在 Linux 中,考虑将文件放在 Jenkins 主目录/var/lib/jenkins下。

在 Jenkins 中绘制替代代码度量

本篇介绍了如何使用绘图插件绘制自定义数据(wiki.jenkins-ci.org/display/JENKINS/Plot+Plugin)。这使您可以通过可视化方式展示数值构建数据。

Jenkins 有许多插件可以创建由构建生成的测试结果的视图。分析收集器插件从这些插件中汇总结果以创建聚合摘要和历史记录(wiki.jenkins-ci.org/display/JENKINS/Analysis+Collector+Plugin)。这非常适合绘制标准结果类型的历史记录,如 JUnit、JMeter、FindBugs 和 NCSS。还有一个 SonarQube 插件(docs.codehaus.org/display/SONAR/Jenkins+Plugin)支持将数据推送到 SonarQube(www.sonarsource.org/)。SonarQube 专注于报告项目的代码质量。然而,尽管选项很多,但可能会有一天你需要绘制自定义结果。

假设你想了解在集成测试期间你的自定义缓存中生成了多少次命中或未命中的历史记录。通过构建的绘图可以让你了解代码的变化是改善还是降低了性能。数据是伪造的:一个简单的 Perl 脚本会生成随机结果。

准备工作

在 Jenkins 的插件管理器部分(http://localhost:8080/pluginManager/available),安装绘图插件。创建一个名为ch3.building_software/plotting的目录。

如何操作...

  1. 创建ch3.building_software/plotting/hit_and_miss.pl文件,并添加以下代码行:

    #!/usr/bin/perl
    my $workspace = $ENV{'WORKSPACE'};
    
    open(P1, ">$workspace/hits.properties")|| die;
    open(P2, ">$workspace/misses.properties")|| die;
    print P1 "YVALUE=".rand(100);
    print P2 "YVALUE=".rand(50);
    
  2. 创建一个自由样式的作业,作业名称ch3.plotting

  3. 源代码管理部分,勾选文件系统,并在路径字段中添加你的绘图目录的完全限定路径,例如/var/lib/jenkins/cookbook/ch3.building_software/plotting

  4. 构建部分,为执行 Shell选择添加构建步骤,或者在 Windows 系统中,选择执行 Windows批处理命令。

  5. 对于命令,添加perl hit_and_miss.pl

  6. 后构建操作部分,选中绘制构建数据复选框。

  7. 将以下值添加到新扩展区域:

    • 绘图组缓存数据

    • 绘图标题命中和未命中

    • 绘图 y 轴标签命中或未命中的次数

    • 绘图样式堆积面积

  8. 数据系列文件中输入misses.properties,在数据系列图例标签中输入Misses

  9. 数据系列文件中输入hits.properties,在数据系列图例标签中输入Hits

  10. 在配置页面底部,点击保存按钮,如下图所示:如何操作...

  11. 多次运行该作业。

  12. 查看Plot链接,你会看到类似以下截图:如何操作...

它是如何工作的...

Perl 脚本生成两个属性文件:hitsmisseshits文件包含介于 0 和 100 之间的YVALUE,而misses文件包含介于0和 50 之间的YVALUE。这些数字是随机生成的。然后绘图插件从YVALUE属性中读取值。

两个属性文件被绘图插件读取。该插件跟踪历史记录,它们的值显示在趋势图中。你将不得不尝试不同的图形类型,找到最佳的绘图方法来适应自定义测量。

目前有两种其他数据格式可供使用:XML 和 CSV。然而,在在线帮助清楚解释所使用的结构之前,我建议仍然使用属性格式。

选择 Perl 的原因是其编码简洁和跨平台特性。该脚本也可以用 Groovy 编写,并在 Maven 项目中运行。你可以在通过 Maven 运行 Groovy 脚本方法中看到一个 Groovy 示例。

更多信息...

绘图插件允许选择多种绘图类型,包括区域条形条形 3D线条线条 3D堆叠区域堆叠条形堆叠条形 3D瀑布。如果选择正确的图形类型,可以生成漂亮的图形。

如果想将这些自定义图形添加到报告中,必须保存它们。您可以通过在浏览器中右键单击图像来完成。

你可能希望有不同大小的图形。你可以通过访问http://host/job/JobName/plot/getPlot?index=n&width=x&height=y生成图像。

[Width][height]参数定义了图形的大小。 n是指向特定图表的索引号。如果只有一个图表,那么n=0。如果配置了两个图表,那么n可以是 0 或 1。要发现索引,请访问图表的链接,并检查跳转到下拉菜单,从中选择最高的图表编号之一,如下截图所示:

更多信息...

要根据本方法中的作业生成尺寸为 800 x 600 的 PNG 格式图形,可以使用类似localhost:8080/job/ch3.plotting/plot/getPlot?index=0&width=800&height=600的 URL。

提示

欲下载图像而不登录自己,请使用通过 Jenkins API 远程触发作业方法中提到的可脚本化身份验证方法。

参见

  • 通过 Maven 运行 Groovy 脚本方法

  • 自适应站点生成方法

  • 通过 Jenkins API 远程触发作业方法

通过 Maven 运行 Groovy 脚本

本方法描述如何使用 GMaven 插件(docs.codehaus.org/display/GMAVEN/Home)运行 Groovy 脚本。

在构建中运行 Groovy 脚本的能力可以让您在 Maven 和 Jenkins 中始终使用同一种脚本语言。Groovy 可以在任何 Maven 阶段运行。有关详细信息,请参阅本篇中关于 Maven 阶段部分。

Maven 可以从构建文件内部执行 Groovy 源代码,也可以在另一个文件位置或从远程 Web 服务器执行。

注意

另一种插件是 GMavenPlus。要比较 GMaven 和 GMavenPlus 插件之间的差异,请访问docs.codehaus.org/display/GMAVENPLUS/Choosing+Your+Build+Tool

您可以在groovy.github.io/GMavenPlus/index.html找到有关如何配置插件的说明。

准备工作

创建一个名为ch3.building_software/running_groovy的目录。

提示

脚本的可维护性

为了以后重复使用,请考虑在构建文件之外集中您的 Groovy 代码。

如何做...

  1. 在模板文件(在介绍中提到)的</project>标签之前添加以下代码行。确保pom.xml文件可被 Jenkins 读取:

    <build>
      <plugins>
        <plugin>
          <groupId>org.codehaus.gmaven</groupId>
          <artifactId>gmaven-plugin</artifactId>
          <version>1.3</version>
          <executions><execution>
          <id>run-myGroovy</id>
          <goals><goal>execute</goal></goals>
          <phase>verify</phase>
          <configuration>
            <classpath>
              <element>
                <groupId>commons-lang</groupId>
                <artifactId>commons-lang</artifactId>
                <version>2.6</version>
              </element>
            </classpath>
            <source>
              Import org.apache.commons.lang.SystemUtils
              if(!SystemUtils.IS_OS_UNIX) { fail("Sorry, Not a UNIX box")}
              def command="ls -l".execute()
              println "OS Type ${SystemUtils.OS_NAME}"
              println "Output:\n ${command.text}"
            </source>
          </configuration>
          </execution></executions>
        </plugin>
      </plugins>
    </build>
    
  2. 创建一个自由风格的作业,将作业名称设为ch3.groovy_verify

  3. 源代码管理部分,勾选文件系统并在路径字段中输入您的绘图目录的完整路径,例如/var/lib/jenkins/cookbook/ch3.building_software/running_groovy

  4. 构建部分中,为调用顶级 Maven 目标选择添加构建步骤。在新展开的部分中,添加以下细节:

    • Maven 版本3.2.1

    • 目标verify

  5. 运行作业。如果您的系统是在*NIX 系统上,您将获得以下输出:

    OS Type Linux
    Output:
    total 12
    -rwxrwxrwx 1 jenkins jenkins 1165 2011-09-02 11:03 pom.xml
    drwxrwxrwx 1 jenkins jenkins 3120 2014-09-02 11:03 target
    
    

    在已正确配置 Jenkins 的 Windows 系统上,脚本将失败并显示以下消息:

    Sorry, Not a UNIX box
    
    

它是如何工作的...

您可以在构建过程中多次执行 GMaven 插件。在示例中,verify阶段是触发点。

要使 Groovy 插件能够找到其核心功能之外导入的类,您需要在<classpath>标签中添加一个元素。源代码包含在<source>标签内:

Import org.apache.commons.lang.SystemUtils
if(!SystemUtils.IS_OS_UNIX) { fail("Sorry, Not a UNIX box")}
def command="ls -l".execute()
println "OS Type ${SystemUtils.OS_NAME}"
println "Output:\n ${command.text}"

Import语句起作用是因为依赖项在<classpath>标签中被提及。

SystemUtils类(commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/SystemUtils.html)提供助手方法,例如判断您正在运行哪个操作系统、Java 版本和用户的主目录。

在这种情况下,fail方法允许 Groovy 脚本使构建失败,注意当您不在*NIX 操作系统上运行构建时。大部分时间,您希望您的构建是与操作系统无关的。然而,在集成测试期间,您可能希望使用特定操作系统通过一个特定的 Web 浏览器执行功能测试。如果您的测试发现自己在错误的节点上,检查将停止构建。

提示

一旦您满意您的 Groovy 代码,请考虑将代码编译成底层 Java 字节码。您可以在 docs.codehaus.org/display/GMAVEN/Building+Groovy+Projects 找到完整的说明。

还有更多...

以下是您可能会发现有用的一些提示。

警告跟踪

重要的是要审查您的日志文件,不仅在失败时,还要注意警告。在这种情况下,您会看到两个警告:

  • [WARNING] 使用平台编码(实际上是 UTF-8)进行复制

  • [WARNING] JAR will be empty - no content was marked for inclusion!

平台编码警告说明将使用默认平台编码复制文件。如果更改服务器并且服务器上的默认编码不同,则复制结果也可能不同。为了保持一致性,最好在<build>标签之前添加以下行以强制在文件中使用特定编码:

<properties><project.build.sourceEncoding>UTF8</project.build.sourceEncoding>
</properties>

更新您的模板文件以考虑这一点。

JAR 警告是因为我们只运行了一个脚本,并没有内容来制作一个 JAR。如果您在比 JAR 打包更早的阶段调用了脚本,就不会触发警告。

我的源代码在哪里?

还有两种指向要执行的 Groovy 脚本的方法。第一种方法是指向文件系统,如下所示:

<source>${script.dir}/scripts/do_some_good.Groovy</source>

另一种方法是通过以下方式通过 URL 连接到 Web 服务器:

<source>http://localhost/scripts/test.Groovy</source>

使用 Web 服务器存储 Groovy 脚本会为基础架构增加额外的依赖性。但是,它也非常适合在具有 Web 访问权限的 SCM 中集中代码。

Maven 阶段

Jenkins 将工作组合在作业中。它对于具有预先和后续构建支持的粗粒度构建是有效的。相比之下,Maven 更加精细,具有 21 个阶段作为触发点。有关更多信息,请访问 Maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html

目标绑定阶段。例如,有四个阶段 pre-sitesitepost-sitesite-deploy 用于站点目标,所有这些阶段都将按顺序由 mvn site 调用,或者直接使用 mvn site:phase 语法调用。

思想是将一系列轻量级作业串在一起。您应该将任何重型作业(例如集成测试或大量 JavaDoc 生成)分配给从节点。您还应该按时间分离以均匀负载并帮助诊断问题。

您可以在 git-wip-us.apache.org/repos/asf?p=maven.git;a=blob;f=maven-core/src/main/resources/META-INF/plexus/components.xml 找到 XML 配置生命周期代码的方式。

您会在 components.xml 中的以下行下找到 Maven 阶段的提及:

<!-- START SNIPPET: lifecycle -->

Maven 插件绑定到特定阶段。对于站点生成,<reporting> 标签围绕大部分配置。在报告下配置的插件生成有用信息,其结果保存在 target/site 目录下。有一些插件会获取生成的结果,然后绘制它们的历史。一般来说,Jenkins 插件不执行测试;它们消耗结果。有一些例外,比如 Sloccount 插件 (wiki.jenkins-ci.org/display/JENKINS/SLOCCount+Plugin) 和任务扫描器插件 (wiki.jenkins-ci.org/display/JENKINS/Task+Scanner+Plugin)。这些差异将在稍后的 第五章 使用度量改进质量 中探讨。

注意

要安装 sloccount 插件,您首先需要安装静态分析实用程序插件。

Groovy 插件在所有阶段都非常有用,因为它不专门针对任何特定任务,比如打包或部署。它为您提供了一种统一的方法来应对超出 Maven 通用功能范围之外的情况。

小贴士

Maven 版本之间的差异

要升级到 Maven 3 项目之间的 Maven 2 和 Maven 3,您需要了解差异和不兼容性。有一些差异,特别是围绕站点生成。它们在 cwiki.apache.org/confluence/display/MAVEN/Maven+3.x+Compatibility+Notes 中总结。

您可以在 cwiki.apache.org/confluence/display/MAVEN/Maven+3.x+Plugin+Compatibility+Matrix 找到插件兼容性列表。

另请参阅

  • 在 Maven 中通过 Groovy 运行 Ant 的配方

  • 使用 groovy-postbuild 插件 响应生成的数据的差异 配方

  • 自适应站点生成 配方

操作环境变量

本配方向您展示如何将变量从 Jenkins 传递到您的构建作业,并说明不同变量是如何被覆盖的。它还描述了一种在关键信息未正确传递时使构建失败的方法。

在典型的开发/验收/生产环境中,您可能希望保留相同的 pom.xml 文件,但传递不同的配置。一个示例是属性文件的扩展名,例如 .dev.acc.prd。如果由于人为错误导致关键配置值丢失,您将希望使构建失败。

Jenkins 有许多插件可用于将信息传递给构建,包括 EnvFile 插件 (wiki.jenkins-ci.org/display/JENKINS/Envfile+Plugin) 和 EnvInject 插件 (wiki.jenkins-ci.org/display/JENKINS/EnvInject+Plugin)。由于 EnvInject 插件据说可以与节点一起工作并提供广泛的属性注入选项,因此选择了 EnvInject 插件用于此配方。

准备工作

安装 EnvInject 插件 (wiki.jenkins-ci.org/display/JENKINS/EnvInject+Plugin)。创建名为ch3.building_software/environment的配方目录。

如何操作...

  1. 创建一个可由 Jenkins 读取的pom.xml文件,并添加以下代码行:

    <project 
    
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.berg</groupId>
    <artifactId>ch3.jenkins.builds.properties</artifactId>
    <version>1.0-SNAPSHOT</version>
    <name>${name.from.jenkins}</name>
    <properties><project.build.sourceEncoding>UTF8</project.build.sourceEncoding>
    </properties>
    <build>
    <plugins><plugin>
    <groupId>org.codehaus.gmaven</groupId>
    <artifactId>gmaven-plugin</artifactId>
    <version>1.3</version>
    <executions><execution>
    <id>run-myGroovy</id>
    <goals><goal>execute</goal></goals>
    <phase>verify</phase>
    <configuration>
    <source>
    def environment = System.getenv()
    println "----Environment"
    environment.each{println it } 
    println "----Property"
    println(System.getProperty("longname"))
    println "----Project and session"
    println "Project: ${project.class}"
    println "Session: ${session.class}"
    println "longname: ${project.properties.longname}"
    println "Project name: ${project.name}"
    println "JENKINS_HOME: ${project.properties.JENKINS_HOME}"
    </source>
    </configuration>
    </execution></executions>
    </plugin></plugins>
    </build>
    </project>
    
  2. 在与pom.xml文件相同的目录中创建一个名为my.properties的文件。然后,在my.properties文件中添加以下代码行:

    project.type=prod
    secrets.file=/etc/secrets
    enable.email=true
    JOB_URL=I AM REALLY NOT WHAT I SEEM
    
  3. 创建一个空白的自由风格作业,作业名称ch3.environment

  4. 源码管理部分,勾选文件系统并在路径字段中添加您目录的完全合格路径,例如/var/lib/jenkins/cookbook/ch3.building_software/environment

  5. 构建部分,为调用顶级 Maven 目标选择添加一个构建步骤。在新展开的部分中,添加以下细节:

    • Maven 版本: 3.2.1

    • 目标: verify

  6. 点击高级按钮,在属性中键入longname=超级好

  7. 通过选中作业配置页面顶部附近的为作业准备环境复选框来注入my.properties中的值。

  8. 对于属性文件路径,添加/full_path/my.properties;例如/home/var/lib/cookbook/ch3.building_software/environment/my.properties

    前面的选项如下图所示:

    如何操作...

  9. 运行作业。构建将失败:

    ----Project and session
    Project: class org.apache.Maven.model.Model
    Session: class org.apache.Maven.execution.MavenSession
    longname: SuperGood
    [INFO] -------------------------------------------------------
    [ERROR] BUILD ERROR
    [INFO] -------------------------------------------------------
    [INFO] Groovy.lang.MissingPropertyException: No such property: name for class: script1315151939046
    
    
  10. 构建部分,对于调用顶级 Maven 目标,点击高级按钮。在新展开的部分中,添加一个额外的属性 name.from.jenkins=带名称的构建

  11. 运行作业。现在应该成功了。

工作原理...

EnvInject 插件对于将属性注入到构建中非常有用。

在这个配方中,Maven 被运行了两次。第一次,它在没有定义name.from.jenkins变量的情况下运行,Jenkins 作业失败了。第二次,它在定义了该变量的情况下运行,Jenkins 作业现在成功了。

Maven 期望定义了name.from.jenkins变量,否则项目的名称也将不会被定义。通常,这还不足以阻止您的作业成功。但是,当运行 Groovy 代码时,特别是println "Project name: ${project.name}"行中的project.name调用将导致构建失败。这对于防止缺少属性值非常有用。

Groovy 代码可以看到org.apache.Maven.model.Model项目的实例和org.apache.Maven.execution.MavenSession类的实例。项目实例是您可以以编程方式访问的 XML 配置的模型。您可以通过project.properties.longname引用来获取longname属性。如果属性不存在,您的 Maven 目标将失败。您还可以通过System.getProperty("longname")调用获取属性。但是,您无法通过使用System.getenv()环境调用获取属性。

值得学习各种选项:

  • 保留 Jenkins 环境变量保留 Jenkins 构建变量:这两个选项影响您的作业看到的与 Jenkins 相关的变量。保持您的环境尽可能干净是很好的,因为这将有助于您以后进行调试。

  • 属性内容:您可以覆盖属性文件中的特定值。

  • 环境脚本文件路径:此选项指向一个脚本,该脚本将设置您的环境。如果您想要检测运行环境的特定细节并相应地配置构建,这将非常有用。

  • 填充构建原因:您可以使 Jenkins 设置BUILD_CAUSE环境变量。该变量包含有关触发作业的事件的信息。

还有更多...

Maven 有一个用于读取属性的插件(mojo.codehaus.org/properties-maven-plugin/)。要在属性文件之间进行选择,您需要在插件配置中设置一个变量,并在 Jenkins 作业中调用它,如下所示:

<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>properties-maven-plugin</artifactId>
<version>1.0-alpha-2</version>
<executions>
<execution>
<phase>initialize</phase>
<goals>
<goal>read-project-properties</goal>
</goals>
<configuration>
<files>
<file>${fullpath.to.properties}</file>
</files>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>

如果您使用相对路径到属性文件,则该文件可以驻留在您的源代码中。如果您使用全路径,则属性文件可以存储在 Jenkins 服务器上。如果包含敏感密码(例如数据库连接密码),则第二个选项更可取。

Jenkins 有能力在您手动运行作业时请求变量。这称为参数化构建(wiki.jenkins-ci.org/display/JENKINS/Parameterized+Build)。在构建时,您可以通过从属性文件位置的选择中进行选择来选择您的属性文件。

另请参见

  • 在 Maven 中通过 Groovy 运行 Ant 的步骤

在 Maven 中通过 Groovy 运行 Ant

Jenkins 与技术背景广泛的观众进行交互。有许多开发人员在转向使用 Maven 之前已经熟练掌握了 Ant 脚本编写,这些开发人员可能更喜欢编写 Ant 任务而不是编辑pom.xml文件。在大部分组织中,仍然运行着关键任务的 Ant 脚本。

在 Maven 中,您可以直接使用 AntRun 插件(maven.apache.org/plugins/maven-antrun-plugin/)或通过 Groovy(docs.codehaus.org/display/GROOVY/Using+Ant+from+Groovy)运行 Ant 任务。AntRun 代表了一条自然的迁移路径。这是最初工作量最小的路径。

对于将 Groovy 作为任务的一部分使用的 Jenkins 管理员来说,Groovy 方法是有意义的。Groovy 作为一种一流的编程语言,拥有一系列难以在 Ant 中复制的控制结构。您可以部分地通过使用Ant-contrib库(ant-contrib.sourceforge.net)来实现这一点。然而,作为一个功能丰富的编程语言,Groovy 更加表达力强。

本教程详细介绍了如何运行涉及 Groovy 和 Ant 的两个 Maven POM。第一个 POM 向您展示了如何在 Groovy 中运行最简单的 Ant 任务,而第二个则执行一个 Ant-contrib 任务,以安全地从大量计算机复制文件。

准备工作

创建一个名为ch3.building_software/antbuilder的目录。

如何做...

  1. 创建一个模板文件并命名为pom_ant_simple.xml

  2. 更改groupIdartifactIdversionname的值以适应您的偏好。

  3. </project>标签之前添加以下 XML 片段:

    <build>
    <plugins><plugin>
    <groupId>org.codehaus.gmaven</groupId>
    <artifactId>gmaven-plugin</artifactId>
    <version>1.3</version>
    <executions>
    <execution>
    <id>run-myGroovy-test</id>
    <goals><goal>execute</goal></goals>
    <phase>test</phase>
    <configuration>
    <source>
    def ant = new AntBuilder()
    ant.echo("\n\nTested ----> With Groovy")
    </source>
    </configuration>
    </execution>
    <execution>
    <id>run-myGroovy-verify</id>
    <goals><goal>execute</goal></goals>
    <phase>verify</phase>
    <configuration>
    <source>
    def ant = new AntBuilder()
    ant.echo("\n\nVerified at ${new Date()}")
    </source>
    </configuration>
    </execution>
    </executions>
    </plugin></plugins>
    </build>
    
  4. 运行mvn test –f pom_ant_simple.xml。查看输出(请注意,没有关于空 JAR 文件的警告):操作步骤...

  5. 运行mvn verify –f pom_ant_simple.xml。查看输出;它应该类似于以下屏幕截图:操作步骤...

  6. 创建第二个模板文件并命名为pom_ant_contrib.xml

  7. 更改groupIdartifactIdversionname的值以适应您的偏好。

  8. </project>标签之前添加以下 XML 片段:

    <build>
    <plugins><plugin>
    <groupId>org.codehaus.gmaven</groupId>
    <artifactId>gmaven-plugin</artifactId>
    <version>1.3</version>
    <executions><execution>
    <id>run-myGroovy</id>
    <goals><goal>execute</goal></goals>
    <phase>verify</phase>
    <configuration>
    <source>
    def ant = new AntBuilder()
    host="Myhost_series"
    print "user: "
    user = new String(System.console().readPassword())
    print "password: "
    pw = new String(System.console().readPassword())
    
    for ( i in 1..920) {
    counterStr=String.format('%02d',i)
    ant.scp(trust:'true',file:"${user}:${pw}${host}${counterStr}:/${full_path_to_location}",
    localTofile:"${myfile}-${counterStr}", verbose:"true")   
    }
    </source>
    </configuration>
    </execution></executions>
    <dependencies>
    <dependency>
    <groupId>ant</groupId>
    <artifactId>ant</artifactId>
    <version>1.6.5</version>
    </dependency>
    <dependency>
    <groupId>ant</groupId>
    <artifactId>ant-launcher</artifactId>
    <version>1.6.5</version>
    </dependency>
    <dependency>
    <groupId>ant</groupId>
    <artifactId>ant-jsch</artifactId>
    <version>1.6.5</version>
    </dependency>
    <dependency>
    <groupId>com.jcraft</groupId>
    <artifactId>jsch</artifactId>
    <version>0.1.42</version>
    </dependency>
    </dependencies>
    </plugin></plugins>
    </build>
    

这只是代表性代码,除非您已经设置它指向真实服务器上的真实文件:

mvn verify –f pom_ant_simple.xml will fail

它的工作原理...

Groovy 运行基本的 Ant 任务而无需额外的依赖关系。创建一个AntBuilder实例(groovy.codehaus.org/Using+Ant+Libraries+with+AntBuilder),然后调用 Ant echo 任务。在底层,Groovy 调用 Ant 用于执行echo命令的 Java 类。在echo命令中,通过直接创建一个匿名对象打印日期:

ant.echo("\n\nVerified at ${new Date()}").

您配置了pom.xml文件以在两个阶段触发 Groovy 脚本:test阶段,然后稍后在verify阶段。test阶段发生在生成 JAR 文件之前,因此避免了创建有关空 JAR 文件的警告。顾名思义,此阶段用于打包前的测试。

第二个示例脚本突显了将 Groovy 与 Ant 结合使用的优势。SCP 任务 (ant.apache.org/manual/Tasks/scp.html) 在许多服务器上多次运行。脚本首先要求输入用户名和密码,避免存储在您的文件系统或版本控制系统中。Groovy 脚本期望您注入 hostfull_path_to_locationmyfile 变量。

注意 Ant SCP 任务与 pom_ant_contrib.xml 文件中表达方式的相似之处。

还有更多...

通过 Groovy 运行 Ant 的另一个示例是动态创建自定义属性文件。这允许您将信息从一个 Jenkins 作业传递到另一个作业。

您可以通过 AntBuilder 使用 echo 任务创建属性文件。以下代码行创建一个包含两行 x=1y=2value.properties 文件:

def ant = new AntBuilder()
ant.echo(message: "x=1\n", append: "false", file: "values.properties")
ant.echo(message: "y=2\n", append: "true", file: "values.properties")

第一个 echo 命令将 append 设置为 false,这样每次构建发生时,都会创建一个新的属性文件。第二个 echo 附加其消息。

注意

你可以移除第二个 append 属性,因为默认值已设置为 true

另请参阅

  • 通过 Maven 运行 Groovy 脚本 配方

基于 JSP 语法错误导致 Jenkins 作业失败

JavaServer Pages (JSP) (www.oracle.com/technetwork/java/overview-138580.html) 是一种使创建简单 Web 应用程序变得简单的标准。您可以将 HTML 编写到文本文件中,例如带有额外标签的页面与 Java 代码交错。如果您在运行的 Web 应用程序中执行此操作,则代码将在下一页调用时重新编译。此过程支持敏捷编程实践,但风险在于开发人员编写混乱、难以阅读的 JSP 代码,难以维护。如果 Jenkins 能够显示有关代码质量的指标,那将很好。

用户首次请求页面时,JSP 页面会即时编译。用户会将此视为页面加载缓慢,并可能阻止他们未来的访问。为了避免这种情况,您可以在构建过程中编译 JSP 页面,并将编译后的代码放置在您 Web 应用程序的 WEB-INF/classes 目录中或打包到 WEB-INF/lib 目录中。这种方法具有更快的第一页加载速度的优势。

拥有已编译源代码的次要优势是您可以在代码库上运行许多统计代码审查工具,并获取可测试性指标。这将生成供 Jenkins 插件显示的测试数据。

本文介绍了如何基于 maven-jetty-jspc-plugin (www.eclipse.org/jetty/documentation/current/jetty-jspc-maven-plugin.html) 编译 JSP 页面的配方。编译后的代码将与 Jetty 服务器一起使用,Jetty 服务器通常用于集成测试。

注意

本教程中提到的 JSP 故意不安全,因此稍后在本书中进行测试。

用于 Tomcat 部署的补充插件是 Tomcat Maven 插件 (tomcat.apache.org/maven-plugin.html)。

准备工作

创建一个名为 ch3.building_software/jsp_example 的目录。

如何操作...

  1. 通过输入以下命令从 Maven 原型创建一个 WAR 项目:

    mvn archetype:generate -DarchetypeArtifactId=maven-archetype-webapp
    
    
  2. 输入以下值:

    • groupId: ch3.packt.builds

    • artifactId: jsp_example

    • version: 1.0-SNAPSHOT

    • package: ch3.packt.builds

  3. 单击 输入以确认值

  4. 通过添加以下构建部分编辑 jsp_example/pom.xml 文件:

    <build>
    <finalName>jsp_example</finalName>
    <plugins>
    <plugin>
    <groupId>org.mortbay.jetty</groupId>
    <artifactId>maven-jetty-jspc-plugin</artifactId>
    <version>6.1.14</version>
    <executions>
    <execution>
    <id>jspc</id>
    <goals>
    <goal>jspc</goal>
    </goals>
    <configuration>
    </configuration>
    </execution>
    </executions>
    </plugin>
    <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-war-plugin</artifactId>
    <version>2.4</version>
    <configuration>
    <webXml>${basedir}/target/web.xml</webXml>
    </configuration>
    </plugin>
    </plugins>
    </build>
    
  5. src/main/webapp/index.jsp 文件中的代码段替换为以下代码行:

    <html>
      <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Hello World Example</title>
      </head>
      <body>
        <% String evilInput= null;
          evilInput = request.getParameter("someUnfilteredInput");
          if (evilInput==null){evilInput="Hello Kind Person";}
        %>
        <form action="index.jsp">
          The big head says: <%=evilInput%><p>
          Please add input:<input type='text' name='someUnfilteredInput'>
          <input type="submit">
        </form>
      </body>
    </html>
    
  6. 使用 mvn package 命令创建 WAR 文件。

  7. 修改 ./src/main/webapp/index.jsp,在以 if 开头的行下面添加 if (evilInput==null),以使其不再是有效的 JSP 文件。

  8. 运行 mvn package 命令。现在,构建将因以下错误消息而失败:

    [ERROR] Failed to execute goal org.mortbay.jetty:maven-jetty-jspc-plugin:6.1.14:jspc (jspc) on project jsp_example: Failure processing jsps -> [Help 1]
    
    

工作原理...

您使用原型创建了一个模板项目。

Maven 插件在看到 index.jsp 页面时,会将其编译为名为 jsp.index_jsp 的类,并将编译后的类放置在 WEB-INF/classes 下。然后,该插件在 WEB-INF/web.xml 中将该类定义为一个 servlet,并将其映射到 /index.jsp。让我们看一下以下示例:

<servlet>
  <servlet-name>jsp.index_jsp</servlet-name>
  <servlet-class>jsp.index_jsp</servlet-class>
</servlet>

<servlet-mapping>
  <servlet-name>jsp.index_jsp</servlet-name>
  <url-pattern>/index.jsp</url-pattern>
</servlet-mapping>

提示

原型列表会随着时间的推移而增加。您可以在 maven-repository.com/archetypes 找到完整的列表。如果您正在使用 Ubuntu,则会在 ~/.m2 目录中找到名为 archetype-catalog.xml 的本地 XML 目录,其中列出了所有的原型。

还有更多...

以下是您应考虑的一些事项。

不同的服务器类型

默认情况下,Jetty Maven 插件(版本 6.1.14)使用 JDK 15 加载 JSP 2.1 库。这对于所有服务器类型都不起作用。例如,如果将此教程生成的 WAR 文件部署到 Tomcat 7 服务器上,则将无法正确部署。如果查看 logs/catalina.out,您将看到以下错误:

javax.servlet.ServletException: Error instantiating servlet class jsp.index_jsp
Root Cause
java.lang.NoClassDefFoundError: Lorg/apache/jasper/runtime/ResourceInjector;

这是因为不同的服务器对 JSP 代码的编译方式以及运行所依赖的库有不同的假设。对于 Tomcat,您需要调整所使用的编译器以及 Maven 插件的依赖关系。有关更多详细信息,请访问 wiki.eclipse.org/Jetty/Feature/Jetty_Maven_Plugin

Eclipse JSP 页面模板

Eclipse 是 Java 开发人员的流行开源 IDE (www.eclipse.org/)。如果您正在使用 Eclipse 的默认 JSP 页面模板,则您的页面可能无法编译。这是因为在撰写本文时,默认编译器不喜欢在 <html> 标签之前提及的元信息,如下所示:

<%@ page language="java" contentType="text/html;charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

由于元信息遵循 JSP 规范,所以很可能以后 JSP 编译器会接受这些信息。在那一天之前,只需在编译之前删除这些行或更改你使用的 JSP 编译器。

另请参阅

  • 配置 Jetty 进行集成测试配方

配置 Jetty 进行集成测试

通常保留测试历史记录的 Jenkins 插件是 Maven 构建中生成的数据的使用者。要让 Maven 自动运行集成、性能或功能测试,它需要访问一个活动的测试服务器。你有两个主要选择:

  • 部署你的艺术品,比如 WAR 文件到一个活动的服务器:这可以通过 Maven Wagon 插件(mojo.codehaus.org/wagon-maven-plugin/)或通过一个 Jenkins 插件来完成,比如名为 Deploy 的插件(wiki.jenkins-ci.org/display/JENKINS/Deploy+Plugin)。

  • 在构建中运行轻量级 Jetty 服务器:这简化了你的基础设施。但是,服务器将作为 Jenkins 作业的一部分运行,消耗潜在的稀缺资源。这将限制 Jenkins 可以运行的并行执行器数量,降低作业的最大吞吐量。这应该委托给专门为此目的设置的专用从节点。

这个配方运行了在基于 JSP 语法错误的失败 Jenkins 作业配方中开发的 Web 应用程序,通过在运行测试之前启动服务器并在测试之后关闭来将 Jetty 与集成测试联系起来。该构建创建了一个自签名证书。为 HTTP 和安全的 TLS 流量定义了两个 Jetty 连接器。为了创建一个到 Telnet 的端口,还定义了shutdown命令。

准备工作

按照基于 JSP 语法错误的失败 Jenkins 作业配方生成一个 WAR 文件。将项目复制到名为ch3.building_software/jsp_jetty的目录中。

如何做...

  1. pom.xml文件的</plugins>标签之前添加以下 XML 片段:

    <plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>keytool-maven-plugin</artifactId>
    <version>1.5</version>
    <executions>
    <execution>
    <phase>generate-resources</phase>
    <id>clean</id>
    <goals>
    <goal>clean</goal>
    </goals>
    </execution>
    <execution>
    <phase>generate-resources</phase>
    <id>generateKeyPair</id>
    <goals>
    <goal>generateKeyPair</goal>
    </goals>
    </execution>
    </executions>
    <configuration>
    <keystore>${project.build.directory}/jetty-ssl.keystore</keystore>
    <dname>cn=HOSTNAME</dname>
    <keypass>jetty8</keypass>
    <storepass>jetty8</storepass>
    <alias>jetty8</alias>
    <keyalg>RSA</keyalg>
    </configuration>
    </plugin>
    <plugin>
    <groupId>org.mortbay.jetty</groupId>
    <artifactId>jetty-maven-plugin</artifactId>
    <version>8.1.16.v20140903</version>
    <configuration>
    <war>${basedir}/target/jsp_example.war</war>
    <stopPort>8083</stopPort>
    <stopKey>stopmeplease</stopKey>
    <connectors>
    <connector implementation="org.eclipse.jetty.server.nio.SelectChannelConnector">
    <port>8082</port>
    </connector>
    <connector implementation="org.eclipse.jetty.server.ssl.SslSocketConnector">
    <port>9443</port>
    <keystore>
    ${project.build.directory}/jetty-ssl.keystore</keystore>
    <password>jetty8</password>
    <keyPassword>jetty8</keyPassword>
    </connector>
    </connectors>
    </configuration>
    <executions>
    <execution>
    <id>start-jetty</id>
    <phase>pre-integration-test</phase>
    <goals>
    <goal>run</goal>
    </goals>
    <configuration>
    <daemon>true</daemon>
    </configuration>
    </execution>
    <execution>
    <id>stop-jetty</id>
    <phase>post-integration-test</phase>
    <goals>
    <goal>stop</goal>
    </goals>
    </execution>
    </executions>
    </plugin>
    
  2. 运行mvn jetty:run命令。现在你会看到 Jetty 服务器启动时的控制台输出。

  3. 使用 Web 浏览器,访问https://localhost:9443位置。在通过有关自签名证书的警告后,你将看到 Web 应用程序正常工作。

  4. 按下Ctrl + C停止服务器。

  5. 运行mvn verify。现在你会看到服务器启动然后停止。

工作原理...

<executions> 标签内,Jetty 在 Maven 的 pre-integration-test 阶段运行,并且在 Maven 的 post-integration-test 阶段停止。在 generate-resources 阶段,Maven 使用 keytool 插件创建自签名证书。证书存储在具有已知密码和别名的 Java keystore 中。密钥加密设置为 RSA。如果您的证书中未正确设置 Common Name (CN),则您的网络浏览器将会报错。要将证书的 Distinguished Name (DN) 更改为您主机的名称,请修改 <dname>cn=HOSTNAME</dname>

Jetty 配置有两种连接器类型:端口 8082 用于 HTTP,端口 9443 用于安全连接。选择这些端口是因为它们在端口 1023 以上,因此您无需管理员权限即可运行构建。端口号还避免了 Jenkins 使用的端口。jettyKeytool 插件都使用 keystore 标签来定义密钥库的位置。

生成的 WAR 文件由 webapp 标签指向,并且 Jetty 运行应用程序。

注意

对于功能测试人员来说,使用自签名证书会增加额外的工作量。每当他们遇到证书的新版本时,他们都需要在其网络浏览器中将证书接受为安全异常。最好使用来自知名权威机构的证书。通过删除密钥生成并将 keystore 标签指向已知文件位置,您可以通过此方法实现这一点。

还有更多...

Maven 3 对于定义插件版本比 Maven 2.2.1 更挑剔。这是有充分理由的。如果你知道你的构建能够很好地与特定版本的 Maven 配合工作,那么这可以防止不必要的变化。例如,在撰写本书时,此示例中使用的 Jetty 插件被保持在版本 8.1.16.v20140903。正如你可以从这里的错误报告中看到的,配置细节随着版本的变化而变化。

另一个优点是,如果插件版本过旧,则插件将被从中央插件仓库中移除。当您下次清理本地仓库时,这将破坏您的构建。这正是您想要的,因为这清晰地表明了需要进行审查然后升级。

另请参阅

  • 基于 JSP 语法错误的 Jenkins 作业失败 方法

  • 自适应站点生成 方法

使用 Rat 查看许可证违规行为

此方法描述了如何在 Jenkins 中搜索任何作业的许可证违规情况。它基于 Apache Rat 项目 (creadur.apache.org/rat/)。您可以通过直接运行贡献的 Ant 任务或通过 Maven 来运行 Rat JAR 文件以搜索许可证违规情况。在此方法中,您将通过 JAR 文件直接运行。报告输出会发送到控制台,准备供 Jenkins 插件(如日志解析插件)处理信息。

准备工作

在 Jenkins 主目录 (/var/lib/jenkins) 下创建 License_Check 目录。登录 Jenkins。

怎么做...

  1. 创建一个名为 License_Check 的 Maven 作业。

  2. 源代码管理部分,勾选Subversion

  3. Modules, Repository URL中填入 http://svn.apache.org/repos/asf/creadur/rat/trunk/

  4. Check-out Strategy设置为尽可能使用 'svn update'

  5. Build部分,添加 clean packageGoals and options

  6. Post steps部分,勾选仅在构建成功时运行

  7. 添加Post-build step来执行Shell(假设你正在运行一个 NIX 系统)。如果需要,将以下文本添加到执行 Shell文本区域中,替换 JAR 版本号:

    java -jar ./apache-rat/target/apache-rat-0.12-SNAPSHOT.jar --help
    java -jar ./apache-rat/target/apache-rat-0.12-SNAPSHOT.jar -d ${JENKINS_HOME}/workspace/License_Check/  -e '*.js'  -e '*target*'
    
    
  8. 点击保存按钮并运行作业。

  9. 查看作业工作区的路径。访问配置 Jenkins界面,例如 http://localhost:8080/configure。在Home Directory下方,点击高级按钮。如下截图所示,Workspace Root Directory 的值变得可见:怎么做...

它是如何工作的...

Rat 源代码被编译然后运行两次——第一次打印出帮助信息,第二次检查许可证头部。

代码库正在改变;随着时间的推移,预计选项的数量会增加。通过运行 help,你将找到最新的信息。

–d 选项告诉应用程序你的源代码在哪个目录中。在这个示例中,你使用了 ${JENKINS_HOME} 变量来定义路径的顶层。接下来,我们假设作业位于 ./job/jobname/workspace 目录下。你在第 9 步骤中检查了这个假设是否正确。如果不正确,你需要调整选项。要为另一个项目生成报告,只需通过替换作业名称更改路径。

–e 选项排除了某些文件名模式的审核。你已经排除了 JavaScript 文件 '*.js''*target*',适用于目标目录下的所有生成文件。在一个复杂的项目中,预计会有很长的排除列表。

注意

即使要检查的目录不存在,构建仍将成功,并报告错误如下:

ERROR: /var/lib/jenkins/jobs/License_Check/workspace
Finished: Success

你将需要使用一个日志解析插件来强制失败

更多内容...

用于更新源代码许可证的一款 Maven 插件是 maven-license 插件 (code.mycila.com/license-maven-plugin/)。你可以使用它来保持源代码许可头部的更新。要添加/更新源代码的 src/etc/header.txt 许可证,请将以下 XML 片段添加到你的构建部分:

<plugin>
<groupId>com.mycila.maven-license-plugin</groupId>
<artifactId>maven-license-plugin</artifactId>
<version>2.6</version>
<configuration>
<header>src/etc/header.txt</header>
</configuration>
</plugin>

然后你需要添加你自己的 src/etc/header.txt 许可证文件。

一个强大的功能是你可以添加变量来扩展。在下面的示例中,${year} 将会被扩展为如下内容:

Copyright (C) ${year} Licensed under this open source License

要格式化你的源代码,你需要运行以下命令:

mvn license:format -Dyear=2012

另请参阅

  • 在 Maven 中审查许可证违规行为食谱

  • 使用 groovy-postbuild 插件对生成的数据进行反应食谱

在 Maven 中审查许可证违规行为

在本示例中,您将通过 Maven 运行 Rat。然后它将检查源代码中的许可证违规行为。

准备就绪

创建名为ch3.building_software/license_maven的目录。

如何操作...

  1. 创建一个模板pom.xml文件。

  2. 更改groupIdartifactIdversionname的值以适应您的偏好。

  3. </project>标记之前添加以下 XML 片段:

    <pluginRepositories>
    <pluginRepository>
    <id>apache.snapshots</id>
    <url>http://repository.apache.org/snapshots/</url>
    </pluginRepository>
    </pluginRepositories>
    <build>
    <plugins><plugin>
    <groupId>org.apache.rat</groupId>
    <artifactId>apache-rat-plugin</artifactId>
    <version>0.11-SNAPSHOT</version>
    <executions><execution>
    <phase>verify</phase>
    <goals><goal>check</goal></goals>
    </execution></executions><configuration>
    <excludeSubProjects>false</excludeSubProjects><numUnapprovedLicenses>597</numUnapprovedLicenses>
    <excludes>
    <exclude>**/.*/**</exclude>
    <exclude>**/target/**/*</exclude>
    </excludes>
    <includes>
    <include>**/src/**/*.css</include>
    <include>**/src/**/*.html</include>
    <include>**/src/**/*.java</include>
    <include>**/src/**/*.js</include>
    <include>**/src/**/*.jsp</include>
    <include>**/src/**/*.properties</include>
    <include>**/src/**/*.sh</include>
    <include>**/src/**/*.txt</include>
    <include>**/src/**/*.vm</include>
    <include>**/src/**/*.xml</include>
    </includes>
    </configuration>
    </plugin></plugins></build>
    
  4. 使用项目名称ch3.BasicLTI_license创建一个 Maven 项目。

  5. 源代码管理部分,选中SubversionURL 仓库https://source.sakaiproject.org/svn/basiclti/trunk

    注意

    不要向 SVN 仓库发送垃圾邮件。确保没有激活任何构建触发器。

  6. 构建部分设置,添加以下详细信息:

    • Root POMpom.xml

    • 目标和选项clean

  7. 预处理步骤部分,调用注入环境变量并将以下内容添加到属性的上下文中:

    rat.basedir=/var/lib/Jenkins/workspace/ch3.BasicLTI_license
    
  8. 后续步骤部分,调用顶级 Maven 目标:

    • Maven 版本3.2.1

    • 目标verify

  9. 点击高级按钮。

  10. 在扩展部分中,将POM部分设置为 Rat 的 POM 文件的完整路径,例如,/var/lib/cookbook/ch3.building_software/license_maven/pom.xml

  11. 后续步骤部分,添加一个复制命令以将报告移动到您的工作空间(例如 cp /var/lib/cookbook/ch3.building_software/license_maven/target/rat.txt ${WORKSPACE})和执行 Shell

  12. 运行作业。您现在可以访问工作区并查看./target/rat.txt。文件应类似于以下屏幕截图:如何操作...

它是如何工作的...

您从一个开源项目中拉取了源代码;在这种情况下,从 Apereo 基金会的一个子版本和 Git 仓库中拉取(source.sakaiproject.org/svn/)。

注意

2013 年,Sakai 基金会 (www.sakaiproject.org) 与 JASIG (www.jasig.org) 合并成为 Apereo 基金会 (www.apereo.org)。

Sakai 是被许多百万学生每天使用的学习管理系统LMS)。Apereo 基金会代表着 100 多个组织,主要是大学。

源代码包含由 Rat Maven 插件检查的不同许可证。插件在verify阶段调用,并检查 Jenkins 注入的${WORKSPACE}变量所定义的作业的工作区位置。

excludeSubProjects语句设置为false,告诉 Rat 除了主项目外还要访问任何子项目。numUnapprovedLicenses语句是在作业失败之前可接受的未批准许可证数量。

excludes 语句排除目标目录和任何其他目录。 includes 语句覆盖 src 目录下的特定文件类型。 根据项目中使用的框架类型,包含的范围将会改变。

注意

有关定制 Rat 以适用于特定许可证类型的信息,请访问:

creadur.apache.org/rat/apache-rat-plugin/examples/custom-license.html

还有更多...

这里还有一些有用的审查提示。

多种方法和反模式

配置 Jenkins 作业有多种方法。 您可以通过在 Maven 插件配置中固定其位置来避免复制 Rat 报告文件。 这样做的好处是避免了复制操作。 您还可以使用多个源码管理器插件(wiki.jenkins-ci.org/display/JENKINS/Multiple+SCMs+Plugin)首先将源代码复制到工作空间中。 您还应考虑将其拆分为两个作业,然后将 Rat 作业指向源代码的工作空间。 最后一种方法是最佳实践,因为它清晰地将测试与源代码分开。

快照

与构件的固定版本不同,快照不能保证其详细信息随时间不变。 如果要测试最新和最好的内容,则快照很有用。 但是,为了获得最可维护的代码,最好使用固定版本构件。

为了捍卫基本稳定性,考虑编写一个在 pom.xml 文件中触发小 Groovy 脚本的作业,以访问所有项目。 脚本需要搜索 version 标签中的 SNAPSHOT 单词,然后为 groovy-postbuild 插件写入一个可识别的警告,以便该作业在必要时失败。 使用这种方法,您可以逐步加强边界,给开发人员改进其构建的时间。

另请参阅

  • 使用 Rat 检查许可证违规 配方

  • 使用 groovy-postbuild 插件对生成的数据做出反应 配方

通过构建描述公开信息

设置插件允许您从构建日志中获取信息,并将其作为构建历史的描述添加。 这非常有用,因为它允许您稍后快速评估问题的历史原因,而无需深入查看控制台输出。 这样可以节省很多鼠标点击。 现在,您可以立即在趋势报告中看到详细信息,而无需逐个查看所有构建结果。

设置插件使用正则表达式来解析描述。 此配方向您展示了如何做到这一点。

准备工作

安装描述设置插件(wiki.jenkins-ci.org/display/JENKINS/Description+Setter+Plugin)。 创建一个名为 ch3.building_software/descriptions 的配方文件目录。

怎么做...

  1. 创建一个模板 pom.xml 文件。

  2. 更改groupIdartifactIdversionname的值以满足您的偏好。

  3. </project>标签之前添加以下 XML 片段:

    <build>
    <plugins><plugin>
    <groupId>org.codehaus.gmaven</groupId>
    <artifactId>gmaven-plugin</artifactId>
    <version>1.3</version>
    <executions><execution>
    <id>run-myGroovy</id>
    <goals><goal>execute</goal></goals>
    <phase>verify</phase>
    <configuration>
    <source>
    if ( new Random().nextInt(50) > 25){
    fail "MySevere issue:  Due to little of resource X"
    } else {
    println "Great stuff happens because: This world is fully resourced"
    }
    </source>
    </configuration>
    </execution></executions>
    </plugin></plugins>
    </build>
    
  4. 创建一个 Maven 项目,作业名称设为 ch3.descriptions

  5. 源代码管理部分,选中文件系统并在路径字段中添加您目录的完全限定路径,例如/var/lib/Jenkins/cookbook/ch3.building_software/description

  6. 勾选设置构建描述并添加以下截图中显示的值:操作步骤...

  7. 多次运行作业并查看构建历史记录。您会发现每次构建的描述都不同:操作步骤...

工作原理...

Groovy 代码是作为install目标的一部分调用的。该代码会根据MySever issue模式使作业失败,或者根据Great stuff happens because模式将输出打印到构建中:

if ( new Random().nextInt(50) > 25){
fail "MySevere issue:  Due to little of resource X"
} else {
println "Great stuff happens because: This world is fully resourced"

作为后置构建操作,将触发 description-setter 插件。在构建成功时,它会查找Great stuff happens because: (.*)模式。

(.*)模式将第一个模式部分后的任何文本拉入"\1"变量中,稍后在设置特定构建的描述中展开。

对于失败的构建也是如此,除了在"\1"展开之前添加了一些额外文本。您在失败构建的描述配置中定义了这些内容。

提示

可以通过扩展正则表达式获得比\1更多的变量。例如,如果控制台输出是fred is happy,那么(.*)模式生成的"\1"等于fred"\2"等于happy

还有更多...

该插件获取其解析文本的能力来自 token-macro 插件 (wiki.jenkins-ci.org/display/JENKINS/Token+Macro+Plugin)。token-macro 插件允许在文本中定义宏;然后通过调用实用方法来扩展它们。这种使用实用程序插件的方法简化了插件的创建,并支持一致性。

另请参阅

  • 使用 groovy-postbuild 插件响应生成的数据 的方法

使用 groovy-postbuild 插件响应生成的数据

构建信息有时会被模糊地记录在日志文件或报告中,这些对于 Jenkins 来说很难暴露。本文将展示一种将这些细节拉到 Jenkins 中的方法。

groovy-postbuild 插件允许您在构建运行后运行 Groovy 脚本。因为该插件在 Jenkins 中运行,所以可以编程地访问服务,例如能够读取控制台输入或更改构建摘要页面。

该方法在 Maven 的 pom.xml 中使用了一个 Groovy 脚本来将文件输出到控制台。然后,插件中的 Groovy 代码会捕获控制台输入,并在构建历史记录中显示关键统计信息。构建摘要详情也被修改了。

准备工作

遵循从 Maven 内部审查许可证违规的配方。添加 groovy-postbuild 插件(wiki.jenkins-ci.org/display/JENKINS/Groovy+Postbuild+Plugin)。

操作方法...

  1. 通过在pom.xml文件中在</plugins>标记之前添加以下 XML 片段来更新文件:

    <plugin>
    <groupId>org.codehaus.gmaven</groupId>
    <artifactId>gmaven-plugin</artifactId>
    <version>1.3</version>
    <executions><execution>
    <id>run-myGroovy</id>
    <goals><goal>execute</goal></goals>
    <phase>verify</phase>
    <configuration>
    <source>
    new File("${basedir}/target/rat.txt").eachLine{line->println line}
    </source>
    </configuration>
    </execution></executions>
    </plugin>
    
  2. 后构建操作部分更新ch3.BasicLTI_license作业的配置。选中Groovy Postbuild。将以下脚本添加到 Groovy 脚本文本输入中:

    def matcher = manager.getMatcher(manager.build.logFile, "^(.*) Unknown Licenses\$")
    if(matcher?.matches()) {
    title="Unknown Licenses: ${matcher.group(1)}"
    manager.addWarningBadge(title)
    manager.addShortText(title, "grey", "white", "0px", "white")
    manager.createSummary("error.gif").appendText("<h2>${title}</h2>", false, false, false, "grey")
    manager.buildUnstable()
    }
    
  3. 确保如果脚本失败选择框设置为什么都不做

  4. 点击保存

  5. 运行作业多次。在构建历史中,您将看到类似以下截图的结果:操作方法...

  6. 单击最新构建链接会显示有关未知许可证的摘要信息的构建页面,如以下截图所示:操作方法...

它是如何工作的...

Rat 许可报告保存到target/rat.txt文件中。然后,Groovy 代码读取 Rat 文件并将其打印到控制台,以便 groovy-postbuild 插件接收。您可以在 groovy-postbuild 插件中完成所有工作,但以后可能希望重用构建。

构建完成后,groovy-postbuild 插件将运行。插件可见一些 Jenkins 服务:

  • manager.build.logFile: 这会获取日志文件,其中现在包括许可信息。

  • manager.getMatcher: 这会检查日志文件以查找与"^(.*) Unknown Licenses\$"匹配的模式。符号^检查行的开头,\$检查行的结尾。以Unknown Licenses模式结尾的任何行将与之前存储在matcher.group(1)中的任何内容匹配。它将title字符串设置为未知许可证的数量。

  • manager.addWarningBadge(title): 这会向构建历史框添加警告徽章,title将用作鼠标悬停在图标上时显示的文本。

  • manager.addShortText: 这会在图标旁添加可见文本。

  • 通过manager.createSummary方法创建摘要。已在 Jenkins 中存在的图像将以标题的形式添加。

还有更多...

通过搜索常规模式将信息提取到报告中称为爬取。爬取的稳定性依赖于在 Rat 报告中生成一致的模式。如果更改 Rat 插件的版本,则模式可能会更改并破坏报告。可能时,最好使用稳定的数据源,例如具有明确定义语法的 XML 文件。

另请参阅

  • 通过构建描述公开信息配方

  • 通过小的配置更改增强安全性配方在第二章中,增强安全性

通过 Jenkins API 远程触发作业

Jenkins 具有远程 API,允许您启用、禁用、运行和删除作业;它还允许您更改配置。API 随着每个 Jenkins 版本的增加而增加。要获取最新的详细信息,您需要查看http://yourhost/job/Name_of_Job/api/。其中yourhost是您的 Jenkins 服务器的位置,Name_of_Job是服务器上存在的作业的名称。

此方案详细介绍了如何使用安全令牌远程触发构建。这将允许您从 Maven 内运行其他作业。

准备工作

此方案期望 Jenkins 安全性已打开,以便您可以作为用户登录。它还假设您已安装了现代版本的wgetwww.gnu.org/software/wget/)。

如何执行...

  1. 创建一个自由风格项目,项目名称ch3.RunMe

  2. 检查此构建已参数化,选择字符串参数,并添加以下细节:

    • 名称myvariable

    • 默认值默认

    • 描述这是我的示例变量

  3. 触发构建部分下,勾选远程触发构建(例如,从脚本中)。

  4. 身份验证令牌文本框中添加changeme

  5. 点击保存按钮。

  6. 点击带参数构建链接。

  7. 将要求您输入名为myvariable的变量。点击构建

  8. 访问您的个人配置页面,例如http://localhost:8080/user/your_user/configure,其中您将your_user替换为您的 Jenkins 用户名。

  9. API 令牌部分,点击显示 API 令牌…按钮。

  10. 将令牌复制到apiToken中。

  11. 从终端控制台远程运行wget以登录并运行作业:

    wget --auth-no-challenge --http-user=username --http-password=apiToken http://localhost:8080/job/ch3.RunMe/build?token=changeme
    
    
  12. 检查 Jenkins 作业以验证其未运行并返回405HTTP 状态代码:

    Resolving localhost (localhost)... 127.0.0.1Connecting to localhost (localhost)|127.0.0.1|:8080... connected.
    HTTP request sent, awaiting response... 405 Method Not Allowed
    2014-08-14 15:08:43 ERROR 405: Method Not Allowed.
    
    
  13. 从终端控制台运行wget以登录并运行返回201HTTP 状态代码的作业:

    wget --auth-no-challenge --http-user=username --http-password=apiToken http://localhost:8080/job/ch3.RunMe/buildWithParameters?token=changeme\&myvariable='Hello World'
    Connecting to localhost (localhost)|127.0.0.1|:8080... connected.
    HTTP request sent, awaiting response... 201 Created
    
    

    注意

    HTTP 可以被第三方抓包。传输密码时请使用 HTTPS。

工作原理...

要运行作业,您需要作为用户进行身份验证,然后获取运行特定作业的权限。这通过apiTokens实现,您应该将其视为密码的一种。

有两个远程方法调用。第一个是 build,用于在不传递参数的情况下运行构建。该方法当前不被接受。第二个有效的方法是buildWithParameters,它期望您至少向 Jenkins 传递一个参数。参数用\&分隔。

wget工具承担了大部分工作;否则,您将不得不编写一些棘手的 Groovy 代码。为了简短的方案,我们选择了简单性和操作系统的依赖性。运行一个可执行文件会使您的构建依赖于操作系统。可执行文件将取决于底层环境的设置方式。然而,有时您需要做出妥协以避免复杂性。

有关更多详细信息,请访问 wiki.jenkins-ci.org/display/JENKINS/Authenticating+scripted+clients.

注意

你可以在以下网址找到等效的 Java 代码:

wiki.jenkins-ci.org/display/JENKINS/Remote+access+API.

还有更多...

以下是一些你应该考虑的事项。

从 Maven 中运行作业

使用 maven-antrun 插件,你可以轻松运行 wget。以下是等效的 pom.xml 片段:

<build>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.7</version>
<executions><execution>
<phase>compile</phase>
<configuration>
<tasks>
<exec executable="wget">
<arg line="--auth-no-challenge --http-user=username --http-password=apiToken http://localhost:8080/job/ch3.RunMe/build?token=changeme" />
</exec>
</tasks>
</configuration>
<goals><goal>run</goal></goals>
</execution></executions>
</plugin>
</build>

你可以使用 exec-maven 插件来实现与 maven-ant 插件相同的目的。有关更多详细信息,请访问 mojo.codehaus.org/exec-maven-plugin/.

远程生成作业

还有一个项目可以让你通过 Maven 远程创建 Jenkins 作业(github.com/evgeny-goldin/maven-plugins/tree/master/jenkins-maven-plugin)。这种方法的优点是它能够在作业之间强制执行一致性和重用。你可以使用一个参数选择 Jenkins 服务器并填充它。这对于生成一组结构一致的作业非常有用。

另请参阅

  • 在 Maven 中通过 Groovy 运行 Ant 示例

自适应站点生成

Jenkins 是一个出色的通信工具。它可以消耗构建生成的测试结果。Maven 有一个用于站点生成的目标,在 pom.xml 文件中,许多 Maven 测试插件被配置。配置受 reporting 标签限制。

当站点生成时,Jenkins Maven 软件项目作业记录,并在作业主页上创建一个快捷图标。这是一个非常显眼的图标,你可以将其与内容链接起来:

自适应站点生成

通过触发 Groovy 脚本,你可以对 Maven 站点生成进行细粒度控制,以在不同的 Maven 阶段中构建站点。

在这个示例中,你将使用 Groovy 生成一个动态站点菜单,该菜单具有根据脚本中的随机选择而不同的菜单链接。然后,第二个脚本生成每个站点生成的新结果页面。如果你想公开自定义的测试结果,这些操作非常有用。在 Jenkins 中报告替代代码度量 的示例描述了如何在 Jenkins 中绘制自定义结果,进一步增强用户体验。

注意

该示例适用于 Maven 版本 2.2.1 或更早版本。Maven 3 在站点生成方面有稍微不同的方法。

要在你的 pom.xml 文件中强制使用最低 Maven 版本,你需要添加 <prerequisites><maven>2.2.1</maven></prerequisites>

准备工作

创建一个名为 ch3.building_software/site 的目录。安装 Copy Data to Workspace 插件 (wiki.jenkins-ci.org/display/JENKINS/Copy+Data+To+Workspace+Plugin)。这将使你练习另一个有用的插件。你将使用此插件将文件复制到 Jenkins 工作空间中,如本教程中所述。这用于将包含密码的敏感配置文件复制到项目中,你不希望它们出现在版本控制系统中。

如何操作...

  1. 在你的模板 pom.xml 文件中的 </project> 之前添加以下 XML 片段(在介绍中提到),确保 pom.xml 文件可被 Jenkins 读取:

    <url>My_host/my_dir</url>
    <description>This is the meaningful DESCRIPTION</description>
    <build>
    <plugins><plugin>
    <groupId>org.codehaus.gmaven</groupId>
    <artifactId>gmaven-plugin</artifactId>
    <version>1.3</version>
    <executions>
    <execution>
    <id>run-myGroovy-add-site-xml</id>
    <goals><goal>execute</goal></goals>
    <phase>pre-site</phase>
    <configuration>
    <source>
    site_xml.Groovy
    </source>
    </configuration>
    </execution>
    <execution>
    <id>run-myGroovy-add-results-to-site</id>
    <goals><goal>execute</goal></goals>
    <phase>site</phase>
    <configuration>
    <source>
    site.Groovy
    </source>
    </configuration>
    </execution></executions>
    </plugin></plugins>
    </build>
    
  2. 在与你的 pom.xml 文件相同的目录中创建 site_xml.Groovy 文件,并使用以下代码行:

    def site= new File('./src/site')
    site.mkdirs()
    defs xml=new File('./src/site/site.xml')
    if (sxml.exists()){sxml.delete()}
    
    sxml<< '<?xml version="1.0" encoding="ISO-8859-1"?>'
    sxml<< '<project name="Super Project">'
    sxml<< '<body>'
    def random = new Random()
    if (random.nextInt(10) > 5){
    sxml<< '    <menu name="My super project">'
    sxml<< '     <item name="Key Performance Indicators" href="/our_results.html"/>'
    sxml<< '   </menu>'
    print "Data Found menu item created\n"
    }
    sxml<< '   <menu ref="reports" />'
    sxml<< '  </body>'
    sxml<< '</project>'
    
    print "FINISHED - site.xml creation\n"
    
  3. 在与你的 pom.xml 文件相同的目录中添加 site.Groovy 文件,并使用以下代码行:

    def site= new File('./target/site')
    site.mkdirs()
    def index = new File('./target/site/our_results.html')
    if (index.exists()){index.delete()}
    index<< '<h3>ImportAnt results</h3>'
    index<< "${new Date()}\n"
    index<< '<ol>'
    
    def random = new Random()
    for ( i in 1..40 ) {
    index<< "<li>Result[${i}]=${random.nextInt(50)}\n"
    }
    index<< '</ol>'
    
  4. 创建一个名为 ch3.site 的 Maven 项目。

  5. 构建 部分,填写以下细节:

    • Maven 版本: 2.2.1

    • 根 POM: pom.xml

    • 目标和选项: site

  6. 构建环境 部分,选择 将数据复制到工作空间

  7. 将你放置文件的任何目录(在本教程中提到)添加到 文件夹路径 字段。

  8. 运行作业多次,查看生成的站点。在右侧,你应该看到一个名为 我的超级项目 的菜单部分。对于一半的运行,将会有一个名为 关键绩效指标 的子菜单链接:如何操作...

工作原理...

有两个 Groovy 脚本在站点目标的两个不同阶段运行。第一个生成 site.xml 文件。Maven 使用此文件在索引页面的左侧创建一个额外的菜单结构。第二个 Groovy 脚本生成一个随机结果页面。

site_xml.Groovy 文件在 pre-site 阶段运行。site.Groovy 文件在站点生成期间执行。site_xml.Groovy 文件生成 src/site 目录,然后生成 src/site/site.xml 文件。这是 Maven 站点生成插件用于定义站点菜单左侧的文件。有关此过程的更多详细信息,请访问 Maven.apache.org/guides/mini/guide-site.html

然后 Groovy 脚本在 if (random.nextInt(10) > 5) 行中随机决定何时显示额外的结果页面菜单项。

site.Groovy 文件生成一个包含 40 个条目的随机结果页面。如果存在旧的结果页面,Groovy 脚本会将其删除。该脚本通过首先创建 target/site 目录来稍微作弊。如果你想要更长或更短的页面,请修改 for ( i in 1..40 ) { 行中的数字 40

构建脚本运行后,Jenkins 检查站点是否位于传统位置,并将图标添加到任务中。

注意

在撰写本书时,只有Maven项目作业意识到生成的站点的存在并发布站点图标。自由样式作业不行。

还有更多...

这里还有一些有用的信息。

搜索示例站点生成配置

有时,在配置站点生成时可能会出现任意的 XML 魔法。学习的一种快速方法是使用软件代码搜索引擎。例如,尝试使用 Black Duck 代码搜索引擎(code.ohloh.net/)搜索术语 <reporting>

Maven 2 和 3 的陷阱

Maven 3 在大多数情况下与 Maven 2 向后兼容。然而,它确实有一些你可以在cwiki.apache.org/confluence/display/MAVEN/Maven+3.x+Compatibility+Notes中审查的差异。关于兼容插件的列表,请访问cwiki.apache.org/confluence/display/MAVEN/Maven+3.x+Plugin+Compatibility+Matrix

在幕后,Maven 3 是 Maven 2 的重写,具有改进的架构和性能。强调兼容性与 Maven 2。你不想破坏传统配置,因为那会导致不必要的维护工作。Maven 3 对语法比 Maven 2 更挑剔。如果你忘记为任何依赖项或插件添加版本号,它会抱怨。例如,在本书的第一版中,基于 JSP 语法错误的 失败的 Jenkins 作业 配方包括一个没有定义版本的 pom.xml 文件中的 keytool-maven-plugin 浮动:

<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>keytool-maven-plugin</artifactId>
<executions>
<execution>
<phase>generate-resources</phase>
<id>clean</id>
<goals>
<goal>clean</goal>
</goals>
</execution>
<execution>
<phase>generate-resources</phase>
<id>genkey</id>
<goals>
<goal>genkey</goal>
</goals>
</execution>
</executions>

当使用 Maven 3 运行时,该配方将失败,并显示以下输出。

Maven 2 和 3 的陷阱

genkey 目标不再存在,因为 Maven 3 正在使用最新版本的插件进行扫描,即版本 1.5。在插件的网站mojo.codehaus.org/keytool/keytool-maven-plugin/上查看,明显我们需要更新版本号和目标:

Maven 2 和 3 的陷阱

更改体现在更新的 pom.xml 文件中:

<plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>keytool-maven-plugin</artifactId>
 <version>1.5</version>
  <executions>
    <execution>
      <phase>generate-resources</phase>
      <id>clean</id>
      <goals>
        <goal>clean</goal>
      </goals>
    </execution>
    <execution>
      <phase>generate-resources</phase>
        <id>generateKeyPair</id>
        <goals>
 <goal>generateKeyPair</goal>
        </goals>
    </execution>
  </executions>
</plugin>

另一个陷阱是 Maven 3 中 Maven 站点插件的使用反映在 <reporting> 部分配置的方式上。

从 Maven 2 升级站点生成的有效方法是从 Maven 3 生成的工作原型开始,并逐步将功能从 Maven 2 项目转移和测试。一旦你有了完整功能的 Maven 3 项目,你可以稍后将其转换为自己的原型,以充当进一步项目的模板。

注意

你可以在maven.apache.org/guides/mini/guide-creating-archetypes.html找到关于构建自己原型的信息。

当从 Maven 2 升级到 3 时,你会发现大多数 JAR 依赖关系和版本都是明确指定的。让我们看一个以下示例:

<dependencies>
  <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
      <version>3.8.1</version>
    <scope>test</scope>
  </dependency>
</dependencies>

升级是寻找是否可以找到新版本,其中已经修复了错误和已知安全问题的理想时机。Maven 仓库搜索引擎(search.maven.org/)是寻找新版本的合适地方。你还可以考虑浏览 search.maven.org/#browse 上的仓库,然后点击 JUnit 的链接:

Maven 2 和 3 的陷阱

现在你可以看到不同的版本号和上传日期。在 JUnit 的情况下,我会升级到最新版本;如果由于 API 不兼容而导致构建失败,那么回退到最后一个稳定的点版本,即版本 3.8.2。

另请参阅

  • 通过 Maven 运行 Groovy 脚本 配方

  • 在 Jenkins 中绘制备选代码指标 配方

  • 基于 JSP 语法错误的 Jenkins 作业失败 配方

第四章。通过 Jenkins 进行沟通

在本章中,我们将涵盖以下配方:

  • 使用简单主题插件为 Jenkins 进行皮肤定制

  • 使用 WAR 覆盖层对 Jenkins 进行皮肤定制和配置

  • 生成主页

  • 创建 HTML 报告

  • 高效使用视图

  • 使用仪表板视图插件节省屏幕空间

  • 使用 HTML5 浏览器发出声音

  • 用于接待区的极端视图

  • 使用 Google 日历进行移动演示

  • 适用于 Android 和 iOS 的移动应用程序

  • 通过 Google Analytics 了解您的受众

  • 使用 R 插件简化强大的可视化

介绍

本章探讨了通过 Jenkins 进行沟通,认识到有不同的目标受众。

Jenkins 是一种有才能的沟通工具。其首页显示所有作业的状态,让您能够快速做出决策。您可以轻松设置多个视图,自然地优先考虑信息。Jenkins 具有大量的插件,可以通过电子邮件、仪表板和 Google 服务通知您。它通过移动设备向您发出呼唤,在您经过大屏幕时辐射信息,并用 USB 海绵导弹发射器向您发射。

它的主要受众是开发人员,但不要忘记希望使用正在开发的软件的更广泛受众。定期看到 Jenkins 以一致的视图和公司的外观和感觉进行构建,可以增强对软件路线图的信心。本章包括帮助您触及更广泛受众的配方。

在创建连贯的沟通策略时,有许多 Jenkins 特定的细节需要配置。以下是本章将考虑的一些细节:

  • 通知:开发人员需要快速了解何时出现问题。Jenkins 有许多插件:您应该选择一些适合团队理念的插件。

  • 页面装饰:页面装饰器是一种插件,可以向每个页面添加内容。您可以通过添加自己的样式表和 JavaScript 便宜地生成公司的外观和感觉。

  • 覆盖 Jenkins:使用 Maven WAR 插件,您可以将自己的内容覆盖在 Jenkins 之上。您可以使用此功能添加自定义内容并配置资源,例如主页,从而增强公司的外观和感觉。

  • 优化视图:前页视图是以选项卡显示的作业列表。受众使用前页快速决定选择哪个作业进行审查。插件扩展了视图类型的选择并优化了信息消化。这可能避免了查找更多信息的需要,节省了宝贵的时间。

  • 随身通知:极端的视图可以在大型监视器上直观地显示信息。如果您将监视器放置在接待处或咖啡机等地方,那么过路人将会吸收工作状态变化的起伏。这种视图巧妙地暗示了您公司的专业水平和产品路线图的稳定性。

  • 跟踪你的受众群体:如果你在公开交流,那么你应该跟踪使用模式,以便改进服务。考虑将你的 Jenkins 页面连接到 Google Analytics 或 Piwik,一个开源分析应用程序。

提示

Subversion 存储库

从本章开始,你将需要一个 Git 或 Subversion 存储库。这将使你能够以最自然的方式使用 Jenkins。为了简洁起见,我们在示例中仅提到 Subversion,但选择 Git 也很容易。如果你还没有存储库,你可以在互联网上注册一些免费或半免费的服务,例如www.straw-dogs.co.uk/09/20/6-free-svn-project-hosting-services/或 Git 存储库的示例 bitbucket.org/

或者,你可以考虑在本地设置 Subversion 或 Git。有关 Ubuntu 的安装说明,请访问 help.ubuntu.com/community/Subversionhelp.ubuntu.com/lts/serverguide/git.html

使用简单主题插件美化 Jenkins

本示例通过主题插件修改了 Jenkins 的外观和感觉。

主题插件是一个页面装饰器:它在每个页面上添加额外的 HTML 标签。该插件允许你上传样式表和 JavaScript 文件。然后通过本地 URL 访问这些文件。然后,每个 Jenkins 页面都使用使用这些 URL 的 HTML 标签装饰。虽然简单,但如果正确制作,视觉效果是强大的。

准备工作

安装主题插件(wiki.jenkins-ci.org/display/JENKINS/Simple+Theme+Plugin)。

如何操作...

  1. 在 Jenkins 的 userContent 目录下,创建一个名为 my.js 的文件,其中包含以下代码行:

    document.write("<h1 id='test'>Example Location</h1>")
    
  2. 在 Jenkins 的 userContent 目录中创建一个名为 mycss.css 的文件,其中包含以下代码行:

    @charset "utf-8";
    #test {
      background-image: url(/userContent/camera.png);
    }
    #main-table{
      background-image: url(/userContent/camera.png) !important;
    
  3. 下载并解压图标存档sourceforge.net/projects/openiconlibrary/files/0.11/open_icon_library-standard-0.11.tar.bz2/download并查看可用图标。或者,你可以使用书籍网站下载的图标。将图标添加到 userContent 目录并将其重命名为 camera.png

  4. 访问 Jenkins 的主配置页面:/configure。在 Theme 部分下,填写 CSS 和 JavaScript 文件的位置:

    • 主题 CSS 的 URL/userContent/myjavascript.css

    • 主题 JS 的 URL/userContent/mycss.js

  5. 点击 保存

  6. 返回 Jenkins 主页并查看你的工作,如下截图所示:如何操作...

工作原理...

简单主题插件是一个页面装饰器。它向每个页面添加以下信息:

<script>
<link rel="stylesheet" type="text/css" href="/userContent/mycss.css" /><script src="img/myjavascript.js" type="text/javascript">
</script>

JavaScript 在生成的页面顶部附近写入一个带有id="test"的标题。通过 CSS 定位符#test触发级联样式表规则会将相机图标添加到背景中。

图片尺寸未经调整,不适合屏幕顶部;它们被浏览器裁剪。这是一个你可以通过实验来解决的问题。

第二个 CSS 规则针对main-table触发,这是 Jenkins 生成的标准首页的一部分。完整的相机图标显示在那里。

当访问 Jenkins 的其他部分时,您会注意到相机图标看起来不合适,而且过大。您需要时间修改 CSS 和 JavaScript 来生成更好的效果。通过小心和自定义代码,您可以使 Jenkins 适应公司形象。

提示

CSS 3 怪癖

各种浏览器类型和版本在支持各种 CSS 标准上存在一些怪异之处。有关概述,请访问www.quirksmode.org/css/contents.html

还有更多...

这里还有一些需要考虑的事情。

CSS 3

CSS 3 有许多功能。要在 JavaScript 生成的标题周围绘制按钮,请将 CSS 文件中的#test部分更改为以下代码:

#test {
  width: 180px; height: 60px;
  background: red; color: yellow;
  text-align: center;
  -moz-border-radius: 40px; -webkit-border-radius: 40px;
}

使用 Firefox,CSS 规则生成了以下按钮:

CSS 3

注意

对于急于行动的人,你可以在 Smashing Magazine 网站上下载 CSS 3 技巧表:coding.smashingmagazine.com/wp-content/uploads/images/css3-cheat-sheet/css3-cheat-sheet.pdf

包含的 JavaScript 库框架

Jenkins 使用 YUI 库yuilibrary.com/。在每个 HTML 页面中装饰,核心 YUI 库(/scripts/yui/yahoo/yahoo-min.js)已经准备好以供重复使用。然而,许多 web 开发人员习惯于 jQuery。你也可以通过安装 jQuery 插件(wiki.jenkins-ci.org/display/JENKINS/jQuery+Plugin)来包含此库。你还可以考虑通过 WAR 叠加层将你喜欢的 JavaScript 库添加到 Jenkins 的/scripts目录中(参见下一个示例)。

信而验证

伴随着巨大的能力而来的是巨大的责任。如果只有少数管理员维护您的 Jenkins 部署,则您很可能信任每个人都可以添加 JavaScript 而不会产生有害的副作用。然而,如果有大量管理员使用各种各样的 Java 库,则您的维护和安全风险会迅速增加。请考虑您的安全策略,并至少添加审计追踪插件(wiki.jenkins-ci.org/display/JENKINS/Audit+Trail+Plugin)以跟踪行动。

另请参阅

  • 使用 WAR 覆盖为 Jenkins 进行换肤和资源配置 配方

  • 生成主页 配方

使用 WAR 覆盖为 Jenkins 进行换肤和资源配置

本配方描述了如何将内容覆盖到 Jenkins WAR 文件上。通过 WAR 覆盖,你可以更改 Jenkins 的外观和感觉,以进行企业品牌化和主页内容配置。本示例基本上只添加了自定义的 favicon.ico(在网页浏览器地址栏中的图标)。包含更多内容几乎不需要额外的努力。

Jenkins 将其版本作为依赖项保存在 Maven 仓库中。你可以使用 Maven 拉取 WAR 文件,展开它,添加内容,然后重新打包。这使你能够提供资源,如图像、主页、地址栏中称为 fav 图标的图标,以及影响搜索引擎浏览你内容的 robots.txt

要小心:如果 Jenkins 的结构和图形内容随时间发生根本性变化,使用 WAR 覆盖将很便宜。然而,如果覆盖物破坏了结构,那么你可能要进行详细的功能测试才能发现这一点。

你还可以考虑通过 WAR 覆盖进行最小更改,也许只更改 favicon.ico,添加图像和 userContent,然后使用简单主题插件(参见前面的配方)进行样式设置。

准备工作

创建名为 ch4.communicating/war_overlay 的目录以存放此配方中的文件。

如何实现...

  1. 浏览到 Maven 仓库 repo.jenkins-ci.org/releases/org/jenkins-ci/main/jenkins-war/ 并查看 Jenkins 的依赖项。

  2. 创建以下 pom.xml 文件。随意更新为更新版本的 Jenkins:

    <project  
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>nl.uva.berg</groupId>
    <artifactId>overlay</artifactId>
    <packaging>war</packaging>
    <!-- Keep version the same as Jenkins as a hint -->
    <version>1.437</version>
    <name>overlay Maven Webapp</name>
    <url>http://maven.apache.org</url>
    <dependencies>
    <dependency>
    <groupId>org.jenkins-ci.main</groupId>
    <artifactId>jenkins-war</artifactId>
    <version>1.437</version>
    <type>war</type>
    <scope>runtime</scope>
    </dependency>
    </dependencies>
    <repositories>
    <repository>
          <id>Jenkins</id>
          <url>http://repo.jenkins-ci.org/releases</url>
         </repository>
    </repositories>
    </project>
    
  3. 访问 favicon.ico 生成网站,例如 www.favicon.cc/。按照其说明,创建你自己的 favicon.ico。或者,使用提供的示例。

  4. favicon.ico 添加到 src/main/webapp 位置。

  5. 创建目录 src/main/webapp/META-INF 并添加一个名为 context.xml 的文件,其中包含以下一行代码:

    <Context logEffectiveWebXml="true" path="/"></Context>
    
  6. 在你的顶层目录中,运行以下命令:

    mvn package
    
  7. 在新生成的目标目录中,你将看到 WAR 文件 overlay-1.437.war。检查内容,验证你是否已修改了 favicon.ico

  8. [可选] 部署 WAR 文件到本地 Tomcat 服务器,验证并浏览更新后的 Jenkins 服务器:如何实现...

工作原理...

Jenkins 通过中央 Maven 仓库公开了其 WAR 文件。这允许你通过标准的 Maven 依赖管理拉取 Jenkins 的特定版本。

Maven 使用约定。它期望在 src/main/webappsrc/main/resources 中找到要覆盖的内容。

context.xml 文件定义了 Web 应用程序的某些行为,例如数据库设置。在此示例中,设置 logEffectiveWebXML 要求 Tomcat 在应用程序启动时记录特定信息(tomcat.apache.org/tomcat-7.0-doc/config/context.html)。 Jenkins Wiki 推荐了此设置(wiki.jenkins-ci.org/display/JENKINS/Installation+via+Maven+WAR+Overlay)。该文件放置在 META-INF 目录中,因为 Tomcat 可以在此处获取设置而无需重新启动服务器。

<packaging>war</packaging> 标签告诉 Maven 使用 WAR 插件进行打包。

您在最终叠加 WAR 的名称中使用了与原始 Jenkins WAR 版本相同的版本号。这样可以更容易地发现 Jenkins 版本是否更改。这再次凸显了使用惯例有助于提高可读性并减少错误机会。在从验收环境部署到生产环境时,应删除版本号。

pom.xml 文件中,您将 repo.jenkins-ci.org/releases 定义为查找 Jenkins 的存储库。

Jenkins WAR 文件作为 war 类型的依赖项和 runtime 范围的依赖项引入。运行时范围表示该依赖项不需要进行编译,但是需要执行。有关作用域的更详细信息,请参阅 maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Dependency_Scope

有关 WAR 叠加的更多详细信息,请参阅 maven.apache.org/plugins/maven-war-plugin/index.html

提示

**避免工作

为了减少维护工作量,最好安装额外的内容,而不是替换可能在其他地方或由第三方插件使用的内容。

还有更多...

如果您希望完全修改 Jenkins 的外观和感觉,则需要涵盖许多细节。以下部分提及了一些细节。

您可以替换哪些类型的内容?

Jenkins 服务器部署到两个主要位置。第一个位置是核心应用程序,第二个位置是存储更改信息的工作空间。为了更全面地了解内容,请查看目录结构。Linux 中一个有用的命令是 tree 命令,它显示目录结构。要在 Ubuntu 下安装,请使用以下命令:

apt-get install tree

对于 Jenkins Ubuntu 工作空间,使用以下命令生成工作空间的树状视图:

tree –d –L 1 /var/lib/Jenkins

├── 指纹(用于存储文件的校验和以唯一标识文件)

├── 工作(存储作业配置和构建结果)

├── 插件(插件部署和通常配置的位置)

├── tools(部署 Maven 和 Ant 等工具的位置)

├── updates(更新)

├── userContent(在/userContent URL 下提供的内容)

└── users(显示在/me URL 下的用户信息)

Web 应用程序的默认 Ubuntu 位置是/var/run/jenkins/war。如果您从命令行运行 Jenkins,则放置 Web 应用程序的选项是:

–webroot

├── css(Jenkins 样式表的位置)

├── executable(用于从命令行运行 Jenkins)

├── favicon.ico(在此方法中替换的图标)

├── help(帮助内容目录)

├── images(不同尺寸的图形)

├── META-INF(manifes 文件和生成的 WAR 的pom.xml文件的位置)

├── robots.txt(用于告诉搜索引擎允许爬行的位置)

├── scripts(JavaScript 库位置)

├── WEB-INF(Web 应用程序的 servlet 部分的主要位置)

└── winstone.jar(Servlet 容器:winstone.sourceforge.net/

搜索引擎和 robots.txt

如果您要添加自己的自定义内容,例如用户主页、公司联系信息或产品详情,请考虑修改顶级robots.txt文件。目前,它将搜索引擎从所有内容中排除在外:

# we don't want robots to click "build" links
User-agent: *
Disallow: /

您可以在www.w3.org/TR/html4/appendix/notes.html#h-B.4.1.1找到robots.txt结构的完整详情。

Google 使用更丰富的结构,允许和禁止;请参阅developers.google.com/webmasters/control-crawl-index/docs/robots_txt?csw=1

下面的robots.txt允许 Google 爬虫访问/userContent/corporate/目录。所有网络爬虫是否会遵守意图尚不确定。

User-agent: *
Disallow: /
User-agent: Googlebot
Allow: /userContent/corporate/

注意

为了帮助保护您的 Jenkins 基础架构,请参考第二章中的方法,Enhancing Security

另请参阅

  • 用简单主题插件为 Jenkins 设置样式的方法

  • 生成主页的方法

生成主页

用户的主页是表达您组织身份的好地方。您可以创建一致的外观和感觉,表达您团队的精神。

本方法将探讨位于/user/userid目录下的主页的操作,并由用户通过 Jenkins /me URL 配置。

注意

值得审查的类似插件是 Gravatar 插件。您可以在wiki.jenkins-ci.org/display/JENKINS/Gravatar+plugin找到插件主页

准备工作

安装 Avatar 插件(wiki.jenkins-ci.org/display/JENKINS/Avatar+Plugin)。

为用户 fakeuser 创建一个 Jenkins 帐户。 您可以配置 Jenkins 以使用许多身份验证策略;选择将影响您如何创建用户。 一个例子是使用 Reviewing project-based matrix tactics via a custom group script 中详细介绍的基于项目的矩阵策略,位于 Chapter 2,Enhancing Security 中的配方。

注意

除非作为 Jenkins 管理员您在 Configure Global Security 页面下配置了 Markup FormatterRaw,否则您将无法使此配方起作用。 通过这样做,您允许任何可以编辑描述的人注入他们自己的脚本代码。 如果您是一个非常信任的小型开发团队,这可能是一种可行的做法。 但是,一般来说,考虑这是一个安全问题。

如何操作...

  1. 浏览到 en.wikipedia.org/wiki/Wikipedia:Public_domain_image_resources 以获取图片的公共领域来源列表。

  2. commons.wikimedia.org/wiki/Main_Page 搜索开源图像。

  3. 通过点击以下截图中显示的 Download Image File: 75 px 链接,从 commons.wikimedia.org/wiki/File%3ACharles_Richardson_(W_H_Gibbs_1888).jpg 下载图像:操作步骤...

    注意

    如果图像不再可用,请选择另一个。

  4. fakeuser 身份登录到您的 Jenkins 服务器并访问其配置页面,地址为 http://localhost:8080/user/fakeuser/configure

  5. Avatar 部分上传图像:操作步骤...

  6. 查看 URL http://localhost:8080/user/fakeuser/avatar/image

    注意

    现在,您随时都可以使用此已知的 URL 来显示您的头像。

  7. 将以下文本添加到用户配置文件描述中:

    <script type="text/JavaScript">
    functionchangedivview()
    {
    var elem=document.getElementById("divid");
    elem.style.display=(elem.style.display=='none')?'block':'none';
    }
    </script>
    <h2>OFFICIAL PAGE</h2>
    <div id="divid">
    <table border=5 bgcolor=gold><tr><td>HELLO WORLD</td></tr></table>
    </div>
    <a href="javascript:;" onClick="changedivview();">Switch</a>  
    
  8. 访问 /user/fakeuser 页面。 您将在描述中看到一个名为 Switch 的链接。 如果您点击该链接,则 HELLO WORLD 内容将会出现或消失。

  9. 复制 fakeuser 的用户目录到一个名为 fakeuser2 的目录,例如,/var/lib/jenkins/user/fakeuser。 在 fakeuser2 目录中找到的 config.xml 文件中,将 <fullName> 标签的值从 fakeuser 更改为 fakeuser2。 将 <emailAddress> 的值更改为 fakeuser2@dev.null

  10. fakeuser2 的身份登录,密码与 fakeuser 相同。

  11. 访问主页 /user/fakeuser2。 注意电子邮件地址的更新。

它是如何工作的...

Avatar 插件允许您将图像上传到 Jenkins。 图像的 URL 位于固定位置。 您可以通过简单的主题插件重复使用它,以添加内容而不使用 WAR 覆盖。

有大量的公共领域和开源图片可供免费使用。在生成自己的内容之前,值得在互联网上查看资源。如果你创建内容,请考虑捐赠给开源存档,比如archive.org

除非你过滤掉 HTML 标签和 JavaScript 的描述(参见第三章 构建软件 中的 通过构建描述公开信息 这一做法),否则你可以使用自定义 JavaScript 或 CSS 动画来为个性化的 Jenkins 添加吸引眼球的效果。

你的fakeuser信息存储在/user/fakeuser/config.xml中。通过将其复制到另一个目录并略微修改config.xml文件,你创建了一个新的用户帐户。这种格式易于阅读,并且易于结构化成用于创建更多帐户的模板。你创建了fakeuser2帐户来证明这一点。

通过使用 WAR 覆盖配方并添加额外的/user/username目录,其中包含自定义的config.xml文件,你可以控制 Jenkins 用户群体,例如,从一个中央配置脚本或在第一次登录尝试时,使用自定义授权脚本(参见第二章 增强安全性 中的 使用脚本领域认证进行配置的做法)。

更多内容……

通过使用模板config.xml来强制执行一致性。这将强制执行更广泛的统一结构。你可以将初始密码设置为已知值或空值。只有在用户从创建到首次登录的时间非常短的情况下,空密码才有意义。你应该考虑这是一种不好的做法,是一个等待发生问题的问题。

描述存储在描述标签下。内容以 URL 转义文本形式存储。例如,<h1>描述</h1>存储为:

<description>&lt;h1&gt;DESCRIPTION&lt;/h1&gt;</description>

许多插件也将它们的配置存储在同一个config.xml文件中。随着你在 Jenkins 服务器中增加插件的数量,这是很自然的,因为你了解了这个产品,你需要偶尔审查你的模板的完整性。

另请参阅

  • 使用简单主题插件装饰 Jenkins 的做法

  • 使用 WAR 覆盖的皮肤和提供 Jenkins 的做法

  • 在第二章 增强安全性 中的 通过自定义组脚本审查基于项目矩阵的策略 这一做法

创建 HTML 报告

作业仪表板左侧菜单是有价值的房地产。开发者的眼睛自然会扫描这个区域。这个教程描述了如何将自定义 HTML 报告的链接添加到菜单中,以便更快地注意到报告。

准备工作

安装 HTML 发布者插件(wiki.jenkins-ci.org/display/JENKINS/HTML+Publisher+Plugin)。我们假设你有一个已提交了 Packt 代码的 Subversion 仓库。

怎么做…

  1. 创建一个自由风格的软件项目,并将其命名为ch4.html_report

  2. 源代码管理部分下,单击Subversion

  3. 模块部分下,将Repo/ch4.communicating/html_report添加到存储库 URL,其中Repo是您的子版本存储库的 URL。

  4. 构建后操作部分下,检查发布 HTML 报告。 添加以下详细信息:

    • 要存档的 HTML 目录target/custom_report

    • 索引页面[s]index.html

    • 报告标题My HTML Report

    • 选中保留过去的 HTML 报告复选框

  5. 单击保存

  6. 运行作业并查看左侧菜单。 现在您将看到一个指向您报告的链接,如下面的屏幕截图所示:如何操作...

工作原理...

您的子版本存储库包含一个index.html文件,该文件被拉入作业的工作区。 插件按照广告中的方式运行,并添加了一个指向 HTML 报告的链接。 这使得您的受众可以有效地找到您生成的自定义信息。

还有更多...

示例报告如下所示:

<html><head><title>Example Report</title>
<link rel="stylesheet" type="text/css" href="/css/style.css" /></head>
<body>
<h2>Generated Report</h2>
Example icon: <img title="A Jenkins Icon" alt="Schedule a build" src="img/clock.png" />
</body></html>

它拉取了主 Jenkins 样式表/css/style.css

当您在应用程序中更新样式表时,可能会出现在清除浏览器缓存之前看不到更改的情况。 Jenkins 以一种巧妙的方式解决了这个延迟问题。 它使用一个带有每个 Jenkins 版本都会更改的唯一数字的 URL。 例如,对于css目录,您有两个 URL:

  • /css

  • /static/uniquenumber/css

大多数 Jenkins URL 使用后一种形式。 考虑为您的样式表也这样做。

注意

每个版本的唯一编号都会更改,因此您需要为每次升级更新 URL。

在 Maven 构建中运行site目标时,将生成一个本地网站(maven.apache.org/plugins/maven-site-plugin)。 此网站在 Jenkins 作业内有一个固定的 URL,您可以使用My HTML Report链接指向它。 这使得诸如测试结果之类的文档易于访问。

另请参阅

  • 高效使用视图配方

  • 使用 Dashboard View 插件节省屏幕空间 配方

高效使用视图

Jenkins 具有令人上瘾的易配置性,非常适合创建大量作业。 这会增加开发人员暴露的信息量。 Jenkins 需要通过有效地利用浏览器空间来避免混乱。 一种方法是定义最小化视图。 在本配方中,您将使用 DropDown ViewsTabBar 插件。 它将视图作为标签删除,并用一个选择框替换这些标签。 这有助于更快地导航。 您还将看到如何使用脚本生成的简单 HTML 表单快速提供大量作业。

提示

在本配方中,您将创建大量视图,稍后可能需要删除。 如果您使用的是虚拟盒映像,请考虑克隆映像,并在完成后将其删除。

准备工作

安装 DropDown ViewsTabBar 插件 (wiki.jenkins-ci.org/display/JENKINS/DropDown+ViewsTabBar+Plugin)。

如何操作...

  1. 复制并粘贴以下 Perl 脚本到一个名为create.pl的可执行文件中:

    #!/usr/bin/perl
    $counter=0;
    $end=20;
    $host='http://localhost:8080';
    while($end > $counter){
      $counter++;
      print "<form action=$host/createItem?mode=copy method=POST>\n";
      print "<input type=text name=name value=CH4.fake.$counter>\n";
      print "<input type=text name=from value=Template1 >\n";
      print "<input type=submit value='Create CH4.fake.$counter'>\n";
      print "</form><br>\n";
      print "<form action=$host/job/CH4.fake.$counter/doDelete method=POST>\n";
      print "<input type=submit value='Delete CH4.fake.$counter'>\n";
      print "</form><br>\n";
    }
    
  2. 根据 Perl 脚本的输出创建一个 HTML 文件,例如:

    perl create.pl > form.html
    
  3. 在网页浏览器中,以管理员身份登录 Jenkins。

  4. 创建作业Template1,添加任何您希望的细节。这是您将复制到许多其他作业中的模板作业。

  5. 在同一个浏览器中加载form.html

  6. 点击其中一个创建 CH4.fake按钮。Jenkins 返回一个错误消息:

    HTTP ERROR 403 Problem accessing /createItem. Reason:
    No valid crumb was included in the request
    
  7. 访问http://localhost:8080/configureSecurity上的配置全局安全性,取消勾选防止跨站请求伪造漏洞框。

  8. 点击保存

  9. 点击所有的创建 CH4.fake按钮。

  10. 访问 Jenkins 的首页,验证作业已经创建并基于Template1作业。

  11. 创建大量视图,并随机选择作业。查看首页,注意混乱。

  12. 访问配置屏幕/configure,在视图选项卡栏提供下拉菜单以选择视图中的视图选项卡栏下拉框中选择DropDownViewsTabBar。在DropDownViewsTabBar的子部分中,勾选显示作业计数框,如下图所示:如何操作...

  13. 点击保存按钮:如何操作...

  14. 在 Jenkins 中,访问配置全局安全性http://localhost:8080/configureSecurity,并勾选防止跨站请求伪造漏洞框。

  15. 点击保存

工作原理是...

只要 Jenkins 中的面包屑安全功能关闭,该表单就能正常工作。当开启此功能时,它会生成一个随机数,表单在提交时必须返回该随机数。这样 Jenkins 就知道该表单是与服务器进行的有效对话的一部分。生成的 HTTP 状态错误在 4xx 范围内,这意味着客户端输入无效。如果 Jenkins 返回了 5xx 错误,则意味着服务器错误。因此,在提交我们自己的数据时,我们不得不关闭此功能。我们不建议在生产环境中这样做。

一旦您以管理员身份登录 Jenkins,您可以创建作业。您可以通过 GUI 或通过发送 POST 信息来执行此操作。在本教程中,我们将一个名为Template1的作业复制到以CH4.fake开头的新作业中,如下所示:

<form action=http://localhost:8080/createItem?mode=copy method=POST>
<input type=text name=name value=CH4.fake.1>
<input type=text name=from value=Template1 >
<input type=submit value='Create CH4.fake.1'>
</form>

您使用的 POST 变量是name用于新作业的名称,from用于模板作业的名称。POST 操作的 URL 是/createItem?mode=copy

要更改主机名和端口号,您需要更新 Perl 脚本中找到的$host变量。

要删除一个作业,Perl 脚本生成的表单中的操作指向/job/Jobname/doDelete(例如,/job/CH4.fake.1/doDelete)。不需要额外的变量。

要增加表单条目的数量,您可以更改变量$end的值为20

还有更多...

Jenkins 使用标准库 Stapler (stapler.kohsuke.org/what-is.html)将服务绑定到 URL。插件也使用 Stapler。当您安装插件时,潜在的操作数量也会增加。这意味着您可以通过类似于本文中的 HTML 表单激活许多操作。您将在第七章中发现,使用 Stapler 编写绑定代码所需的工作量很小,探索插件

另见

  • 使用仪表板视图插件节省屏幕空间 步骤

使用仪表板视图插件节省屏幕空间

高效使用视图步骤中,您发现可以使用 Views 插件节省水平选项卡空间。在这个步骤中,您将使用 Dashboard View 插件来压缩水平空间的使用。压缩水平空间有助于高效吸收信息。

仪表板视图插件允许您配置视图的区域以显示特定功能,例如作业的网格视图或显示失败作业子集的区域。用户可以在屏幕上拖放这些区域。

注意

开发人员已经使仪表板易于扩展,因此稍后会有更多选择。

准备工作

安装仪表板视图插件 (wiki.jenkins-ci.org/display/JENKINS/Dashboard+View)。要么手动创建一些作业,要么使用上一个步骤中提供的 HTML 表单创建作业。

操作步骤...

  1. 作为 Jenkins 管理员,登录到 Jenkins 实例的主页。

  2. 点击屏幕顶部的第二个标签页上的+号创建一个新视图。

  3. 选择仪表板视图。

  4. 作业部分,选择一些您的虚拟作业。

  5. 仪表板控件保留为默认设置。

  6. 点击确定。您现在将看到一个空白的视图屏幕。

  7. 在左侧菜单中,点击编辑视图链接。

  8. 在视图的仪表板控件部分,选择以下内容:

    • 将仪表板控件添加到视图顶部:- 作业网格

    • 将仪表板控件添加到视图底部:- 不稳定的作业

  9. 在配置屏幕底部,点击确定按钮。现在您将看到仪表板视图: 操作步骤...

您可以使用箭头图标扩展或收缩功能区域:

操作步骤...

工作原理...

仪表板插件将屏幕划分为不同的区域。在仪表板配置期间,您可以选择作业网格和不稳定的作业控件。其他仪表板控件包括作业列表、最新构建、从属统计、测试统计图或网格以及测试趋势图。随着插件的成熟,将会有更多的选择。

与其他视图相比,作业网格控件节省空间,因为显示的作业密度很高。

提示

如果你还在使用 Many Views 标签(请参阅前面的教程),可能会有一点小问题。当你点击仪表板标签时,会显示原始的视图集,而不是选择框。

还有更多...

仪表板插件提供了一个框架,供其他插件开发者创建仪表板视图。这种用法的一个例子是项目统计插件 (wiki.jenkins-ci.org/display/JENKINS/Project+Statistics+Plugin)。

另请参阅

  • 创建 HTML 报告 教程

  • 高效使用视图 教程

使用 HTML5 浏览器发出声音

这个教程描述了如何在 Jenkins 用户的浏览器中发送自定义声音,当事件发生时,比如一个成功的构建。你也可以在任意时间发送声音消息。这不仅适用于喜欢被名人唱歌或者大喊的开发者,也适用于在大型服务器群中寻找计算机的系统管理员。

准备工作

安装 Jenkins 声音插件 (wiki.jenkins-ci.org/display/JENKINS/Jenkins+Sounds+plugin)。确保已安装兼容的网络浏览器,如最新版本的 Firefox 或 Chrome。

注意

若要了解更多关于浏览器中的 HTML5 兼容性的详细信息,请考虑查阅:en.wikipedia.org/wiki/Comparison_of_layout_engines_%28HTML5%29

如何做...

  1. 以 Jenkins 管理员身份登录,访问配置系统屏幕/configure

  2. Jenkins 声音部分,勾选通过启用 HTML5 音频浏览器播放

    注意

    如果 Jenkins 在查找声音存档时出现问题,例如错误消息中出现文件未找到 'file:/C:/Users/Alan/.jenkins/jar:file:/C:/Users/Alan/.jenkins/plugins/sounds/WEB-INF/lib/classes.jar/sound-archive.zip',那么解压classes.jar文件,并将sounds-archive.zip文件移动到错误消息中提到的相同目录中。最后,将配置指向存档,例如file:/C:/Users/Alan/.jenkins/plugins/sounds/WEB-INF/lib/sound-archive.zip

  3. 点击保存按钮。

  4. 选择位于 Jenkins 主页上的Job creation链接。

  5. 创建一个名为 ch4.sound新作业

  6. 选择构建一个自由风格的软件项目

  7. 点击确定

  8. 后构建操作部分,勾选Jenkins 声音选项。

  9. 添加两个声音:EXPLODEdoh如何做...

  10. 点击保存

  11. 点击立即构建链接。

  12. 成功时,你的浏览器将播放EXPLODEwav 文件。

  13. 编辑你的作业,使其失败,例如添加一个不存在的源代码仓库。

  14. 再次构建任务。失败时,你的网络浏览器将播放dohwav 文件。

工作原理...

你已成功配置了你的作业,根据构建的成功或失败播放不同的声音。

您还可以通过配置哪些事件转换将触发声音来进一步优化插件的反应,例如,如果前一个构建结果是失败,当前构建结果是成功。这在对于上一个构建结果一组复选框中定义。

该插件作为页面装饰器工作。它添加了以下异步轮询新声音的 JavaScript。您的浏览器正在执行大部分工作,释放服务器资源:

<script src="img/script" type="text/javascript"></script><script type="text/javascript" defer="defer">function _sounds_ajaxJsonFetcherFactory(onSuccess, onFailure) {
  return function() {
    newAjax.Request("/sounds/getSounds", {
      parameters: { version: VERSION },
      onSuccess: function(rsp) {
        onSuccess(eval('x='+rsp.responseText))
      },
      onFailure: onFailure
    });
  }
} 
if (AUDIO_CAPABLE) {
    _sounds_pollForSounds(_sounds_ajaxJsonFetcherFactory);
}</script>

还有更多...

该声音插件还允许您向连接的网络浏览器流式传输任意声音。这不仅对于恶作剧和针对您分布式团队的激励演讲有用,还可以执行诸如在重新启动服务器之前发出 10 分钟警告警报等有用操作。

您可以在www.archive.org/details/opensource_audio找到一些不错的音乐收藏。

例如,您可以在www.archive.org/details/OpenPathMusic44V2找到一份“每个孩子一台笔记本电脑”音乐库的副本。在收藏中,您将发现shenai.wav。首先,将声音添加到互联网上的某个地方,以便找到。一个好的地方是 Jenkins 的userContent目录。要在任何连接的网络浏览器上播放声音,您需要访问触发地址(将localhost:8080替换为您自己的地址):

http://localhost:8080/sounds/playSound?src=http://localhost:8080/userContent/shenai.wav

另请参阅

  • 在第一章中的 Maintaining Jenkins通过 Firefox 与 Jenkins 保持联系 配方

接待区的极端观点

敏捷项目强调沟通的作用胜过于文档的需求。信息辐射器有助于快速获得反馈。信息辐射器具有两个主要特征:它们随时间变化,并且呈现的数据易于消化。

eXtreme Feedback Panel 插件是信息辐射器的一个示例。它是一个高度视觉化的 Jenkins 视图。如果布局格式一致,并在大型监视器上显示,则非常适合此任务。还将其视为对您的开发流程的积极广告。您可以将其显示在接待处后面,或者放在一个受欢迎的社交区域,例如靠近咖啡机或项目室。

在此配方中,您将添加 eXtreme Feedback Panel 插件,并通过描述中的 HTML 标签修改其外观。

准备工作

安装 eXtreme Feedback Panel 插件(wiki.jenkins-ci.org/display/JENKINS/eXtreme+Feedback+Panel+Plugin)。

如何做...

  1. 创建一个名为Blackboard Report Pro Access的作业,并添加以下描述:

    <center>
    <p>Writes Blackboard sanity reports<br>
    and sends them to a list.
    <table border="1" class="myclass"><tr><td>More Details</td></tr></table>
    </center>
    
  2. 创建一个名为eXtreme的新视图(/newView)。选中 eXtremeFeedBack Panel,然后点击 OK

  3. 选择 6-24 个已经创建的作业,包括本配方中之前创建的作业。

  4. 将列数设置为2

  5. 将刷新时间设置为20秒。

  6. 点击显示作业描述

  7. 点击确定

  8. 尝试设置(特别是字体像素大小)。优化视图取决于使用的显示器以及观众观看显示器的距离,如下图所示:如何做...

它的工作原理...

设置和运行这个信息辐射器很容易。结果呈现了软件流程动态的精美视图。

将刷新率设置为 20 秒存在争议。更新之间的长时间延迟会降低观看者的兴趣。

你已经写了一个描述,在极端视图中部分格式化,但在作业配置页面和 Jenkins 的其他位置中是 HTML 转义的。你可以看到信息区比其他项目更容易消化。这突显了编写一致描述的必要性,这些描述遵循内部惯例,并且在一定长度以下,以自然地适应屏幕。为工作取一个更长、更具描述性的名称有助于观众更好地理解工作的背景。

注意

通过 URL http://localhost:8080/view/Jobname/configure快速配置视图,将Jobname中的任何空格替换为%20

还有更多...

信息辐射器有趣且形态各异。从在大型显示器上显示不同视图,到 USB 海绵导弹的发射和名人的声音滥用(参见使用 HTML5 浏览器制造噪音配方)。

Jenkins 中值得探索的一些示例电子项目包括:

记住,让我们小心一些。

另请参阅

  • 使用仪表板视图插件节省屏幕空间配方

  • 使用 HTML5 浏览器制造噪音配方

使用 Google 日历进行移动演示

Jenkins 插件可以将构建历史推送到不同的知名社交媒体服务。现代 Android 或 iOS 手机预装了这两种服务的应用程序,降低了采用的门槛。在这个配方中,我们将配置 Jenkins 与 Google 日历一起工作。

准备工作

下载并安装 Google 日历插件(wiki.jenkins-ci.org/display/JENKINS/Google+Calendar+Plugin)。确保你有一个用于 Gmail 的测试用户帐户。

如何做...

  1. 登录 Gmail 并访问日历页面。

  2. 通过单击添加链接在我的日历部分下创建新的日历。

  3. 添加日历名称 Test for Jenkins

  4. 点击 创建日历。默认情况下,新日历是私有的。暂时保持私有。

  5. 我的日历 部分,点击 Test for Jenkins 旁边的向下图标。选择 日历设置 选项。

  6. 在 XML 按钮上右键单击 复制链接位置如何做...

  7. 查看 嵌入此日历 部分。它描述了如何将您的日历添加到网页中。将提供的代码复制并粘贴到空的 HTML 页面中。保存并在 web 浏览器中查看。

  8. 以管理员身份登录 Jenkins。

  9. 创建一个名为 Test_G 的新作业。

  10. 构建后 部分,勾选 将作业状态发布到 Google 日历

  11. 将您从 XML 按钮复制的日历详细信息添加到 日历网址 文本框中。

  12. 添加您的 Gmail 登录名和密码。

    提示

    您的 Gmail 凭据将以明文形式存储在 server.xml 文件中。除非您的服务器得到了适当的安全保护,否则不建议这样做。

    如何做...

  13. 点击 保存

  14. 构建您的作业,确保它成功。

  15. 登录 Gmail。访问 日历 页面。您现在会看到构建成功已经发布,如下面的截图所示:如何做...

工作原理...

通过在 Google 中创建日历,并仅使用三个配置设置,您已将选定的 Jenkins 作业暴露给了 Google 日历。使用相同数量的配置,您可以将大多数现代智能手机和平板电脑连接到日历。

注意

Jenkins 有一个凭据管理器,您可以在 http://localhost:8080/credential-store/ 找到它。凭据管理器可以与许多插件一起使用;然而,在撰写本文时,与 Google 日历插件不兼容。获取最新的兼容性信息,请访问:wiki.jenkins-ci.org/display/JENKINS/Credentials+Plugin

还有更多...

在 Jenkins 工作空间中的插件目录下,您将找到一个用于 Google 插件配置帮助的 HTML 文件 /plugins/gcal/help-projectConfig.html

用以下内容替换原文:

<div>
<p>
Add your local comments here:
</p>
</div>

重新启动 Jenkins 服务器后,访问插件配置 /configure。您现在会看到新内容,如下面的截图所示:

还有更多...

此示例是一种反模式。如果您需要根据本地需求更改内容,那么最好与社区合作,在 Jenkins SCM 中添加内容,以便每个人都能看到并改进。

您将立即收到通知,您的内容尚未国际化。它需要翻译成 Jenkins 原生支持的语言。幸运的是,在每个 Jenkins 页面的底部,都有一个链接,志愿者可以使用它来上传翻译。翻译需要很少的启动工作量,并且是开始参与开源项目的简单方式。

注意

有关如何在 Jenkins 中使用属性文件进行国际化的更多开发详细信息,请阅读 wiki.jenkins-ci.org/display/JENKINS/Internationalization

另请参阅

  • Android 和 iOS 的移动应用程序 教程

Android 和 iOS 的移动应用程序

有许多用于通知 Jenkins 作业状态的丰富移动应用程序。本教程指向它们的主页,以便您可以选择您喜欢的。

准备就绪

您将需要一个可以从互联网访问的 Jenkins 实例或使用 ci.jenkins-ci.org/,这是最佳实践的一个很好的例子。我们还假设您有一个移动设备。

如何做...

  1. 作为管理员,访问配置系统/configure)屏幕。

  2. 检查 Jenkins URL;如果指向 localhost,请更改为使您的服务器链接能够从互联网访问。

  3. 访问以下应用程序页面,如果兼容,安装并使用:

  4. 在您的移动设备上,搜索 Google Marketplace 或 iTunes 并安装任何新的 Jenkins 应用程序,这些应用程序是免费的并具有积极的用户推荐。

它是如何工作的...

大多数应用程序使用 Jenkins 的 RSS 源(例如 /rssLatest/rssFailed)获取信息,然后通过移动 Web 浏览器加载链接的页面。除非 Jenkins URL 配置正确,否则链接将断开,您的浏览器将返回404 页面未找到错误。

您很快会注意到,您的应用程序刷新率可能会产生过多的通知,与接收及时信息之间存在微妙的平衡。

JenkinsMobi 应用可以在 Android 和 iOS 操作系统上运行。它使用 XML 的远程 API 来收集数据 (www.slideshare.net/lucamilanesio/jenkinsmobi-jenkins-xml-api-for-mobile-applications),而不是更原始的 RSS 订阅。这个选择使得应用的作者能够添加各种功能,使其成为收藏中最引人注目的应用之一。

还有更多...

这里还有一些需要考虑的事情。

Android 1.6 和 Hudson 应用

Jenkins 由于关于 Hudson 名称的商标问题而从 Hudson 的源代码中分离出来 (en.wikipedia.org/wiki/Jenkins_%28software%29)。大多数开发者转向了与 Jenkins 的合作。这导致了很多第三方 Hudson 代码要么得不到支持,要么被重新命名为 Jenkins。然而,Hudson 和 Jenkins 有很大的共同基础,包括 RSS 订阅的内容。这些细节可能随着时间的推移而有所不同。对于较旧版本的 Android,如 Android 1.6,在 Google Marketplace 中你不会看到任何 Jenkins 应用。可以尝试寻找 Hudson 应用。它们大多在 Jenkins 上运行。

Virtualbox 和 Android x86 项目

有多种选择可以运行 Android 应用。最简单的方法是通过 Google Marketplace 下载到移动设备上。然而,如果你想在 PC 上通过模拟器来玩耍 Android 应用,可以考虑下载 Android SDK (developer.android.com/sdk/index.html),并使用模拟器和像 adb 这样的工具 (developer.android.com/guide/developing/tools/adb.html) 来上传和安装应用。

你也可以通过 VirtualBox、VMware Player 等虚拟机运行一个 x86 映像 (www.android-x86.org)。这种方法的一个显著优势是 Android OS 的原始速度,以及保存虚拟机在特定状态下的能力。然而,你不会总是得到预安装的 Google Marketplace。你要么自己找到特定应用的 .apk 文件,要么添加其他的市场,比如 Slide me (m.slideme.org)。不幸的是,第二市场提供的选择要少得多。

Virtualbox 和 Android x86 项目

Windows Android 模拟器 bluestacks.com/home.html 展示了很大的潜力。它不仅是一个模拟器,还提供了一个云服务,可将应用程序从您的移动设备移入和移出模拟器。这承诺是一种高效的开发方法。然而,如果您选择使用此模拟器,请务必彻底审查您在安装时同意的许可证。BlueStacks 希望获取关于您的系统的详细信息,以帮助改进其产品。

参见

  • 使用 Google 日历进行移动演示的食谱

通过 Google Analytics 了解您的受众

如果您有将构建历史或其他信息(例如主页)推送到公共位置的策略,那么您将希望了解查看者的习惯。一种方法是使用 Google Analytics。通过 Google,您可以实时观察访问者访问您的网站。详细的报告提到了流量的整体量、浏览器类型(例如,如果移动应用程序正在访问您的网站)、入口点和国家来源等内容。当您的产品达到路线图的关键点并且您希望了解客户兴趣时,这是特别有用的。

在此食谱中,您将创建一个 Google Analytics 帐户并在 Jenkins 中配置跟踪。然后,您将实时观看流量。

准备工作

安装 Google Analytics 插件 (wiki.jenkins-ci.org/display/JENKINS/Google+Analytics+Plugin)。

提示

如果您不是 Jenkins URL 的所有者,请在创建 Google Analytics 档案之前先征得许可。

如何操作...

  1. 使用您的 Gmail 帐户登录 Google Analytics (www.google.com/analytics/)。

  2. 填写创建新帐户页面的详细信息:

    • 账户名称:我的 Jenkins 服务器

    • 网站名称:Jenkins 服务器 X

    • 网站 URL:与 Jenkins /configure 屏幕中的 Jenkins URL 相同。

    • 报告时区:输入正确的值

    • 选择数据共享设置 | 共享设置 | 不共享我的 Google Analytics 数据

    • 点击获取跟踪 ID

    • 点击接受以接受Google Analytics 服务条款

  3. 点击创建帐户

  4. 您现在位于新创建的档案的 帐户 页面。复制 TrackingID,类似于 UA-121212121212121-1

  5. 打开第二个浏览器,并以管理员身份登录 Jenkins。

  6. Jenkins 配置系统 屏幕 (/configure) 中,添加从 Google Analytics Web Property ID 复制的 Profile ID,并将 Domain Name 设置为您的 Jenkins URL。

  7. 点击保存按钮。

  8. 访问 Jenkins 的首页以触发跟踪。

  9. 返回 Google Analytics,您应该仍然在 跟踪代码 选项卡上。点击页面底部的 保存。现在,您将看到警告 跟踪未安装 已消失。

工作原理...

该插件在每个 Jenkins 页面上都添加了一个 JavaScript 页面跟踪器,其中包括域和配置文件 ID。JavaScript 是通过从 Google Analytics 主机中获取并保持更新的,如下所示的代码所示:

<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', ' UA-121212121212121-1']);
_gaq.push(['_setDomainName', 'Domain Name']);
_gaq.push(['_trackPageview']);

(function() {
  varga = document.createElement('script'); 
  ga.type = 'text/javascript'; ga.async = true;
  ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
  var s = document.getElementsByTagName('script')[0]; 
  s.parentNode.insertBefore(ga, s);
})();
</script>

Google Analytics 有能力彻底深入了解您的网络使用情况。考虑浏览 Jenkins 并查看通过实时报告功能生成的流量。

注意

Google 定期更新其分析服务。如果您注意到任何更改,则分析的帮助页面将记录这些更改(support.google.com/analytics)。

还有更多...

Google Analytics 的开源版本是 Piwik(piwik.org/)。您可以在本地设置服务器并使用等效的 Jenkins 插件(wiki.jenkins-ci.org/display/JENKINS/Piwik+Analytics+Plugin)来生成统计信息。这样做的好处是可以将您的本地数据使用保持在您的控制之下。

顾名思义,Piwik 插件是一个页面装饰器,以与 Google Analytics 插件类似的方式注入 JavaScript。

另请参阅

  • 生成首页 示例

使用 R 插件简化强大的可视化效果

R 是一种流行的统计编程语言 en.wikipedia.org/wiki/R_(programming_language)。它有许多扩展,并具有强大的图形功能。在本示例中,我们将向您展示如何在 Jenkins 任务中使用 R 的图形功能,然后指向一些优秀的入门资源。

注意

要查看可改善 Jenkins UI 的插件的完整列表,包括 Jenkins 的图形功能,请访问 wiki.jenkins-ci.org/display/JENKINS/Plugins#Plugins-UIplugins

准备工作

安装 R 插件(wiki.jenkins-ci.org/display/JENKINS/R+Plugin)。查看 R 安装文档(cran.r-project.org/doc/manuals/r-release/R-admin.html)。

如何做...

  1. 从命令行安装 R 语言:

    sudo apt-get install r-base
    
    
  2. 查看可用的 R 包:

    apt-cache search r-cran | less
    
    
  3. 创建一个名为 ch4.powerfull.visualizations 的自由式任务。

  4. 构建 部分,在 添加构建步骤 下选择 执行 R 脚本

  5. 脚本 文本区域添加以下代码:

    paste('=======================================');
    paste('WORKSPACE: ', Sys.getenv('WORKSPACE'))
    paste('BUILD_URL: ', Sys.getenv('BUILD_URL'))
    print('ls /var/lib/jenkins/jobs/R-ME/builds/')
    paste('BUILD_NUMBER: ', Sys.getenv('BUILD_NUMBER'))
    paste('JOB_NAME: ', Sys.getenv('JOB_NAME'))
    paste('JENKINS_HOME: ', Sys.getenv('JENKINS_HOME'))
    paste( 'JOB LOCATION: ', Sys.getenv('JENKINS_HOME'),'/jobs/',Sys.getenv('JOB_NAME'),'/builds/', Sys.getenv('BUILD_NUMBER'),"/test.pdf",sep="")
    paste('=======================================');
    
    filename<-paste('pie_',Sys.getenv('BUILD_NUMBER'),'.pdf',sep="")
    pdf(file=filename)
    slices<- c(1,2,3,3,6,2,2)
    labels <- c("Monday", "Tuesday", "Wednesday", "Thursday", "Friday","Saturday","Sunday")
    pie(slices, labels = labels, main="Number of failed jobs for each day of the week")
    
    filename<-paste('freq_',Sys.getenv('BUILD_NUMBER'),'.pdf',sep="")
    pdf(file=filename)
    Number_OF_LINES_OF_ACTIVE_CODE=rnorm(10000, mean=200, sd=50)
    hist(Number_OF_LINES_OF_ACTIVE_CODE,main="Frequency plot of Class Sizes")
    
    filename<-paste('scatter_',Sys.getenv('BUILD_NUMBER'),'.pdf',sep="")
    pdf(file=filename)
    Y <- rnorm(3000)
    plot(Y,main='Random Data within a normal distribution')
    
  6. 点击 保存 按钮。

  7. 点击 立即构建 图标。

  8. 构建历史 下,点击 工作空间 按钮。

  9. 通过单击链接 freq_1.pdfpie_1.pdfscatter_1.pdf 来查看生成的图形,如下截图所示:如何做...

以下截图是由 R 脚本在构建过程中生成的随机数据的值的直方图。该数据模拟了大型项目中的班级规模。

如何操作...

另一个视图是饼图。伪数据表示一周中每天失败任务的数量。如果你将其与你自己的值绘制在一起,可能会看到特别糟糕的日子,比如周末前后的日子。这可能会影响开发人员的工作方式,或者周内的动力分配。

如何操作...

执行以下步骤:

  1. 运行任务并查看 工作区

  2. 点击 控制台输出。你会看到类似于以下内容的输出:

    Started by user anonymous
    Building in workspace /var/lib/jenkins/workspace/ch4.Powerfull.Visualizations
    [ch4.Powerfull.Visualizations] $ Rscript /tmp/hudson6203634518082768146.R
    [1] "======================================="
    [1] "WORKSPACE:  /var/lib/jenkins/workspace/ch4.Powerfull.Visualizations"
    [1] "BUILD_URL:  "
    [1] "ls /var/lib/jenkins/jobs/R-ME/builds/"
    [1] "BUILD_NUMBER:  9"
    [1] "JOB_NAME:  ch4.Powerfull.Visualizations"
    [1] "JENKINS_HOME:  /var/lib/jenkins"
    [1] "JOB LOCATION: /var/lib/jenkins/jobs/ch4.Powerfull.Visualizations/builds/9/test.pdf"
    [1] "======================================="
    Finished: SUCCESS
    
    
  3. 点击 返回项目

  4. 点击 工作区

工作原理...

用几行 R 代码,你就生成了三个不同的、精美的 PDF 图表。

R 插件在构建过程中运行了一个脚本。该脚本将 WORKSPACE 和其他 Jenkins 环境变量打印到控制台上:

paste ('WORKSPACE: ', Sys.getenv('WORKSPACE'))

然后,文件名以附加到字符串 pie_ 的构建号设置。这样可以使脚本每次运行时生成不同的文件名,如下所示:

filename <-paste('pie_',Sys.getenv('BUILD_NUMBER'),'.pdf',sep="")

脚本现在通过命令 pdf(file=filename) 打开输出到 filename 变量中定义的位置。默认情况下,输出目录是任务的工作区。

接下来,我们为图表定义了伪数据,表示一周中任意一天失败任务的数量。注意,在模拟世界中,星期五是一个糟糕的日子:

slices <- c(1,2,3,3,6,2,2)
labels <- c("Monday", "Tuesday", "Wednesday", "Thursday", "Friday","Saturday","Sunday")

绘制饼图:

pie(slices, labels = labels, main="Number of failed jobs for each day of the week")

对于第二个图表,我们在正态分布内生成了 10,000 个随机数据。伪数据表示运行给定作业的活动代码行数,如下所示:

Number_OF_LINES_OF_ACTIVE_CODE=rnorm(10000, mean=200, sd=50)

hist 命令生成频率图:

hist(Number_OF_LINES_OF_ACTIVE_CODE,main="Frequency plot of Class Sizes")

第三个图表是一个散点图,包含在正态分布内随机生成的 3,000 个数据点。这代表了一个典型的抽样过程,比如使用 Sonar 或 FindBugs 找到的潜在缺陷数量,如下所示:

Y <- rnorm(3000)
plot(Y,main='Random Data within a normal distribution')

我们将把将真实数据与 R 的绘图功能链接起来的工作留给读者作为练习。

更多内容...

这里还有几点让你思考。

RStudio 或 StatET

用于 R 的一个流行的 IDE 是 RStudiowww.rstudio.com/)。开源版本是免费的。功能集包括带有代码完成和语法高亮的源代码编辑器、集成帮助、可靠的调试功能以及一系列其他功能,如下面的截图所示:

RStudio 或 StatET

Eclipse 环境的另一种选择是 StatET 插件(www.walware.de/goto/statet)。

快速获取帮助

学习 R 的第一步是从 R 控制台输入 help.start()。该命令会启动一个带有主要文档概述的浏览器。

如果你想要 R 命令的描述,那么在命令前输入 ? 将生成详细的帮助文档。例如,在我们查看 rnorm 命令的配方时。键入 ?rnorm 将产生类似的文档:

正态分布

描述

用平均值等于 mean 和标准差等于 sd 的正态分布的密度、分布函数、分位数函数和随机生成。

使用方法

dnorm(x, mean = 0, sd = 1, log = FALSE)

pnorm(q, mean = 0, sd = 1, lower.tail = TRUE, log.p = FALSE)

qnorm(p, mean = 0, sd = 1, lower.tail = TRUE, log.p = FALSE)

rnorm(n, mean = 0, sd = 1)

了解更多信息

R 语言有很好的文档。以下是一些有用的资源:

另请参阅

  • 在 第五章 的 使用指标来提高质量 中的 使用 R 插件分析项目数据 配方

第五章。使用指标提高质量

在本章中,我们将涵盖以下内容:

  • 通过 Sloccount 估算你的项目价值

  • 通过代码覆盖率查找“臭味”代码

  • 激活更多的 PMD 规则集

  • 创建自定义 PMD 规则

  • 使用 FindBugs 查找错误

  • 启用额外的 FindBug 规则

  • 使用 FindBugs 查找安全缺陷

  • 验证 HTML 的有效性

  • 使用 JavaNCSS 进行报告

  • 使用外部 pom.xml 文件检查样式

  • 伪造 Checkstyle 结果

  • 将 Jenkins 与 SonarQube 集成

  • 使用 R 插件分析项目数据

    注意

    一些构建文件和代码有故意的错误,比如糟糕的命名约定、糟糕的编码结构或平台特定的编码。

    这些缺陷存在是为了让 Jenkins 有一个测试的目标。

介绍

本章探讨了使用 Jenkins 插件显示代码指标和失败构建。自动化降低成本并提高一致性。这个过程不会感到疲倦。如果你在项目开始之前确定了成功和失败的标准,那么这将减少发布会议中的主观辩论。

在 2002 年,NIST 估计软件缺陷每年给美国造成了大约 600 亿美元的损失 (www.abeacha.com/NIST_press_release_bugs_cost.htm)。预计这个成本已经大大增加。

为了节省成本并提高质量,你需要尽早在软件生命周期中消除缺陷。Jenkins 测试自动化创建了一张测量的安全网。另一个关键的好处是,一旦你添加了测试,就很容易为其他项目开发类似的测试。

Jenkins 与最佳实践(如测试驱动开发TDD)或行为驱动开发BDD))配合得很好。使用 TDD,你首先编写失败的测试,然后构建通过测试所需的功能。使用 BDD,项目团队以行为的形式编写测试描述。这使得描述对更广泛的受众可理解。更广泛的受众对实施细节具有更多的影响。

回归测试增加了重构软件时没有破坏代码的信心。代码测试覆盖率越高,信心越足。通过代码覆盖率查找“有异味”的代码的方法向您展示了如何使用 Cobertura(cobertura.github.io/cobertura/)来测量覆盖率。类似的框架还有 Emma(emma.sourceforge.net/)。您还会在静态代码审查方面找到 PMD 和 FindBugs 的相关方法。静态意味着您可以查看代码而无需运行它。PMD 检查.java文件是否存在特定的错误模式。使用 PMD 规则设计器编写新的错误检测规则相对较容易。FindBugs 扫描编译后的.class文件;您可以直接查看应用的.jar文件。FindBugs 规则准确,大多数指向实际缺陷。在本章中,您将使用 FindBugs 搜索安全缺陷,并使用 PMD 搜索设计规则违例。

本章还提到了使用已知缺陷的 Java 类。我们将使用这些类来检查测试工具的价值。这与病毒检查器的基准类似,病毒检查器会解析具有已知病毒签名的文件。注入已知缺陷的优势在于您可以了解到违反的规则。这是收集项目中发现的实际缺陷并对其进行特征化和重复利用的好方法。考虑将自己的类添加到项目中,以查看 QA 过程是否能够捕捉到缺陷。

良好的文档和源代码结构有助于代码的可维护性和可读性。Sun 编码规范强制执行跨项目的一致标准。在本章中,您将使用 Checkstyle 和 JavaNCSS 来将您的源代码与 Sun 编码规范进行比较(www.oracle.com/technetwork/java/codeconventions-150003.pdf)。

Jenkins 插件生成的结果可以通过违例插件(wiki.jenkins-ci.org/display/JENKINS/Violations)聚合为一个报告。还有其他针对特定工具的插件,例如 PMD 或 FindBugs 插件。这些插件由分析收集器插件支持(wiki.jenkins-ci.org/display/JENKINS/Analysis+Collector+Plugin),该插件将其他报告聚合为一个统一的整体。可以通过 Portlets 仪表板插件显示单个插件报告,该插件在第四章 通过 Jenkins 进行通信中讨论过 使用仪表板视图插件节约屏幕空间

Jenkins 不仅限于测试 Java;许多插件如 SLOCCount 或 DRY 插件(它可以发现代码的重复)是与语言无关的。甚至还有针对.NET 中的 NUnit 测试或其他语言的编译的特定支持。

注意

NUnit、JUnit、RUnit 和几个其他单元测试框架都遵循 xUnit 标准。详细信息请参阅维基百科条目:en.wikipedia.org/wiki/XUnit

如果你缺少特定功能,你总是可以按照第七章 插件探索中的详细说明构建自己的 Jenkins 插件。

有许多关于软件度量的好介绍。这些包括关于指标细节的维基书籍(en.wikibooks.org/wiki/Introduction_to_Software_Engineering/Quality/Metrics)和 Diomidis Spinellis 撰写的一本写得很好的书籍Code Quality: The Open Source Perspective

在本章的将 Jenkins 与 SonarQube 集成中,你将把 Jenkins 项目链接到 Sonar 报告上。Sonar 是一个专业工具,用于收集软件指标并将其分解为可理解的报告。Sonar 详细说明了项目的质量。它使用了一系列指标,包括本章中提到的 FindBugs 和 PMD 等工具的结果。项目本身正在快速发展。考虑使用 Jenkins 进行早期警告并发现明显的缺陷,比如糟糕的提交。然后你可以使用 Sonar 进行更深入的审查。

最后,你将运行解析项目中所有文件并报告简单指标的 R 代码。这个自定义过程很容易根据 R 语言中包含的丰富的统计包进行复杂的分析。

注意

在撰写本文时,FindBugs 和 PMD Jenkins 插件都需要特定版本的 Maven。作为管理员,你可以通过主配置屏幕(http://hostname/configure)下的Maven部分,通过按下添加 Maven按钮来自动安装 Maven 版本。稍后当你创建一个任务时,Jenkins 会给你选择 Maven 版本的选项。

当处理多模块的 Maven 项目时,Maven 插件会生成一系列结果。Maven 项目类型严格假设结果存储在常规位置,但这并不总是一致的。对于自由样式项目,你可以明确告诉 Jenkins 插件在哪里找到结果,使用与 Ant 文件集一致的正则表达式(ant.apache.org/manual/Types/fileset.html)。

通过 sloccount 估算你项目的价值

了解项目价值的一种方法是计算项目中的代码行数并在代码语言之间进行计数。 由 Dr. David Wheeler(www.dwheeler.com/sloccount/)编写的 SLOCCount,发音为“sloc-count”,是一个用于计算潜在大型软件系统中物理源代码行(SLOC)的命令行工具套件。 通过这些指标,您可以估算编写代码和估算开发成本需要多少小时。

准备工作

安装 SLOCCount 插件(wiki.jenkins-ci.org/display/JENKINS/SLOCCount+Plugin)。 为此配方代码创建一个新目录。 如 www.dwheeler.com/sloccount 所述,在 Jenkins 实例上安装 SLOCCount。 如果您正在运行 Debian 操作系统,则以下安装命令将起作用:

sudo apt-get install sloccount

有关如何在其他系统上安装 SLOCCount 的详细信息,请查看:www.dwheeler.com/sloccount/sloccount.html

如何操作...

  1. 创建一个自由风格的项目并将其命名为ch5.quality.sloccount。 将SLOCCOUNT REPORT Project添加为描述。

  2. 源代码管理部分,勾选Subversion,添加存储库 URLsource.sakaiproject.org/svn/shortenedurl/trunk

  3. 构建部分中,从添加构建步骤中选择执行 shell。 添加/usr/bin/sloccount --duplicates --wide --details . >./sloccount.sc 命令

  4. 后构建操作部分,检查发布 SLOCCount 分析结果,添加到文本输入SLOCCount 报告sloccount.sc

  5. 单击保存

运行任务并查看详情。 您现在将看到相关语言的概述,如下图所示:

如何操作...

在顶级,您还将看到随时间推移代码每种语言的代码行数的时间序列。 这对需要估算完成项目所需资源的经理非常有用:

如何操作...

报告还允许您深入研究特定文件。 文件越大,开发人员就越容易迷失代码的含义。 如果您看到一个特别大的文件,那么值得审查,如下图所示:

如何操作...

要将您生成的报告与更广泛的 Sakai 项目进行比较,请访问www.openhub.net/p/sakai#

工作原理...

该秘籍引入了实际代码,这是一个基于 Java 的服务,用于生成缩短的 URL(confluence.sakaiproject.org/display/SHRTURL)。Jenkins 插件将 SLOCCount 生成的结果转换为详细信息。报告分为四个标签页的表格,按文件、模块、文件夹和语言进行汇总和排序。通过这些信息,您可以估计从头开始重建项目所需的工作程度。

工作描述包含指向 open hub (blog.openhub.net/2014/07/black-duck-open-hub/) 的 URL,这是一个值得信赖的第三方服务。Open hub 是一个众所周知的服务,其隐私规则有着良好的描述(blog.openhub.net/privacy/)。然而,如果您不完全信任第三方服务的声誉,那么就不要通过 Jenkins 描述进行链接。

您可以通过访问www.openhub.net/p/sakai#了解有关 Sakai 学习管理系统的信息。缩短的 URL 服务只是其中的一小部分。综合统计数据可以让访问者更好地了解更广泛的背景,如下面的屏幕截图所示:

它是如何工作的...

还有更多...

还有一些细节需要考虑。

软件成本估算

SLOCCount 使用 COCOMO 模型 (en.wikipedia.org/wiki/COCOMO) 来估算项目成本。您不会在 Jenkins 报告中看到此内容,但如果您从命令行运行 SLOCCount,您可以生成估算成本。

成本估计为 effort * personcost * overhead

随着时间推移,变化最大的元素是人力成本(以美元计)。您可以使用命令行参数–personcost来更改该值。

再见 Google 代码搜索;你好 code.ohoh.net

谷歌宣布已关闭其源代码搜索引擎。幸运的是,code.ohloh.net(之前是koders.com)另一个可行的搜索引擎,宣布将提供对ohloh.net中描述的代码库的覆盖。使用这个搜索引擎,您将能够审查大量的开源项目。该搜索引擎补充了您可以在您喜爱的在线存储库(如 GitHub 和 Bitbucket)中搜索的代码。

另请参阅

  • 通过 Jenkins 进行通信 的第四章中的 使用 Google Analytics 了解您的受众 秘籍

  • 使用 R 插件分析项目数据 秘籍

通过代码覆盖寻找“臭味”代码

本秘籍使用 Cobertura (cobertura.sourceforge.net/) 来查找未被单元测试覆盖的代码。

没有持续的实践,编写单元测试将变得像向stdout写入调试信息一样困难。大多数流行的 Java 特定 IDE 都内置支持运行单元测试。Maven 将它们作为测试目标的一部分运行。如果您的代码没有回归测试,那么在重构过程中代码更容易中断。测量代码覆盖率可用于搜索未测试代码的热点。

欲了解更多信息,您可以查看:onjava.com/onjava/2007/03/02/statement-branch-and-path-coverage-testing-in-java.html

准备工作

安装 Cobertura 代码覆盖插件 (wiki.jenkins-ci.org/display/JENKINS/Cobertura+Plugin)。

怎么做...

  1. 使用以下命令生成模板项目:

    mvn archetype:generate -DgroupId=nl.berg.packt.coverage -DartifactId=coverage -DarchetypeArtifactId=maven-archetype-quickstart -Dversion=1.0-SNAPSHOT 
    
    
  2. 使用以下命令测试未修改项目的代码覆盖率:

    mvn clean cobertura:cobertura
    
    
  3. 审查 Maven 的输出。它看起来类似于以下输出:

    -------------------------------------------------------
    T E S T S
    -------------------------------------------------------
    Running nl.berg.packt.coverage.AppTest
    Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time
    elapsed: 0.036 sec
    
    Results :
    Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
    
    [INFO] [cobertura:cobertura {execution: default-cli}]
    [INFO] Cobertura 1.9.4.1 - GNU GPL License (NO WARRANTY) –
    Cobertura: Loaded information on 1 classes.
    Report time: 107ms
    [INFO] Cobertura Report generation was successful.
    
    
  4. 在网络浏览器中,查看/target/site/cobertura/index.html。请注意,如下屏幕截图所示,没有代码覆盖率:怎么做...

  5. 将以下内容添加到src/main/java/nl/berg/packt/coverage/Dicey.java

    package nl.berg.packt.coverage;
    import java.util.Random;
    public class Dicey {
      private Random generator;
      public Dicey(){
        this.generator = new Random();
        throwDice();
      }
    
      private int throwDice() {
        int value = generator.nextInt(6) + 1;
        if (value > 3){
          System.out.println("Dice > 3");
        }else{
          System.out.println("Dice < 4");
        }
        return value;
      }
    }
    
  6. 修改src/test/java/nl/berg/packt/coverage/AppTest.java以通过更改testApp()方法来实例化一个新的 Dicey 对象:

    Public void testApp(){
      new Dicey();
      assertTrue( true );
    }
    
  7. 使用以下命令测试 JUnit 测试的代码覆盖率:

    mvn clean cobertura:cobertura
    
    
  8. 查看 Maven 输出,注意 Dicey 构造函数内部的 println 也已包含在内:

    -------------------------------------------------------
    T E S T S
    -------------------------------------------------------
    Running nl.berg.packt.coverage.AppTestDice < 4 Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.033 sec
    
  9. 在网络浏览器中打开view /target/site/cobertura/index.html。您的项目现在具有代码覆盖率,并且您可以看到尚未调用的代码行,如下屏幕截图所示:怎么做...

  10. 将以下构建部分添加到您的pom.xml中:

    <build>
      <plugins>
        <plugin>
          <groupId>org.codehaus.mojo</groupId>
          <artifactId>cobertura-maven-plugin</artifactId>
            <version>2.6</version>
            <configuration>
            <formats>
              <format>xml</format>
              <format>html</format>
            </formats>
          </configuration>
        </plugin>
      </plugins>
    </build>
    
  11. 使用以下命令测试 JUnit 测试的代码覆盖率:

    mvn clean cobertura:cobertura
    
    
  12. 访问位置target/site/cobertura,注意现在结果也存储在coverage.xml中。

  13. 运行mvn clean以删除目标目录。

  14. 将 Maven 项目添加到您的 Subversion 仓库中。

  15. 创建一个名为ch5.quality.coverage的新 Maven 项目。

  16. 源代码管理部分中,勾选Subversion并添加您的存储库位置。

  17. 构建部分下的目标和选项中添加clean cobertura:cobertura

  18. 后期构建操作部分中勾选发布 Cobertura 覆盖率报告。对于 Cobertura xml 报告模式输入,添加**/target/site/cobertura/coverage.xml

  19. 点击保存

  20. 点击两次立即构建以生成工作的趋势,然后审查结果。

趋势图是类,条件(例如 if 语句的分支),文件,代码行,方法和包的百分比的线性图。Jenkins 使用不同颜色的线显示每种类型,如下屏幕截图所示:

怎么做...

它是如何工作的...

Cobertura 在编译期间对 Java 字节码进行仪器化。Maven 插件会生成 HTML 和 XML 报告。HTML 报告允许你从命令行快速查看代码状态。XML 报告需要 Jenkins 插件解析。

你将插件配置放在了build部分而不是报告部分,以避免运行带有额外阶段的site目标。

自由样式项目被用来使 Cobertura 插件捡起多个 XML 报告。这是由文件集 **/target/site/cobertura/coverage.xml 定义的,该文件集表示工作空间下任何 target/site/cobertura 目录下的任何报告都称为 coverage.xml

Maven 运行了 clean cobertura:coberturaclean 目标会删除所有的 target 目录,包括以前编译和仪器化的代码。cobertura:cobertura 目标编译和仪器化代码,运行单元测试,然后生成报告。

testApp 单元测试调用了 Dicey 类的构造函数。构造函数随机生成从 1 到 6 的数字,模拟骰子,并在一个 if 语句的两个分支中进行选择。cobertura 报告允许你放大到源代码并发现做出的选择。该报告非常适用于识别遗漏的测试。如果你重构代码,那么在这些区域将没有单元测试,以便在代码意外更改行为时发现。该报告还擅长发现比周围环境更复杂的代码。代码越复杂,越难理解,也越容易引入错误。

以下文章是如何使用 cobertura 以及生成的指标背后含义的绝佳示例:www.ibm.com/developerworks/java/library/j-cq01316/index.html?ca=drs

更多内容...

另一个开源工具替代品是 Emma (emma.sourceforge.net)。Emma 还有一个相关的 Jenkins 插件 wiki.jenkins-ci.org/display/JENKINS/Emma+Plugin。在 Maven 中,你不需要在 pom.xml 文件中添加任何配置。你只需运行目标 clean emma:emma package 并将 Jenkins 插件指向结果。

注意

另一个替代框架是 Jacoco (www.eclemma.org/index.html)。Jacoco 被设计为 Emma 的一个后代。你可以在这里找到其 Jenkins 插件的完整描述:wiki.jenkins-ci.org/display/JENKINS/JaCoCo+Plugin

激活更多的 PMD 规则集

PMD 有规则来捕获特定的错误。它将这些规则捆绑到规则集中。例如,有一个主题是关于 Android 编程的规则集,另一个是关于代码大小或设计的规则集。默认情况下,测量了三个非有争议的 PMD 规则集:

  • 基础:此规则集包含每个开发人员都应遵循的明显实践,例如不要忽略已捕获的异常。

  • 未使用的代码:此规则集可查找从未使用过的代码以及可消除的行,避免浪费并增加可读性。

  • 导入:此规则集可发现不必要的导入。

此示例向您展示如何启用更多规则。主要风险是额外规则会生成大量误报,使真正的缺陷难以辨别。好处是您将捕获更广泛的缺陷,其中一些在进入生产环境后会造成严重后果。

准备工作

安装 Jenkins PMD 插件 (wiki.jenkins-ci.org/display/JENKINS/PMD+Plugin)。

提示

Jenkins bug [Jenkins-22252]

issues.jenkins-ci.org/browse/JENKINS-22252

在撰写本文时,Jenkins 中的 Maven 3.2.1 与 PMD 插件不兼容。短期解决方案是在构建中使用 Maven 3.0.5。但是,到您阅读此警告时,我期望该问题已得到解决。

您可以从 Jenkins 的主配置屏幕 (http://localhost:8080/configure) 自动安装不同版本的 Java、Maven 或 Ant。

如何做...

  1. 使用以下命令生成模板项目:

    mvn archetype:generate -DgroupId=nl.berg.packt.pmd -DartifactId=pmd -DarchetypeArtifactId=maven-archetype-quickstart -Dversion=1.0-SNAPSHOT
    
    
  2. 使用以下内容将 Java 类 src/main/java/nl/berg/packt/pmd/PMDCandle.java 添加到项目中:

    package nl.berg.packt.pmd;
    import java.util.Date;
    public class PMDCandle {
      private String MyIP = "123.123.123.123";
      public void dontDontDoThisInYoourCode(){
        System.out.println("Logging Framework please"); 
        try {
          int x =5;
        }catch(Exception e){} String myString=null;
        if (myString.contentEquals("NPE here"));
      }
    }
    
  3. 使用以下命令测试您的未修改项目:

    mvn clean pmd:pmd
    
    
  4. 查看目录 target,您会注意到结果 java-basic.xmljava-imports.xmljava-unusedcode.xml,以及聚合结果 pmd.xml

  5. 在 web 浏览器中查看文件 target/site/pmd.html

  6. 将以下报告部分添加到您的 pom.xml 文件中:

    <reporting>
      <plugins>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-jxr-plugin</artifactId>
          <version>2.3</version>
        </plugin>
       <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-pmd-plugin</artifactId>
      <version>3.2</version>
      <configuration>
      <targetJdk>1.6</targetJdk>
      <format>xml</format>
      <linkXref>true</linkXref>
      <minimumTokens>100</minimumTokens>
      <rulesets>
        <ruleset>/rulesets/basic.xml</ruleset>
        <ruleset>/rulesets/braces.xml</ruleset>
        <ruleset>/rulesets/imports.xml</ruleset>
        <ruleset>/rulesets/logging-java.xml</ruleset>
        <ruleset>/rulesets/naming.xml</ruleset>
        <ruleset>/rulesets/optimizations.xml</ruleset>
        <ruleset>/rulesets/strings.xml</ruleset>
        <ruleset>/rulesets/sunsecure.xml</ruleset>
        <ruleset>/rulesets/unusedcode.xml</ruleset>
      </rulesets>
      </configuration>
        </plugin>
      </plugins>
    </reporting>
    
  7. 使用以下命令测试您的项目:

    mvn clean pmd:pmd
    
    
  8. 在 web 浏览器中查看文件 target/site/pmd.html,注意到现在发现了额外的违规行为。这是由于在 pom.xml 文件中添加了额外规则造成的。

  9. 运行 mvn clean 来删除 target 目录。

  10. 将源代码添加到您的 Subversion 仓库。

  11. 创建一个名为 ch5.quality.pmd 的新 Maven Jenkins 作业,包含以下详细信息:

    • 源代码管理 | Subversion:您的仓库

    • 构建 | 目标和选项clean pmd:pmd

    • 构建设置发布 PMD 分析结果

  12. 单击 保存

  13. 单击 立即构建 两次以生成趋势。查看结果。

顶层报告汇总了缺陷数量及其优先级。它还提到了一些详细信息,如下图所示:

如何做...

你可以放大代码并查看高亮显示的区域以查找缺陷:

如何做...

工作原理...

Maven PMD 插件测试了一系列规则集。当你从 PMD 网站下载二进制包(pmd.sourceforge.net/)时,你可以通过列出 pmd.jar 文件的内容找到规则集的路径。在 *NIX 系统下执行此操作的命令是:

unzip –l pmd-version.jar | grep rulesets

你添加了一个标准的基准,一个具有已知缺陷的 Java 类,触发 PMD 警告。例如,以下两行代码中有多个缺陷:

String myString=null;
if (myString.contentEquals("NPE here"));

最重要的缺陷是 Java 程序员需要首先放置文本来避免 NullPointerException,例如:

"NPE here".contentEquals(myString)

myStringnull 时,首先返回 false。if 语句周围缺少大括号是一个问题。当触发 if 语句时,同样适用于缺少要运行的命令。

另一个微不足道的例子是将基础设施细节硬编码到你的源代码中。例如,密码、IP 地址和用户名。最好将细节移到仅驻留在部署服务器上的属性文件中。以下一行测试 PMD 是否能够发现这种类型的缺陷:

private String MyIP = "123.123.123.123";

FindBugs 和 PMD 都有自己的一套 bug 模式检测器。两者都不会捕获所有类型的缺陷。因此,值得运行这两个工具来捕获最广泛范围的缺陷。有关这两款产品的评论,请访问www.freesoftwaremagazine.com/articles/destroy_annoying_bugs_part_1

你可能会对其他几个静态代码审查工具感兴趣,例如 QJPro (qjpro.sourceforge.net/) 和 Jlint (jlint.sourceforge.net/)。

还有更多...

Out-of-the-box,PMD 测试了一组合理的 bug 缺陷;然而,每个项目都是不同的,你需要进行调整。

减少 PMD 规则集的速率

重要的是要理解规则集的重要性,并塑造 Maven 配置,仅包括有用的规则。如果你不为一个中等规模的项目做这个,报告将包含数千个违规行为,隐藏了真正的缺陷。然后报告将需要时间在你的网络浏览器中渲染。考虑启用一个长列表的规则,只有当你想要使用体积作为项目成熟度的指标时。

要减少,排除代码的部分并系统地清理报告的区域。

注意

你可以在这里找到当前的 PMD 规则集:pmd.sourceforge.net/rules/index.html

不要重复自己的原则

剪切和粘贴编程,克隆,然后修改代码会导致重构的噩梦。如果代码没有正确封装,很容易在代码库中散落着略有不同的代码片段。如果你想要删除已知的缺陷,那将需要额外的工作。

PMD 通过查找重复代码来支持不要重复自己(DRY)原则。触发点通过 minimumTokens 标签进行配置。然而,PMD 插件不会拾取结果(存储在 cpd.xml 中)。您需要安装和配置 DRY 插件(wiki.jenkins-ci.org/display/JENKINS/DRY+Plugin)或 Jenkins 违规插件。

注意

如果您从其网站下载了 PMD 二进制文件(sourceforge.net/projects/pmd/files/pmd/),那么在 bin 目录中,您会找到 cpdgui。这是一个允许您在源代码中探索重复的 Java swing 应用程序。

参见

  • 创建自定义 PMD 规则 配方

  • 使用 R 插件分析项目数据 配方

创建自定义 PMD 规则

与其他静态代码审查工具相比,PMD 有两个额外的功能。第一个是 cpdgui 工具,允许您查找从代码库的一个部分复制粘贴到另一个部分的代码。第二个,也是我们将在这个配方中探索的,是使用 Xpath 为 Java 源代码设计自定义 bug 发现规则的能力。

准备工作

确保您已安装了 Jenkins PMD 插件(wiki.jenkins-ci.org/display/JENKINS/PMD+Plugin)。从 pmd.sourceforge.net 下载并解压 PMD 发行版。访问 PMD bin 目录,并验证您是否具有启动脚本 run.sh designerdesigner.bat

如何做...

  1. 使用以下命令从命令行创建一个 Maven 项目:

    mvn archetype:generate -DgroupId=nl.berg.packt.pmdrule -DartifactId=pmd_design -DarchetypeArtifactId=maven-archetype-quickstart -Dversion=1.0-SNAPSHOT
    
    
  2. pom.xml 文件中,</project> 标记之前添加一个 reporting 部分,内容如下:

    <reporting>
      <plugins>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-jxr-plugin</artifactId>
          <version>2.1</version>
        </plugin>
      <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-pmd-plugin</artifactId>
      <version>2.6</version>
      <configuration>
      <targetJdk>1.6</targetJdk>
      <format>xml</format>
      <rulesets>
        <ruleset>password_ruleset.xml</ruleset>
      </rulesets>
      </configuration>
        </plugin>
      </plugins>
    </reporting>
    

    注意

    此配方仅适用于版本 2.6。

  3. 在顶层目录下,创建名为 password_ruleset.xml 的文件,内容如下:

    <?xml version="1.0"?>
    <ruleset name="STUPID PASSWORDS ruleset"
    
      xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd"
      xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd">
      <description>
      Lets find stupid password examples
      </description>
    </ruleset>
    
  4. 编辑 src/main/java/nl/berg/packt/pmdrule/App.java,使得主方法为:

    public static void main( String[] args )
    {
      System.out.println( "Hello World!" );
      String PASSWORD="secret";
    }
    
  5. 根据您的操作系统,使用启动脚本 bin/run.sh designerbin/designer.bat 运行 pmd designer。

  6. 点击屏幕左上角的 JDK 选项,选择 JDK 1.6 作为 Java 版本。

  7. 源代码 文本区域中,添加要针对测试的示例代码。在本例中:

    public class RuleTest {
      static final String PASSWORD="secret";
    }
    
  8. 对于 查询(如果有的话) 文本区域,添加:

    //VariableDeclaratorId[@Image='PASSWORD']
    
  9. 点击 Go。你现在会看到结果 第 2 行第 20 列的 ASTVariableDeclarorID,如下截图所示:如何做...

  10. 在屏幕顶部的 操作 菜单选项下,选择 创建规则 XML。添加以下值:

    • 规则名称:无密码

    • 规则消息:如果我们看到密码,我们应该标记

    • 规则描述:让我们找到愚蠢的密码示例

  11. 点击 创建规则 XML。生成的 XML 应该有一个类似于的片段:

    <rule  name="NO_PASSWORD"
      message="If we see a PASSWORD we should flag"
      class="net.sourceforge.pmd.rules.XPathRule">
      <description>
      If we see a PASSWORD we should flag
      </description>
      <properties>
        <property name="xpath">
        <value>
    <![CDATA[
    //VariableDeclaratorId[@Image='PASSWORD']
    
    ]]>
        </value>
        </property>
      </properties>
      <priority>3</priority>
      <example>
    <![CDATA[
    public class RuleTest {
        static final String PASSWORD="secret";
    }
    ]]>
      </example>
    </rule>
    

    如何做...

  12. 将生成的代码复制并粘贴到password_ruleset.xml中的</ruleset>之前。

  13. 将项目提交到您的 Subversion 存储库。

  14. 在 Jenkins 中,创建一个名为ch5.quality.pmdruleMaven作业。

  15. 源代码管理部分,勾选Subversion,并为存储库 URL添加您的 Subversion 存储库位置。

  16. 构建部分的目标和选项中,将值设置为clean site

  17. 构建设置部分,勾选发布 PMD 分析结果

  18. 点击保存

  19. 运行作业。

  20. 查看PMD 警告链接,如下截图所示:操作步骤...

工作原理是什么...

PMD 分析源代码并将其分解为称为抽象语法树(AST)的元数据(onjava.com/pub/a/onjava/2003/02/12/static_analysis.html)。PMD 能够使用 Xpath 规则在 AST 中搜索模式。W3Schools 提供了 Xpath 的简明介绍(www.w3schools.com/xpath/)。设计工具使您能够编写 Xpath 规则,然后针对源代码示例测试您的规则。为了可读性,测试代码中应该只包含必要的细节。然后将规则存储在 XML 中。

要将 XML 规则打包在一起,你必须将规则添加为<ruleset>标记的一部分。

Maven PMD 插件有能力从其类路径、本地文件系统或通过 HTTP 协议从远程服务器读取规则集。您通过添加配置选项添加了您的规则集:

<ruleset>password_ruleset.xml</ruleset>

如果你建立了一套规则集,应该将所有规则都放入一个项目中以便管理。

您还可以根据已有规则创建自己的自定义规则集,提取您喜欢的错误检测模式。这可以通过带有指向已知规则的<rule>标记来实现,例如,以下从imports.xml规则集中提取了DuplicateImports规则:

<rule ref="rulesets/imports.xml/DuplicateImports"/>

本示例生成的规则测试了名称为PASSWORD的变量。我们在真实项目中多次触发了该规则。

我们将 Maven PMD 插件的版本锁定为 2.6,以确保在插件的将来发布版本后仍然可以使用本示例。

注意

PMD 主页是了解 Xpath 规则可能性的好地方。它包含了规则集的描述和详细信息,例如,日志规则;请参阅pmd.sourceforge.net/pmd-4.3.0/rules/logging-java.html

还有更多...

如果静态代码审查工具能够就如何修复代码提出建议将是非常有效的。然而,这有点危险,因为检测器并不总是准确的。作为一个实验,我编写了一个小型的 Perl 脚本,首先修复字面量,然后删除一些资源的浪费。这段代码是一个概念验证,因此不能保证正确运行。它的好处在于简洁,参见:

source.sakaiproject.org/contrib/qa/trunk/static/cleanup/easy_wins_find_java.pl

另请参阅

  • 激活更多的 PMD 规则集 示例

使用 FindBugs 查找错误

在静态代码审查工具发现的缺陷数量中很容易迷失方向。另一个质量保证攻击模式是逐个清理缺陷包,集中开发者的时间在最常用的功能上。

这个示例将向您展示如何为特定包生成和报告 FindBugs 发现的缺陷。

准备工作

安装 Jenkins FindBugs 插件 (wiki.jenkins-ci.org/display/JENKINS/FindBugs+Plugin)。

提示

Java 版本

FindBugs 插件版本 3 需要 Java 7 或更高版本。

如何操作...

  1. 从命令行创建一个 Maven 项目:

    mvn archetype:generate -DgroupId=nl.berg.packt.FindBugs_all - DartifactId=FindBugs_all -DarchetypeArtifactId=maven- archetype-quickstart -Dversion=1.0-SNAPSHOT
    
    
  2. pom.xml 文件中,在</project>标签之前添加一个构建部分,内容如下:

    <build>
    <plugins>
    <plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>FindBugs-maven-plugin</artifactId>
    <version>3.0.0</version>
    <configuration>
    <FindBugsXmlOutput>true</FindBugsXmlOutput>
    <FindBugsXmlWithMessages>true</FindBugsXmlWithMessages>
    <onlyAnalyze>nl.berg.packt.FindBugs_all.candles.*</onlyAnal yze>
    <effort>Max</effort>
    </configuration>
    </plugin>
    </plugins>
    </build>
    
  3. 创建目录 src/main/java/nl/berg/packt/FindBugs_all/candles

  4. candles 目录中包括名为 FindBugsCandle.java 的文件,内容如下:

    package nl.berg.packt.FindBugs_all.candles;
    
    public class FindBugsCandle {
      public String answer="41";
      public boolean myBad(){
        String guess= new String("41");
    if (guess==answer){ return true; }
        return false;
      }
    }
    
  5. 创建一个名为 ch5.quality.FindBugsMaven项目。

  6. 源代码管理部分,选中Subversion单选框,添加到Repository URL中您的存储库 URL。

  7. 构建部分中添加 clean compile findBugs:findBugs 作为目标和选项

  8. 构建后操作选项中,选择发布 FindBugs 分析结果

  9. 点击保存

  10. 运行作业。

  11. 查看结果。

第一页是一个摘要页面,可以让您有效地放大细节,如下图所示:

如何操作...

查看诸如BAD_PRACTICE之类的类别,可以查看触发的每种错误类型的描述:

如何操作...

您可以随后查看相关的代码。突出显示的代码有助于集中注意力,如下图所示:

如何操作...

工作原理...

在这个示例中,您已经创建了一个标准的 Maven 项目,并添加了一个带有已知缺陷的 Java 文件。

pom.xml 配置强制 FindBugs 仅报告 nl.berg.packt.FindBugs_all.candles 包中类的缺陷。

在标准蜡烛中,guess==answer 这一行是一个典型的程序错误。两个对象的引用被比较,而不是它们字符串的值。由于 guess 对象是在上一行创建的,结果将始终为 false。这类缺陷可能会出现在程序中作为微妙的问题。JVM 缓存字符串,有时两个表面上不同的对象实际上是同一个对象。

更多内容...

FindBugs 在开发者中很受欢迎,并为多个流行的 IDE 提供插件。其结果通常作为其他工具的更广泛报告的一部分。

FindBugs Eclipse 插件

Eclipse 插件的自动安装位置为 findbugs.cs.umd.edu/eclipse

默认情况下,FindBugs Eclipse 插件只启用了有限数量的规则。要增加测试集,您需要转到 窗口 下的 首选项 菜单选项,在左侧菜单中选择 FindBugs。在右侧,您将看到 报告的 (可见的) 缺陷类别 选项在 报告者配置 下。您现在可以调整可见的类别,如下图所示:

FindBugs Eclipse 插件

Xradar 和 Maven 仪表板

但是,对于生成的软件度量的累积,还有其他替代方案。Maven 仪表板就是一个例子 (mojo.codehaus.org/dashboard-maven-plugin/)。您将需要将其连接到自己的数据库。在书籍 Apache Maven 3 Cookbook, Srirangan, Packt Publishing (www.packtpub.com/application-development/apache-maven-3-cookbook) 中的 第四章,报告和文档 中有一个名为 设置 Maven 仪表板 的配方。

Xradar 是仪表板的另一个例子 (xradar.sourceforge.net/usage/maven-plugin/howto.html),而 QALab 是第三个 (qalab.sourceforge.net/multiproject/maven2-qalab-plugin/index.html)。

另请参阅

  • 启用额外的 FindBug 规则 配方

  • 使用 FindBugs 查找安全缺陷 配方

  • 激活更多 PMD 规则集 配方

启用额外的 FindBug 规则

FindBugs 拥有广泛的辅助缺陷模式检测器。这些检测器被捆绑到一个贡献者项目中,托管在 SourceForge (sourceforge.net/projects/fb-contrib/)。

本配方详细介绍了如何从 fb-contrib 项目中添加额外的缺陷检测器到 FindBugs,并使用这些检测器捕获已知缺陷。

准备就绪

假设您已经按照之前的配方使用 FindBugs 查找错误。您将使用该配方的 Maven 项目作为起点。

提示

fb-contrib 版本更改

在以下配方中,Maven 会自动下载一个库文件(.jar)。构建可能会失败,因为开发人员已经增加了版本号。在这种情况下,要找到正确的文件名,请浏览downloads.sourceforge.net/project/fb-contrib/Current/

如何做...

  1. 将顶层的pom.xml文件复制到pom_fb.xml

  2. 用以下内容替换pom_fb.xml的 FindBugs <plugin>部分:

    <plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>FindBugs-maven-plugin</artifactId>
    <version>3.0.0</version>
    <configuration>
    <FindBugsXmlOutput>false</FindBugsXmlOutput>
    <FindBugsXmlWithMessages>true</FindBugsXmlWithMessages>
    <onlyAnalyze>nl.berg.packt.FindBugs_all.candles.*</onlyAnal yze>
    <pluginList>http://downloads.sourceforge.net/project/fb- contrib/Current/fb-contrib-6.0.0.jar</pluginList>
    <effort>Max</effort>
    </configuration>
    </plugin>
    
  3. src/main/java/nl/berg/packt/fingbugs_all/candles目录中,向FindBugsFBCandle.java Java 类添加以下代码片段:

    package nl.berg.packt.FindBugs_all.candles;
    
    public class FindBugsFBCandle {
      public String FBexample(){
        String answer="This is the answer";
        return answer;
      }
    }
    
  4. 将更新提交到您的 Subversion 仓库。

  5. 创建一个名为ch5.quality.FindBugs.fb的 Jenkins Maven作业。

  6. 源代码管理部分,选中Subversion单选框,并为仓库 URL添加代码的 URL。

  7. build部分设置:

    • Root POM设置为pom_fb.xml

    • 目标和选项设置为clean compile Findbugs:Findbugs

  8. 构建设置部分,检查发布 FindBugs 分析结果

  9. 点击保存

  10. 运行作业。

  11. 当作业构建完成后,查看FindBugs 警告链接。您现在将看到一个新的警告USBR_UNNECESSARY_STORE_BEFORE_RETURN

它是如何工作的...

要包含外部检测器,您添加了一行额外的内容到 FindBugs Maven 配置中,如下所示:

<pluginList>http://downloads.sourceforge.net/project/fb- contrib/Current/fb-contrib-6.0.0.jar</pluginList>

值得访问 SourceForge 检查检测器的最新版本。

目前,使用 Maven 的依赖管理无法从存储库中拉取检测器,尽管这可能会改变。

在这个配方中,您已经添加了一个 Java 类来触发新的错误检测规则。反模式是在返回之前创建答案对象的不必要行。匿名返回对象更加简洁,例如:

return "This is the answer";

反模式触发了USBR_UNNECESSARY_STORE_BEFORE_RETURN模式,该模式在fb-contrib项目的主页上有描述。

还有更多...

Java 语言有许多难以理解的微妙边界情况,直到通过真实示例解释。捕捉知识的一种极好方式是在您的代码中遇到问题时自己编写示例。注入标准蜡烛是测试团队知识的一种自然方式,并在 QA 过程中进行目标练习。

FindBugs 项目根据 Joshua Bloch 和 Neal Gafter 的书《Java Puzzlers》(www.javapuzzlers.com/)的内容生成了一些他们的检测器。

另请参阅

  • 使用 FindBugs 查找错误配方

  • 使用 FindBugs 查找安全缺陷配方

  • 激活更多 PMD 规则集配方

使用 FindBugs 查找安全缺陷

在本示例中,你将使用 FindBugs 发现 Java 服务器页面中的安全漏洞以及有缺陷的 Java 类中的一些安全缺陷。

准备工作

要么按照第三章 构建软件 中的 基于 JSP 语法错误失败的 Jenkins 任务 配方,要么使用 Packt Publishing 网站提供的项目下载。

如何操作...

  1. <build> 下的 <plugins> 中编辑 pom.xml 文件,添加 FindBugs 插件并添加以下内容:

    <plugins>
    <plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>findBugs-maven-plugin</artifactId>
    <version>3.0.0</version>
    <configuration>
    <FindBugsXmlOutput>true</FindBugsXmlOutput>
    <FindBugsXmlWithMessages>true</FindBugsXmlWithMessages>
    <effort>Max</effort>
    </configuration>
    </plugin>
    
  2. 创建目录结构 src/main/java/nl/berg/packt/finbugs_all/candles

  3. 添加 Java 文件 FindBugsSecurity.java,内容如下:

    package nl.berg.packt.FindBugs_all.candles;
    
    public class FindBugsSecurityCandle {
      private final String[] permissions={"Read", "SEARCH"};
      private void infiniteLoop(int loops){
        infiniteLoop(99);
      }
    
      public String[] exposure(){
        return permissions;
      }
      public static void main(String[] args) { 
        String[] myPermissions = new FindBugsSecurityCandle().exposure();
        myPermissions[0]="READ/WRITE";
        System.out.println(myPermissions[0]);
      }
    }
    
  4. 将更新提交到你的 Subversion 仓库。

  5. 创建一个名为 ch5.quality.FindBugs.securityMaven Jenkins 任务。

  6. 源代码管理 部分,选中 Subversion 单选框,并在 Repository URL 文本框中添加你的 Subversion 仓库位置

  7. 目标和选项build 部分下,将值设置为 clean package findBugs:findBugs

  8. 构建设置 部分,选中 发布 FindBugs 分析结果

  9. 点击 保存

  10. 运行该任务。

  11. 当任务完成后,查看 FindBugs Warning 链接。注意,JSP 包存在一个关于 XSS_REQUEST_PARAMETER_TO_JSP_WRITER 的警告。然而,该链接无法找到源代码的位置。

  12. src/main/webapp/index.jsp 复制到 jsp/jsp.index_jsp

  13. 提交到你的 Subversion 仓库。

  14. 再次运行任务。

  15. FindBugs Warning 链接下查看结果。你现在可以查看 JSP 源代码了。

工作原理...

JSP 首先从文本转换为 Java 源代码,然后编译。FindBugs 通过解析编译后的 Java 字节码来工作。

原始的 JSP 项目存在严重的安全漏洞。它信任来自互联网的输入。这导致了许多攻击向量,包括 XSS 攻击 (en.wikipedia.org/wiki/Cross-site_scripting)。使用允许标记的白名单来解析输入是减少风险的一种方法。FindBugs 发现了这个缺陷并以 XSS_REQUEST_PARAMETER_TO_JSP_WRITER 进行警告。Jenkins FindBugs 插件详细说明了错误类型,因为你在配置中打开了消息:

<FindBugsXmlWithMessages>true</FindBugsXmlWithMessages>

FindBugs 插件尚未实现对 JSP 文件位置的理解。当单击链接到源代码时,插件会在错误的位置查找。一个临时解决方案是将 JSP 文件复制到 Jenkins 插件期望的位置。

FindBugs 报告的行号位置也毫无意义。它指向了生成自 .jsp 文件的 .java 文件中的行,而不是直接指向 JSP 文件。尽管存在这些限制,FindBugs 仍然能够发现有关 JSP 缺陷的有用信息。

注意

JSP Bug 检测的替代方案是 PMD。你可以从命令行配置它仅扫描 JSP 文件,使用选项 –jsp,参见:pmd.sourceforge.net/jspsupport.html

还有更多...

虽然 FindBugs 有一些属于安全类别的规则,但还有其他发现安全相关缺陷的 bug 检测器。标准烛台类包括两种此类缺陷。第一个是一个递归循环,将不断从其内部调用相同的方法,如下面的代码所示:

private void infiniteLoop(int loops){
  infiniteLoop(99);
}

也许程序员打算使用计数器来在 99 个循环后强制退出,但是并不存在执行此操作的代码。如果调用此方法,最终结果是它将不断调用自身,直到堆栈保留的内存被消耗完并且应用程序失败。这也是一个安全问题;如果攻击者知道如何到达此代码,他们可以通过拒绝服务DOS)攻击使相关应用程序崩溃。

标准烛台中捕获的另一个攻击是能够更改看起来不可变的数组中的内容。确实,数组的引用不能更改,但是数组元素的内部引用可以。在示例中,一个有动机的黑客可以访问内部对象,并将 READ 权限更改为 READ/WRITE 权限。为了防止这种情况发生,考虑制作原始数组的防御性副本,并将副本传递给调用方法。

注意

OWASP 项目提供了大量关于测试安全性的信息,请查看以下链接:

www.owasp.org/index.php/Category:OWASP_Java_Project

另请参阅

  • 使用 FindBugs 查找 bug 的方法

  • 启用额外的 FindBug 规则 配方

  • 激活更多 PMD 规则集 配方

  • 第三章 中的 为集成测试配置 Jetty 配方,构建软件

验证 HTML 的有效性

该配方告诉你如何使用 Jenkins 对 HTML 页面进行验证,以符合 HTML 和 CSS 标准。

Web 浏览器并不挑剔。您可以在应用程序中拥有损坏的模板,生成的 HTML 在一个浏览器上可以正常工作,但在另一个浏览器上却很难看。验证可以提高一致性,并及早发现非平凡但难以发现的问题。

您可以上传并验证您的 HTML 文件是否符合 W3C 的统一验证器 (code.w3.org/unicorn)。统一验证器将根据多个聚合服务检查您的网页的正确性。Jenkins 插件会自动为您执行此操作。

准备工作

安装 Unicon 验证插件(wiki.jenkins-ci.org/display/JENKINS/Unicorn+Validation+Plugin)。如果还没有安装,请同时安装 Plot 插件(wiki.jenkins-ci.org/display/JENKINS/Plot+Plugin)。

如何操作...

  1. 创建一个名为 ch5.quality.html 的自由风格作业。

  2. 构建 部分内,添加构建步骤,选择 Unicorn 验证器

  3. 对于要验证的站点 Site to validate 输入,请添加允许测试的站点的 URL。

  4. 单击 保存

  5. 运行作业。

  6. 查看 工作区,单击 unicorn_output.html 链接,然后单击 markup-validator_errors.properties。对于属性文件的内容,您将看到类似 YVALUE=2 的内容。

  7. 配置 项目。在 后构建操作 部分,勾选 绘制构建数据,添加以下细节:

    • 绘图组:验证错误

    • 绘图标题:标记验证错误

    • 要包含的构建数:40

    • 绘图 y 轴标签:错误

    • 绘图样式:区域

    • 数据系列文件markup-validator_errors.properties

    • 验证 从属性文件加载数据 单选框是否被选中

    • 数据系列图例标签:反馈错误

  8. 单击 保存

  9. 运行作业。

  10. 查看 绘图 链接。如何操作...

工作原理...

Unicon 验证插件使用 W3C 的验证服务生成配置的 URL 的报告。插件处理返回的报告并获取缺陷的绝对计数。然后,总计值被放置在属性文件中,然后绘图插件会获取这些值(请参阅 第三章 中的 在 Jenkins 中绘制替代代码度量 配方,构建软件)。如果看到警告突然激增,请查看 HTML 页面以查找重复缺陷。

还有更多...

从单元测试中获得良好的代码覆盖率相当困难。这在项目较大且有多个团队采用不同实践的情况下尤为明显。通过使用尽可能访问应用程序中尽可能多的链接的工具,可以显著提高对 Web 应用程序的自动化测试覆盖率。这包括 HTML 验证器、链接检查器、搜索引擎爬虫和安全工具。考虑在集成测试期间设置一系列工具来访问您的应用程序,并记住解析日志文件以查找意外错误。您可以使用 第一章 中的 通过日志解析故意失败的构建 配方自动化日志解析,维护 Jenkins

注意

有关逐步验证在线内容的详细信息,请访问 www.w3.org/QA/2002/09/Step-by-step

使用 JavaNCSS 进行报告

JavaNCSS (javancss.codehaus.org/) 是一个软件度量工具,它计算两种类型的信息:第一种是包中活动的、注释的或与 JavaDoc 相关的源代码行数的总数。第二种类型基于存在多少不同的决策分支来计算代码的复杂性。

Jenkins JavaNCSS 插件忽略了复杂性计算,而是专注于更容易理解的行数统计。

注意

NCSS 代表非注释源语句,即代码行数减去注释和额外的换行符。

准备就绪

安装 JavaNCSS 插件 (wiki.jenkins-ci.org/display/JENKINS/JavaNCSS+Plugin)。

如何做...

  1. 创建一个名为 ch5.quality.ncssMaven项目。

  2. 源代码管理部分,选择Subversion单选框。

  3. 添加仓库 URL source.sakaiproject.org/contrib/learninglog/tags/1.0

  4. 查看构建触发器,确保没有激活。

  5. 构建部分的目标和选项下,键入clean javancss:report

  6. 构建设置部分,勾选发布 Java NCSS 报告

  7. 点击保存

  8. 运行该作业。

  9. 查看Java NCSS 报告链接。

  10. 查看工作区中的顶级 pom.xml 文件,例如,http://localhost:8080job/ch5.quality.ncss/ws/pom.xml怎么做...

工作原理...

该作业从 Sakai 项目的学习日志工具子版本库中提取了源代码。该项目是一个多模块项目,API 与实现分离。

JavaNCSS 不需要编译的类或对 Maven pom.xml 文件的修改;这使得循环简单。该作业运行了一个 Maven 目标,通过 JavaNCSS Jenkins 插件发布了报告。

回顾报告,实现相对于其他包具有更多的活动代码行数。API 的文档对其他开发人员重用代码至关重要。值得注意的是,API 中没有 JavaDoc 行。

摘要表中的缩写具有以下含义:

  • :这是包中类的数量。

  • 函数:这是包中函数的数量。

  • JavaDocs:这是包中不同 JavaDoc 块的数量。这并不完全准确,因为大多数现代 IDE 使用样板模板生成类。因此,您可能会生成大量质量低劣的 JavaDoc,从而产生误导性结果。

  • NCSS:这是源代码中非注释行的数量。

  • JLC:这是 JavaDoc 的行数。

  • SLCLC:这是仅包含单个注释的行数。

  • MLCLC:这是多行注释中包含的源代码行数。

构建摘要显示了当前任务与上一任务之间的变更(增量)信息,例如:

    classes (+28)
    functions (+349)
    ncss (+2404)
    javadocs (+22)
    javadoc lines (+80)
    single line comments (+63)
    multi-line comments (+215)

+ 符号表示代码已添加,- 表示已删除。如果你看到大量代码涌入,但 JavaDoc 的涌入量低于平常,那么要么代码是自动生成的,要么更可能是为了赶上市场而匆忙开发。

这还不是全部...

当你已经习惯于相对简单的 JavaNCSS 摘要的含义后,考虑将 JDepend 添加到您的代码度量安全网中。JDepend 生成了更广泛的与质量相关的指标(clarkware.com/software/JDepend.htmlmojo.codehaus.org/jdepend-maven-plugin/plugin-info.html,以及 wiki.jenkins-ci.org/display/JENKINS/JDepend+Plugin)。

JDepend 生成的最重要的指标之一是循环依赖。如果类 A 依赖于类 B,而类 B 又依赖于类 A,那么这就是一个循环依赖。当存在这样的依赖关系时,表明存在某种事情可能出错的风险,例如资源竞争、无限循环或同步问题。可能需要重构以消除责任不清晰性。

使用外部 pom.xml 文件检查代码样式

如果你只想检查代码的文档质量而不更改其源代码,则注入自己的 pom.xml 文件。这个配方向你展示了如何为 Checkstyle 进行此操作。Checkstyle 是一个工具,根据明确定义的标准(例如 Sun 编码规范)检查大多数文档。

准备就绪

安装 Checkstyle 插件(wiki.jenkins-ci.org/display/JENKINS/Checkstyle+Plugin)。

小贴士

如果您因为 AbstractMapBasedMultimap 上的 illegalAccessError 错误而遇到问题,那么这可能是由于 Jenkins-22252 报告的错误所致(issues.jenkins-ci.org/browse/JENKINS-22252)。当前解决方案是使用 Maven 的版本 3.0.5 运行。

如何执行...

  1. 创建名为 /var/lib/jenkins/OVERRIDE 的目录。

  2. 确保目录的所有者是 Jenkins 用户和组 sudo chown jenkins:jenkins /var/lib/jenkins/OVERRIDE

  3. 创建文件 /var/lib/Jenkins/OVERRIDE/pom_checkstyle.xml,内容如下:

    <project  
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>nl.berg.packt.checkstyle</groupId>
      <artifactId>checkstyle</artifactId>
      <packaging>pom</packaging>
      <version>1.0-SNAPSHOT</version>
      <name>checkstyle</name>
      <url>http://maven.apache.org</url>
    
    <modules>
    <module>api</module>
    <module>help</module>
    <module>impl</module>
    <module>util</module>
    <module>pack</module>
    <module>tool</module>
    <module>assembly</module>
    <module>deploy</module>
    <module>bundle</module>
    </modules>
    <build>
    <plugins>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-checkstyle-plugin</artifactId>
            <version>2.8</version>
          </plugin>
        </plugins>
    </build>
    <properties>
    <project.build.sourceEncoding>UTF-8
    </project.build.sourceEncoding>
    </properties>
    </project>
    
  4. 确保文件的所有者是 Jenkins 用户和组 sudo chown jenkins:jenkins /var/lib/jenkins/OVERRIDE/pom_checkstyle.xml

  5. 创建一个名为 ch5.quality.checkstyle.overrideMaven 任务。

  6. 源码管理 部分,选中 Subversion 并添加 Subversion 存储库 source.sakaiproject.org/svn/profile2/tags/profile2-1.4.5

  7. 添加预构建步骤的预步骤部分中,选择执行 shell

  8. 在命令文本区域中添加 cp /var/lib/Jenkins/OVERRIDE/pom_checkstyle.xml

  9. build部分下添加:

    • 根 POMpom_checkstyle.xml

    • 目标和选项clean checkstyle:checkstyle

  10. 构建设置部分,勾选发布 Checkstyle 分析结果

  11. 单击保存

  12. 运行作业多次,查看输出。如何操作...

工作原理...

profile2 工具在全球范围内由数百万用户在 Sakai 学习管理系统(sakaiproject.org)中使用。这是一个真实的工业级编码。它是一个社交中心,用于管理其他人可以看到你帐户详细信息的内容。该项目将代码分为实现、API 和模型。

在这个案例中,您创建了一个替换的pom.xml文件。您不需要复制原始pom.xml中的任何依赖项,因为 Checkstyle 不需要编译代码来进行计算。

然后作业将pom_checkstyle.xml文件复制到主工作区。pom_checkstyle.xml文件中未详细配置 Checkstyle,因为我们只对总体趋势感兴趣。但是,如果您想要放大细节,可以配置 Checkstyle 以基于特定指标生成结果,例如布尔表达式的复杂性或非注释源语句(NCSS)checkstyle.sourceforge.net/config_metrics.html

还有更多...

您可以使用 Jenkins XML API 远程查看大多数质量测量工具的统计信息。Checkstyle、PMD、FindBugs 等的语法是:

Jenkins_HOST/job/[Job-Name]/[Build-Number]/[Plugin-URL]Result/api/xml

例如,在这个案例中,类似下面的 URL 将起作用:

localhost:8080/job/ch5.quality.checkstyle.override/11/checkstyleResult/api/xml

此食谱的返回结果类似于以下内容:

<checkStyleReporterResult>
<newSuccessfulHighScore>true</newSuccessfulHighScore>
<warningsDelta>38234</warningsDelta>
<zeroWarningsHighScore>1026944</zeroWarningsHighScore>
<zeroWarningsSinceBuild>0</zeroWarningsSinceBuild>
<zeroWarningsSinceDate>0</zeroWarningsSinceDate>
</checkStyleReporterResult>

要远程获取数据,您需要进行身份验证。有关如何执行远程身份验证的信息,请参阅第三章中的通过 Jenkins API 远程触发作业食谱,构建软件

另请参阅

  • 伪造 Checkstyle 结果 食谱

伪造 Checkstyle 结果

本食谱详细介绍了如何伪造 Checkstyle 报告。 这将允许您将自定义数据挂接到 Checkstyle Jenkins 插件(wiki.jenkins-ci.org/display/JENKINS/Checkstyle+Plugin),公开您的自定义测试结果而无需编写新的 Jenkins 插件。 与在第三章 构建软件中使用在 Jenkins 中绘制替代代码指标的食谱相比,它显示结果的位置。 您可以使用 Analysis Collector 插件(wiki.jenkins-ci.org/display/JENKINS/Analysis+Collector+Plugin)将虚假结果与其他指标摘要汇总。

准备工作

如果尚未安装 Checkstyle,请安装并在您的 Subversion 存储库中为代码创建一个新目录。

如何做...

  1. 创建一个名为generate_data.pl的 Perl 脚本文件,内容如下:

    #!/usr/bin/perl
    $rand=int(rand(9)+1);
    
    print <<MYXML;
    <?xml version="1.0" encoding="UTF-8"?>
    <checkstyle version="5.4">
    <file name="src/main/java/MAIN.java">
        <error line="$rand" column="1" severity="error"  message="line=$rand" source="MyCheck"/>
    </file>
    </checkstyle>
    MYXML
    #Need this extra line for the print statement to work
    
  2. 创建目录src/main/java.

  3. 添加 Java 文件src/main/java/MAIN.java,内容如下:

    //line 1
    public class MAIN {
    //line 3
    public static void main(String[] args) {
      System.out.println("Hello World"); //line 5
    }
    //line 7
    }
    //line 9
    
  4. 将文件提交到您的 Subversion 存储库。

  5. 创建一个 Jenkins 自由风格作业ch5.quality.checkstyle.generation

  6. 源代码管理部分,选中Subversion并添加存储库 URL:您的存储库 URL。

  7. 构建部分,选择构建步骤执行 Shell。 在命令输入中添加命令perl generate_data.pl > my-results.xml

  8. 后构建操作部分,选中发布 Checkstyle 分析结果。 在Checkstyle 结果文本输入中,添加my-results.xml

  9. 点击保存

  10. 运行作业多次,审查结果和趋势。

顶层报告提到了您的新规则:

如何做...

点击代码链接MAIN.java会带您到代码页面,并随机选择由 Perl 代码突出显示的错误行,如下截图所示:

如何做...

它是如何工作的...

本章中使用的插件将其信息存储在 XML 文件中。 Checkstyle XML 结构是所有工具中最简单的,因此是我们生成的虚假结果所选择的 XML 格式。

Perl 代码创建一个简单的 XML 结果文件,选择 1...9 之间的一行失败。 输出格式与以下代码类似:

<checkstyle version="5.4">
<file name="src/main/java/MAIN.java">
    <error line="9" column="1" severity="error" message="line=9" source="MyCheck"/>
</file>

文件位置是相对于 Jenkins 工作空间的。 Jenkins 插件打开此位置找到的文件,以便它可以将其显示为源代码。

对于找到的每个错误,创建一个<error>标签。 该插件将严重级别错误映射到

还有更多...

您可能不必将结果强制转换为虚假格式。首先考虑使用 xUnit 插件 (wiki.jenkins-ci.org/display/JENKINS/xUnit+Plugin)。这是一个实用插件,支持从不同的回归测试框架转换结果。该插件将不同的结果类型转换为标准化的 JUnit 格式。您可以在以下位置找到 JUnit 结果模式:windyroad.org/dl/Open%20Source/JUnit.xsd

另请参阅

  • 使用外部 pom.xml 检查样式 配方

将 Jenkins 与 SonarQube 集成

SonarQube,以前称为 Sonar,是一个快速发展的应用程序,用于报告质量指标和查找代码热点。本篇详细介绍了如何通过 Jenkins 插件生成代码指标,然后直接将其推送到 Sonar 数据库。

准备工作

安装 Sonar 插件 (docs.codehaus.org/display/SONAR/Jenkins+Plugin)。

下载并解压 SonarQube。您可以直接从 bin 目录中运行它,选择其中的 OS 目录。例如,Desktop Ubuntu 的启动脚本是 bin/linux-x86-32/sonar.sh console。现在您有一个不安全的默认实例运行在端口 9000 上。要获取更完整的安装说明,请查看:

docs.codehaus.org/display/SONAR/Setup+and+Upgradedocs.sonarqube.org/display/SONAR/Installing

如何做...

  1. 在主要的 Jenkins 配置 (/configure) 中,在 Sonar 部分为 Name 添加 localhost

  2. 点击 保存

  3. 创建一个名为 ch5.quality.sonarMaven 作业。

  4. 源代码管理 部分的 Repository URL 下添加 source.sakaiproject.org/svn/announcement/tags/announcement-2.9.3

  5. 构建触发器 部分,验证未选择任何构建触发器。

  6. 构建 部分的 Goals and options 下添加 clean install

  7. 对于 后构建操作 部分,勾选 Sonar

  8. 点击 保存

  9. 运行该作业。

  10. 点击 Sonar 链接并查看新生成的报告。

报告的顶层提供了关键质量指标的快速摘要,如下图所示:

如何做...

从左侧菜单中,您可以深入了解详细信息:

如何做...

它的工作原理...

源代码是 Sakai 中使用的公告工具。该项目是一个带有一些相对复杂细节的多模块项目。

默认的 SonarQube 实例预配置了内存数据库。Jenkins 插件已经知道默认配置,并且需要很少的额外配置。Jenkins Sonar 插件不需要你重新配置 pom.xml。Jenkins 插件处理生成结果的所有细节。

该作业首先运行 Maven 清理工具来清除工作空间中的旧编译代码,然后运行 install 目标,将代码编译为其一个阶段的一部分。

Jenkins Sonar 插件然后直接与 Sonar 数据库联系,并添加先前生成的结果。现在你可以在 Sonar 应用程序中看到结果了。

还有更多……

Sonar 是一个专门用于测量软件质量指标的应用程序。像 Jenkins 一样,它拥有一个专门的、活跃的社区。你可以期待一个积极进取的改进路线图。例如,它具有指出可疑代码热点的能力、视觉上吸引人的报告仪表板、易于配置和详细控制检查规则以查看等功能,目前都使它与 Jenkins 有所区别。

SonarQube 插件

通过添加额外的插件很容易扩展 Sonar 的功能。你可以在以下 URL 中找到官方提到的插件集:

docs.codehaus.org/display/SONAR/Plugin+Library

这些插件包括一些与 Jenkins 中找到的功能相当的功能。Sonar 明显不同的地方在于治理插件,代码覆盖率成为捍卫项目质量的核心。

备选的聚合器 - 违规插件

Jenkins 违规插件接受来自一系列质量度量工具的结果,并将它们合并成一个统一的报告。这个插件是 Jenkins 中最接近 Sonar 的功能。在决定是否需要在基础架构中添加额外应用程序之前,值得对其进行审查,以查看它是否满足你的质量度量需求。

另请参阅

  • 通过代码覆盖率寻找“有味道”的代码 配方

  • 激活更多的 PMD 规则集 配方

  • 使用 JavaNCSS 进行报告 配方

使用 R 插件分析项目数据

这个配方描述了如何使用 R 来处理项目工作空间中每个文件的度量标准。该配方通过遍历工作空间并收集特定扩展名(如 Java)的文件列表来实现此目的。然后,R 脚本分析每个文件,最终将结果以图形格式绘制到 PDF 文件中。这种工作流程几乎适用于所有与软件项目质量相关的分析。该配方很容易定制,以适应更复杂的任务。

在这个例子中,我们正在查看文本文件的字数大小,将大文件的名称打印到控制台,并绘制所有文件的大小。通过可视化表示,你可以很容易地看出哪些文件特别大。如果你的属性文件比其他属性文件大得多,那么它可能是损坏的。如果 Java 文件太大,那么它就难以阅读和理解。

准备工作

假设你已经按照第四章中Simplifying powerful visualizations using the R plugin一节的方法,并且已经安装了 R 插件(wiki.jenkins-ci.org/display/JENKINS/R+Plugin)。

操作步骤...

  1. 创建一个名为ch5.R.project.data的自由样式作业。

  2. 源代码管理部分,选择Subversion

  3. 添加仓库 URLsource.sakaiproject.org/svn/profile2/trunk

  4. 构建部分,选择添加构建步骤,然后选择执行 R 脚本

  5. 脚本文本区域添加以下代码:

    processFile <- function(file){
      text <- readLines(file,encoding="UTF-8")
      if (length(text)> 500) print(file)
      length(text)
    }
    javaFiles <- list.files(Sys.getenv('WORKSPACE'), recursive = TRUE, full.names = TRUE, pattern = "\\.java$")
    propertiesFiles <- list.files(Sys.getenv('WORKSPACE'), recursive = TRUE, full.names = TRUE, pattern = "\\.properties$")
    resultJava <- sapply(javaFiles, processFile)
    resultProperties <- sapply(propertiesFiles,processFile)
    warnings()
    filename <-paste('Lengths_JAVA_',Sys.getenv('BUILD_NUMBER'),'.pdf',sep ="")
    pdf(file=filename)
    hist(resultJava,main="Frequency of length of JAVA files")
    
    filename <-paste('Lengths_Properties_',Sys.getenv('BUILD_NUMBER'),'.pdf',sep="")
    pdf(file=filename)
    hist(resultProperties,main="Frequency of length of Property files")
    
  6. 点击保存按钮。

  7. 点击立即构建图标。

  8. 查看构建的控制台输出。它应该类似于以下内容:

    At revision 313948
    no change for https://source.sakaiproject.org/svn/profile2/trunk since the previous build
    [ch5.R.project.data] $ Rscript /tmp/hudson7641363251840585368.R
    [1] "/var/lib/jenkins/workspace/ch5.project.data/api/src/java/org/sakaiproject/profile2/logic/SakaiProxy.java"
    [1] "/var/lib/jenkins/workspace/ch5.project.data/impl/src/java/org/sakaiproject/profile2/conversion/ProfileConverter.java"
    [1] "/var/lib/jenkins/workspace/ch5.project.data/impl/src/java/org/sakaiproject/profile2/dao/impl/ProfileDaoImpl.java"
    14: In readLines(file, encoding = "UTF-8") :
      incomplete final line found on '/var/lib/jenkins/workspace/ch5.project.data/tool/src/java/org/apache/wicket/markup/html/form/upload/MultiFileUploadField_ca_ES.properties'
    Finished: SUCCESS
    
  9. 访问工作空间,查看文件Lengths_Properties_1.pdfLengths_JAVA_1.pdf操作步骤...

注意具有大量行的落单文件。属性文件的长度应该大致相同,因为它们包含了 GUI 的国际翻译。

操作步骤...

这感觉像是一个平衡良好的项目,因为只有少数文件有大量的代码行。

工作原理...

你从子版本加载了profile2 工具。这个代码被全球数百万学生使用,代表了成熟、现实的生产代码。

在你的 R 脚本中,你定义了一个函数,它以文件名作为输入,然后将文件读入文本对象。然后函数检查行数是否大于 500。如果行数大于 500,则文件名会打印到控制台输出。最后,函数返回文本文件的行数。

processFile <- function(file){
  text <- readLines(file,encoding="UTF-8")
  if (length(text)> 500) print(file)
  length(text)
}

接下来,脚本会在工作空间下查找属性和 Java 文件。文件搜索由pattern参数定义的值进行过滤。在这种情况下,.java

javaFiles <- list.files(Sys.getenv('WORKSPACE'), recursive = TRUE, full.names = TRUE, pattern = "\\.java$")
propertiesFiles <- list.files(Sys.getenv('WORKSPACE'), recursive = TRUE, full.names = TRUE, pattern = "\\.properties$")

文件名列表逐个传递给之前定义的processFile函数。结果是一系列文件长度,存储在resultJavaresultProperties对象中:

resultJava <- sapply(javaFiles, processFile)
resultProperties <- sapply(propertiesFiles,processFile)

warnings()函数生成了在运行sapply命令时生成的问题列表:

14: In readLines(file, encoding = "UTF-8") :
  incomplete final line found on '/var/lib/jenkins/workspace/ch5.project.data/tool/src/java/org/apache/wicket/markup/html/form/upload/MultiFileUploadField_ca_ES.properties'

这表明期望文件末尾有一个新行。这不是一个关键问题。显示警告是发现损坏文件的有益方法。

最后,我们生成了两个结果的直方图,一个用于 Java 文件,另一个用于属性文件。文件名由一个常量字符串和一个唯一设置为每次构建的BUILD_NUMBER环境变量组成。pdf函数告诉 R 输出要存储在 PDF 文件中,而hist函数则绘制结果的直方图:

filename <-paste('Lengths_JAVA_',Sys.getenv('BUILD_NUMBER'),'.pdf',sep="")
pdf(file=filename)
hist(resultJava,main="Frequency of length of JAVA files")

还有更多...

当编写用于处理文件的 R 代码时,不要重复造轮子。R 有许多用于操作文本的库。stringi库就是一个例子(cran.r-project.org/web/packages/stringi/stringi.pdf)。这是一些计算文本文件中单词数量的示例代码:

library(stringi)
processFile <-function(file){
stri_stats_latex(readLines(file,encoding="UTF-8"))
}
results<-processFile(file.choose())
paste("Number of words in file:", results[4])

脚本定义了函数processFile。该函数需要一个文件名。文件被读入stri_stats_latex函数中。这个函数包含在stringi库中。它以矢量(一系列数字)的形式返回文件的摘要。

file.choose()函数弹出一个对话框,允许您浏览文件系统并选择文件。调用返回文件的完全限定路径。它将值传递给processFile函数调用。结果存储在结果矢量中。然后脚本打印出第四个数字,即文件中的单词数。

另一个用于文本挖掘的有趣的 R 包是tm:(cran.r-project.org/web/packages/tm/tm.pdf)。tm包具有加载一组文本文件并以多种不同方式分析它们的能力。

另请参阅

  • 利用 R 插件简化强大的可视化 在 第四章 中的配方,通过 Jenkins 进行通信

  • 通过日志解析添加一个警告存储使用违规的作业 在 第一章 中的配方,维护 Jenkins

第六章。远程测试

在本章中,我们将涵盖以下配方:

  • 从 Jenkins 部署 WAR 文件到 Tomcat

  • 创建多个 Jenkins 节点

  • 为从节点定制设置脚本

  • 使用 FitNesse 进行测试

  • 激活 FitNesse HtmlUnit 夹具

  • 运行 Selenium IDE 测试

  • 使用 Selenium WebDriver 触发 failsafe 集成测试

  • 创建 JMeter 测试计划

  • 报告 JMeter 性能指标

  • 使用 JMeter 断言进行功能测试

  • 启用 Sakai Web 服务

  • 使用 SoapUI 编写测试计划

  • 报告 SoapUI 测试结果

介绍

本章结束时,您将对 Web 应用程序和 Web 服务运行性能和功能测试。其中包括两个典型的设置配方:第一个是通过 Jenkins 将 WAR 文件部署到应用服务器,第二个是创建多个从节点,准备将测试工作从主节点移开。

通过 Jenkins 进行远程测试会显著增加基础设施中的依赖关系,从而增加了维护工作量。远程测试是一个特定于域的问题,减少了可以编写测试的受众规模。

本章强调了使测试编写对大众可及的必要性。接纳尽可能多的受众可以提高测试捍卫应用程序意图的机会。

突出显示的技术包括:

  • FitNesse:这是一个 wiki,您可以在其中编写不同类型的测试。使用 wiki 类似的语言来实时表达和更改测试,为功能管理员、顾问和最终用户提供了一个表达其需求的地方。您将学会如何通过 Jenkins 运行 FitNesse 测试。FitNesse 还是一个框架,您可以扩展 Java 接口以创建新的测试类型。这些测试类型称为夹具;有许多可用的夹具,包括用于数据库测试、从命令行运行工具以及对 Web 应用程序进行功能测试的夹具。

  • JMeter:这是一个流行的开源工具,用于压力测试。它还可以通过使用断言进行功能测试。JMeter 有一个允许您构建测试计划的 GUI。然后将测试计划存储在 XML 格式中。可以通过 Maven 或 Ant 脚本执行 JMeter。JMeter 非常高效,通常一个实例就足以对基础设施造成很大压力。但是,对于超高负载场景,JMeter 可以触发一系列 JMeter 实例。

  • Selenium:这是功能测试 Web 应用程序的事实工业标准。使用 Selenium IDE,您可以在 Firefox 或 Chrome 中记录您的操作,以 HTML 格式保存以供以后重播。测试可以通过 Maven 使用 Selenium RC(远程控制)重新运行。通常会使用具有不同操作系统和浏览器类型的 Jenkins 从节点来运行测试。另一种选择是使用 Selenium Grid(code.google.com/p/selenium/wiki/Grid2)。

  • Selenium 和 TestNG 单元测试:编写单元测试使用 TestNG 框架进行功能测试的程序员特定方法。单元测试应用 Selenium WebDriver 框架。Selenium RC 是控制 Web 浏览器的代理。相反,WebDriver 框架使用本机 API 调用来控制 Web 浏览器。您甚至可以运行 HtmlUnit 框架,消除了对真实 Web 浏览器的依赖。这使得测试独立于操作系统,但去除了测试浏览器特定依赖的能力。WebDriver 支持许多不同类型的浏览器。

  • SoapUI:这简化了为 Web 服务创建功能测试的过程。该工具可以读取 Web 服务公开的 WSDL(Web 服务定义语言)文件,使用该信息生成功能测试的骨架。GUI 使理解过程变得容易。

从 Jenkins 部署 WAR 文件到 Tomcat

部署 Web 应用程序进行集成测试的三种主要方法如下:

  • 在 Jenkins 作业中启动 Jetty 等容器本地运行 Web 应用程序。应用程序数据库通常是内存中的,并且存储的数据在作业结束后不会持久化。这样可以节省清理工作,并消除对基础设施的不必要依赖。

  • 每晚都会创建一个夜间构建,应用程序会通过调度程序重新构建。不需要轮询 SCM。这种方法的优点是团队分布广,确切地知道新构建存在的时间和 URL,以及部署脚本很简洁。

  • 部署到应用服务器。首先,在 Jenkins 中打包 Web 应用程序,然后部署准备好由第二个 Jenkins 作业进行测试。这种方法的缺点是,您正在动态替换应用程序,主机服务器可能不会始终稳定地响应。

在此示例中,您将使用 Deploy 插件将 WAR 文件部署到远程 Tomcat 7 服务器。此插件可以在一系列服务器类型和版本范围内部署,包括 Tomcat、GlassFish 和 JBoss。

准备就绪

为 Jenkins 安装 Deploy 插件(wiki.jenkins-ci.org/display/JENKINS/Deploy+Plugin)。下载最新版本的 Tomcat 7 并解压缩(tomcat.apache.org/download-70.cgi)。

如何做...

  1. 为简单的 WAR 文件从命令行创建一个 Maven 项目:

    mvn archetype:generate -DgroupId=nl.berg.packt.simplewar -DartifactId=simplewar -Dversion=1.0-SNAPSHOT -DarchetypeArtifactId=maven-archetype-webapp 
    
    
  2. 将新创建的项目提交到您的 Git 或子版本库中。

  3. 为避免与监听端口 8080 的 Jenkins 冲突,在 Tomcat 根目录下编辑 conf/server.xml,将默认连接器端口号更改为 38887

     <Connector port="38887" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
    
    
  4. 从命令行启动 Tomcat:

    bin/startup.sh
    
    
  5. 登录 Jenkins。

  6. 创建名为 ch6.remote.deploy 的 Maven

  7. 源代码管理 部分,选中 Subversion 单选框,将您自己的子版本库 URL 添加到 Repository URL

  8. 构建部分,对于目标和选项,添加clean package

  9. 后期构建操作部分,勾选部署 war/ear 到容器,添加以下配置:

    • WAR/EAR 文件: target/simplewar.war

    • 容器: Tomcat 7.x

    • 管理器用户名: jenkins_build

    • 管理器密码: mylongpassword

    • Tomcat URL: http://localhost:38887

  10. 点击保存

  11. 运行构建。

  12. 构建将以类似以下的输出失败: java.io.IOException: 服务器返回 HTTP 响应代码: 401,网址为: http://localhost:38887/manager/text/list

  13. 通过在conf/tomcat-users.xml中添加以下内容,编辑:在</tomcat-users>之前:

    <role rolename="manager-gui"/>
    <role rolename="manager-script"/>
    <role rolename="manager-jmx"/>
    <role rolename="manager-status"/>
    <user username="jenkins_build" password="mylongpassword" roles="manager-gui,manager-script,manager-jmx,manager-status"/>
    
  14. 重新启动 Tomcat。

  15. 在 Jenkins 中,再次构建该任务。现在构建将成功。查看 Tomcat 日志logs/catalina.out将显示类似于以下内容的输出: Oct 06, 2014 9:37:11 PM org.apache.catalina.startup.HostConfig deployWAR

    信息: 正在部署 Web 应用程序存档 /xxxxx/apache-tomcat-7.0.23/webapps/simplewar.war

  16. 使用 Web 浏览器访问http://localhost:38887/simplewar/,如下面的屏幕截图所示: 操作步骤...

注意

一个可能的陷阱:如果你在后期构建配置中拼错了 WAR 文件的名称,那么它会悄无声息地失败,但构建仍然会成功。

工作原理...

在撰写本文时,Deploy 插件部署到以下服务器类型和版本:

  • Tomcat 4.x/5.x/6.x/7.x

  • JBoss 3.x/4.x

  • GlassFish 2.x/3.x

在此示例中,Jenkins 打包了一个简单的 WAR 文件并部署到了 Tomcat 实例。默认情况下,Tomcat 监听8080端口,Jenkins 也是如此。通过编辑conf/server.xml,将端口移动到了38887,避免了冲突。

Jenkins 插件调用 Tomcat Manager。在部署失败且出现401未经授权错误(www.w3.org/Protocols/rfc2616/rfc2616-sec10.html)后,你创建了一个具有所需角色的 Tomcat 用户。实际上,新用户比部署所需的权限更大。用户有权查看用于监控的 JMX 数据。这会帮助你以后进行调试。

在生产环境中部署时,使用 SSL 连接以避免在网络上传送未加密的密码。

还有更多...

启动时,Tomcat 日志会提到缺少 Apache Tomcat 本机库:

信息: 基于 APR 的 Apache Tomcat 本机库,允许在生产环境中获得最佳性能,在 java.library.path 中找不到: /usr/java/packages/lib/i386:/usr/lib/i386-linux-gnu/jni:/lib/i386-linux-gnu:/usr/lib/i386-linux-gnu:/usr/lib/jni:/lib:/usr/lib

该库在 Linux 平台上运行时提高了性能,基于 Apache Portable Runtime 项目的努力 (apr.apache.org/)。

你可以在bin/tomcat-native.tar.gz中找到源代码。构建说明可以在tomcat.apache.org/native-doc/找到。

另请参阅

  • 第三章 中的 为 Jetty 配置集成测试 配方,构建软件

创建多个 Jenkins 节点

测试是一个繁重的过程。如果您想要扩展您的服务,那么您需要计划将大部分工作分配给其他节点。

Jenkins 在组织中的一个进化路径是从一个 Jenkins 主节点开始。随着作业数量的增加,我们需要将更重的作业,例如测试,推送到从节点。这使得主节点更轻巧且更专业地聚合结果。还有其他原因可以分配测试,例如当您希望在不同的操作系统下使用不同的网络浏览器或在本机运行 .NET 应用程序时进行功能测试。

此配方使用 Multi slave config 插件 (wiki.jenkins-ci.org/display/JENKINS/Multi+slave+config+plugin) 在本地安装额外的 Jenkins 节点。它是针对 Linux 的,允许 Jenkins 通过 SSH 安装、配置和控制从节点。

准备工作

在 Jenkins 中安装 Multi slave config 插件。您还需要一个 Ubuntu 的测试实例,如 使用测试 Jenkins 实例 配方中描述的那样,第一章,维护 Jenkins

如何操作...

  1. 从从节点的命令行创建用户 jenkins-unix-nodex

    sudo adduser jenkins-unix-nodex
    
    
  2. 使用空密码为主 Jenkins 生成私钥和公共证书:

    sudo -u jenkins ssh-keygen -t rsa
    Generating public/private rsa key pair.
    Enter file in which to save the key 
    (/var/lib/jenkins/.ssh/id_rsa): 
    Created directory '/var/lib/jenkins/.ssh'.
    Enter passphrase (empty for no passphrase): 
    Enter same passphrase again: 
    Your identification has been saved in 
    /var/lib/jenkins/.ssh/id_rsa.
    Your public key has been saved in 
    /var/lib/jenkins/.ssh/id_rsa.pub
    
    
  3. 创建 .ssh 目录和 Jenkins 的公共证书到 .ssh/authorized_keys

    sudo -u jenkins-unix-nodex mkdir /home/jenkins-unix-nodex/.ssh 
    sudo cp /var/lib/jenkins/.ssh/id_rsa.pub /home/jenkins-unix-nodex/.ssh/authorized_keys
    
    
  4. 更改 authorized_keys 的所有者和组为 jenkins-unix-nodex:jenkins-unix-nodex

    sudo chown jenkins-unix-nodex:jenkins-unix-nodex /home/jenkins-unix-nodex/.ssh/authorized_keys
    
    
  5. 测试您是否可以无密码登录到 jenkins-unix-nodex 作为 jenkins

    sudo –u Jenkins ssh jenkins-unix-nodex@localhost
    The authenticity of host 'localhost (127.0.0.1)' can't be established.
    ECDSA key fingerprint is 
    xx:yy:21:zz:46:dd:02:fa:1w:15:27:20:e6:74:3e:a2.
    Are you sure you want to continue connecting (yes/no)? yes
    Warning: Permanently added 'localhost' (ECDSA) to the list of known hosts.
    
    

    注意

    您将需要接受密钥指纹。

  6. 登录到 Jenkins。

  7. 访问凭据存储库(localhost:8080/credential-store)。

  8. 单击 全局凭据 链接,如下图所示:如何操作...

  9. 单击 添加凭据

  10. 添加以下详细信息:

    • 类型:带私钥的 SSH 用户名

    • 范围全局

    • 用户名jenkins-unix-nodex

    • 私钥来自 Jenkins 主机的 ~/.ssh

  11. 单击 保存如何操作...

  12. 访问 Manage Jenkins 下的 MultiSlave Config Pluginlocalhost:8080/multi-slave-config-plugin/?)。

  13. 单击 添加从节点

  14. 添加到 使用空格分隔的名称创建从节点unix-node01,然后单击 继续

  15. Multi Slave Config Plugin – 添加从节点 屏幕上,添加以下详细信息:

    • 描述我是一个愚蠢的 Ubuntu 节点

    • 执行器数量2

    • 远程文件系统根目录/home/jenkins-unix-nodex

    • 设置标签unix dumb functional

  16. 选择启动方法为 通过 SSH 在 Unix 机器上启动从节点 并添加详细信息:

    • 主机localhost

    • 凭据jenkins-unix-nodex

  17. 点击保存

  18. 返回到主页面。 您现在将看到Build Executor Status中包含Masterunix-node01,如下图所示:如何做...

它是如何工作的...

在这个示例中,您已经将一个节点部署到本地*NIX 框中。 使用了第二个用户帐户。 该帐户使用了 Jenkins 用户的公钥以便更轻松地进行管理:Jenkins 现在可以在没有密码的情况下使用sshscp

多从节点配置插件可以消除部署从节点的繁琐工作。 它允许您从一个模板从节点复制并部署多个节点。

Jenkins 可以以多种不同的方式运行节点:使用 SSH,主节点运行自定义脚本,或通过 Windows 服务(wiki.jenkins-ci.org/display/JENKINS/Distributed+builds)。 最可靠的方法是通过 SSH 协议。 这种方法的优点是多方面的:

  • 使用 SSH 是流行的,意味着对大多数人来说学习曲线较为平缓。

  • SSH 是一种可靠的技术,经过多代人的实践证明其稳健性。

  • 大多数操作系统都有 SSH 守护程序,不仅仅是*NIX。 一种选择是在 Windows 上安装 Cygwin(www.cygwin.com/)并带有一个 SSH 守护程序。

    注意

    如果您希望在 Cygwin 下的 Windows 中运行您的 Unix 脚本,请考虑安装 Cygpath 插件。 该插件将 Unix 样式路径转换为 Windows 样式。 有关更多信息,请访问

    wiki.jenkins-ci.org/display/JENKINS/Cygpath+Plugin

配置的节点已分配了三个标签:unixdumbfunctional。 在创建新作业时,检查设置限制此项目可以运行的位置并添加其中一个标签,将确保作业在具有该标签的节点上运行。

主节点根据优先级列表计算要运行作业的节点。 除非另有配置,否则在只有主节点时创建的作业仍将在主节点上运行。 新创建的作业默认将在从节点上运行。

当部署多个 Jenkins 节点时,如果您的环境结构保持一致,则可以节省工作量。 考虑使用从相同基本镜像开始的虚拟环境。 CloudBees(www.cloudbees.com)是一个以部署虚拟实例为中心的商业服务的示例。

注意

您可以在wiki.jenkins-ci.org/display/JENKINS/Step+by+step+guide+to+set+up+master+and+slave+machines找到有关为 Jenkins 从节点安装 Windows 服务的更多信息。

还有更多...

从版本 1.446 开始(jenkins-ci.org/changelog),Jenkins 已经内置了 SSH 守护程序。这将减少编写客户端代码的工作量。命令行界面可以通过 SSH 协议访问。您可以通过 Jenkins 管理网页设置守护程序的端口号,或者将端口号浮动。

Jenkins 使用头部信息发布端口号为 X-SSH-Endpoint。要自己查看,请使用 curl(curl.haxx.se/)查找从 Jenkins 返回的头部信息。例如,对于 *NIX 系统,可以尝试从命令行输入:

curl -s -D - localhost:8080 -o /dev/null

头部信息被发送到stdout供您查看,而正文被发送到/dev/null,这是一个系统位置,忽略所有输入。

来自 Jenkins 的响应将类似于以下内容:

HTTP/1.1 200 OK
Cache-Control: no-cache,no-store,must-revalidate
X-Hudson-Theme: default
Content-Type: text/html;charset=UTF-8
Set-Cookie: JSESSIONID.bebd81dc=1mkx0f5m97ipsjqhygljrbqmo;Path=/;HttpOnly
Expires: Thu, 01 Jan 1970 00:00:00 GMT
X-Hudson: 1.395
X-Jenkins: 1.583
X-Jenkins-Session: 5c9958f6
X-Hudson-CLI-Port: 39269
X-Jenkins-CLI-Port: 39269
X-Jenkins-CLI2-Port: 39269
X-Frame-Options: sameorigin
X-SSH-Endpoint: localhost:57024
X-Instance-Identity: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjOABhI+cuNtKfu5b46FKGr/IXh9IgaTVgf16QgCmoAR41S00gXJezDRJ1i4tC0tB6Tqz5SuKqcDDxU19fndIe7qhmNOPdAIMUU8i/UmKLC4eY/WfYqE9y4PpIR23yCVd2RB+KzADEhTB/voiLLoEkogj22WtUd7TZWhzRnAW58wrzI6uAWHqOtHvlO7MxFo1AY4ZyXLw202Dz+1tlKkECr5oy9dFyKy3U1lnpilg6snG70AYz+/uFs52FeOl3qkCfDVCGMDHqLEvJJzWsZ5hAv37fEaj1QyMA69joBjesgt1n1CeJeD0cy5+BIkwoHmrGW2VwvrxssIkm3RVhjJbeQIDAQABContent-Length: 19857
Server: Jetty(8.y.z-SNAPSHOT)

另请参阅

  • 第一章中的 使用测试 Jenkins 实例 方法,维护 Jenkins

  • 从节点的自定义设置脚本方法

从节点的自定义设置脚本

此方法向您展示如何在从节点上运行自己的初始化脚本。这使您可以执行节点系统清理、检查健康状况、设置测试以及执行其他必要的任务。

准备工作

要使此方法生效,您需要按照创建多个 Jenkins 节点的方法描述安装一个从节点。

您还将安装了从节点设置插件(wiki.jenkins-ci.org/display/JENKINS/Slave+Setup+Plugin)。

操作方法...

  1. 创建一个名为ch6.remote.slave.setup的自由样式作业。

  2. 检查限制此项目可运行的位置。

  3. 标签表达式 中添加文本dumb,如以下截图所示:操作方法...

  4. 点击保存,然后构建作业。

  5. 点击返回仪表板

  6. 构建执行者状态下点击unix-node01

  7. 点击脚本控制台

  8. 将以下文本添加到脚本控制台,然后点击运行

    println "pwd".execute().text
    println "ls ./workspace".execute().text
    
  9. 创建目录/var/lib/jenkins/myfiles

  10. 创建文件/var/lib/jenkins/myfiles/banner.sh,内容如下:

    #!/bin/sh
    echo -------------------------- > slave_banner.txt
    echo THIS IS A SLAVE INIT BANNER  >> slave_banner.txt
    echo WORKING ON SLAVE: ${NODE_TO_SETUP_NAME} >> slave_banner.txt
    date >> slave_banner.txt
    echo SCRIPT DOES SOME WORK HERE >> slave_banner.txt
    echo -------------------------- >> slave_banner.txt
    mv slave_banner.txt  /home/jenkins-unix- nodex/workspace/ch6.remote.slave.setup/
    
  11. 访问配置系统页面(http://localhost:8080/configure)。

  12. 从节点设置部分,点击添加按钮添加从节点设置列表

  13. 添加以下细节:

    • 设置文件目录/var/lib/jenkins/myfiles

    • 复制后的设置脚本./banner.sh

    • 标签表达式dumb

    操作方法...

  14. 检查 立即保存部署

  15. 点击保存

  16. 运行作业ch6.remote.slave.setup

  17. 查看工作空间。您现在将看到一个名为banner.txt的文件,内容类似于以下内容:

    --------------------------
    THIS IS A SLAVE INIT BANNER
    WORKING ON SLAVE: unix-node01
    Tue Oct 14 13:39:09 CEST 2014
    SCRIPT DOES SOME WORK HERE
    --------------------------
    
    

工作原理...

您使用从节点设置插件将banner.sh/var/lib/jenkins复制到从节点的主目录下的 banner.sh。此操作在每次节点上运行作业之前运行。

选择保存后部署以确保从节点上获取的脚本是最新的。

你使用脚本控制台发现了节点的主目录位置。你还验证了工作区包含了与ch6.remote.slave.setup作业同名的目录。

在作业中,您将其运行限制在具有dumb标签的节点上。这样,您就可以确保作业在节点上运行。

banner.sh默认使用的是sh shell,实际上指向了Bourne Again Shell (www.gnu.org/software/bash/),或者是Debian Almquist Shell (gondor.apana.org.au/~herbert/dash/)的dash

注意

有关在 Ubuntu 中使用破折号的原因,请访问wiki.ubuntu.com/DashAsBinSh

为了显示已运行,脚本将一个带有时间戳的小横幅输出到banner.txt。脚本中的最后一个命令将banner.txt移动到节点工作区下的作业目录。

作业运行后,从节点将工作空间复制回 Jenkins 主服务器的工作空间。稍后您会查看结果。

还有更多...

如果您的 Jenkins 节点支持其他语言,例如 Perl,您可以通过在脚本的第一行添加#!约定,指向脚本语言的二进制完整路径来运行它们。要发现二进制文件的路径,您可以使用节点脚本控制台并运行which命令:

println "which perl".execute().text

这导致了/usr/bin/perl

一个“Hello World”Perl 脚本将如下代码所示:

#!/usr/bin/perl
print "Hello World"

另请参阅

  • 创建多个 Jenkins 节点配方

使用 FitNesse 进行测试

FitNesse (fitnesse.org)是一个完全集成的独立 wiki 和验收测试框架。您可以在表格中编写测试并运行它们。在 wiki 语言中编写测试扩大了潜在测试编写者的受众,并减少了学习新框架所需的初始工作量。

使用 FitNesse 进行测试

如果测试通过,则表格行以绿色显示。如果失败,则以红色显示。测试可以被 wiki 内容包围,以在相同位置提供上下文信息,如用户故事。您还可以考虑在 FitNesse 中创建您的 Web 应用程序的模拟以及将测试指向这些模拟。

本配方描述了如何远程运行 FitNesse 并在 Jenkins 中显示结果。

准备工作

fitnesse.org/FitNesseDownload下载最新稳定的 FitNesse JAR。从wiki.jenkins-ci.org/display/JENKINS/FitNesse+Plugin安装 Jenkins 的 FitNesse 插件。

注意

用于测试此配方的发布号是20140901

如何做...

  1. 创建目录fit/logs并将其放置在fitnesse-standalone.jarfit目录中。

  2. 从命令行运行 FitNesse 帮助并查看选项:

    java -jar fitnesse-standalone.jar –help
    Usage: java -jar fitnesse.jar [-vpdrleoab]
    -p <port number> {80}
    -d <working directory> {.}
    -r <page root directory> {FitNesseRoot}
    -l <log directory> {no logging}
    -f <config properties file> {plugins.properties}
    -e <days> {14} Number of days before page versions expire
    -o omit updates
    -a {user:pwd | user-file-name} enable authentication.
    -i Install only, then quit.
    -c <command> execute single command.
    -b <filename> redirect command output.
    -v {off} Verbose logging
    
    
  3. 从命令行运行 FitNesse 并查看启动输出:

    java -jar fitnesse-standalone.jar -p 39996 -l logs -a tester:test
    Bootstrapping FitNesse, the fully integrated standalone wiki and acceptance testing framework.
    root page: fitnesse.wiki.fs.FileSystemPage at ./FitNesseRoot#latest
    logger: /home/alan/Desktop/X/fitness/logs
    authenticator: fitnesse.authentication.OneUserAuthenticator
    page factory: fitnesse.html.template.PageFactory
    page theme: fitnesse_straight
    Starting FitNesse on port: 39996
    
    
  4. 使用 web 浏览器,访问http://localhost:39996

  5. 单击验收测试链接。

  6. 单击套件链接。这将激活一组测试。根据您的计算机,测试可能需要几分钟才能完成。直接链接是http://localhost:39996/FitNesse.SuiteAcceptanceTests?suite

  7. 单击测试历史记录链接。您需要以用户tester和密码test登录。

  8. 查看fit/logs目录中的日志。再次运行套件后,您现在将看到类似于以下条目:

    127.0.0.1 - tester [01/Oct/2014:11:14:59 +0100] "GET /FitNesse.SuiteAcceptanceTests?suite HTTP/1.1" 200 6086667
    
    
  9. 登录 Jenkins 并创建一个名为ch6.remote.fitnesse的自由风格软件项目。

  10. 构建部分,从添加构建步骤中选择执行 fitnesse 测试选项。

  11. 检查FitNesse 实例已运行选项,并添加:

    • FitNesse 主机localhost

    • FitNesse 端口39996

    • 目标页面FitNesse.SuiteAcceptanceTests?suite

    • 检查目标是否为套件?选项

    • HTTP 超时(毫秒)180000

    • fitnesse xml 结果文件路径fitnesse-results.xml

  12. 后构建操作部分,检查发布 FitNesse 结果报告选项。

  13. 将值fitnesse-results.xml添加到输入fitnesse xml 结果文件路径中。

  14. 单击保存

  15. 运行该任务。

  16. 通过点击FitNesse 结果链接查看最新的任务。如何做...

它的工作原理...

FitNesse 有一组内置的验收测试,用于检查自身是否存在回归。Jenkins 插件调用测试,并要求以 XML 格式返回结果,使用 HTTP GET 请求的 URL:http://localhost:39996/FitNesse.SuiteAcceptanceTests?suite&format=xml。结果看起来类似于以下内容:

<testResults>
<FitNesseVersion>v20140901</FitNesseVersion>
<rootPath>FitNesse.SuiteAcceptanceTests</rootPath>
<result>
<counts><right>103</right>
<wrong>0</wrong>
<ignores>0</ignores>
<exceptions>0</exceptions>
</counts>
<runTimeInMillis>27</runTimeInMillis>
<relativePageName>CopyAndAppendLastRow</relativePageName>
<pageHistoryLink>
FitNesse.SuiteAcceptanceTests.SuiteFitDecoratorTests.CopyAndAppendLastRow?pageHistory&resultDate=20141101164526
</pageHistoryLink>
</result>

然后,Jenkins 插件解析 XML 并生成报告。

默认情况下,FitNesse 页面上没有启用安全性。在这个示例中,启动时定义了用户名和密码。但是,我们没有进一步定义页面的安全权限。要激活,您需要转到页面左侧的属性链接,并检查secure-test的安全权限。

您还可以通过文本文件中的用户列表或 Kerberos/ActiveDirectory 进行身份验证。有关更多详细信息,请查看fitnesse.org/FitNesse.FullReferenceGuide.UserGuide.AdministeringFitNesse.SecurityDescription

也有一个为 LDAP 认证贡献的插件:github.com/timander/fitnesse-ldap-authenticator

注意

考虑应用 深度安全性:通过防火墙在 FitNesse 服务器上添加 IP 限制可以创建额外的防御层。例如,你可以在 wiki 前面放置一个 Apache 服务器,并启用 SSL/TLS 来确保密码加密。一个比 Apache 更轻量的替代方案是 Nginx:wiki.nginx.org

还有更多...

你可以在其 GitHub 主页上找到有关构建最新版本 FitNesse 的源代码信息:github.com/unclebob/fitnesse

如果你喜欢 FitNesse,为什么不参与社区讨论呢?你可以订阅它的 Yahoo 群组 <fitnesse-subscribe@yahoogroups.com>,然后在 <fitnesse@yahoogroups.com.> 发布消息。Yahoo 的使用准则讨论了一般礼仪:info.yahoo.com/guidelines/us/yahoo/groups/

另请参阅

  • 激活 FitNesse HtmlUnit fixtures 教程

激活 FitNesse HtmlUnit fixtures

FitNesse 是一个可扩展的测试框架。可以编写自己的测试类型,称为 fixtures,并通过 FitNesse 表调用新的测试类型。这允许 Jenkins 运行不同于现有测试的替代测试。

此教程向你展示了如何集成使用 HtmlUnit fixture 的功能测试。同样的方法也适用于其他 fixtures。

准备工作

此教程假设你已经执行了 使用 FitNesse 进行测试 教程。

如何操作...

  1. 访问 sourceforge.net/projects/htmlfixtureim/,下载并解压缩 HtmlFixture-2.5.1

  2. HtmlFixture-2.5.1/lib 目录移动到 FitNesseRoot 目录下。

  3. HtmlFixture-2.5.1/log4j.properties 复制到 FitNesseRoot/log4j.properties

  4. 启动 FitNesse:

    java -jar fitnesse-standalone.jar -p 39996 -l logs -a tester:test
    
    
  5. 在网络浏览器中访问 http://localhost:39996/root?edit,添加以下内容,将 FitHome 替换为你的 Fitnesse 服务器主目录的完全限定路径:

    !path /FitHome/FitNesseRoot/lib/*
    !fixture com.jbergin.HtmlFixture 
    
  6. 访问 http://localhost:39996。在左侧菜单中,点击 编辑

  7. 在页面底部添加文本 ThisIsMyPageTest

  8. 点击 保存

  9. 点击新的 ThisIsMyPageTest 链接。

  10. 点击 工具 按钮。

  11. 选择 属性

  12. 点击 页面类型 测试。

  13. 一个弹出窗口会询问你的 用户名密码。输入 testertest

  14. 你将被返回到 ThisisMyPageTest 页面;点击 保存

  15. 点击左侧菜单上的 编辑 按钮。

  16. 在以 !contents 开头的行后添加以下内容:

    |Import|
    |com.jbergin|
    '''STORY'''
    This is an example of using HtmlUnit:http://htmlunit.sourceforge.net/
    '''TESTS'''
    !|HtmlFixture|
    |http://localhost:8080/login| Login||
    |Print Cookies||
    |Print Response Headers||
    |Has Text|log in|
    |Element Focus|search-box|input|
    |Set Value|ch5||
    |Focus Parent Type|form|/search/||
    
  17. 点击 保存

  18. 点击 测试如何操作...

  19. 在 Jenkins 中 新建任务 下,从 ch6.remote.fitness 复制 现有任务 / 复制任务名称 ch6.remote.fitness_fixture

  20. 构建 部分,下面的 目标 | 目标页面FitNesse.SuiteAcceptanceTests 替换为 ThisIsMyPageTest

  21. 不勾选 目标是否为套件?

  22. 点击 Save

  23. 运行任务。由于额外的调试信息与结果一起发送,导致 Jenkins 插件解析器混淆而失败。

  24. 访问测试页面 http://localhost:39996/ThisIsMyPageTest?edit,用以下代码替换测试表格的内容:

    !|HtmlFixture|
    |http://localhost:8080/login| Login|
    |Has Text|log in|
    |Element Focus|search-box|input|
    |Set Value|ch5|
    |Focus Parent Type|form|/search/|
    
  25. 再次运行 Jenkins 任务。现在结果将被解析。

工作原理...

Fixture 是用 Java 编写的。通过将下载的库放置在 FitNesse 的 lib 目录中,使它们可访问。然后在根页面中定义类路径和夹具位置,允许在启动时加载夹具。有关更多详细信息,请查看文件 HtmlFixture-2.5.1/README

接下来,你使用 wiki 的 CamelCase 笔记法创建了链接到不存在的 ThisIsMyPageTest 页面。然后添加了一个 HtmlUnit 夹具测试。

首先,你需要导入夹具,其库路径在 Root 页面中定义:

|Import|
|com.jbergin|

接下来,添加了一些示例描述性 wiki 内容以显示你可以创建一个故事而不影响测试。最后,添加了测试。

表格 !|HtmlFixture| 的第一行定义要使用的夹具。第二行存储要测试的位置。

打印命令,如 Print CookiesPrint Response Headers 返回有助于构建测试的信息。

如果你不确定一系列可接受的命令,则故意制造语法错误,命令将作为结果返回。例如:

|Print something||

Has Text 命令是一个断言,如果返回页面的文本中找不到 log in 则失败。

通过聚焦到特定元素然后 Set Value,你可以向表单添加输入。

在测试期间,如果你想要显示特定请求的返回内容,则需要三列;例如,第一行显示返回的页面,第二行则不显示:

|http://localhost:8080/login| Login||
|http://localhost:8080/login| Login|

将 HTML 页面作为结果的一部分返回,为 Jenkins 插件提供了需要解析的额外信息。这容易出错。因此,在第 19 步中,你移除了额外的列,确保可靠的解析。

可以在 htmlfixtureim.sourceforge.net/documentation.shtml 找到此夹具的完整文档。

还有更多...

FitNesse 有可能增加 Jenkins 可执行的远程测试的词汇量。有几个有趣的夹具需要审查:

另请参阅

  • 使用 FitNesse 进行测试 配方

运行 Selenium IDE 测试

Selenium IDE 允许你在 Firefox 中记录你在网页中的点击操作,并重放它们。这对于功能测试非常有用。测试计划以 HTML 格式保存。

这个示例展示了如何使用 Maven 和 Jenkins 自动重放测试。它使用内存中的 X 服务器 Xvfb (en.wikipedia.org/wiki/Xvfb),这样 Firefox 就可以在无头服务器上运行。Maven 使用 Selenium RC 运行测试,然后充当测试和浏览器之间的代理。虽然我们使用 Firefox 进行录制,但你也可以使用其他类型的浏览器运行测试。

随着 Selenium 2.0 的发布,Selenium 服务器现在具有内置的网格功能 (code.google.com/p/selenium/wiki/Grid2)。本章不讨论这个功能,只是说明 Selenium 网格允许你在多个操作系统上并行运行 Selenium 测试。

准备工作

安装 Selenium HTML 报告插件 (wiki.jenkins-ci.org/display/JENKINS/seleniumhtmlreport+Plugin) 和 EnvInject 插件 (wiki.jenkins-ci.org/display/JENKINS/EnvInject+Plugin)。同时需要 Xvfb 和 Firefox。在 Ubuntu Linux 环境中安装 Xvfb 运行 sudo apt-get install xvfb

注意

在 Jenkins 插件管理器中,该插件称为环境注入器插件,而在 Wiki 中称为 EnvInject 插件。这可能会让人感到困惑,但两个名称都属于同一个插件。

如何操作...

  1. 从命令行创建一个简单的 Maven 项目:

    mvn archetype:generate -DgroupId=nl.berg.packt.selenium -DartifactId=selenium_html -DarchetypeArtifactId=maven-archetype-quickstart -Dversion=1.0-SNAPSHOT
    
    
  2. 在新创建的 pom.xml 文件中,在 </project> 标签之前添加以下 build 部分:

    <build>
        <plugins>
         <plugin>
          <groupId>org.codehaus.mojo</groupId>
          <artifactId>selenium-maven-plugin</artifactId>
          <version>2.3</version>              
           <executions>
            <execution>
              <id>xvfb</id>
              <phase>pre-integration-test</phase>
              <goals>
                 <goal>xvfb</goal>
              </goals>
             </execution>
             <execution>
                <id>start-selenium</id>
                <phase>integration-test</phase>
             <goals>
             <goal>selenese</goal> 
            </goals>
           <configuration> <suite>src/test/resources/selenium/TestSuite.xhtml</suite>
         <browser>*firefox</browser>                        
         <multiWindow>true</multiWindow>
         <background>true</background>                           <results>./target/results/selenium.html</results> <startURL>http://localhost:8080/login/</startURL>
          </configuration>
         </execution>
        </executions>
       </plugin>
      </plugins>
    </build>
    
  3. 创建 src/test/resources/log4j.properties 文件,并添加以下内容:

    log4j.rootLogger=INFO, A1
    log4j.appender.A1=org.apache.log4j.ConsoleAppender
    log4j.appender.A1.layout=org.apache.log4j.PatternLayout
    log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
    
  4. 创建目录 src/test/resources/selenium

  5. 创建文件 src/test/resources/selenium/TestSuite.xhtml,并添加以下内容:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html  xml:lang="en" lang="en">
    <head>
      <meta content="text/html; charset=UTF-8" http-equiv="content-type" />
      <title>My Test Suite</title>
    </head>
    <body>
    <table id="suiteTable" cellpadding="1" cellspacing="1" border="1" class="selenium"><tbody>
    <tr><td><b>Test Suite</b></td></tr>
    <tr><td><a href="MyTest.xhtml">Just pinging Jenkins Login Page</a></td></tr>
    </tbody></table>
    </body>
    </html>
    

    HTML 将会渲染成以下截图:

    如何操作...

  6. 创建测试文件 src/test/resources/selenium/MyTest.xhtml,并添加以下内容:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html  xml:lang="en" lang="en">
    <head profile="http://selenium-ide.openqa.org/profiles/test-case">
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>MyTest</title>
    </head><body>
    <table cellpadding="1" cellspacing="1" border="1">
    <thead>
    <tr><td rowspan="1" colspan="3">MyTest</td></tr>
    </thead><tbody>
    <tr><td>open</td><td>/login?from=%2F</td><td></td></tr>
    <tr><td>verifyTextPresent</td><td>log in</td><td></td></tr>
    </tbody></table></body></html>
    

    HTML 将会按照以下截图进行渲染:

    如何操作...

  7. 从命令行运行 Maven 项目,验证构建是否成功,如下所示:

    mvn clean integration-test –Dlog4j.configuration=file./src/test/resources/log4j.properties
    
    
  8. 运行 mvn clean 然后提交项目到你的 Subversion 仓库。

  9. 登录到 Jenkins 并创建一个名为 ch6.remote.selenium_html 的 Maven 作业。

  10. Global 部分(配置页面顶部),勾选 Prepare an environment for the job 并添加 DISPLAY=:20Properties Content

  11. Source Code Management 部分,勾选 Subversion,并将你的 Subversion URL 添加到 Repository URL

  12. build 部分,将 clean integration-test –Dlog4j.configuration=file./src/test/resources/log4j.properties 添加到 Goals and options

  13. 后构建操作部分,勾选发布 Selenium HTML 报告

  14. target/results添加到Selenium 测试结果位置

  15. 检查如果解析结果文件时发生异常,则将构建结果状态设置为失败

  16. 单击保存

  17. 运行作业,查看结果,如下图所示:操作步骤...

工作原理...

创建了一个原始的 Selenium IDE 测试套件,包含两个 HTML 页面。第一个TestSuite.xhtml定义了套件,其中包含指向测试的 HTML 链接。我们只在MyTest.xhtml中定义了一个测试。

该测试访问本地 Jenkins 的登录页面,并验证登录文本是否存在。

pom.xml文件定义了启动和关闭 Xvfb 服务器的阶段。默认配置是让 Xvfb 在DISPLAY 20上接受输入。

Maven 假设 Xvfb 二进制文件已安装,并且不尝试将其作为依赖项下载。对于 Firefox 浏览器也是如此。这样做会导致一个脆弱的特定于操作系统的配置。在复杂的 Jenkins 环境中,这种依赖项最有可能失败。自动化功能测试必须具有显著的优势,以抵消增加的维护工作量。

选项Multiwindow设置为 true,因为测试在它们自己的 Firefox 窗口中运行。选项Background设置为 true,以便 Maven 在后台运行测试。结果存储在相对位置./target/results/selenium.html,准备供 Jenkins 插件解析。有关 Selenium-Maven-plugin 的更多信息,请访问mojo.codehaus.org/selenium-maven-plugin/

Jenkins 作业将DISPLAY变量设置为20,以便 Firefox 在 Xvfb 中呈现。然后运行 Maven 作业并生成结果页面。然后 Jenkins 插件解析结果。

增加自动功能测试的可靠性的两种方法是:

  • 使用 HtmlUnit,它不需要特定于操作系统的配置。但是,您将失去执行跨浏览器检查的能力。

  • 运行 WebDriver 而不是 Selenium RC。WebDriver 使用本地 API 调用,功能更可靠。与 Selenium RC 一样,WebDriver 可以针对多种不同的浏览器类型运行。

下一个示例将展示如何使用 WebDriver 和 HtmlUnit 进行单元测试。

还有更多...

在我的开发 Jenkins Ubuntu 服务器上,运行此示例的作业失败了。原因是 Maven 插件对 Selenium 的依赖项不喜欢由自动更新脚本安装的新版本 Firefox。解决问题的方法是在 Jenkins 主目录下安装一个已知工作的 Firefox 二进制文件,并在pom.xml文件中直接指向该二进制文件,将<browser>*firefox</browser>替换为<browser>*firefox Path</browser>

这里,Path类似于/var/lib/Jenkins/firefox/firefox-bin

另一个问题的原因是需要为 Firefox 创建一个自定义配置文件,其中包含停止弹出窗口或拒绝自签名证书的辅助插件。有关更完整的信息,请参阅:docs.seleniumhq.org/docs/

注意

Firefox 的替代方案是 Chrome。有一个 Jenkins 插件可以帮助在 Jenkins 节点上部署 Chrome (wiki.jenkins-ci.org/display/JENKINS/ChromeDriver+plugin)。

在 Maven pom.xml 文件中,您将不得不将浏览器更改为 *chrome

另请参见

  • 使用 Selenium WebDriver 触发失败安全集成测试的方法

使用 Selenium WebDriver 触发失败安全集成测试

单元测试是程序员保护其代码免受回归的自然方式。单元测试轻量且易于运行。编写单元测试应该像编写打印语句一样容易。JUnit (www.junit.org/) 是 Java 的流行单元测试框架,另一个是 TestNG (testng.org/doc/index.html)。

此方案使用 WebDriver 和 HtmlUnit 与 TestNG 结合编写简单的自动化功能测试。使用 HtmlUnit 而不是真正的浏览器可以创建稳定的与操作系统无关的测试,虽然它们不测试浏览器兼容性,但可以发现大多数功能失败。

准备工作

创建一个项目目录。查看 Maven 编译器插件文档 (maven.apache.org/plugins/maven-compiler-plugin/)。

如何做...

  1. 创建带有以下内容的 pom.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <project  
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>nl.uva.berg</groupId>
        <artifactId>integrationtest</artifactId>
        <version>1.0-SNAPSHOT</version>
        <build> 
          <plugins>
            <plugin>
              <groupId>org.apache.maven.plugins</groupId>
              <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
            </plugin>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-failsafe-plugin</artifactId>
            <version>2.10</version>
        </plugin>
        </plugins>
      </build>
      <dependencies>
        <dependency>
          <groupId>org.testng</groupId>
            <artifactId>testng</artifactId>
            <version>6.1.1</version>
            <scope>test</scope>
      </dependency>
      <dependency>
        <groupId>org.seleniumhq.selenium</groupId>
        <artifactId>selenium-htmlunit-driver</artifactId>
        <version>2.15.0</version>
      </dependency>
      </dependencies>
    </project>
    
  2. 通过添加以下内容的 TestIT.java 文件创建名为 src/test/java/nl/berg/packt/webdriver 的目录:

    package nl.berg.packt.webdriver;
    
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.htmlunit.HtmlUnitDriver;
    import org.testng.Assert;
    import org.testng.annotations.*; 
    import java.io.File;
    import java.io.IOException;
    
    public class TestIT {
      private static final String WEBPAGE = "http://www.google.com";
      private static final String TITLE = "Google";
      private WebDriver driver;
    
      @BeforeSuite
      public void creatDriver(){
        this.driver= new HtmlUnitDriver(true);
      }
    
      @Test
      public void getLoginPageWithHTMLUNIT() throws IOException, InterruptedException {
          driver.get(WEBPAGE);
          System.out.println("TITLE IS ==>\""+driver.getTitle()+"\"");
        Assert.assertEquals(driver.getTitle(), TITLE);
      }
    
      @AfterSuite
      public void closeDriver(){
        driver.close();
      }
    }
    
  3. 在顶级项目目录中,运行 mvn clean verify。构建应该成功,并输出类似于以下内容:

    TITLE IS ==>"Google"
    Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 4.31 sec
    Results :
    Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
    
    
  4. 将代码提交到您的子版本库。

  5. 登录 Jenkins 并创建名为 ch6.remote.driver 的新的 maven 项目。

  6. Source Code Management 部分,勾选 Subversion

  7. Modules | Repository URL 下,添加本地子版本库的位置。

  8. Goals and optionsbuild 部分中,添加 clean verify

  9. 单击 保存

  10. 运行该作业。成功构建后,您将看到一个指向最新测试结果的链接,详细说明功能测试情况。

它是如何工作的...

Maven 使用 Failsafe 插件 (maven.apache.org/surefire/maven-failsafe-plugin/) 运行集成测试。如果其 integration-test 阶段包含故障,则插件不会导致构建失败。相反,它允许运行 post-integration-test 阶段,以执行拆卸任务。

pom.xml 文件提到了两个依赖项:一个是 TestNG,另一个是 HtmlUnit 驱动程序。如果要使用真正的浏览器,则需要定义它们的 Maven 依赖项。

有关 Failsafe 插件如何与 TestNG 框架配合使用的详细信息,请参阅 maven.apache.org/plugins/maven-failsafe-plugin/examples/testng.html

Java 类使用注解来定义代码将在单元测试周期的哪个部分调用。@BeforeSuite 在测试套件开始时调用 WebDriver 实例的创建。@AfterSuite 在测试运行结束后关闭驱动程序。@test 定义方法为一个测试。

测试访问 Google 页面并验证标题的存在。HtmlUnit 注意到返回的 Google 页面和资源中的样式表和 JavaScript 存在一些错误;然而,断言成功。

示例测试的主要弱点是未能将断言与网页导航分开。考虑根据网页创建 Java 类(code.google.com/p/selenium/wiki/PageObjects)。页面对象返回其他页面对象。然后,在单独的类中运行测试断言,将返回的页面对象的成员与预期值进行比较。这种设计模式支持更高程度的可重用性。

提示

支持页面对象架构的 Groovy 中的优秀框架是Gebwww.gebish.org/)。

还有更多……

大脑处理的所有感官信息的 80% 通过眼睛传递。一张图片可以节省一千字的描述性文本。WebDriver 有捕获屏幕截图的能力。例如,以下代码对于 Firefox 驱动程序将截图保存到 loginpage_firefox.png

public void getLoginPageWithFirefox() throws IOException, InterruptedException {
  FirefoxDriver driver = new FirefoxDriver();
  driver.get("http://localhost:8080/login); 
 FileUtils.copyFile(driver.getScreenshotAs(OutputType.FILE), new File("loginpage_firefox.png"));
  driver.close();
}

注意

不幸的是,HtmlUnit 驱动程序不会创建截图:code.google.com/p/selenium/issues/detail?id=1361

然而,您可以在 groups.google.com/forum/#!msg/selenium-developers/PTR_j4xLVRM/k2yVq01Fa7oJ 找到一个实验性更新。

另见

  • 运行 Selenium IDE 测试食谱

  • 激活 FitNesse HtmlUnit 夹具食谱

创建 JMeter 测试计划

JMeter(jmeter.apache.org)是一个用于压力测试的开源工具。它允许您可视化地创建测试计划,然后根据该计划对系统进行测试。

JMeter 可以进行多种类型的请求,称为采样器。它可以对 HTTP、LDAP 和数据库进行采样,使用脚本等等。它可以通过监听器进行可视化报告。

注意

有关 JMeter 的入门书籍是:《Apache JMeter》作者 Emily H. Halili,由 Packt Publishing 出版,ISBN 1847192955(www.packtpub.com/beginning-apache-jmeter)。

同一出版商出版的另外两本更高级的书籍是 www.packtpub.com/application-development/performance-testing-jmeter-29www.packtpub.com/application-development/jmeter-cookbook-raw

在这个示例中,您将编写一个用于访问网页的测试计划,这些网页的 URL 在文本文件中定义。在下一个示例中,报告 JMeter 测试计划,您将配置 Jenkins 运行 JMeter 测试计划。

准备工作

下载并解压现代版本的 JMeter。(jmeter.apache.org/download_jmeter.cgi)。JMeter 是一个 Java 应用程序,因此将在正确安装了 Java 的任何系统上运行。

如何实现...

  1. 创建子目录 plansexample

  2. 创建一个 CSV 文件 ./data/URLS.csv,内容如下:

    localhost,8080,/login
    localhost,9080,/blah
    
  3. 运行 JMeter GUI—例如,./bin/jmeter.shjmeter.bat,根据操作系统而定。GUI 将启动一个新的测试计划。

  4. 右键单击 测试计划,然后选择 添加 | 线程(用户) | 线程组

  5. 线程数(用户数) 更改为 2

  6. 右键单击 测试计划,然后选择 添加 | 配置元素 | CSV 数据文件设置。添加以下细节:

    • 文件名:CSV 文件的完整路径

    • 变量名称(逗号分隔)HOSTPORTURL

    • 分隔符(使用 '\t' 表示制表符),

  7. 右键单击 测试计划,然后选择 添加 | 配置元素 | HTTP Cookie 管理器

  8. 右键单击 测试计划,然后选择 添加 | 监听器 | 查看树状结果

  9. 右键单击 线程组,然后选择 添加 | 采样器 | HTTP 请求。添加以下细节:

    • 名称${HOST}:${PORT}${URL}

    • 服务器名称或 IP${HOST}

    • 端口号${PORT}

    • 可选任务 下,勾选 从 HTML 文件中检索所有嵌入资源

  10. 点击 测试计划 然后 文件 | 保存。将测试计划保存为 example/jmeter_example.jmx

  11. 按下 Ctrl + R 运行测试计划。

  12. 点击 查看结果树 并查看响应:如何实现...

  13. 将此项目提交到您的 Subversion 存储库。

工作原理...

JMeter 使用线程并行运行请求。每个线程应该大约模拟一个用户。实际上,真实用户对系统的影响远远小于线程。线程可以每秒击中系统多次,而通常用户大约每二十秒点击一次。

测试计划使用了许多元素:

  • 线程组:这定义了运行的线程数。

  • Cookie 管理器:这个元素用于每个线程跟踪 cookie。如果您想在请求之间通过 cookie 跟踪,请确保使用这个元素。例如,如果一个线程登录到一个 Tomcat 服务器,需要为每个线程存储唯一的 Jsessionid

  • CSV Data Set Config:此元素解析 CSV 文件的内容,并将值放入HOSTPORTURL变量中。每个迭代每个线程读取 CSV 文件的一行。使用${variable_name}表示法在元素中展开变量。

  • 查看结果树:此监听器将结果显示在 GUI 中,以请求和响应的树形式显示。这对调试很有用,但稍后应该将其删除。

一个常见的错误是假设一个线程等同于一个用户。主要区别在于线程的响应速度可能比平均用户快。如果在请求中不添加延迟因素,那么您可能会使用少量线程来让您的应用程序负荷过重。例如,阿姆斯特丹大学的在线系统每次点击的典型延迟为 25 秒。

提示

如果您想要诱发应用程序中的多线程问题,则使用随机延迟元素而不是常量延迟。这也更好地模拟了典型用户交互。

还有更多...

考虑将用户代理和其他浏览器标头存储在文本文件中,然后通过 CSV Data Set Config 元素选择这些值进行 HTTP 请求。如果返回给您的 Web 浏览器的资源(如 JavaScript 或图像)取决于用户代理,则这是有用的。然后,JMeter 可以循环遍历用户代理,断言资源存在。

另请参阅

  • 报告 JMeter 性能指标 的示例

  • 使用 JMeter 断言进行功能测试 的示例

报告 JMeter 性能指标

在这个示例中,将向您展示如何配置 Jenkins 来运行 JMeter 测试计划,然后收集和报告结果。还将解释如何从 Ant 脚本传递变量到 JMeter。

准备就绪

假设您已经按照上一个示例创建了 JMeter 测试计划。您还需要安装 Jenkins 性能插件 (wiki.jenkins-ci.org/display/JENKINS/Performance+Plugin)。

如何做...

  1. 在 JMeter 中打开./examples/jmeter_example.jmx,并另存为./plans/URL_ping.jmx

  2. 选择CSV Data Set Config,将Filename更改为${__property(csv)}

  3. 文件菜单下选择保存选项。

  4. 在项目的顶层创建一个build.xml文件,并添加以下内容:

    <project default="jmeter.tests">
    <property name="jmeter" location="/var/lib/jenkins/jmeter" />
    <property name="target" location="${basedir}/target" />   
    <echo message="Running... Expecting variables [jvarg,desc]" />
    <echo message="For help please read ${basedir}/README"/>
    <echo message="[DESCRIPTION] ${desc}" />
    <taskdef  name="jmeter"  classname="org.programmerplanet.ant.taskdefs.jmeter.JMeterTask" classpath="${jmeter}/extras/ant-jmeter-1.0.9.jar" />
          <target name="jmeter.init">
          <mkdir  dir="${basedir}/jmeter_results"/>
          <delete includeemptydirs="true">
          <fileset dir="${basedir}/jmeter_results" includes="**/*" />
          </delete>
        </target>
        <target name="jmeter.tests" depends="jmeter.init" description="launch jmeter load tests">
        <echo message="[Running] jmeter tests..." />
    <jmeter jmeterhome="${jmeter}" resultlog="${basedir}/jmeter_results/LoadTestResults.jtl">
        <testplans dir="${basedir}/plans" includes="*.jmx"/>
        <jvmarg value="${jvarg}" />
        <property name="csv" value="${basedir}/data/URLS.csv" />
        </jmeter>
      </target>
    </project>
    
  5. 将更新提交到您的 Subversion 项目。

  6. 登录 Jenkins。

  7. 使用名称为ch6.remote.jmeter的新自由风格任务。

  8. 源代码管理下,勾选Subversion,并将您的 Subversion 仓库 URL 添加到Repository URL中。

  9. 构建部分中,添加构建步骤Invoke Ant

  10. 点击新的Invoke Ant子部分中的高级,并添加属性:

    jvarg=-Xmx512m
    desc= This is the first iteration in a performance test environment – Driven by Jenkins
    
  11. 后构建操作部分,勾选发布性能测试结果报告。将输入jmeter_results/*.jtl添加到报告文件中。

  12. 点击保存

  13. 运行作业几次并查看在 性能趋势 链接下找到的结果。

它是如何工作的...

build.xml 文件是一个 Ant 脚本,用于设置环境,然后调用库 /extras/ant-jmeter-1.0.9.jar 中定义的 JMeter Ant 任务。该 JAR 文件作为标准 JMeter 发行版的一部分安装。

找到 plans 目录下的任何 JMeter 测试计划都将被运行。将测试计划从 examples 目录移动到 plans 目录将其激活。结果将汇总在 jmeter_results/LoadTestResults.jtl 中。

Ant 脚本将 csv 变量传递给 JMeter 测试计划;CSV 文件的位置为 ${basedir}/data/URLS.csv${basedir} 是由 Ant 自动定义的。顾名思义,它是 Ant 项目的基目录。

你可以在 JMeter 元素中使用结构 ${__functioncall(parameters)} 调用 JMeter 函数。你已经将函数调用 ${__property(csv)} 添加到测试计划 CSV Data Set Config 元素中。该函数引入了在 Ant 脚本中定义的 csv 的值。

Jenkins 作业运行 Ant 脚本,Ant 脚本然后运行 JMeter 测试计划并汇总结果。然后 Jenkins 性能插件解析结果,生成报告。

还有更多...

要快速构建复杂的测试计划,请考虑使用内置于 JMeter 中的透明代理 (jmeter.apache.org/usermanual/component_reference.html#HTTP_Proxy_Server)。你可以在本地机器上的给定端口上运行它,并设置浏览器中的代理首选项以匹配。然后,记录的 JMeter 元素将为您提供捕获请求中发送的参数的很好的概念。

一个替代方案是 BadBoy (www.badboysoftware.biz/docs/jmeter.htm),它有自己的内置网络浏览器。它允许您以与 Selenium IDE 类似的方式记录操作,然后保存到 JMeter 计划中。

另请参阅

  • 创建 JMeter 测试计划 的方法

  • 使用 JMeter 断言进行功能测试 的方法

使用 JMeter 断言进行功能测试

此方法将向您展示如何在 Jenkins 作业中使用 JMeter 断言。JMeter 可以通过断言测试其 HTTP 请求和其他采样器的响应。这使得 JMeter 可以基于一系列 JMeter 测试来使 Jenkins 构建失败。当从 HTML 应用程序的底层代码快速变化时,这种方法尤其重要。

测试计划登录到您的本地 Jenkins 实例并检查登录响应中的大小、持续时间和文本。

准备工作

我们假设您已经执行了 创建 JMeter 测试计划报告 JMeter 性能指标 的方法。

注意

该配方需要在 Jenkins 中创建一个名为 tester1 的用户。随意更改用户名和密码。记得在不再需要时删除测试用户。

如何操作...

  1. 在 Jenkins 中创建名为 tester1 的用户,密码为 testtest

  2. 运行 JMeter。在测试计划元素中将名称更改为 LoginLogoutPlan,为用户定义变量添加:

    • 名称用户tester1

    • 名称密码testtest

    如何操作...

  3. 测试计划上右键单击,然后选择添加 | 配置元件 | HTTP Cookie 管理器

  4. 测试计划上右键单击,然后选择添加 | 监听器 | 查看树形结果

  5. 测试计划上右键单击,然后选择添加 | 线程(用户) | 线程组

  6. 线程组上右键单击,然后选择添加 | 取样器 | HTTP 请求,如下图所示:如何操作...

  7. 将以下细节添加到HTTP 请求取样器中:

    • 名称/j_aceqi_security_check

    • 服务器名称或 IPlocalhost

    • 端口号8080

    • 路径/j_aceqi_security_check

  8. 发送请求参数部分中添加:

    • 名称j_username${USER}

    • 名称j_password${PASS}

  9. 线程组上右键单击,然后选择添加 | 取样器 | HTTP 请求

  10. 将以下细节添加到HTTP 请求取样器中。如有必要,拖放新创建的元素,使其位于 /j_acegi_security_check 之后。

  11. 将以下细节添加到HTTP 请求取样器中:

    • 名称/logout

    • 服务器名称或 IPlocalhost

    • 端口号8080

    • 路径/logout

  12. 将测试计划保存到位置 ./plans/LoginLogoutPlan_without_assertions.jmx

  13. 将更改提交到您的本地 SVN 仓库。

  14. 在 Jenkins 中运行先前创建的作业 ch6.remote.jmeter。注意,在性能报告链接中,/j_acegi_security_check HTTP 请求取样器成功。

  15. ./plans/LoginLogoutPlan_without_assertions.jmx 复制到 ./plans/LoginLogoutPlan.jmx

  16. 在 JMeter 中编辑 ./plans/LoginLogoutPlan.jmx

  17. 在 JMeter 元素 j_acegi_security_check 上右键单击,选择添加 | 断言 | 持续时间断言

  18. 在新创建的断言中,将持续时间(毫秒)设置为 1000

  19. 在 JMeter 元素 j_acegi_security_check 上右键单击,选择添加 | 断言 | 大小断言

  20. 在新创建的断言中,将字节大小设置为 40000,并将比较类型设置为 <

  21. 在 JMeter 元素 j_acegi_security_check 上右键单击,选择添加 | 断言 | 响应断言,并填写细节:

    • 应用于部分中检查仅主样本

    • 要测试的响应字段部分中检查文本响应

    • 模式匹配规则部分中检查包含

    • 对于要测试的模式添加 仪表板 [Jenkins]

    如何操作...

  22. 保存测试计划并提交到您的本地子版本库。

  23. 运行 JMeter(Ctrl + R)并查看 查看结果树。请注意,大小和响应断言失败。

  24. 在 Jenkins 中运行先前创建的作业 ch6.remote.jmeter。注意,在 性能报告 链接中 /j_acegi_security_check 也会失败。

工作原理...

上一个配方中的脚手架没有改变。在 plans 目录下找到的任何 JMeter 测试计划都会在运行 Jenkins 作业时调用。

你创建了一个新的测试计划,其中包含两个 HTTP 请求采样器。第一个采样器将变量 j_usernamej_password 提交到登录 URL /j_acegi_security_check。响应包含一个包含有效会话 ID 的 cookie,该 ID 被存储在 cookie 管理器中。还添加了三个断言元素作为 HTTP 请求登录采样器的子项。如果其中任何一个断言失败,则 HTTP 请求结果也会失败。在 Jenkins 中,您可以根据可定义的阈值配置作业以失败或警告的方式运行。

三个断言对于测试计划来说是典型的。它们是:

  • 对返回结果的大小进行断言。大小不应大于 40,000 字节。

  • 对持续时间进行断言。如果响应时间太长,那么您就有了一个需要进一步检查的性能回归。

  • 最强大的断言用于检查文本模式。—在这种情况下,查看返回标题的详细信息。JMeter 元素还可以根据正则模式解析文本。

还有更多...

JMeter 具有使用请求进行压力测试的能力。每秒钟发出一个请求的 200 个线程大致相当于同时登录到一个应用程序的 5,000 个用户,每 25 秒点击一次。一个粗略的经验法则是,一个站点在一年中最繁忙的时间内约有 10% 的成员登录到应用程序中。因此,每秒点击一次的 200 个线程适合总成员数为 50,000 的站点。

了解使用模式也很重要;您对系统的使用了解越少,您就需要建立更宽的安全边界。为额外的容量进行计划不是不寻常的。额外的容量可能会成为您是否度假的差异。

注意

为了扩展其负载生成能力,JMeter 具有运行多个 JMeter 从节点的能力。有关此主题的官方教程,请参阅:jmeter.apache.org/usermanual/jmeter_distributed_testing_step_by_step.pdf

另请参阅

  • 创建 JMeter 测试计划 配方

  • 报告 JMeter 性能指标 配方

启用 Sakai web 服务

Sakai CLE 是全球许多大学使用的应用程序。基于超过一百万行的 Java 代码,Sakai CLE 允许学生与在线课程和项目站点进行交互。它赋予教师轻松创建这些站点的权限。

在这个示例中,您将启用 Web 服务并编写自己的简单 ping 服务。在下一个示例中,您将为这些服务编写测试。

准备就绪

您可以在sakaiproject.org找到到最新下载的链接。

source.sakaiproject.org/release/2.8.1下载并解压 Sakai CLE 版本 2.8.1。

最新版本可以在source.sakaiproject.org/release找到。

请注意,服务器在第一次启动时所需的时间比后续启动要长。这是由于样例课程的初始创建。

如何做...

  1. 编辑sakai/sakai.properties以包含:

    webservices.allowlogin=true
    webservices.allow=.*
    webservices.log-denied=true
    
  2. 在 NIX 系统中,从根文件夹./start-sakai.sh运行 Sakai,或者在 Windows 中运行./start-sakai.bat。如果 Jenkins 或另一个服务正在端口8080上运行,Sakai 将无法启动,并显示:

    2012-01-14 14:09:16,845 ERROR main 
    org.apache.coyote.http11.Http11BaseProtocol - Error starting endpoint
    java.net.BindException: Address already in use:8080
    
    
  3. 停止 Sakai ./stop-sakai.sh 或者 ./stop-sakai.bat

  4. 将端口号移动到39955,例如修改conf/server.xml文件:

    <Connector port="39955" maxHttpHeaderSize="8192" URIEncoding="UTF-8" maxThreads="150" minSpareThreads="25" maxSpareThreads="75" enableLookups="false" redirectPort="8443" acceptCount="100" connectionTimeout="20000" disableUploadTimeout="true" />
    
  5. 在 NIX 系统中,从根文件夹./start-sakai.sh运行 Sakai,或者在 Windows 中运行./start-sakai.bat

    注意

    第一次启动可能需要很长时间,因为演示数据被填充到内置数据库中。

  6. 在 Web 浏览器中访问http://localhost:39955/portal

  7. admin用户登录,密码为admin

  8. 注销。

  9. 访问http://localhost:39955/sakai-axis/SakaiScript.jws?wsdl

  10. 通过将以下内容添加到./webapps/sakai-axis/PingTest.jws来创建一个简单的未经身份验证的 Web 服务:

    public class PingTest {
      public String ping(String ignore){
        return "Insecure answer =>"+ignore;
      }
      public String pong(String ignoreMeAsWell){
        return youCantSeeMe();}
      private String  youCantSeeMe(){
        return "PONG";
      }
    }
    
  11. 要验证服务是否可用,请访问http://localhost:39955/sakai-axis/PingTest.jws?wsdl

  12. 要验证 REST 服务是否可用,请访问http://localhost:39955/direct

它是如何工作的...

Sakai 软件包是自包含的,拥有自己的数据库和 Tomcat 服务器。它的主要配置文件是sakai/sakai.properties。您已经更新了它以允许从任何地方使用 Web 服务。在实际部署中,IP 地址受到更严格的限制。

为了避免与本地 Jenkins 服务器端口冲突,修改了 Tomcat 的conf/server.xml文件。

Sakai 同时具有 REST 和 SOAP Web 服务。您将在/directURL 下找到 REST 服务。许多服务在/direct/describe下描述。服务向下提供一级。例如,要创建或删除用户,您需要使用在/direct/user/describe中描述的用户服务。

REST 服务使用 Sakai 框架注册到 Entitybroker (confluence.sakaiproject.org/display/SAKDEV/Entity+Provider+and+Broker)。Entitybroker 确保服务之间的一致处理,节省了编码工作量。Entitybroker 负责以正确的格式提供服务信息。要以 XML 格式查看 Sakai 认为您当前是谁,请访问http://localhost:39955/direct/user/current.xml,要以 JSON 格式查看,请用current.xml替换为current.json

SOAP 服务基于 Apache AXIS 框架 (axis.apache.org/axis/)。要创建一个新的基于 SOAP 的 Web 服务,您可以将一个扩展名为.jws的文本文件放入webapps/sakai-axis目录中。Apache AXIS 在第一次调用时即时编译代码。这样可以实现快速应用程序开发,因为调用者可以立即看到对文本文件的任何修改。

PingTest包含一个没有包的类。类名与去除.jws扩展名的文件名相同。任何公共方法都会成为 Web 服务。如果访问http://localhost:39955/sakai-axis/SakaiScript.jws?wsdl,您会注意到youCantSeeMe方法没有公开; 这是因为它具有私有范围。

大多数有趣的 Web 服务都需要通过/sakai-axis/SakaiLogin.jws登录 Sakai,方法是login并传递usernamepassword作为字符串。返回的字符串是一个 GUID(一个由字母和数字组成的长随机字符串),需要将其传递给其他方法以证明身份验证。

在交易结束时登出,使用方法logout并传递 GUID。

还有更多...

Sakai CLE 不仅仅是一个学习管理系统,它还是一个使开发新工具变得简单的框架。

新 Sakai 开发人员的程序员咖啡厅位于以下 URL:confluence.sakaiproject.org/display/BOOT/Programmer%27s+Cafe

基于程序员咖啡厅的训练营定期在 Sakai 会议上或通过咨询活动进行。训练营指导开发人员使用 Eclipse 作为首选的标准 IDE 来创建他们的第一个 Sakai 工具。

您可以在www.packtpub.com/sakai-cle-courseware-management-for-elearning-research/book找到书籍Sakai CLE 课程管理:官方指南Packt Publishing

注意

另一个相关产品是 Apereo 开放学术环境OAEwww.oaeproject.org/

Apereo OAE,就像 Sakai 一样,是社区驱动的。它具有独特的功能,例如能够在多个组织中同时运行,每个组织看起来都不同,并且可以根据配置的组在组织之间搜索文档或不搜索文档。

另请参阅

  • 使用 SoapUI 编写测试计划示例

  • 报告 SoapUI 测试结果示例

使用 SoapUI 编写测试计划

SoapUI(www.soapui.org/)是一个工具,允许高效地编写功能、性能和安全性测试,主要用于 Web 服务。

在本示例中,您将使用 SoapUI 对上一示例中创建的 Sakai SOAP Web 服务进行基本功能测试。

准备工作

如前一示例所述,我们假设您的 Sakai CLE 在端口39955上运行,并且PingTest服务可用。

要下载并安装 SoapUI,请访问www.soapui.org/getting-started/installing-soapui/installing-on-windows.html并按照安装说明进行操作。

要使 Linux 软件包与旧版本的 SoapUI 配合使用,您可能需要取消注释 SoapUI 启动脚本中的以下行:

JAVA_OPTS="$JAVA_OPTS -Dsoapui.jxbrowser.disable=true"

注意

此示例已针对 SoapUI 的 5.0.0 版本进行了测试。

如何操作...

  1. 启动 SoapUI。

  2. 右键单击项目,然后选择新建 Soap 项目

  3. 在对话框中填写以下详细信息:

    • 项目名称SakaiSoapTests

    • 初始 WSDL/WADLhttp://localhost:39955/sakai-axis/PingTest.jws?wsdl

    如何操作...

  4. 勾选创建测试套件

  5. 点击确定

  6. 点击确定以生成测试套件对话框。

  7. 点击确定以创建测试套件

  8. 在左侧导航器中,单击PingTestSoapBinding TestSuite旁边的+图标。如何操作...

  9. 点击ping TestCase旁边的+图标。

  10. 点击测试步骤(1)旁边的+图标。

  11. 右键单击ping,然后选择打开编辑器

  12. 在编辑器顶部,点击添加断言图标 如何操作...

  13. 选择断言包含,然后点击确定

  14. 对于内容选择NOT IN TEXT,然后点击确定

  15. 在左侧导航中,右键单击PingTestSoapBinding TestSuite,然后选择显示测试套件编辑器

  16. 在编辑器中点击开始测试图标 如何操作...

  17. 查看结果。ping TestCase由于断言而失败,而pong TestCase成功。

  18. 创建名为src/test/soapui的目录。

  19. 右键单击SakaiSoapTest,然后在目录src/test/soapui另存项目为SakaiSoapTests-soapui-project.xml如何操作...

工作原理...

SoapUI 让制作 Soap 服务的测试套件变得简单。SoapUI 使用PingTest WSDL 文件来发现服务的详细信息。

WSDL 代表 Web Services Description Language (www.w3.org/TR/wsdl)。 生成一个包含有关 PingTest 服务位置和使用信息的 XML 文件。

从 WSDL 文件中,SoapUI 为 PingPong 服务创建了一个基本测试。 您在 Ping 服务下添加了一个断言,检查 SOAP 响应中是否存在文本 NOT IN TEXT。 由于文本确实存在,断言失败。

SoapUI 具有广泛的断言,它可以强制执行,包括检查 Xpath 或 Xquery 匹配,检查状态码,或由自定义脚本测试的断言。

最后,项目以 XML 格式保存,准备在下一个配方的 Maven 项目中重用。

还有更多...

SoapUI 不仅仅是 Web 服务的功能测试。 它通过检查边界输入执行安全性测试。 它还具有用于压力测试的负载运行程序。

另一个重要功能是它能够从 WSDL 文件构建模拟服务。 这允许在 Web 服务仍在开发中时在本地构建测试。 早期创建的测试减少了到达生产环境的缺陷数量,降低了成本。 您可以在 www.soapui.org/Service-Mocking/mocking-soap-services.html 找到模拟服务的优秀介绍。

另请参阅

  • 启用 Sakai Web 服务 配方

  • 报告 SoapUI 测试结果 配方

报告 SoapUI 测试结果

在这个配方中,您将创建一个 Maven 项目,该项目运行上一个配方中创建的 SoapUI 测试。 使用 xUnit 插件 (wiki.jenkins-ci.org/display/JENKINS/xUnit+Plugin) 的 Jenkins 项目将解析结果并生成详细报告。

准备工作

安装 Jenkins xUnit 插件。 运行 启用 Sakai Web 服务使用 SoapUI 编写测试计划 配方。 现在你已经拥有运行 Sakai CLE 和一个准备好使用的 SoapUI 测试计划。

要尝试最新版本的 Maven 插件,请访问 www.soapui.org/Test-Automation/maven-2x.html

如何做...

  1. 创建一个项目目录。 在项目的根目录下,添加一个包含以下内容的 pom.xml 文件:

    <project 
    
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <name>Ping regression suite</name>
      <groupId>test.soapui</groupId>
      <artifactId>test.soapui</artifactId>
      <version>1.0-SNAPSHOT</version>
      <packaging>jar</packaging>
      <description>Sakai webservices test</description>
    <pluginRepositories>
      <pluginRepository>
        <id>eviwarePluginRepository</id>
        <url>http://www.eviware.com/repository/maven2/</url>
      </pluginRepository>
    </pluginRepositories>
      <build>
        <plugins>
          <plugin>
            <groupId>eviware</groupId>
            <artifactId>maven-soapui-plugin</artifactId>
            <version>4.0.1</version>
            <executions>
              <execution>
                <id>ubyregression</id>
                <goals>
              <goal>test</goal>
            </goals>
            <phase>test</phase>
          </execution>
        </executions>
        <configuration>
    <projectFile>src/test/soapui/SakaiSoapTests-soapui-project.xml</projectFile>
      <host>localhost:39955</host> <outputFolder>${project.build.directory}/surefire-reports</outputFolder>
              <junitReport>true</junitReport>
              <exportwAll>true</exportwAll>
              <printReport>true</printReport>
            </configuration>
          </plugin>
        </plugins>
      </build>
    </project>
    
  2. 确保您已将 SoapUI 项目正确放置在 src/test/soapui/SakaiSoapTests-soapui-project.xml

  3. 从命令行运行:

    mvn clean test
    
    
  4. 登录 Jenkins。

  5. 创建一个名为 ch6.remote.soapui 的 Maven 项目。

  6. 源代码管理 部分,检查 Subversion,添加您的 仓库 URL

  7. 构建 部分,下 目标和选项,添加 clean test

  8. 后构建操作 部分,检查 发布测试工具结果报告

  9. 单击 添加 按钮。

  10. 选择 JUnit

  11. JUNIT 模式 下添加 **/target/surefire-reports/TEST-PingTestSoapBinding_TestSuite.xml

  12. 单击 保存

  13. 运行作业。

  14. 点击 Latest Test Result 链接。您将看到一个失败和一个成功的作业,如下图所示:如何操作...

  15. 您将在 http://localhost:8080/job/ch6.remote.soapui/ws/target/surefire-reports/PingTestSoapBinding_TestSuite-ping_TestCase-ping-0-FAILED.txt 找到失败的完整细节。

工作原理...

Maven 项目使用了 maven-soapui plugin (www.soapui.org/Test-Automation/maven-2x.html)。由于插件在主要的 Maven 仓库之一中不可用,您必须配置它以使用 eviwarePluginRepository 仓库。

SoapUI 插件被配置为从项目文件 src/test/soapui/SakaiSoapTests-soapui-project.xml 中获取其计划,并将结果保存到 project.build.directory 相对于工作空间的根目录。

设置的选项是:

<junitReport>true</junitReport>
<exportwAll>true</exportwAll>
<printReport>true</printReport>

junitReport 设置为 true 告诉插件创建一个 JUnit 报告。exportwAll 设置为 true 意味着所有测试的结果都会被导出,而不仅仅是错误。这个选项在调试阶段很有用,除非您有严重的磁盘空间限制,否则应该设置为 onprintReport 设置为 true 确保 Maven 发送一个小的测试报告到控制台,输出类似于:

SoapUI 4.0.1 TestCaseRunner 概要

-----------------------------

总测试套件数:1

总测试用例数:2(1 个失败)

总请求断言数:1

总失败断言数:1

总导出结果数:1

[ERROR] java.lang.Exception: Not Contains in [ping] failed;

[响应包含令牌 [不安全的答案 =>?]]

ping 测试用例失败,因为断言失败。pong 测试用例成功,因为服务存在。因此,即使没有断言,使用 SoapUI 的自动生成功能也可以快速生成一个框架,确保所有服务都在运行。随着项目的发展,您始终可以稍后添加断言。

创建 Jenkins 任务很简单。xUnit 插件允许您导入许多类型的单元测试,包括从 Maven 项目创建的 JUnit 测试。在第 10 步中设置位置为 **/target/surefire-reports/TEST-PingTestSoapBinding_TestSuite.xml

提示

自定义报告选项是另一种将自定义数据引入并显示其在 Jenkins 中的历史趋势的方法。它通过使用自定义样式表解析插件找到的 XML 结果来实现。这使您可以灵活地添加自己的定制结果。

还有更多...

ping 服务很危险,因为它不过滤输入,输入通过输出反射回来。

许多网络应用程序使用 Web 服务将内容加载到页面中,以避免重新加载整个页面。一个典型的例子是当你输入搜索词并且替代建议即时显示时。通过一点社会工程魔法,受害者最终会发送一个包含脚本的请求到 Web 服务。在返回响应时,脚本将在客户端浏览器中运行。这绕过了同源策略的初衷(en.wikipedia.org/wiki/Same_origin_policy)。这被称为非持久性攻击,因为脚本不会持久存储。

对于 XSS 攻击,Web 服务比网页更难测试。幸运的是,SoapUI 简化了测试流程,使其达到了可控制的水平。你可以在www.soapui.org/Security/working-with-security-tests.html找到关于 SoapUI 安全测试的入门教程。

另请参阅

  • 启用 Sakai Web 服务 配方

  • 使用 SoapUI 编写测试计划 配方

第七章 探索插件

在本章中,我们将涵盖以下内容:

  • 个性化 Jenkins

  • 测试然后推广构建

  • 享受固定 JSGames

  • 查看 GUI 样本插件

  • 更改 FileSystem SCM 插件的帮助信息

  • 向作业描述添加横幅

  • 创建一个 RootAction 插件

  • 导出数据

  • 在启动时触发事件

  • 使用 Groovy 钩子脚本并在启动时触发事件

  • 当 Web 内容发生变化时触发事件

  • 回顾三个 ListView 插件

  • 创建我的第一个 ListView 插件

介绍

本章有两个目的:第一个是展示一些有趣的插件,第二个是简要回顾插件的工作原理。如果你不是程序员,可以跳过关于"插件工作原理"讨论。

当我开始撰写这本书时,有超过 300 个 Jenkins 插件可用,撰写本页时已超过 1,000 个。很可能已经有插件满足你的需求。Jenkins 不仅是一个持续集成服务器,也是一个创建额外功能的平台。一旦掌握了一些概念,程序员可以调整现有插件以适应组织的需求。

如果你发现缺少某个功能,通常更容易修改现有的功能,而不是从头开始编写一个。如果你想要适应的话,插件教程(wiki.jenkins-ci.org/display/JENKINS/Plugin+tutorial)是一个很好的起点。该教程提供了你日常使用的基础架构相关背景信息。

插件中有大量信息可供了解。以下是一些关键点:

  • 已有许多插件,还会有更多的开发。为跟上这些变化,你需要定期审查 Jenkins 插件管理器中可用的部分。

  • 与社区合作:如果你将改进集中提交,那么它们将对更广泛的观众可见。在社区的仔细关注下,代码更有可能被审查和进一步改进。

  • 不要重复造轮子:有了这么多插件,在大多数情况下,修改已存在的插件比从头开始编写要容易。

  • 固定插件是指当无法通过 Jenkins 插件管理器更新插件到新版本时发生。固定有助于维护稳定的 Jenkins 环境。

  • 大多数插件工作流程易于理解。然而,随着你使用的插件数量增多,无意中配置错误的可能性也增加。

  • Jenkins Maven 插件允许你在 Maven 构建中运行一个测试 Jenkins 服务器,而无需风险。

  • 规范节约精力:插件中文件的位置很重要。例如,你可以在 Jenkins 中找到插件的描述显示在文件位置/src/main/resources/index.jelly中。遵循 Jenkins 的约定,你编写的源代码量将被最小化,可读性将提高。

  • 在 Jenkins 中常用的三个框架是:

    • Jelly用于创建 GUI

    • Stapler将 Java 类绑定到 URL 空间

    • XStream用于将配置持久化为 XML

    注意

    本章中提到的一些插件的源代码在 Subversion 中。在撰写本文时,如果有代码被移动,很可能已经转移到 Jenkins 的 GitHub 存储库(github.com/jenkinsci)。插件开发者的约定是在旧的 Subversion 存储库中留下一个README文件,列出新的 Git 位置。

个性化 Jenkins

本教程重点介绍了两个改善用户体验的插件:Green Balls 插件和 Favorite 插件。

Jenkins 拥有广泛的国际受众。有时,在 Jenkins 外观表达方式上可能会有微妙的文化差异。一个例子是,当一个构建成功时,蓝色的圆球被显示为图标。然而,许多人自然地将交通灯中的绿色与继续前进的信号联系在一起。

Favorite 插件允许你选择你喜欢的项目并在视图中显示一个图标以突出显示你的选择。

准备好了

安装 Green Balls 和 Favorite 插件(wiki.jenkins-ci.org/display/JENKINS/Green+Balls, wiki.jenkins-ci.org/display/JENKINS/Favorite+Plugin)。

如何做...

  1. 创建一个空的新自由风格作业,命名为ch7.plugin.favourite

  2. 多次构建该作业,查看构建历史。现在你会看到绿色的球而不是通常的蓝色,如下面的屏幕截图所示:如何做...

  3. 返回到主页。

  4. 要创建一个新的视图,请单击+图标。

  5. 填写FAV作为名称。

  6. 检查列表视图

  7. 作业过滤器部分,选择使用正则表达式将作业包含到视图中。为正则表达式添加.*

  8. 部分,请确保您有三列名称状态收藏夹,如下面的屏幕截图所示:如何做...

  9. 点击确定

  10. 你将会进入FAV视图。通过点击星形图标,你可以选择/取消选择你喜欢的项目,如下面的屏幕截图所示:如何做...

它如何运作...

Green Balls 插件表现如宣传的那样。Favorite 插件允许你选择最感兴趣的项目并将其显示为收藏夹图标。这提醒你项目需要一些即时行动。

注意

如果你对与社区合作感兴趣,那么这些插件是你可以增加额外功能的示例。你可以在这里找到官方的参与指南:wiki.jenkins-ci.org/display/JENKINS/Beginners+Guide+to+Contributing

还有更多...

最喜欢的项目的反义词,至少暂时是一个构建失败的项目。Claim 插件(wiki.jenkins-ci.org/display/JENKINS/Claim+plugin)允许个别开发人员声明失败的构建。这使得将工作流程映射到个人责任成为可能。

一旦安装了 Claims 插件,您就能在作业的后构建操作部分找到一个名为允许声明破损构建的复选框。一旦启用,如果构建失败,您可以声明特定的构建,并添加有关您动机的注释。

还有更多...

现在,在 Jenkins 主页上,有一个指向保留所有声明构建摘要的日志的链接。项目经理现在可以阅读有关问题的快速概述。该日志是直接链接到正在处理当前问题的团队成员,如下截图所示:

还有更多...

Favorite 插件在其简单性中非常优雅。在下一个配方中,测试然后推广将表示允许进一步将复杂工作流程纳入的信号。

另请参阅

  • 测试然后推广构建配方

  • 与标记 JSGames 有趣配方

测试然后推广构建

在自动测试之前,您不希望 QA 团队审查应用程序。为实现此目的,您可以使用推广插件。

在 Jenkins 中,推广是一种视觉信号。在特定构建旁边设置一个图标,以提醒团队执行操作。

促进和前面配方中提到的 Favorite 插件之间的区别在于,促进可以根据各种自动操作自动触发。这些操作包括运行脚本或验证其他上游或下游作业的状态。

在这个配方中,您将编写两个简单的作业。第一个作业将触发第二个作业;如果第二个作业成功,则将提升第一个作业。这是一个现实的质量保证流程的核心,即测试作业推动打包作业。

准备就绪

安装推广构建插件(wiki.jenkins-ci.org/display/JENKINS/Promoted+Builds+Plugin)。

如何操作...

  1. 创建一个名为ch7.plugin.promote_action的自由风格作业。

  2. 运行此作业并验证其成功。

  3. 创建一个名为ch7.plugin.to_be_promoted的自由风格作业。

  4. 在配置页面的顶部附近,勾选当...促进构建

  5. 填写以下细节:

    • 名称:由自动功能测试验证

    • 图标选择绿色星号

    • 检查在以下下游项目成功构建时

    • 作业名称ch7.plugin.promote_action

    如何操作...

  6. 后构建操作部分检查构建其他项目

  7. 要构建的项目填写ch7.plugin.promote_action

  8. 勾选仅在构建稳定时触发

  9. 点击保存

  10. 构建作业。

  11. 单击推广状态链接,如下图所示:如何实现...

  12. 查看构建报告。如何实现...

工作原理...

推广构建类似于 Favorite 插件,但具有工作流自动化。您可以根据由构件创建触发的作业来推广。这是典型的工作流程,当您希望作业在被拾起和审查之前经过基线质量测试时。

该插件具有足够的配置选项,使其适应大多数工作流程。另一个示例是,对于典型的开发、验收和生产基础设施,您不希望在开发和验收被推广之前将构件部署到生产环境。配置此方法是具有一系列作业,最后一个推广到生产取决于上游开发和验收作业的推广。

如果您想要添加人工干预,那么在作业配置中检查仅在手动批准时并添加批准者名单。

还有更多...

如果您依赖于人工干预且没有自动测试,请考虑使用简化的推广构建插件(wiki.jenkins-ci.org/display/JENKINS/Promoted+Builds+Simple+Plugin)。正如其名称所示,该插件简化了配置,并且可以很好地与大多数 QA 工作流配合使用。简化配置使得更容易解释,使更广泛的受众可以使用。

您可以在主 Jenkins 配置页面中配置不同类型的推广,如下图所示:

还有更多...

明智地使用自动保存功能。此选项告诉 Jenkins 保留构建的所有构件。如果作为增量构建过程的一部分使用,将最终占用大量磁盘空间。

该插件允许您提升推广。通过左侧构建上的链接可提供一个简单的选择。此功能允许您将一系列玩家添加到推广过程中。

当最终推广发生时,例如到GA一般可用),推广将被锁定,不再能够被降级。

还有更多...

用户推广的能力取决于其权限。例如,如果您使用基于矩阵的安全性,则需要在作业的配置页面中看到额外选项之前更新其表格,如下图所示:

还有更多...

另请参阅

  • 个性化 Jenkins 教程

与固定 JSGames 玩耍

本教程向您展示如何固定 Jenkins 插件。固定插件将阻止您能够在 Jenkins 插件管理器内更新其版本。

现在老板走了,生活并不总是关于代码质量。为了减轻压力,考虑让你的团队通过 JSGames 插件放松。

准备工作

安装 JSGames 插件 (wiki.jenkins-ci.org/display/JENKINS/JSGames+Plugin)。

如何操作...

  1. 检查并回顾你选择的目录下的标签 jsgames-0.2,命令如下:

    git clone https://github.com/jenkinsci/jsgames-plugin
    git tag
    git checkout jsgames-0.2
    
    
  2. 查看 Jenkins 的首页;你会看到一个指向 JS Games 的链接,如下所示:如何操作...

  3. 点击链接,你将可以选择两个游戏,马里奥卡丁车俄罗斯方块如何操作...

  4. 作为 Jenkins 管理员,访问管理插件部分,然后点击已安装选项卡 (http://localhost:8080/pluginManager/installed)。注意 JSGames 插件没有被固定。

  5. 从命令行,列出插件目录 (JENKINS_HOME/plugin) 的内容,例如:

    ls /var/lib/jenkins/plugins
    
    

    输出将类似于:

    ant                             ant.jpi
    jsgames                     jsgames.jpi
    maven-plugin             maven-plugin.jpi
    
    
  6. 在插件目录中,创建一个名为 jsgames.jpi.pinned 的文件,例如:

    sudo touch /var/lib/jenkins/plugins/jsgames.jpi.pinned
    sudo chown jenkins /var/lib/jenkins/plugins/jsgames.jpi.pinned
    
    
  7. 在你的网络浏览器中,刷新已安装插件页面。现在你会看到 jsgames 插件被固定了:如何操作...

它是如何工作的...

固定一个插件会阻止 Jenkins 管理员更新插件的新版本。要固定一个插件,你需要在插件目录中创建一个与插件同名的文件,以 pinned 为扩展名结尾。参见 wiki.jenkins-ci.org/display/JENKINS/Pinned+Plugins

Jenkins 的新版本大约每周发布一次,包含 bug 修复和功能更新。这导致改进快速地进入市场,但有时也会导致失败。将插件固定可以防止插件在你评估新版本的稳定性和价值之前被意外更新。固定是保持生产服务器稳定的工具。

还有更多...

源代码包括一个顶级 pom.xml 文件来控制 Maven 构建过程。按照惯例,四个主要的源代码区域是:

  • src/test:这包含构建过程中的测试代码。对于 JSGames,有一堆 JUnit 测试。

  • src/main/java:这是 Java 代码的位置。Jenkins 使用 Stapler (wiki.jenkins-ci.org/display/JENKINS/Architecture) 将此目录中的 Java 对象与 Jenkins 在 src/main/resources 下找到的视图相映射。

  • src/main/resources:这是插件的视图位置。当你在 Jenkins 中进行交互时,例如 JS Games 的链接,你会使用与插件相关联的 GUI。视图是使用 Jelly 标记定义的。

  • src/main/webapp:这是资源的位置,如图像、样式表和 JavaScript。该位置映射到 URL 空间。/src/main/webapp映射到 URL /plugin/name_of_plugin。例如,位置/src/main/webapp/tetris/resources/tetris.js映射到 URL /plugin/jsgames/tetris/resources/tetris.js

参见

  • 创建 RootAction 插件的步骤

查看 GUI 示例插件

本篇描述如何通过 Maven 运行 Jenkins 测试服务器。在测试服务器中,你将看到示例 GUI 插件。GUI 插件展示了许多标签元素,稍后你可以在自己的插件中使用。

准备工作

创建一个目录来保存本篇的结果。

如何操作...

  1. 在 recipe 目录中,在pom.xml文件中添加以下内容:

    <?xml version="1.0"?>
    <project   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
     <modelVersion>4.0.0</modelVersion>
    <parent>
      <groupId>org.jenkins-ci.plugins</groupId>
      <artifactId>plugin</artifactId>   
      <version>1.584</version>
    </parent>
      <artifactId>Startup</artifactId>
      <version>1.0-SNAPSHOT</version>
      <packaging>hpi</packaging>
      <name>Startup</name>
      <repositories>
        <repository>
        <id>repo.jenkins-ci.org</id>
        <url>http://repo.jenkins-ci.org/public/</url>
        </repository>
        </repositories>
        <pluginRepositories>
        <pluginRepository>
        <id>repo.jenkins-ci.org</id>
        <url>http://repo.jenkins-ci.org/public/</url>
      </pluginRepository>
      </pluginRepositories>
      <properties>
        <project.build.sourceEncoding>UTF-8   
        </project.build.sourceEncoding>
      </properties>
    </project>
    
  2. 从命令行运行mvn hpi:run。如果你在端口8080上有一个默认的 Jenkins 运行,那么你将看到类似于以下的错误消息:

    2012-02-05 09:56:57.827::WARN:  failed SelectChannelConnector @ 0.0.0.0:8080
    java.net.BindException: Address already in use
    at sun.nio.ch.Net.bind0(Native Method)
    
    
  3. 如果服务器仍在运行,按下Ctrl + C

  4. 要在端口8090上运行,请输入以下命令:

    mvn hpi:run -Djetty.port=8090
    
    
  5. 服务器现在正在运行,并从控制台生成一个SEVERE错误:

    SEVERE: Failed Inspecting plugin  /DRAFT/Exploring_plugins/hpi_run/./work/plugins/Startup.hpl
    java.io.IOException: No such file: /DRAFT/Exploring_plugins/hpi_run/target/classes
    
    
  6. 访问localhost:8090/jenkins。在页面底部,查看 Jenkins 的版本号,如下截图所示:如何操作...

  7. 通过插件管理器(http://localhost:8090/pluginManager/available)安装 UI 示例插件。

  8. 在首页上,点击UI 示例链接:如何操作...

  9. 查看所提及的各种示例类型,例如 AutoCompleteTextBox(http://localhost:8090/ui-samples/AutoCompleteTextBox/)。

工作原理...

对于开发目的,从 Maven 运行测试服务器的能力非常棒。你可以修改代码,编译,打包,然后在本地 Jenkins 实例上查看,而无需担心配置或破坏真实服务器。你不必太担心安全性,因为测试服务器只在测试期间运行。

目标hpi:run尝试打包并部署一个名为 Startup 的插件。但是,由于包不可用,它会记录一个投诉,并忠实地运行一个 Jenkins 服务器。Jenkins 服务器的版本号与pom.xml中定义的<parent>标签内的<version>标签相同。

为了避免与本地 Jenkins 实例使用相同的端口,你设置了jetty.port选项。

一旦运行,访问 GUI 示例插件会展示如何在 Jelly 中创建各种 GUI 元素的示例。这些元素稍后在编程自己的插件时会派上用场。插件中使用的 Jelly 文件位于/src/main/resources目录下。Jenkins 使用 Stapler 将在src/main/java中找到的任何相关类绑定起来。

你可以在work文件夹中找到 Jenkins 的工作空间。你在测试服务器上所做的任何配置更改都将保留在这里。为了重新开始,你需要手动删除该目录。

对于本章中的所有配方,我们将固定 Jenkins 版本为 1.584。原因有两个:

  • 依赖项占用了大量空间。Jenkins war 文件和测试 war 文件大约占用本地 Maven 存储库的 120 MB。将此数字乘以使用的 Jenkins 版本数量,您很快就会填满几 GB 的存储空间。

  • 将 Jenkins 版本固定在特定版本可以稳定配方。

欢迎更新到最新版本的 Jenkins,因为本章中的示例应该仍然适用。如果遇到困难,您可以随时返回已知的安全版本号。

更多内容...

在幕后,Maven 做了大量的繁重工作。pom.xml 文件定义了 repo.jenkins-ci.org/public/ 存储库以获取依赖项。它调用版本 1.584 的 org.jenkins-ci.plugins.plugin。版本号与 Maven 运行的 Jenkins 版本号同步。

要发现可接受的版本号,请访问 repo.jenkins-ci.org/public/org/jenkins-ci/plugins/plugin/

Jenkins 服务器的详细信息以及包含的任何额外插件可以在 1.584/plugin-1.584.pom 相对于前述 URL 找到。UI Samples 插件版本也固定在版本 1.584。

官方页面和插件构建的最新信息可以在 wiki.jenkins-ci.org/display/JENKINS/Plugin+tutorial 找到。

参见

  • 更改 FileSystem SCM 插件的帮助 配方

更改 FileSystem SCM 插件的帮助

本配方审查了 FileSystem SCM 插件的内部工作原理。该插件允许您将代码放在本地目录中,并在构建中被检索到。例如,您将更改插件帮助文件中的文本。

准备工作

创建一个准备接受本配方代码的目录。在新创建的目录中,下载插件的源码:

git clone https://github.com/jenkinsci/filesystem_scm-plugin cd filesystem_scm-plugin/

操作方法...

  1. 查看标签信息,然后检出最新的稳定标签:

    git tag –l
    filesystem_scm-0.1
    filesystem_scm-1.10
    filesystem_scm-1.20
    filesystem_scm-1.5
    filesystem_scm-1.6
    filesystem_scm-1.7
    filesystem_scm-1.8
    filesystem_scm-1.9
    git checkout –b filesystem_scm-1.20
    
    
  2. 在顶级目录中,编辑 pom.xml 文件,在 <parent> 下更改版本为 1.584

      <parent>
        <groupId>org.jenkins-ci.plugins</groupId>
        <artifactId>plugin</artifactId> 
        <version>1.584</version>
      </parent>
    
  3. 用以下代码替换存储库和 pluginRepositories 部分:

      <repositories>
        <repository>
          <id>repo.jenkins-ci.org</id>
          <url>http://repo.jenkins-ci.org/public/</url>
        </repository>
      </repositories>
      <pluginRepositories>
        <pluginRepository>
          <id>repo.jenkins-ci.org</id>
          <url>http://repo.jenkins-ci.org/public/</url>
        </pluginRepository>
      </pluginRepositories>
    
  4. src/main/webapp/help-clearWorkspace.html 的内容替换为以下代码:

    <div>
      <p>
    <h3>HELLO WORLD</h3>
      </p>
    </div>
    
  5. 运行 mvn clean install。单元测试失败,输出为:

    Failed tests:   test1(hudson.plugins.filesystem_scm.SimpleAntWildcardFilterTest): expected:<2> but was:<0>
    Tests run: 27, Failures: 1, Errors: 0, Skipped: 0
    
    
  6. 运行 mvn clean package -Dmaven.test.skip=true 来跳过失败的测试。插件现在已经打包完毕。

    将插件上传到插件管理器的 高级 部分 (http://localhost:8080/pluginManager/advanced) 的 ./target/filesystem_scm.hpi 中:

    操作方法...

  7. 重新启动 Jenkins 服务器。

  8. 登录 Jenkins 并访问已安装插件的列表 (http://localhost:8080/pluginManager/installed)。

  9. 创建一个名为 ch7.plugins.filesystem_scm 的 Maven 作业。

  10. 源码管理部分下,您现在有一个名为文件系统的部分。

  11. 点击帮助图标获取清理工作区的相关信息。如下截图所示:操作步骤...

  12. 要删除插件,请删除 jpi 文件和位于 JENKINS_HOME/plugins 下的扩展目录。

  13. 重启 Jenkins。

工作原理...

恭喜,你已经更新了 SCM 插件。

首先,您修改了插件的 pom.xml 文件,更新了测试 Jenkins 服务器的版本,并指向了 Maven 下载工件的正确存储库。接下来,您修改了其帮助文件。

对于每个 Java 类,您都可以通过关联的 config.jelly 文件配置其 GUI 表示。映射来自 src/main/java/package_path/classname.java

src/main/resources/package_path/classname/config.jelly

例如,src/main/resources/hudson/plugins/filestem_scm/FSSCM/config.jelly 配置了 src/main/java/hudson/plugins/filesystem_s_c_m/FSSCM.java 的 Jenkins GUI。

帮助文件的位置在 config.jelly 中的 entry Jelly 标记的 help 属性中定义:

  <f:entry title="Clear Workspace" help="/plugin/filesystem_scm/help-clearWorkspace.html">
    <f:checkbox name="fs_scm.clearWorkspace" checked="${scm.clearWorkspace}"/>
  </f:entry>

src/main/webapps 目录为静态内容(如图像、样式表和 JavaScript 文件)提供了一个稳定的 Jenkins URL /plugin/name_of_plugin。这就是为什么帮助文件存储在这里。修改 help-clearWorkspace.html 会更新 entry 标签指向的帮助。

变量 ${scm.clearworkspace} 是对 FSSCM 实例中 clearWorkspace 成员的引用。

还有更多...

插件通常包含两种类型的 Jelly 文件,即 global.jellyconfig.jellyconfig.jelly 文件生成配置作业时看到的配置元素。global.jelly 文件在主 Jenkins 配置页面中呈现。

使用 XStream 框架将数据持久化为 XML 文件。您可以在 Jenkins 工作区的 /jobs/job_name/plugin_name.xml 下找到作业配置的数据,以及在 ./work/name_of_plugin.xml 下找到全局插件配置的数据。

另请参阅

  • 查看 GUI 示例插件的配方

向作业描述添加横幅

想象一个场景。您的公司有一个面向公众的 Jenkins 实例。所有者不希望项目所有者在项目描述中写入未转义的标记。这会带来太多安全问题。但是,所有者确实希望在每个描述的底部放置公司横幅。在管理层开始购买不必要的建议之前,您有 15 分钟来解决这个问题。在前五分钟内,您确定转义标记插件(请参阅第二章中的查找 Jenkins 中的 500 错误和 XSS 攻击配方,增强安全性)执行了描述的转义。

此配方向您展示如何修改 Markup 插件以向所有描述添加横幅。

准备就绪

假设你正在本地进行测试,请为你的项目创建一个目录。在你新创建的目录中,检出转义标记插件的escape-markup-plugin-0.1标签:

git clone https://github.com/jenkinsci/escaped-markup-plugin

操作步骤...

  1. 访问插件源代码的本地副本,列出可能的标签,并检出插件的稳定版本:

    cd escaped-markup-plugin
    git tag -l
    git –b checkout escaped-markup-plugin-0.1
    
    
  2. 在项目的顶级目录中,尝试使用命令mvn install创建插件。构建失败。

  3. pom.xml文件中的 Jenkins 插件版本从1.408更改为1.58

    <parent>
      <groupId>org.jenkins-ci.plugins</groupId>
      <artifactId>plugin</artifactId>
      <version>1.584</version>
    </parent>
    
  4. 用以下代码替换repositoriespluginRepositories部分:

      <repositories>
        <repository>
          <id>repo.jenkins-ci.org</id>
          <url>http://repo.jenkins-ci.org/public/</url>
        </repository>
      </repositories>
      <pluginRepositories>
        <pluginRepository>
          <id>repo.jenkins-ci.org</id>
          <url>http://repo.jenkins-ci.org/public/</url>
        </pluginRepository>
      </pluginRepositories>
    
  5. 使用mvn install构建插件。构建将成功。你现在可以在target/escaped-markup-plugin.hpi找到该插件。

  6. 通过访问插件管理器(http://localhost:8080/pluginManager/advanced)下的高级选项卡安装插件。

  7. 上传插件部分,上传escaped-markup-plugin.hpi文件。

  8. 重新启动服务器,例如:

    sudo /etc/init.d/jenkins restart
    
    
  9. 访问 Jenkins 安全配置页面(http://localhost:8080/configureSecurity)并查看标记格式化器

  10. 用以下代码替换src/main/resources/index.jelly

    <div>
      This plugin escapes the description of project, use, view, and build  to prevent from XSS.
      Revision: Unescaped banner added at the end.
    </div>
    
  11. 用以下代码替换src/main/java/org/jenkinsci/plugins/escapedmarkup/EscapedMarkupFormatter.java的类定义:

    public class EscapedMarkupFormatter extends MarkupFormatter
    {
      private final String BANNER= "\n<hr><h2>THINK BIG WITH xyz dot blah</h2><hr>\n";
    
      @DataBoundConstructor
      public EscapedMarkupFormatter() {
    }
    @Override
    public void translate(String markup, Writer output) throws IOException {
        output.write(Util.escape(markup)+BANNER);
      }
        @Extension
        public static class DescriptorImpl extends MarkupFormatterDescriptor {
        @Override
        public String getDisplayName() {
          return "Escaped HTML with BANNER";
        }
      }
    }
    
  12. 使用mvn install进行构建。构建失败是由于测试未通过(这是件好事)。

  13. 再次使用以下命令构建,这次跳过测试:

    mvn -Dmaven.test.skip=true -DskipTests=true clean install
    
    
  14. 关闭 Jenkins,如下所示:

    sudo /etc/init.d/jenkins stop
    
    
  15. 从 Jenkins 插件目录和相同目录中的扩展版本中删除转义标记插件,例如:

    sudo rm /var/lib/jenkins/plugins/escaped-markup-plugin.jpi
    sudo rm -rf /var/lib/jenkins/plugins/escaped-markup-plugin
    
    
  16. 将插件target/escaped-markup-plugin.hpi复制到 Jenkins 插件目录。

  17. 重启 Jenkins。

  18. 访问已安装的插件页面:http://localhost:8080/pluginManager/installed。你现在将看到插件的更新描述,如下图所示:操作步骤...

  19. 在 Jenkins 中,作为管理员,访问配置页面:http://localhost:8080/configureSecurity

  20. 对于标记格式化器选择带 BANNER 的转义 HTML,如以下截图所示:操作步骤...

  21. 点击保存

  22. 创建一个名为ch7.plugin.escape的新作业。

  23. 在作业的主页面内,你现在将看到横幅:操作步骤...

工作原理...

标记插件会转义描述中的标签,以防注入任意脚本操作。插件的使用方法在第二章增强安全性中的 通过模糊测试在 Jenkins 中查找 500 错误和 XSS 攻击配方中已经解释过了。

在这个配方中,我们修改了插件以转义项目描述,然后添加了一个横幅。横幅包含任意 HTML。

首先,您编译并上传了 Markup 插件。然后修改源代码以在作业描述末尾包含横幅。该插件重新部署到一个用于审查的牺牲测试实例上。您也可以使用mvn hpi:run目标通过 Maven 运行 Jenkins。有多种部署方法,包括直接将插件转储到 Jenkins 插件目录中。决定使用哪种部署方法取决于个人喜好。

插件渲染的描述在src/main/resources/index.jelly中定义。您更新了文件以准确描述新的横幅功能。

在 Jenkins 中,扩展点是模拟 Jenkins 功能的 Java 接口或抽象类。Jenkins 拥有丰富的扩展点(wiki.jenkins-ci.org/display/JENKINS/Extension+points)。您甚至可以制作自己的(wiki.jenkins-ci.org/display/JENKINS/Defining+a+new+extension+point)。

Markdown 插件进行了最小的更改以满足我们的需求。我们扩展了MarkupFormatter扩展点。

Jenkins 使用注解。@Override注解告诉编译器重写该方法。在这种情况下,我们重写了translate方法,并使用一个实用类来使用 Jenkins 实用方法过滤markup字符串。最终,结果字符串加上横幅字符串被添加并传递给 Java 写入器。然后将写入器传递回调用方法。

插件的selectbox中的文本(见第 19 步)是在DescriptorImpl类的getDisplayName()方法中定义的。

注意

编写新的插件并理解 Jenkins 的对象模型需要比复制一个可以工作的插件然后进行微调要付出更多的努力。向已经存在的插件添加横幅功能所需的代码更改量很小。

还有更多……

Jenkins 有大量的文档可用。然而,对于技术宅程序员来说,最详细的信息源是审阅代码、在 IDE(如 Eclipse)中查找的 JavaDoc 以及代码补全功能。如果将 Jenkins 插件项目作为 Maven 项目导入 Eclipse,则最新版本的 Eclipse 会为您解决依赖关系,从而在编辑文件时启用代码补全功能。在 Jenkins 这样一个快速发展的项目中,有时会出现添加功能和文档之间存在的滞后情况。在这种情况下,代码需要是自说明的。代码补全结合良好编写的 JavaDoc 可以减轻开发人员的学习曲线。

下一张屏幕截图展示了在 Eclipse IDE 中运行 Jenkins 时代码补全的工作:

还有更多……

另请参阅

  • 在 第二章,增强安全性* 中查找在 Jenkins 中发现 500 错误和 XSS 攻击的方法

  • 更改 FileSystem SCM 插件的帮助 方法

  • 创建 RootAction 插件 方法

创建一个 RootAction 插件

在构建自己的插件之前,值得看看是否可以改编另一个插件。在 Fun with pinning JSGames 方法中,插件在首页创建了一个链接,如下截图所示:

创建 RootAction 插件

在这个方法中,我们将使用插件的元素在 Jenkins 主页上创建一个链接。

准备工作

在本地创建一个目录以存储你的源代码。

如何操作...

  1. 复制 Looking at the GUI samples plugin 方法中的pom.xml文件,替换:

      <artifactId>Startup</artifactId>
      <version>1.0-SNAPSHOT</version>
      <packaging>hpi</packaging>
       <name>Startup</name>
    

    使用以下内容:

      <artifactId>rootaction</artifactId>
      <version>1.0-SNAPSHOT</version>
      <packaging>hpi</packaging>
       <name>Jenkins Root Action Plugin</name>
    
  2. 创建目录src/main/java/jenkins/plugins/rootactionsrc/main/resourcessrc/main/webapp

  3. src/main/java/jenkins/plugins/rootaction中添加文件MyRootAction.java,内容如下:

    package jenkins.plugins.rootaction;
    import hudson.Extension;
    import hudson.model.RootAction;
    
    @Extension
    public class MyRootAction implements RootAction {
    
      public final String getDisplayName() {
        return "Root Action Example";
      }
    
      public final String getIconFileName() {
        return "/plugin/rootaction/myicon.png";
      }
    
      //Feel free to modify the URL
      public final String getUrlName() {
        return "http://www.uva.nl";
      }
    }
    
  4. src/main/webapp目录中,添加一个名为myicon.pngpng文件。例如图片请见:www.iconfinder.com/icondetails/46509/32/youtube_icon

  5. 添加文件src/main/resources/index.jelly,内容如下:

    <div>
      This plugin adds a root link.
    </div>
    
  6. 在顶级目录中运行命令:

    mvn -Dmaven.test.skip=true -DskipTests=true clean install hpi:run -Djetty.port=8090
    
    
  7. 访问主页:http://localhost:8090/jenkins如何操作...

  8. 点击Root Action Example链接。现在你的浏览器被发送到阿姆斯特丹大学的主网站(www.uva.nl)。

  9. 查看 Jenkins 安装的插件页面(http://localhost:8090/pluginManager/installed)。

工作原理...

你实现了RootAction扩展点。它用于在 Jenkins 的主菜单中添加链接。

扩展点易于扩展。链接名称在getDisplayName方法中定义,图标的位置在getIconFileName方法中,链接到的 URL 在getUrlName中定义。

还有更多...

惯例节省了编程工作。按照惯例,插件的描述定义在src/main/resources/index.jelly中,链接名称在pom.xml文件中的<name>标签旁边的<packaging>标签下,例如:

  <artifactId>rootaction</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>hpi</packaging>
   <name>Jenkins Root Action Plugin</name>

Jenkins wiki 中的详细信息位置计算为一个固定的 URL (wiki.jenkins-ci.org/display/JENKINS/),该 URL 后跟插件名称,并且名称中的空格被+符号替换。对于这个插件也是如此,生成的链接为http://wiki.jenkins-ci.org/display/JENKINS/Jenkins+Root+Action+Plugin

还有更多...

另请参阅

  • Fun with pinning JSGames 方法

导出数据

Job Exporter 插件创建一个包含项目相关属性列表的属性文件。当你想让 Jenkins 将信息从一个作业传递到另一个作业时,这非常方便。

准备工作

安装 Job Exporter 插件(wiki.jenkins-ci.org/display/JENKINS/Job+Exporter+Plugin)。

如何做…

  1. 下载已知版本号的源代码:

    svn export -r 40275 https://svn.jenkins-ci.org/trunk/hudson/plugins/job-exporter
    
    
  2. 创建一个名为ch7.plugins.job_export的自由风格作业。

  3. 构建部分,添加一个构建步骤导出运行时参数

  4. 点击保存

  5. 运行作业。

  6. 在控制台输出中,您将看到作业构建历史中类似的输出:

    (Replace with email)
    Started by user Alan Mark Berg 
    Building remotely on unix-node01 (dumb functional unix) in workspace
     /home/jenkins-unix-nodex/workspace/c7.plugins.job_export ################################################################### job-exporter plugin started
     hudson.version: 1.584
     host: home.local
     id: 2014-10-13_16-58-18
     duration: 2.5 sec
     slave: unix-node01
     started: 2014-10-13T16:58:18
     result: SUCCESS
     summary: Executor #1 for unix-node01 : executing c7.plugins.job_export #1
     executor: 1
     elapsedTime: 2602
     number: 1
     jobName: c7.plugins.job_export
     we have 1 build cause:       Cause.UserIdCause  Started by user Alan Mark Berg
     user.id: aaaaaaa
     user.name: Alan Mark Berg
     user.fullName: Alan Mark Berg
     user.emailAddress: xxxxx@yyyy.zzz
     new file written: /home/jenkins-unix-nodex/workspace/c7.plugins.job_export/hudsonBuild.properties
     job-exporter plugin  finished.  That's All Folks! ################################################################### Finished: SUCCESS
    
    
  7. 审查新创建的属性文件,您将看到类似的文本:

    #created by com.meyling.hudson.plugin.job_exporter.ExporterBuilder
    #Thu Feb 02 15:58:51 CET 2012
    build.user.id=Alan
    build.result=SUCCESS
    
    

工作原理…

Job Exporter 插件使 Jenkins 能够将与作业相关的信息导出到一个属性文件中,后续可以通过其他作业重新使用。

审查src/main/java/com/meyling/hudson/plugin/job_exporter/ExporterBuilder.java中的代码,该代码扩展了hudson.tasks.Builder,当运行构建时会调用其perform方法。 当调用perform方法时,Build实例会接收hudson.model.Build对象。 Build实例包含有关构建本身的信息。 调用build.getBuiltOnStr()方法会返回一个包含构建运行在哪个节点上的节点名称的字符串。 该插件使用一些这些方法来发现稍后输出到属性文件的信息。

还有更多…

在审查插件代码时,您可以找到一些有趣的技巧,可以在您自己的插件中重复使用。该插件通过以下方法发现环境变量:

final EnvVars env = build.getEnvironment(new LogTaskListener(Logger.getLogger(
  this.getClass().getName()), Level.INFO));

在此方法中,EnvVarshudson.EnvVars类(javadoc.jenkins-ci.org/hudson/EnvVars.html)。 EnvVars甚至有一个方法可以从远程 Jenkins 节点获取环境变量。

您还可以在Jenkins 管理区域的系统信息下找到为 Jenkins 定义的所有环境变量列表(http://localhost:8080/systemInfo)。

另请参阅

  • 我的第一个 ListView 插件 配方

在启动时触发事件

经常在服务器启动时,您会希望执行清理操作,例如运行发送电子邮件给所有 Jenkins 管理员警告他们启动事件的作业。 您可以使用 Startup Trigger 插件实现这一点。

准备工作

安装 Startup Trigger 插件(wiki.jenkins-ci.org/display/JENKINS/Startup+Trigger)。

如何做…

  1. 下载源代码:

    svn export -r 40275 https://svn.jenkins-ci.org/trunk/hudson/plugins/startup-trigger-plugin
    
    
  2. 创建一个名为ch7.plugin.startup的自由风格作业。

  3. 构建触发器部分,勾选当作业节点启动时构建

  4. 点击保存

  5. 重新启动 Jenkins。

  6. 返回项目页面,您会注意到已触发一个作业。

  7. 审查构建历史控制台输出。您将看到类似的输出:

    Started due to the start of a node.
    Building on master in workspace /var/lib/jenkins/workspace/ch7.plugins.startup
    Finished: SUCCESS
    
    

工作原理…

Startup Trigger 插件在启动时运行作业。 这在执行管理任务(例如,审查文件系统)时非常有用。它的设计也很简洁。

Startup Trigger 插件在 Java 类/src/main/java/org/jvnet/hudson/plugins/triggers/startup/HudsonStartupTrigger中扩展了hudson.triggers.Trigger,并覆盖了方法start,该方法在 Jenkins 启动时调用。

start方法调用父类的 start 方法,如果它不是一个新实例,则调用方法project.scheduleBuild,然后启动构建。

@Override
  public void start( BuildableItem project, boolean newInstance )
  {
    super.start( project, newInstance );

    // do not schedule build when trigger was just added to the job
    if ( !newInstance )
    {
      project.scheduleBuild( new HudsonStartupCause() );
    }
  }

启动的原因在HudsonStartupCause中定义,它本身扩展了hudson.model.Cause。该插件覆盖了getShortDescription()方法,返回字符串Started due to Hudson startup。该字符串作为日志的一部分输出到控制台中:

@Override
   public String  getShortDescription()
  {
    return "Started due to Hudson startup.";
  }

参见

  • 当网页内容更改时触发事件的方法

  • 在启动时的 Groovy 钩子脚本和触发事件

在启动时的 Groovy 钩子脚本和触发事件

在前述的方法中,您看到您可以使用插件来运行任意的启动代码。另一种方法是将 Groovy 脚本init.groovy放在 Jenkins 主目录中。然后,您的 Jenkins 实例将在启动时运行 Groovy 脚本。

准备就绪

访问Scriptler网站scriptlerweb.appspot.com/catalog/list并查看当前可用的 Groovy 脚本。

操作步骤...

  1. 访问scriptlerweb.appspot.com/script/show/256001并查看安装的插件列表脚本。

  2. 在 Jenkins 主目录中创建以下init.groovy脚本,如下面的代码所示:

    import jenkins.model.Jenkins
    import java.util.logging.LogManager
    def logger = LogManager.getLogManager().getLogger("")logger.info("RUNNING init.groovy from ${Jenkins.instance.getRootDir().absolutePath}")logger.info("Here are the Jenkins environment variables on startup")
    def env = System.getenv()
    env.each{
     logger.info("${it}")
    }
    logger.info("<PLUGINS>")
    count=0
    for(plugin in hudson.model.Hudson.instance.pluginManager.plugins.sort())
    {
     logger.info( plugin.shortName)
     count = count+1
    }
    logger.info("<PLUGINS>\nFound " + count + " plugins")
    logger.info("End of init.groovy \n... Goodbye Cruel world")
    
  3. 重新启动 Jenkins 实例:

    sudo /etc/init.d/jenkins restart
    
    
  4. 查看位于/var/log/jenkins/jenkins.log的日志文件。输出结果类似于以下内容(注意为了简洁起见,已删除了每秒钟的时间戳的每一行):

    INFO: RUNNING init.groovy from /var/lib/jenkins
    INFO: Here are the Jenkins environment variables on startup
    INFO: TERM=xterm
    INFO: JENKINS_HOME=/var/lib/jenkins
    INFO: SHLVL=1
    INFO: XFILESEARCHPATH=/usr/dt/app-defaults/%L/Dt
    INFO: COLORTERM=gnome-terminal
    INFO: MAIL=/var/mail/jenkins
    INFO: XDG_SESSION_COOKIE=3e4cca1158bd9704ef8146c500000008-1413227204.360563-1079526024
    INFO: QT_QPA_PLATFORMTHEME=appmenu-qt5
    INFO: PWD=/var/lib/jenkins
    INFO: LOGNAME=jenkins
    INFO: _=/usr/bin/daemon
    INFO: NLSPATH=/usr/dt/lib/nls/msg/%L/%N.cat
    INFO: SHELL=/bin/bash
    INFO: PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
    INFO: DISPLAY=:0.0
    INFO: USER=jenkins
    INFO: HOME=/var/lib/jenkins
    INFO: XAUTHORITY=/home/alan/.Xauthority
    INFO: XDG_SEAT=seat0
    INFO: XDG_SESSION_ID=c3
    INFO: XDG_VTNR=7
    INFO: LANG=en_US.UTF-8
    INFO: <PLUGINS>
    INFO: ant
    INFO: antisamy-markup-formatter
    INFO: buildresult-trigger
    INFO: claim
    INFO: credentials
    INFO: cvs
    INFO: 
    Found 46 plugins
    INFO: End of init.groovy
    ... Goodbye Cruel world
    
    
  5. 访问http://localhost:8080/systemInfo并将日志文件与 Jenkins 中显示的系统信息进行比较,如下面的截图所示:操作步骤...

工作原理...

Jenkins 在启动时会寻找 Groovy 脚本来运行。可接受的位置在这里提到(wiki.jenkins-ci.org/display/JENKINS/Groovy+Hook+Script),包括:

  • $JENKINS_HOME/init.groovy

  • $JENKINS_HOME/init.groovy.d/*.groovy(文件按其词法顺序运行)

Jenkins 从init.groovy中运行代码。它使用了我们初始化的标准java.util.logging框架,该框架的初始化代码如下:def logger = LogManager.getLogManager().getLogger("")

建议使用日志记录框架而不是老式的println语句。在日志记录框架中,配置与报告分开。通过一点努力,这使您可以更改输出位置(文件系统、syslog 服务器等),格式、过滤器、旋转等。有关日志记录器框架的更多详细信息,请参阅docs.oracle.com/javase/8/docs/technotes/guides/logging/overview.html

记录器可以以各种级别报告;然后您可以过滤结果。在此示例中,我们使用了info级别,因为我们没有在大声报告问题。

首先,脚本遍历环境变量:

def env = System.getenv()
env.each{
  logger.info("${it}")
}

接下来,您使用了 Scriptler 示例的稍微修改版本来列出 Jenkins 中的所有活动插件,如以下代码所示:

for(plugin in hudson.model.Hudson.instance.pluginManager.plugins.sort()) {
  logger.info( plugin.shortName)

最后,我们与系统信息页面进行了视觉比较,该页面也显示了相同的环境细节。

还有更多...

如果您希望分析系统信息以支持调试,请安装 Support Core 插件(wiki.jenkins-ci.org/display/JENKINS/Support+Core+Plugin)。安装完成后,您可以在 URL http://localhost:8080/support/处进行配置。

单击生成捆绑包按钮将支持数据归档下载到您的浏览器中。 Jenkins 还将每小时生成类似的归档,并将 ZIP 文件放置在目录$JENKINS_HOME/support下。信息存储在多个文本文件中。例如,文件support/plugins/active列出了所有活动插件的当前版本:

ant:1.2
antisamy-markup-formatter:1.2
backup:1.6.1
cas1:1.0.1
credentials:1.16.1

以下截图显示了支持页面:

还有更多...

另请参阅

  • 启动时触发事件示例

  • 当网页内容更改时触发事件示例

当网页内容更改时触发事件

在这个示例中,URL 触发器插件将在网页更改其内容时触发构建。

Jenkins 部署到各种基础设施。在您的选择系统上,标准插件有时无法触发。Web 服务器是众所周知的技术。在大多数情况下,您要连接的系统具有其自己的 Web 界面。如果应用程序没有,则仍然可以设置一个网页,在需要 Jenkins 反应时更改该网页。

准备工作

安装 XTrigger 插件(wiki.jenkins-ci.org/display/JENKINS/XTrigger+Plugin)。这将自动安装 URL 触发器插件和一些其他插件,这些插件监视两次检查之间的更改,例如运行本地脚本、Groovy 代码或监视文件或文件夹更改。

如何做

  1. 创建一个名为ch7.plugin.url的新自由样式作业。

  2. 构建触发器部分,选中[URL 触发器] - 使用 URL 轮询复选框。

  3. 点击添加要监视的 URL

  4. 对于URL,添加http://localhost:8080

  5. 检查检查 URL 内容

  6. 添加内容性质中选择值监视内容变化,如下面的截图所示:操作步骤...

  7. 添加一分钟的时间表

  8. 点击保存

  9. 在右侧,点击链接URLTrigger Log操作步骤...

    现在,您将每分钟看到日志信息更新,内容类似于以下电子邮件:

    Inspecting Monitor a change of the content for URL http://localhost:8080
    Polling started on Oct 13, 2014 5:49:00 PM
    Polling for the job ch7.plugin.url
    Looking nodes where the poll can be run.
    Looking for a candidate node to run the poll.
    Looking for a node with no predefined label.
    Trying to poll with the last built on node.
    Trying to poll on master node.
    
    Polling on master.
    Invoking the url:   http://localhost:8080
    Inspecting the content
    The content of the URL has changed.
    
    Polling complete. Took 0.13 sec.
    Changes found. Scheduling a build.
    
    
  10. 删除作业,因为我们不想每分钟轮询http://localhost:8080

它是如何工作的...

您已经配置插件每分钟访问我们的本地 Jenkins http://localhost:8080,下载并比较更改。一分钟的时间表是积极主动的;考虑使用与您的 SCM 存储库类似的时间间隔,例如每 5 分钟一次。

由于返回的每个页面存在细微差异,触发器被激活。这一点通过查看URLTrigger Log得到了验证。

URLTrigger 插件也可用于 JSON 和文本或 XML 响应。

还有更多...

URI 模式的一部分指向您的本地文件系统(en.wikipedia.org/wiki/File_URI_scheme)。当您将本地文件加载到 Web 浏览器中时,您会看到这些示例,如下图所示:

更多内容...

本地文件系统的更改无法通过此插件监视。如果重新配置作业指向位置file:///,您将收到以下错误消息:

java.lang.ClassCastException: sun.net.www.protocol.file.FileURLConnection cannot be cast to java.net.HttpURLConnection

您将不得不使用文件系统 SCM 插件。

另请参阅

  • 启动时触发事件的方法

回顾三个 ListView 插件

Jenkins 首页放射出的信息很重要。您对项目质量的最初感知可能会通过这次初次接触来评判。

在这个示例中,我们将回顾可以添加到列表视图中的最后成功最后失败最后持续时间列,如下面的截图所示:

回顾三个 ListView 插件

在下一个示例中,您将学习如何为列表视图编写自己的列插件。

准备就绪

安装 List View Columns 插件;最后失败版本列插件(wiki.jenkins-ci.org/display/JENKINS/Last+Failure+Version+Column+Plugin);最后成功描述列插件(wiki.jenkins-ci.org/display/JENKINS/Last+Success+Description+Column+Plugin);以及最后成功版本列插件(wiki.jenkins-ci.org/display/JENKINS/Last+Success+Version+Column+Plugin)。

如何操作...

  1. 在选择的目录中将源代码安装到本地:

    git clone https://github.com/jenkinsci/lastfailureversioncolumn-plugin
    git clone https://github.com/jenkinsci/lastsuccessversioncolumn-plugin
    git clone https://github.com/jenkinsci/lastsuccessdescriptioncolumn-plugin
    
    
  2. 在 Jenkins 中,创建一个名为 ch7.plugin.lastview 的新的自由样式作业。不需要进一步的配置。

  3. 在主页面上,点击 All 选项卡旁边的 + 选项卡,如下图所示:操作步骤...

  4. 创建一个名为 LAST列表视图

  5. 作业过滤器 | 作业 下勾选 ch7.plugin.lastview 复选框:操作步骤...

  6. 点击 确定。您将返回到显示 LAST 列表视图的主页面:操作步骤...

  7. 按下 构建 图标以运行 ch7.plugin.lastview 作业:操作步骤...

  8. 刷新页面。最后成功版本 列现在有了数据,并附带构建历史的链接。

  9. 最后成功说明 列中,点击 N/A 链接。

  10. 在右侧,点击 添加描述

  11. 为构建添加描述:这是我的精彩描述

  12. 点击 提交

  13. 通过点击页面顶部显示的面包屑中的 LAST 返回到 LAST 列表视图,如下图所示:操作步骤...

  14. 最后成功说明 列现在已经填充:操作步骤...

工作原理...

这三个插件执行类似的功能;唯一的区别是列的细节稍有不同。细节对于快速决策项目非常有用,例如,当构建成功时,向构建添加描述(例如将核心库更新为与现代浏览器兼容)可以让普通查看者了解项目中的最后一个重要操作的概况,而无需深入了解源代码。这样可以节省大量的点击:

工作原理...

更多内容...

这里有大量的 ListView 插件,其中包括:

  • 额外列插件:添加了计算成功和失败构建数量的选项,一个快捷方式到项目的配置页面,一个启用/禁用项目按钮,以及一个项目描述按钮。每个新列都允许您更好地了解项目的状态或更有效地执行操作。

  • Cron 列插件:显示项目中计划的触发器以及它们是否启用或禁用。如果您想要比较来自 Melody 插件的系统监视信息,这将非常有用。

  • Emma Coverage 插件:显示由 Emma 插件报告的代码覆盖率结果。如果您的组织有内部样式指南,并且代码需要达到特定的代码覆盖率水平,这将特别有用。

  • 进度条插件:显示正在运行的作业的进度条。这为前台页面增加了一种活动感。

另请参阅

  • 创建我的第一个 ListView 插件 配方

  • 第四章, 通过 Jenkins 进行通信 中的高效使用视图配方

  • 第四章, 通过 Jenkins 进行通信 中的使用 Dashboard View 插件节省屏幕空间配方

  • 第一章, 维护 Jenkins 中的通过 JavaMelody 进行监控配方

创建我的第一个 ListView 插件

在最后一个配方中,您将创建您的第一个自定义 ListView 插件。这允许您向标准列表视图添加一个额外的列,其中包含注释。列的内容代码是一个占位符,只等着您用自己的精彩实验替换它。

准备就绪

创建一个准备好的代码目录。

操作方法...

  1. 创建一个顶级pom.xml文件,内容如下:

    <artifactId> rootaction</artifactId>
      <version>1.0-SNAPSHOT</version>
      <packaging>hpi</packaging>
       <name>Jenkins Root Action Plugin</name>
    <?xml version="1.0"?>
    <project 
    
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
    http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
         <groupId>org.jenkins-ci.plugins</groupId>
         <artifactId>plugin</artifactId>
         <version>1.548</version>
    </parent>
      <artifactId>rootaction</artifactId>
      <version>1.0-SNAPSHOT</version>
      <packaging>hpi</packaging>
       <name>Jenkins Root Action Plugin</name>
      <repositories>
        <repository>
          <id>repo.jenkins-ci.org</id>
          <url>http://repo.jenkins-ci.org/public/</url>
        </repository>
      </repositories>
      <pluginRepositories>
        <pluginRepository>
          <id>repo.jenkins-ci.org</id>
          <url>http://repo.jenkins-ci.org/public/</url>
        </pluginRepository>
      </pluginRepositories>
     <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      </properties>
    </project>
    
  2. 创建目录src/main/java/jenkins/plugins/comments

  3. 在 comments 目录中,添加CommentsColumn.java,其内容如下:

    package jenkins.plugins.comments;
    import org.kohsuke.stapler.StaplerRequest;
    import hudson.views.ListViewColumn;
    import net.sf.json.JSONObject;
    import hudson.Extension;
    import hudson.model.Descriptor;
    import hudson.model.Job;
    
      public class CommentsColumn extends ListViewColumn {
        public String getFakeComment(Job job) {
          return "Comments for <em>"+job.getName()+"</em>"+
          "Short URL: <em>"+job.getShortUrl()+"</em>";
        }
    
        @Extension
        public static final Descriptor<ListViewColumn> DESCRIPTOR = new DescriptorImpl();
        public Descriptor<ListViewColumn> getDescriptor(){
          return DESCRIPTOR;
        }
    
        private static class DescriptorImpl extends Descriptor<ListViewColumn> {
          @Override
          public ListViewColumn newInstance(StaplerRequest req,
          JSONObject formData) throws FormException {
          return new CommentsColumn();
        }
        @Override
        public String getDisplayName() {
          return "FakeCommentsColumn";
        }
      }
    }
    
  4. 创建目录src/main/resources/jenkins/plugins/comments/CommentsColumn

  5. CommentsColumn目录中,添加column.jelly,其内容如下:

    <j:jelly >
      <j:set var="comment" value="${it.getFakeComment(job)}"/>
      <td data="${comment}">${comment}</td>
    </j:jelly>
    
  6. CommentsColumn目录中,添加columnHeader.jelly,其内容如下:

    <j:jelly >
      <th>${%Fake Comment}</th>
    </j:jelly>
    
  7. CommentsColumn目录中,添加columnHeader.properties,其内容如下:

    Fake\ Comment=My Fake Column [Default]
    
  8. CommentsColumn目录中,添加columnHeader_an.properties,其内容如下:

    Fake\ Comment=My Fake Column [an]
    
  9. src/main/resources目录中,添加插件描述文件index.jelly,其内容如下:

    <div>
      This plugin adds a comment to the sections mentioned in list view.
    </div>
    
  10. 在顶级目录中,运行以下命令:

    mvn -Dmaven.test.skip=true clean install hpi:run -Djetty.port=8090
    
    
  11. 访问 Jenkins 作业创建页面:http://localhost:8090/jenkins/view/All/newJob。创建一个名为ch7.plugin.l的新自由样式作业。

  12. 在 Jenkins 的主页面,http://localhost:8090/jenkins,现在将有一个名为我的假栏 [默认]的列视图。如果您将 web 浏览器的首选语言更改为阿拉贡语 [an],那么该列现在将被称为我的假栏 [an],如下面的屏幕截图所示:操作方法...

在 Ubuntu 的默认 Firefox 浏览器中,您可以在编辑/首选项内容选项卡下的语言部分更改首选语言,如下面的屏幕截图所示:

操作方法...

工作原理...

在这个配方中,创建了一个基本的 ListView 插件,具有以下结构:

├── pom.xml
└── src
 └── main
 ├── java
 │   └── jenkins
 │       └── plugins
 │           └── comments
 │               └── CommentsColumn.java
 └── resources
 ├── index.jelly
 └── jenkins
 └── plugins
 └── comments
 └── CommentsColumn
 ├── columnHeader_an.properties
 ├── columnHeader.jelly
 ├── columnHeader.properties
 └── column.jelly

插件中包含的一个 Java 文件是CommentsColumn.java,位于/src/main/java/jenkins/plugins/comments下。该类扩展了ListViewColumn扩展点。

方法getFakeComment期望输入类型为Job并返回一个字符串。此方法用于填充列中的条目。

在 ListView 中 GUI 是在 /src/main/resources/packagename/Classname/ 下定义的。你可以找到 /src/main/java/jenkins/plugins/comments/CommentsColumn.java 对应到 /src/main/resources/Jenkins/plugins/comments/CommentsColumn 目录的 GUI。在这个目录中,有两个 Jelly 文件 columnHeader.jellycolumn.jelly

正如其名称所示,columnHeader.jelly 渲染了 ListView 中列的标题。其内容如下:

<j:jelly >
  <th>${%Fake Comment}</th>
</j:jelly>

FAKE CommentcolumnHeader.properties 中定义。% 符号告诉 Jelly 根据 web 浏览器返回的语言设置值查找不同的属性文件。在这个示例中,我们将 web 浏览器的语言值设置为 an,这会首先查找 columnHeader_an.properties 文件。如果 web 浏览器返回的语言没有自己的属性文件,那么 Jelly 将默认使用 columnHeader.properties

columns.jelly 的内容如下:

<j:jelly >
  <j:set var="comment" value="${it.getFakeComment(job)}"/>
  <td data="${comment}">${comment}</td>
</j:jelly>

it.getFakeComment 调用了 CommentsColumn 类的 getFakeComment 方法。这是对象实例的默认名称。返回的对象类型是按约定定义的,文件结构/src/main/resources/Jenkins/plugins/comments/CommentsColumn

返回的字符串被放置在变量 comment 中,然后显示在 <td> 标签中。

注意

如果你对 Jenkins 中可用的 Jelly 标签感兴趣,请参阅 wiki.jenkins-ci.org/display/JENKINS/Understanding+Jelly+Tags

还有更多...

如果你想参与社区活动,那么治理页面是必读的(wiki.jenkins-ci.org/display/JENKINS/Governance+Document)。关于许可证的问题,该页面说明了:

核心完全采用 MIT 许可证,因此大多数基础设施代码(运行项目本身的代码)和许多插件也是如此。我们鼓励托管的插件使用相同的 MIT 许可证,以简化用户的操作,但插件可以自行选择许可证,只要它是 OSI 批准的开源许可证即可。

你可以在 opensource.org/licenses/alphabetical 找到已批准的 OSI 许可证列表。

大多数插件的顶级目录中都有一个 LICENSE.txt 文件,采用 MIT 许可证(en.wikipedia.org/wiki/MIT_License)。例如,请查看 github.com/jenkinsci/lastfailureversioncolumn-plugin/blob/master/LICENSE.txt。其结构类似于以下内容:

The MIT License

Copyright (c) 20xx, Name x, Name y…

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

另见

  • 审查三个 ListView 插件 配方

附录 A. 提高质量的流程

质量保证要求专家关注各种细节。这些细节与人类行为相关,而不仅仅是技术性的。本章提到了运行成功项目所需的软技能以及本书配方中所规范化的配置技能。以下是一些通过实践获得的观察。

早期失败

在软件生命周期的后期纠正问题,成本会更高。尽早失败比之后失败要便宜得多。持续集成允许您自动早期失败。通过插件或连接的云服务添加额外的测试会更有机会早期发现问题,从而提高质量并降低成本。接受问题是一种拥抱,因为这样可以节省时间和金钱。

以下是一些相关资源:

  • 在第一章 Maintaining Jenkins 中的通过日志解析有意失败的构建配方

  • 在第六章 Testing Remotely 中的使用 Selenium Webdriver 触发故障安全集成测试 配方

  • 通过项目生命周期的错误成本递增在ntrs.nasa.gov/search.jsp?R=20100036670

数据驱动的测试

如果您使用数据驱动的测试方法,您可以有效地覆盖您的测试范围。例如,在编写 JMeter 测试计划时,您可以使用 CSV 配置元素从文本文件中读取变量。这允许 JMeter 从 CSV 文件中读取参数,例如主机名,并横跨您的基础设施。这使得一个测试计划可以攻击许多服务器。对于 SoapUI 也是如此;通过添加 Excel 数据源并循环遍历行,您可以测试具有许多不同测试用户的应用程序,每个用户都具有一系列角色。数据驱动的测试有一种易于维护的倾向。在重构期间,不需要像应用程序中的 URL 一样更改测试计划,可以将 URL 因素化为 CSV 文件。

以下是一些相关资源:

  • 在第六章 Testing Remotely 中的创建 JMeter 测试计划 配方

  • 在第六章 Testing Remotely 中的使用 SoapUI 编写测试计划 配方

  • 在第六章 Testing Remotely 中的用于从属节点的自定义设置脚本 配方

  • 在第六章 Testing Remotely 中的使用 Apache JMeter 测试云应用程序 配方

  • 使用 SoapUI 进行数据驱动方法的测试,www.soapui.org/Data-Driven-Testing/functional-tests.html

历史教训

团队往往有自己的编码习惯。如果项目因代码质量而失败,请尝试弄清楚哪些代码指标会阻止代码达到生产环境。哪些错误经常出现?看看以下例子:

  • 周五下午的代码失效:我们都是人,都有次要议程。到了一周的末尾,程序员可能把注意力放在代码之外的地方。一小部分程序员会受到影响,他们的代码质量会受到影响,而在排班的最后阶段会不断注入更多的缺陷。考虑安排一个每周执行的 Jenkins 作业,在注意力最不集中的时间附近设置更严格的质量指标阈值。

  • 代码变动: 在将产品从验收环境移至产品环境之前,代码提交突然激增表明存在最后一刻的匆忙。对于一些有着较强代码质量意识的团队来说,这也是额外警惕的迹象。对于其他纪律性较差的团队来说,这可能是朝着毁灭的天真推进。如果项目失败,QA 因代码变动激增而不堪重负,请考虑根据提交速度设置一个警告 Jenkins 作业。如有必要,您可以展示您自己的定制指标。有关更多信息,请参阅 第三章 中的 构建软件 中的 在 Jenkins 中绘制替代代码指标 配方。

  • 一个流氓程序员:并非所有开发者都能创造出统一高质量的代码。在一个项目中可能存在持续的表现不佳情况。流氓程序员会被人工代码审查发现。然而,作为第二道防线,考虑在 FindBugs 和 PMD 的静态代码审查报告中设置阈值。如果某个开发者没有遵循接受的做法,构建将会以极高的频率失败。有关更多信息,请参阅 第五章 中的 使用指标提高质量 中的 使用 FindBugs 查找错误 配方。

  • GUI 没有意义: 当您构建一个 Web 应用程序,最后时刻却被告知 GUI 与产品所有者预期的交互方式不太一样时,这不是很痛苦吗?一个解决方案是在 FitNesse 中编写一个模型,并用夹具将其包围起来进行自动功能测试。当 GUI 与计划的工作流程不符时,那么 Jenkins 将开始大声喊叫。有关更多信息,请参阅 第六章 中的 远程测试 中的 激活 FitNesse HtmlUnit 夹具 配方。

  • 跟踪责任:错误总会发生,需要吸取教训。然而,如果没有清晰的责任链条记录,很难确定谁需要学习机会。一种方法是通过一系列连接的任务来构建 Jenkins 中的工作流程,并使用推广构建插件确保正确的团队在正确的时点进行验证。这种方法也适用于提醒团队完成短期任务。有关更多信息,请参阅第七章中的测试然后推广构建配方,探索插件

将测试自动化视为一个软件项目

如果您将自动化测试视为一个软件项目,并应用已知原则,那么您将节省维护成本并提高测试的可靠性。

不要重复自己DRY)原则是一个很好的例子。在时间压力下,从代码库的一个区域复制并粘贴类似的测试是诱人的:不要这样做。项目发展会扭曲代码库的形状;测试需要可重用以适应这种变化。脆弱的测试会增加维护成本。一个具体的例子是在第六章中简要讨论的,远程测试,就是使用 Selenium WebDriver 的页面对象。如果将代码分开成页面,那么当页面之间的工作流程发生变化时,大部分测试代码仍然保持不变。

有关更多信息,请参阅第五章中的激活更多 PMD 规则集配方,使用指标提高质量

保持简单愚蠢KISS)原则意味着尽可能地保持项目的每个方面简单。例如,可以使用真实的浏览器进行自动化功能测试,也可以使用 HtmlUnit 框架模拟浏览器。第二种选择避免了设置内存中的 X 服务器或 VNC(en.wikipedia.org/wiki/Virtual_Network_Computing)的需要,并且还会跟踪浏览器版本。这些额外的琐事会降低运行 Jenkins 作业的可靠性,但会增加测试的价值。因此,对于小型项目,考虑从 HtmlUnit 开始。对于较大的项目,额外的努力是值得的。有关更详细信息,请参阅第三章中的使用 Selenium WebDriver 触发 failsafe 集成测试配方,构建软件

考虑是否需要一个独立的集成服务器,或者是否可以使用 Maven 中的集成目标调用 Jetty 服务器。有关更详细信息,请参阅第三章中的为集成测试配置 Jetty配方,构建软件

可视化,可视化,可视化

当您拥有由不同团队和个人开发的许多项目散布在多个服务器上时,要理解关键指标和出现的问题是困难的。

80% 的信息通过您的大脑进行视觉处理,并且您的大脑是一个出色的模式识别器,理解底层复杂性的技巧之一是可视化您的 Jenkins 作业结果。

SonarQube 是可视化和获取项目整体质量概览的绝佳起点,并且用于深入研究代码不同领域之间的关系和耦合。有关更多信息,请参阅第五章中的 将 Jenkins 与 SonarQube 集成 配方,使用指标改善质量

但是,如果您有专门的需求,您将需要构建图形生成。测试结果通常以 XML 或 CSV 格式存储。一旦积累了结果,您可以使用您选择的语言轻松地转换它们。

R 是专为统计学家和科学家设计的语言。数据收集后,会尝试探索哪些变量是相关的。为此,R 社区创建了许多辅助图形包。有关详细信息,请参阅第五章中的 使用 R 插件分析项目数据 配方,使用指标改善质量

以下图形是总结本书内容的词云。在 10 行代码内,R 语言生成了它。R 使用 tmwordcloud 包的组合。您可以从本书的网站下载代码。

可视化,可视化,可视化

R 中的图形库展示了令人瞩目的成果示例。将example()命令置于您选择的函数周围,基于该函数运行示例代码。以下代码显示了plothist图形函数的图形。代码包含在图形中:

example(plot)
example(hist)

x <- rchisq(100, df = 4)
hist(x, freq = FALSE, ylim = c(0, 0.2))
curve(dchisq(x, df = 4), col = 2, lty = 2, lwd = 2, add = TRUE)

一旦您发现了一个新的有趣函数,您可以通过搜索文档进一步探索其帮助。例如,键入 ?rchisq 将输出以下信息:

密度、分布函数、卡方分布(chi²)的分位函数和随机生成具有 df 自由度和可选非中心参数 ncp 的卡方分布。

有关更多信息,请参阅第四章中简化 使用 R 插件进行强大的可视化 配方,通过 Jenkins 进行通信

下图显示了hist函数生成的图形:

可视化,可视化,可视化

rgl 包具有生成引人注目图形的广泛功能。

要从 Ubuntu 命令行安装 rgl 包及其依赖项,请键入以下命令:

sudo apt-get install r-cran-rgl

要查看一些示例,请从 R 控制台运行以下命令:

library(rgl)
example(plot3d)
example(ellipse3d)
example(surface3d)
example(persp3d)

你会看到类似以下截图的输出:

可视化,可视化,可视化

以下是一些相关资源:

约定是好的

遵循约定,你会减少维护量并降低代码中隐藏的缺陷数量。当有多个开发人员参与编写代码时,编码约定尤为重要。约定有助于可读性。一致缩进的代码会让人注意到编写不好的部分。良好结构化的变量名有助于避免组织不同部分编写的代码之间的命名冲突。命名中的结构突出了以后可以移动到配置文件中的数据,并增加了使用正则表达式进行半自动重构的机会,例如,你可以编写一小段 R 代码来可视化每个模块的全局变量数量。全局变量越多,多个用途使用相同变量的风险就越大。因此,图表是代码质量的一个粗略指标。

以下是一些相关资源:

测试框架和商业选择不断增加

在过去几年中,测试自动化方面取得了很多进展。一个例子是静态代码审查被更全面地用于安全检查。SonarQube 是一个全面报告项目质量的工具,新框架正在出现以改进旧框架。以下是一些含义:

  • SonarQube: 这可以衡量项目质量。其社区活跃。SonarQube 将比 Jenkins 的全部质量度量插件更快地发展。考虑使用 Jenkins 插件来提前警告负面质量变化,使用 SonarQube 进行深度报告。有关更多信息,请参阅 第五章 使用指标改进质量 中的 将 Jenkins 与 SonarQube 集成 配方。

  • 静态代码审查工具: 这些正在改进。FindBugs 已将评论功能移到云中。正在开发更多的错误模式检测器。静态代码审查工具在查找安全性缺陷方面变得更加出色。随着时间的推移,您可能会期望显着改进的工具,可能只需更新当前工具的版本即可。有关更多详细信息,请参阅 第五章 使用指标改进质量 中的 使用 FindBugs 查找安全性缺陷 配方

  • 代码搜索: 如果代码搜索引擎根据缺陷密度或编码实践在其搜索结果中对特定代码片段的位置进行排名,那不是很好吗?然后,您可以搜索广泛的开源产品以找到最佳实践。您可以搜索缺陷以删除,然后将补丁发送回代码的社区。

  • : CloudBees 允许您在云中创建按需的从节点。预计在 Jenkins 周围会有更多类似云的集成。

有关 SonarQube 功能和 CloudBees 云服务的更多信息,请访问 www.sonarqube.org/features/www.CloudBees.com/products/dev

将工作分配到 Jenkins 节点

由于其丰富的插件,Jenkins 可以轻松连接到许多类型的系统。因此,在组织中,Jenkins 的使用可能会像病毒一样扩散。测试和 JavaDoc 生成会占用系统资源。最好使用主 Jenkins 快速报告分布在一系列 Jenkins 节点上的作业。这种方法使得更容易分析失败在基础架构中的位置。

如果您在规模上使用 JMeter 进行性能测试,请考虑将其从 Jenkins 转移到诸如 BlazeMeter (blazemeter.com/) 等云服务。

对于使用 Selenium 进行功能测试,也有许多云服务可供选择。考虑使用它们不仅仅是因为负载,还因为它们提供了广泛的浏览器类型和版本。一个商业服务的例子是 Sauce Labs (saucelabs.com/)。定期审查市场以了解新的云服务是值得的。

以下是一些相关资源:

  • 在第一章 维护 Jenkins 中的 通过 JavaMelody 进行监控 配方

  • 创建多个 Jenkins 节点 在第六章中的Testing Remotely食谱中

  • 自定义从属节点的设置脚本 在第六章中的Testing Remotely食谱中

使 QA/集成服务器处于饥饿状态

几百年前,煤矿工人会因矿井中甲烷和一氧化碳的积聚而死亡。为了提前警告这种情况,人们在矿井中引入了金丝雀。由于它们更加敏感,鸟类会首先晕倒,给矿工足够的时间逃脱。考虑在您的验收环境中为集成服务器采取同样的做法:故意使它们资源匮乏。如果它们崩溃了,您将有足够的时间进行审查,然后看着生产中的爆炸。

要了解更多信息,请参考第一章中的通过 JavaMelody 进行监控食谱,Maintaining Jenkins

阅读 Jenkins 的变更日志

Jenkins 践行其所宣扬的。次要版本号发布大约每周一次。新功能出现,错误被解决,新错误被引入。一般来说,绝大多数的变更都会带来改进,但也有少数不会。然而,一旦引入,错误通常会很早被发现并迅速被修复。

在更新 Jenkins 以获取新功能和潜在稳定性故障之前,值得阅读变更日志(jenkins-ci.org/changelog)。偶尔,您可能希望因安全问题而加快部署到生产环境的速度,或者由于稳定性失误而错过某个版本。

注意

如果您专注于稳定性而不是功能丰富性,请考虑使用更老但更稳定的长期支持版本。更多详细信息请访问:wiki.jenkins-ci.org/display/JENKINS/LTS+Release+Line

避免人为瓶颈

您的测试环境越简单,维护所需的技能就越少。随着您学习使用插件并探索新工具和脚本语言的潜力,组织需要维护稳定系统的知识越多。如果您希望在没有随机短信请求建议的情况下度假,请确保您的知识已传递至少给第二人。这听起来很明显,但在您日常工作的忙碌中,这个原则经常被遗忘或搁置一边。

共享知识的最简单方法之一是让几名开发人员一起参加同一场会议和活动(www.CloudBees.com/company/events/juc)。

这就是经理在知识传播中发挥重要作用的地方。他们需要及时计划和活动,以便分享知识,而不是期望它会以魔术般的方式发生。

避免群体思维

在纸上变得完美很容易,定义了一套完整的 JavaDocs 和单元测试的重要性。然而,现实世界在最好的日子里也是混乱的。由于需要交付而产生的项目动力是一股难以抵御的力量。

与项目动力相关的是项目团队或资源所有者可能发生的群体思维现象。如果团队有错误的集体态度,作为质量保证专业人员,注入已经学到的现实主义会更加困难。质量保证不仅仅是尽早发现和捕获缺陷,还要在项目周期的不同阶段注入客观的成功或失败标准。

考虑将可衡量的标准添加到 Jenkins 构建中。显然,如果代码无法编译,则产品不应提交给验收和生产。不太明显的是,关于单元测试代码覆盖率的规则是否值得在发布管理会议上辩护?

在项目开始之前让整个团队参与,并在任何编码之前就达成一致,同意构建失败的度量标准。一种方法是将一个小成功项目与一个小失败项目进行比较。如果后来发生争议,那么争论的焦点就是流程和数字,而不是个性。

更多信息,请参阅 第五章 使用指标提高质量 中的 通过代码覆盖寻找“有味道的代码” 配方。

培训和社区

参与 Jenkins 和更广泛的测试人员社区的培训对于通向优化环境的长期学习路径至关重要。以下是一些相关资源:

对成功开发者进行可见的奖励

这是一个对资源经理的呼吁。开发人员和测试人员专门从事有时很难向不了解他们问题领域的人解释的技术问题。要达到最高水平的专业知识,并跟踪趋势需要时间(有时是他们自己的很多时间)、精力和动力。削弱他们的动力或低估建立技能所需的时间最终将降低产品的质量,并且最终会花费更多。考虑一下你可以做些什么来支持他们,从工资水平的跳跃、学习路径、为开发人员保留时间阅读和实践新想法,到会议和小工具。例如,在加薪之后,Kickstarter(www.kickstarter.com/)是一个很好的地方,可以寻找激励性的奖励,并激发开发人员的创造力。

最后,不要让开发人员做非开发性的工作。一般来说,他们需要高度专注于理解详细的需求,并将其转化为牢固的代码的复杂任务。

稳定性和代码维护

本书提到了许多插件和一些语言和测试工具。在开发中进行实验然后推向验收是可以的,但是在生产中拥有更多的多样性,需要更多的技能来维护,尤其是编写流畅的工作流。微妙的选择,比如将 Jenkins 插件固定在已知版本,并且将 Jenkins 服务器的生产版本稳定在固定时间段内,有助于提高上线时间。同样重要的是,监控负载并将大部分工作远离主 Jenkins,确保工作的时序性。

限制工作维护意味着保持配置的简单和相似。在一个具有高度多样性的复杂组织中,这是不现实的。采用测试驱动的方法是有帮助的;惯例也简化了配置。随着多样性的增加,沟通和达成惯例变得重要。简单的策略——比如一份文档智慧的源头(例如,一个共同的维基),定期的经验总结会议,以及每周的回顾——变得至关重要。

质量保证资源

认为测试是测试人员的唯一责任是错误的。程序员应该对他们的代码质量负责,架构师应该对他们的设计质量负责,管理人员应该对项目的精神和项目规划负责,等等。以下是一些实用的资源范例,涵盖了可行的质量保证领域——这不仅仅是为了测试人员:

  • 关于避免经过多年的艰辛和挫折的经典错误的许多明智的话语。其中一组深思熟虑的评论可以在www.exampler.com/testing-com/writings/classic/mistakes.html找到。

  • 如果单元测试充分覆盖了你的代码,那么如果你在更新过程中破坏了一段代码,你将在下一次构建过程中迅速发现这一点。JUnit 可以说是这个领域中最著名的框架。你可以在junit.org/找到该框架的主页。

  • Jenkins 主页(jenkins-ci.org/)涵盖了大量关于配置、插件、社区、提示和技巧的实用信息。

  • 开放式网络应用安全项目OWASP)是一个关于安全测试的信息和工具的重要来源。OWASP 致力于提高软件的安全性。其使命是使软件安全可见,以便全球个人和组织能够就真实的软件安全风险做出知情决策。你可以在www.owasp.org/index.php/Main_Page找到 OWASP 的主页。

  • 如果你想要 OWASP 材料的实体书或电子书,你可以从 Lulu(www.lulu.com/spotlight/owasp)下载或购买。

  • 你可以在www.owasp.org/index.php/OWASP_Testing_Guide_v4_Table_of_Contents找到 OWASP 的安全测试指南。

  • 一个流行的商业公司销售云端 Jenkins 基础设施的例子是 Sauce Labs(docs.saucelabs.com/ci-integrations/jenkins/)。

  • 有许多优秀的免费软件测试杂志可供下载。专业测试员就是其中之一,可以在www.professionaltester.com/找到。

  • uTest 是世界上最大的致力于专业测试员和软件测试的开放社区。它的唯一目的是促进和推进测试专业及从事这项重要工作的人。更多信息,请访问www.utest.com/about-us

  • 越来越多的免费 MOOC 课程,其中一些支持软件测试员的学习路径。你可以在www.mooc-list.com/找到当前正在运行的 MOOC 课程的完整列表。

  • 有数以百计的优秀博客聚焦于测试。马丁·福勒的博客(martinfowler.com/)是一个很好的资源,而 Jenkins 的创始人小冈晃佑还有另一个博客(kohsuke.org/)。

  • 静态代码审查允许作业在不需要人工干预的情况下找到各种问题。我在 Free Software Magazine 上撰写的一系列关于静态代码审查的文章可以在www.freesoftwaremagazine.com/articles/destroy_annoying_bugs_part_1找到。

还有更多

总是有更多要考虑的地方。以下是一些精选的内容:

  • 模糊团队边界:诸如 FitNesse 和 Selenium IDE 等工具使非 Java 程序员编写测试更加容易。编写测试越容易,相关测试捕获用户期望的本质细节的可能性就越大。寻找支持降低学习曲线的工具的新 Jenkins 插件。有关更多信息,请参阅第六章中的 运行 Selenium IDE 测试 配方,远程测试

  • 故意添加缺陷:通过轮流使用 Jenkins 构建,然后故意添加失败的代码,可以测试团队的警觉性和响应时间。

    提示

    警告

    在添加缺陷之前,请确保团队已经同意了这个过程,否则你可能会在深夜收到愤怒的电子邮件。

  • 使用链接爬虫和安全扫描器增加代码覆盖率:模糊器发现正在攻击的应用程序的输入,然后发射意外输入。这不仅对安全测试有好处,而且对边界测试也有好处。如果您的服务器返回意外错误,则使用模糊器触发更彻底的审核。模糊器和链接爬虫是增加测试代码覆盖率的廉价方法。有关更多信息,请参阅第二章中的 在 Jenkins 中通过模糊测试查找 500 错误和 XSS 攻击 配方,增强安全性

  • 在您的开发环境中,定期查看新的 Jenkin 插件。插件数量正在迅速增加,可能会有新的方式将 Jenkins 连接到组织基础设施的不同部分以进行持续集成。

最后评论

Jenkins 与积极的自动化测试的结合构成了对编码项目的坚实安全网络。本书中的配方支持最佳实践。

生成高质量的作品需要高度关注细节。Jenkins 可以关注许多细节,然后在发生违规行为时大声呼喊。

每个项目都是不同的,有许多方法来构建工作流程。幸运的是,有超过 1000 个插件,并且数量迅速增长,Jenkins 足够灵活,可以适应甚至最隐蔽的基础设施。

如果您没有您想要的确切插件,那么对于 Java 程序员来说,自行适应或创建自己的插件是很简单的。

注意

没有蓬勃发展的开源 Jenkins 社区,这一切都不可能实现。Jenkins 是开源精神在实践中的又一个积极例证。如果您同意,请考虑参与。

posted @ 2024-05-20 11:58  绝不原创的飞龙  阅读(32)  评论(0编辑  收藏  举报