對于多版本項目,要提供新版本來跟上新功能或缺陷報告增加的速度,并同時仍然保持可接受的質(zhì)量水平,可能是一項不小的挑戰(zhàn)。構建自動化可確保準確性和消除人為錯誤的可能性,從而部分地解決此問題。自動化還可讓成員將精力集中在需要人類智慧的問題上,而不用分心進行自動化后通常能更快更有效地運行的任務,從而提高了團隊效率。
在本文中,我們將了解如何實現(xiàn)構建過程的自動化,以獲得較高的效率和質(zhì)量。本文中的示例將利用 Rational 軟件交付平臺(IBM Rational Software Delivery, SDP)中的內(nèi)置 Ant 支持(構建自動化過程作為 Ant 構建文件實現(xiàn))以及運行時(如 WebSphere Application Server)中的支持。本文最后將給出一些可以用于進一步簡化此流程的可選功能。
盡管在構造* 階段之前并不會開始執(zhí)行,但任務自動化應該在細化* 階段就進行規(guī)劃,以便在交付代碼進行測試之后即能供實現(xiàn)團隊使用。在進行了分析和設計后,組件的遠景以及應該如何對其進行構建、測試和部署就應該清楚了。在此遠景的啟發(fā)下,應該以允許重復的方式開始完成任務自動化工作。
為了便于進行重復,可能需要在開始前進行一些任務準備工作(如準備測試數(shù)據(jù)),并在完成后進行清理。對軟件配置管理(軟件存儲庫)、設計或目標部署環(huán)境的更改也應該反映在任務自動化中。在工作預估和項目規(guī)劃期間,應該考慮實現(xiàn)和維護此自動化的開銷??梢赃M行測試,以觀察任務自動化對具有多個迭代的項目的影響,確定何時每個迭代的構建、單元測試和部署的時間大幅度減少。
本文中的自動化過程適合于基于 Rational SDP 的工具,如:
對于部署平臺,可以將其用于使用 WebSphere Application Server 作為基礎的 WebSphere 應用服務器系列,如 WebSphere Application Server、WebSphere Application Server Network Deployment 和 WebSphere Process Server。
示例過程可以應用于其他 Rational 和 WebSphere 產(chǎn)品。為了簡單起見,我們將所使用的工具稱為集成開發(fā)環(huán)境(Integrated Development Environment,IDE)。
此過程可以在各種環(huán)境配置上運行。圖 1 顯示了一個示例環(huán)境。
此環(huán)境包含一個或多個開發(fā)工作站,供開發(fā)人員編寫代碼之用。更改保存到存儲庫中。此處我們假設使用 Rational ClearCase 存儲庫,為每個開發(fā)工作站提供了一個快照視圖。
開發(fā)工作站應該安裝了基于 Rational SDP 的工具。開發(fā)工作站應該具有配置為使用軟件存儲庫的工作區(qū)。文章“使用 Rational Software Architect 和 ClearCase Remote Client”提供了關于如何使用 Rational ClearCase 進行此類配置的更多信息。還可以使用其他存儲庫;有關將 Ant 與并發(fā)版本系統(tǒng) (Concurrent Versions System, CVS) 一起使用的更多信息,請參見參考資料。
任何開發(fā)工作站都可以作為構建工作站使用。最好將用于進行構建的工作站分離開,以避免開發(fā)人員間出現(xiàn)使用競爭。構建工作站應該與任何其他開發(fā)計算機具有相同的配置,而且能夠訪問以下服務器:
可以在 Windows? 或 Linux? 上實現(xiàn)典型的開發(fā)或構建工作站。對于目標部署服務器,WebSphere 產(chǎn)品提供了更為廣泛的受支持平臺。
所有自動化步驟都將包括在一個 Ant 構建文件中,以便進行維護。如果您尚不熟悉 Rational 工具,請按照以下所述進行操作:
ar-autotaskcode.zip
,并單擊 Finish。
build.xml
作為文件名。單擊 Finish。(這就是我們在此要涉及的所有步驟。) 列出 Ant 構建文件,如清單 1 中所示。
<?xml version="1.0" encoding="UTF-8"?> <project name="Automation Project" default="init" basedir="."> <!-- Read project properties from a properties file. --> <property file="build.properties" /> <!-- A stub for the default target --> <target name="init" description="Initialize automation environment"> <!-- Set the standard DSTAMP, TSTAMP, and TODAY properties. --> <tstamp /> <!-- Set a variable to host environment variables. --> <property environment="env" /> <!-- Print the current WORKSPACE value. --> <echo message="Workspace: ${env.WORKSPACE}" /> <!-- Delete old export directory. --> <delete dir="${destination.dir}" /> <!-- Create the target export directory for the build. --> <mkdir dir="${destination.dir}" /> </target> </project> |
可以現(xiàn)在下載完整的 Ant 構建文件 ar-autotaskcode.zip。
在包含 Ant 構建項目的同一個目錄中創(chuàng)建屬性文件來存儲其屬性。ar-autotaskcode.zip 中也提供了完整的屬性文件。
現(xiàn)在 Ant 構建文件已經(jīng)準備好開始添加表示自動化過程的新 Ant 目標了。
圖 2 顯示了構建自動化程序的摘要。
此部分將對這個過程的每個步驟進行詳細描述。
第一步是從 ClearCase 存儲庫獲得最新的代碼,如清單 2 中所示。
<target name="updateview" depends="init" description="Update ClearCase snapshot view"> <!-- update snapshot view --> <ccupdate viewpath="${workspace.dir}" graphical="false" overwrite="true" |
由于工作區(qū)配置為指向 ClearCase 視圖,更新視圖實際上將更新工作區(qū)內(nèi)容。
可以實現(xiàn)代碼檢查自動化。盡管不能消除手動代碼檢查需求,但建議的最佳實踐是,采用自動化檢查來確定開發(fā)團隊在代碼質(zhì)量標準方面所處的位置。Rational SDP 提供了內(nèi)置的代碼檢查支持。(有關如何從 Ant 進行調(diào)用的更多信息,請參見 Code review headless mode reference。)
另外還可以使用多種工具來執(zhí)行自動化代碼檢查,如 PMD 和 CheckStyle。清單 3 中的示例說明了如何將 PMD 作為 Ant 任務調(diào)用并生成 HTML 格式的結果。要運行此任務,需要將 pmd-3.8.jar、jakarta-oro-2.0.8.jar 和 jaxen-1.1-beta-10.jar 放置在 lib.dir 屬性所指定的目錄。
<target name="reviewcode" description="Review code using PMD"> <taskdef name="pmd" classname="net.sourceforge.pmd.ant.PMDTask" classpath="${lib.dir}/pmd-3.8.jar" /> <pmd shortFilenames="true"> <!-- Determine the ruleset to be used --> <ruleset>rulesets/favorites.xml</ruleset> <ruleset>basic</ruleset> <!-- Generate and HTML report into the designated directory --> <formatter type="html" toFile="${report.dir}/pmd_automated_code_review_report.html" /> <!-- Files to be configured for review --> <fileset dir="${workspace.dir}/"> <!-- Include all .java files except those under directories that are automatically generated --> <include name="**/*.java" /> <!-- A sample exlusion directory that has generated java source code --> <exclude name="**/generated/**/*.java" /> </fileset> </pmd> </target> |
執(zhí)行了此步驟后,將在 report.dir 屬性指定的目錄下找到 HTML 格式的 pmd_automated_code_review_report.html。(有關自動化代碼檢查的更多信息,請參見參考資料部分。)
現(xiàn)在我們使用 IDE 中提供的內(nèi)置功能來構建要包括在構建版本中的不同項目。
對于要在 IDE 中運行的 SDP 提供的 Ant 任務,Ant 構建文件需要在與工作區(qū)相同的 Java? Runtime Environment (JRE) 中運行。否則,如果從命令行運行,runAnt 批處理文件將進行所需的初始化工作,以將這些任務的定義包括進來。這將在運行過程時的選項部分進行討論。清單 4 中的代碼使用 IDE 內(nèi)置的“projectBuild”Ant 任務構建存在于工作區(qū)中的項目之一。
<target name="buildproject" description="Build a project"> <!-- Build the project with some options --> <projectBuild projectName="${project.name}" BuildType="full" failonerror="false" DebugCompilation="false" /> <!-- Print build errors --> <echo message="projectBuild: projectName=${project.name} project Error Count=${ProjectErrorCount} project Error Messages=${ProjectErrorMessages}" /> </target> |
執(zhí)行時可能出現(xiàn)的錯誤會輸出到控制臺,但構建不會終止。要更改此行為,可以將 failonerror
屬性設置為 true
。
可以通過將 project.name
屬性設置為要構建的項目的名稱而為不同的項目使用相同的目標,如清單 5 中所示。
<target name="buildall"> <!-- Invoke the "buildproject" target for a project from the workspace --> <antcall target="buildproject"> <!-- Pass the name of the project to be built --> <param name="project.name" value="MyFirstProject" /> </antcall> <!-- Invoke the "buildproject" target to build another project --> <antcall target="buildproject"> <!-- The project name is different --> <param name="project.name" value="MySecondProject" /> </antcall> </target> |
有時候會忽略此步驟。為所發(fā)布的每個構建版本使用一個版本號的方法對跟蹤缺陷和新添加的功能非常有用。Ant 提供了一個簡單 buildnumber 任務,可實現(xiàn)此目的。清單 6 顯示了根據(jù)需要記錄更多有關版本信息的另一種方法。
<target name="baseline" description="Record build information"> <!-- The name of the file that holds the build information. If no such file exists, a new one gets created. --> <propertyfile file="${destination.dir}/build.info"> <!-- Initial build number is 0001. Then, any subsequent build increments |
"baseline"
目標創(chuàng)建名為 build.info 的文件,其中包含版本號和構建時間。如果該文件已存在,則會使用新版本號和構建時間對其進行更新。您可能需要在此文件中添加更多信息,如運行構建操作的用戶的名稱或創(chuàng)建構建版本的計算機的名稱。還可以按照提取 "init"
目標中 WORKSPACE
環(huán)境變量的相同方法從環(huán)境提取此信息,如 Ant 構建文件中所述。
此步驟調(diào)用 JUnit 測試用例,這些用例不需要運行時資源(如數(shù)據(jù)源等)。我們假定您已經(jīng)獲得了運行此步驟所需的此類測試用例。清單 7 說明了如何在工作區(qū)調(diào)用所有 JUnite 測試用例,并假設全部都以單詞“Test”作為結尾。當然,如果命名約定不同,則可以對此進行相應的更改。
<target name="predeptests" description="Invoke pre-deployment JUnit test cases"> <!-- Run JUnit and print a summary when done. --> <junit printsummary="yes" haltonfailure="no"> <classpath> <!-- Set the class path to include all needed classes that are used by the JUnit test cases. --> </classpath> <!-- Generate reports in an XML format --> <formatter type="xml" /> <!-- Run a batch of JUnit test cases and generate reports to the report directory. --> <batchtest fork="yes" todir="${report.dir}"> <fileset dir="${workspace.dir}/"> <!-- Include all .java files that end with "Test" --> <include name="**/*Test.java" /> </fileset> </batchtest> </junit> </target> |
JUnit Ant 任務需要 junit.jar??梢詫⑵浞旁?"init"
目標中提到的 Ant 構建項目的屬性文件的 lib.dir 屬性指定的目錄下。可以使用 JUnitReport Ant 任務將 JUnit 任務生成的報告轉換為其他格式。在我們的示例中,報告將在 report.dir 屬性指定的目錄中生成。
在此步驟中,我們要對可部署單元進行打包,以準備好在下一步中進行部署。清單 8 顯示了如何導出企業(yè)應用程序。
<target name="exportear" description="Export an Enterprise Application"> <!-- Export EAR file--> <earExport earprojectname="${project.name}" |
與步驟 3(構建代碼)期間處理一組項目的方式類似,我們可以在導出企業(yè)應用程序時采用相同的方式。清單 9 中的代碼說明了如何進行此工作。
<target name="exportall" depends="buildall" |
對于其他項目類型,可以使用 warExport
、ejbExport
和 jar
任務(分別用于導出 Web 模塊、EnterpriseJavaBeans (EJB) 模塊和 Java 庫)。這些都是 SDP 提供的 Ant 任務。
在此步驟中,我們將部署上一步導出的單元。對于我們的自動化過程,我們將使用包裝 wsadmin
的內(nèi)置 Ant 任務。清單 10 顯示了 wsListApps
、wsUninstallApp
和 wsInstallApp
Ant 任務,這些任務分別提供用于列出已安裝應用程序、卸載企業(yè)應用程序和安裝企業(yè)應用程序的管理功能。請記得在運行此步驟前啟動目標應用服務器。
關于 wsadmin 和 Ant
WebSphere Application Server Ant 支持基于其命令行管理工具 wsadmin
。作為本文示例的替代方法,可以使用 Exec Ant 任務調(diào)用 wsadmin
并按照調(diào)用任何其他庫執(zhí)行文件的方式傳遞程序參數(shù)。WebSphere Application Server 還提供了包裝 wsadmin
的 Ant 任務 WsAdmin。還有其他包裝特定操作的 WsAdmin 任務的 Ant 任務,如應用程序安裝方面的 InstallApplication 和 StartApplication。我們的示例中使用了后一個選項。
<target name="listapps" description="List installed Enterprise Applications"> <!-- Define the wsListApps task that lists installed Enterprise Applications. --> <taskdef name="wsListApps" classname="com.ibm.websphere.ant.tasks.ListApplications"> <!-- Include all JAR files under WebSphere Application Server lib directory. --> <classpath> <fileset dir="${was.home}/lib/" includes="*.jar" /> </classpath> </taskdef> <!-- List all installed Enterprise Application the profile specified. --> <wsListApps profilename="${was.profilename}" wasHome="${was.home}/" conntype="SOAP" host="${was.hostname}" port="${was.hostport}" user="${was.username}" password="${was.userpassword}" /> </target> <target name="uninstallapp" depends="listapps" |
根據(jù)需要部署的應用程序的數(shù)量不同,可以使用 project.name 參數(shù)的不同值多次調(diào)用 installapp
目標。installapp
目標將調(diào)用 uninstallapp
目標來確保企業(yè)應用程序已經(jīng)卸載(如果已安裝)。兩個目標多次調(diào)用 listapps
,以在卸載和安裝前后列出應用程序。清單 11 說明了如何進行此工作。
<target name="installallapps" description="Install all Enterprise Applications"> <!-- Invoke installapp target to install an Enterprise Application. --> <antcall target="installapp"> <!-- Pass the name of the Enterprise Application to be installed. --> <param name="project.name" value="MyAppEAR" /> </antcall> <!-- Another invocation to the installapp target can be done |
此步驟與運行部署前單元測試類似,不過 JUnit 測試用例的本質(zhì)不同。部署后測試用例預期使用已經(jīng)部署在運行時上且正在正常工作的代碼。這些測試用例可以利用服務器端的資源和測試組件,如 Cactus。就構建自動化過程而言,此步驟只是調(diào)用一組 JUnit 測試用例。
設置了所有構建版本后,自動化過程會將庫部署單元和生成的報告上載到 FTP 服務器上。此步驟對于備份和保持整個構建版本的標識都非常有用。清單 12 中所示的目標說明了如何使用 FTP 來上載構建文件。
<target name="uploadbuild" description="Upload build to an FTP server"> <!-- Upload everything under the destination.dir to the FTP server. --> <ftp server="${ftp.hostname}" remotedir="/" userid="${ftp.username}" password="${ftp.userpassword}" separator="\" verbose="yes" binary="yes"> <fileset dir="${destination.dir}"> <include name="**/*.*" /> </fileset> </ftp> </target> |
最后,該過程將向測試人員發(fā)送電子郵件(如清單 13中所示),告知其開始測試。以下示例假定不會在 SMTP 服務器上進行身份驗證。
<target name="notifyteam" description="Notify testing team of the new build"> <!-- Read build information from the build.info file. --> <property file="${destination.dir}/build.info" /> <!-- Send a mail to the testing team. --> <mail mailhost="${smtp.hostname}" mailport="${smtp.hostport}" |
如果您的 SMTP 服務器要求進行身份驗證,將需要下載 JavaMail .jar 文件。
本部分將簡單描述運行構建過程時一些可用的選項。
上面所述的自動化過程并不施加任何控制任務流的條件。如果需要此類控制,可以使用允許某些任務中在出現(xiàn)錯誤時失敗的屬性。例如,wsInstallApp
任務具有用于此目的的 failonerror
屬性。
使用條件是控制流的另一種方式。有關 Ant 中的條件的更多信息,請參見 Conditions task。Ant 還提供了依賴關系來在目標之間建立聯(lián)系,以確保執(zhí)行目標序列得以執(zhí)行。
從 IDE 運行 Ant 構建文件非常簡單。如圖 3 中所示,可以從 Ant 視圖中選擇出現(xiàn)在樹視圖下的 Ant 目標之一上的 Run Ant 選項。
在 Modify attributes and launch 對話框中,從 JRE 選項卡選擇 Run in the same JRE as the workspace,如圖 4 中所示。單擊 Apply 和 Run。
執(zhí)行之后,輸出將打印到 Console 視圖,如圖 5 中所示。
<IDE installation directory>\rwd\eclipse\plugins\com.ibm.etools.j2ee.ant_6.0.1.XXX 下提供了有關自定義 Ant 來使用 Rational SDP 資源從命令行運行的信息。該目錄下提供了一個批處理文件 runAnt,可允許運行您的 Ant 構建文件。此批處理文件需要設置 WORKSPACE
環(huán)境變量。此變量指向包含自動化資源的工作區(qū)??梢詮拿钚性O置此變量,或者添加代碼行來指向 runAnt 批處理文件,如清單 14 中所示。
set WORKSPACE=C:\workspaces\MyWorkSpace runAnt.bat -buildfile <path to the Ant build file>\build.xml init |
可以不使用前一示例中的 init
目標,而以類似的方式調(diào)用 Ant 構建文件中的其他目標。
由于此構建過程已自動化,開發(fā)團隊可能會決定每天都要執(zhí)行此過程,具體取決于其需要提供構建版本進行測試的頻率。此執(zhí)行可以為部分執(zhí)行(運行 Ant 目標的子集),也可以完全執(zhí)行。在這兩種情況下,可以對過程進行計劃,以按所需的頻率運行。有關如何在 Windows 平臺上進行任務計劃的更多信息,請參見“使用 WebSphere Studio 和 Ant 執(zhí)行無人值守的日常構建——第 2 部分”。
學習本文后,希望您已經(jīng)通過使用實現(xiàn)軟件開發(fā)團隊的重復構建任務的自動化的過程提高了效率和質(zhì)量。所使用的構建自動化過程僅僅是 Rational and WebSphere 系列軟件產(chǎn)品提供的自動化功能的一個子集。您將需要對此過程進行調(diào)整,以與工作環(huán)境、所使用的工具和運行時、團隊的知識以及所開發(fā)的解決方案類型匹配。
作者要感謝 Nouran Abdel-Hamid、Rosaline Makar、Amr Ali 和 Ahmed Mamdouh:正是得益于您們的工作,才最終得到了這個自動化解決方案。