在閱讀關於 撰寫任務 [1] 的教學後,本教學說明如何取得和設定屬性,以及如何使用巢狀檔案集和路徑。最後,說明如何將任務貢獻給 Apache Ant。
目標是撰寫一個任務,在路徑中搜尋檔案並將該檔案的位置儲存在屬性中。
我們可以使用其他教學中的建置檔並稍作修改。這就是使用屬性的優點,我們可以重複使用幾乎整個指令碼。 :-)
<?xml version="1.0" encoding="UTF-8"?> <project name="FindTask" basedir="." default="test"> ... <target name="use.init" description="Taskdef's the Find-Task" depends="jar"> <taskdef name="find" classname="Find" classpath="${ant.project.name}.jar"/> </target> <!-- the other use.* targets are deleted --> ... </project>
建置檔位於 tutorial-tasks-filesets-properties.zip [2] 檔案中的 /build.xml.01-propertyaccess(未來版本儲存為 *.02...,最後版本為 build.xml;來源相同)。
我們的步驟一是要將屬性設定為值,並印出該屬性的值。因此,我們的場景將是
<find property="test" value="test-value"/> <find print="test"/>
好的,可以使用核心任務重新撰寫
<property name="test" value="test-value"/> <echo message="${test}"/>
但我必須從已知的地方開始 :-)
所以該怎麼辦?處理三個屬性(property、value、print)和一個執行方法。由於這只是一個簡介範例,所以我不會做太多檢查
import org.apache.tools.ant.BuildException; public class Find extends Task { private String property; private String value; private String print; public void setProperty(String property) { this.property = property; } // setter for value and print public void execute() { if (print != null) { String propValue = getProject().getProperty(print); log(propValue); } else { if (property == null) throw new BuildException("property not set"); if (value == null) throw new BuildException("value not set"); getProject().setNewProperty(property, value); } } }
如其他教學中所述,屬性存取是透過 Project
實例完成。我們透過公開的 getProject()
方法取得這個實例,我們從 Task
(更精確地說,從 ProjectComponent
)繼承這個方法。透過 getProperty(propertyname)
讀取屬性(非常簡單,不是嗎?)。此屬性會傳回值為 String
或 null
(如果未設定)。
設定屬性... 其實並不困難,但有一個以上的設定器。您可以使用 setProperty()
方法,它會如預期般執行工作。但在 Ant 中有一個黃金法則:屬性是不可變的。而且此方法會將屬性設定為指定值,無論之前是否有值。因此,我們使用另一種方式。 setNewProperty()
僅在沒有名稱相同的屬性時設定屬性。否則,會記錄訊息。
(順便一提,簡短說明 Ant 的「命名空間」,不要與 XML 命名空間混淆:<antcall>
會為屬性名稱建立新的空間。呼叫者的所有屬性都會傳遞給被呼叫者,但被呼叫者可以在呼叫者不知情的情況下設定自己的屬性。)
還有一些其他設定器(但我沒有使用過,所以無法說明,抱歉 :-)
將上面我們的兩行範例放入名稱為 use.simple
的目標後,我們可以從我們的測試案例呼叫它
import org.junit.Assert; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.apache.tools.ant.BuildFileRule; public class FindTest { @Rule public final BuildFileRule buildRule = new BuildFileRule(); @Before public void setUp() { configureProject("build.xml"); } @Test public void testSimple() { buildRule.executeTarget("useSimple"); Assert.assertEquals("test-value", buildRule.getLog()); } }
且所有運作正常。
Ant 提供一個常見的檔案打包方式:檔案組。由於您正在閱讀本教學,我想您已經了解它們,我不必花更多時間說明它們在建置檔中的用法。我們的目標是搜尋路徑中的檔案。在此步驟中,路徑只是一個檔案組(或更精確地說:一個檔案組集合)。因此我們的用法會是
<find file="ant.jar" location="location.ant-jar"> <fileset dir="${ant.home}" includes="**/*.jar"/> </find>
我們需要什麼?一個具有兩個屬性(file、location)和巢狀檔案組的任務。由於我們已經在上述範例中說明屬性處理,而巢狀元素的處理則在其他教學中說明,因此程式碼應該非常容易
public class Find extends Task { private String file; private String location; private List<FileSet> filesets = new ArrayList<>(); public void setFile(String file) { this.file = file; } public void setLocation(String location) { this.location = location; } public void addFileset(FileSet fileset) { filesets.add(fileset); } public void execute() { } }
好,那個任務不會做太多事,但我們可以在所述方式中使用它,而不會失敗。在下一步中,我們必須實作 execute 方法。在實作之前,我們將實作適當的測試案例(TDD,測試驅動開發)。
在其他教學中,我們已經重複使用建置檔中已寫入的目標。現在,我們將透過 Java 程式碼設定大部分測試案例(有時透過 Java 編碼撰寫目標比透過 Java 編碼容易得多)。可以測試什麼?
您可能會找到更多測試案例。但現在這些就夠了。
對於這些點中的每一點,我們都會建立一個 testXX
方法。
public class FindTest { @Rule public final BuildFileRule buildRule = new BuildFileRule(); @Rule public ExpectedException tried = ExpectedException.none(); ... // constructor, setUp as above @Test public void testMissingFile() { tried.expect(BuildException.class); tried.expectMessage("file not set"); Find find = new Find(); find.execute(); } @Test public void testMissingLocation() { tried.expect(BuildException.class); tried.expectMessage("location not set"); Find find = new Find(); find.setFile("ant.jar"); find.execute(); } @Test public void testMissingFileset() { tried.expect(BuildException.class); tried.expectMessage("fileset not set"); Find find = new Find(); find.setFile("ant.jar"); find.setLocation("location.ant-jar"); } @Test public void testFileNotPresent() { buildRule.executeTarget("testFileNotPresent"); String result = buildRule.getProject().getProperty("location.ant-jar"); assertNull("Property set to wrong value.", result); } @Test public void testFilePresent() { buildRule.executeTarget("testFilePresent"); String result = buildRule.getProject().getProperty("location.ant-jar"); assertNotNull("Property not set.", result); assertTrue("Wrong file found.", result.endsWith("ant.jar")); } }
如果我們執行此測試類別,所有測試案例(testFileNotPresent
除外)都會失敗。現在,我們可以實作我們的任務,以便這些測試案例通過。
protected void validate() { if (file == null) throw new BuildException("file not set"); if (location == null) throw new BuildException("location not set"); if (filesets.size() < 1) throw new BuildException("fileset not set"); } public void execute() { validate(); // 1 String foundLocation = null; for (FileSet fs : filesets) { // 2 DirectoryScanner ds = fs.getDirectoryScanner(getProject()); // 3 for (String includedFile : ds.getIncludedFiles()) { String filename = includedFile.replace('\\','/'); // 4 filename = filename.substring(filename.lastIndexOf("/") + 1); if (foundLocation == null && file.equals(filename)) { File base = ds.getBasedir(); // 5 File found = new File(base, includedFile); foundLocation = found.getAbsolutePath(); } } } if (foundLocation != null) // 6 getProject().setNewProperty(location, foundLocation); }
在 //1 中,我們檢查任務的前提條件。在 validate()
方法中執行此操作是一種常見的方式,因為我們將前提條件與實際工作分開。在 //2 中,我們反覆執行所有巢狀檔案組。如果我們不想處理多個檔案組,addFileset()
方法必須拒絕進一步呼叫。我們可以透過其 DirectoryScanner
取得檔案組的結果,就像在 //3 中所做的那樣。之後,我們建立檔案路徑的平台非相依字串表示形式(//4,當然也可以用其他方式執行)。我們必須執行 replace()
,因為我們使用簡單的字串比較。Ant 本身是平台非相依的,因此可以在檔案系統上執行,其中斜線 (/
,例如 Linux) 或反斜線 (\
,例如 Windows) 作為路徑分隔符號。因此,我們必須統一它。如果我們找到檔案,我們會在 //5 中建立一個絕對路徑表示形式,以便我們可以在不知道 basedir 的情況下使用該資訊。(這在與多個檔案組一起使用時非常重要,因為它們可以有不同的 basedir,而目錄掃描器的傳回值是相對於其 basedir 的。)最後,如果我們找到一個檔案,我們會將其位置儲存在屬性中(//6)。
在 *1 上,我們只重新命名清單。這只是為了更佳閱讀來源。在 *2 上,我們必須提供正確的方法:addName(Type t)
。因此,在此處將檔案集合替換為路徑。最後,我們必須在 *3 上修改我們的建置檔案,因為我們的任務不再支援巢狀檔案集合。因此,我們將檔案集合包裝在路徑內。
測試案例使用 Ant 屬性 ant.home
作為參考。此屬性是由啟動 ant 的 Launcher
類別所設定。我們可以在建置檔案中使用該屬性作為 內建屬性 [3]。但是,如果我們建立新的 Ant 環境,我們必須自行設定該值。而且我們在 fork 模式中使用 <junit>
任務。因此,我們必須修改我們的建置檔案
<target name="junit" description="Runs the unit tests" depends="jar"> <delete dir="${junit.out.dir.xml}"/> <mkdir dir="${junit.out.dir.xml}"/> <junit printsummary="yes" haltonfailure="no"> <classpath refid="classpath.test"/> <sysproperty key="ant.home" value="${ant.home}"/> <formatter type="xml"/> <batchtest fork="yes" todir="${junit.out.dir.xml}"> <fileset dir="${src.dir}" includes="**/*Test.java"/> </batchtest> </junit> </target>
提供檔案集合支援的任務非常方便。但是,還有另一種組合檔案的方法:<path>
。如果檔案都在共同的基礎目錄下,檔案集合很簡單。但如果情況並非如此,您就會遇到問題。另一個缺點是速度:如果您在龐大的目錄結構中只有少數檔案,為什麼不改用 <filelist>
呢?<path>
以路徑包含其他路徑、檔案集合、目錄集合和檔案清單的方式結合這些資料類型。這就是 Ant-Contrib [4] <foreach>
任務修改為支援路徑而非檔案集合的原因。所以我們也想要這樣。
從檔案集合變更為路徑支援非常簡單
將 Java 程式碼從private List<FileSet> filesets = new ArrayList<>(); public void addFileset(FileSet fileset) { filesets.add(fileset); }變更為
private List<Path> paths = new ArrayList<>(); *1 public void addPath(Path path) { *2 paths.add(path); }並將建置檔案從
<find file="ant.jar" location="location.ant-jar"> <fileset dir="${ant.home}" includes="**/*.jar"/> </find>變更為
<find file="ant.jar" location="location.ant-jar"> <path> *3 <fileset dir="${ant.home}" includes="**/*.jar"/> </path> </find>
變更為
現在我們修改測試案例。喔,沒什麼好做的 :-) 將 testMissingFileset()
重新命名(並非一定要做,但最好以其功能命名)並更新該方法中的 expected-String(現在預期會出現 路徑未設定 訊息)。較複雜的測試案例會根據建置指令碼。因此,必須以上述方式修改目標 testFileNotPresent 和 testFilePresent。
測試已完成。現在我們必須調整工作實作。最容易修改的是 validate()
方法,我們將最後一行變更為 if (paths.size()<1) throw new BuildException("path not set");
。在 execute()
方法中,我們的工作稍多一些。... 嗯... 實際上工作更少,因為 Path
類別會為我們處理整個 DirectoryScanner
和建立絕對路徑的工作。因此,execute 方法只會變成
public void execute() { validate(); String foundLocation = null; for (Path path : paths) { // 1 for (String includedFile : path.list()) { // 2 String filename = includedFile.replace('\\','/'); filename = filename.substring(filename.lastIndexOf("/") + 1); if (foundLocation == null && file.equals(filename)) { foundLocation = includedFile; // 3 } } } if (foundLocation != null) getProject().setNewProperty(location, foundLocation); }
當然,我們必須在 //1 上反覆執行路徑。在 //2 和 //3 中,我們會看到 Path 類別會為我們執行工作:沒有 DirectoryScanner(在 2 中)和沒有建立絕對路徑(在 3 中)。
到目前為止都很好。但是檔案是否可能在路徑中的多個地方?—當然。
取得所有檔案會很好嗎?—這要看情況...
在本節中,我們將延伸該工作以支援傳回所有檔案的清單。Ant 本身不支援清單作為屬性值。因此,我們必須了解其他工作如何使用清單。使用清單最有名的工作是 Ant-Contrib 的 <foreach>
。所有清單元素都會串接並以可自訂的分隔符號(預設為 ,
)分隔。
因此,我們執行下列動作
<find ... delimiter=""/> ... </find>
如果設定了分隔符號,我們將傳回所有找到的檔案作為清單,並使用該分隔符號。
因此,我們必須
因此,我們新增測試案例
在建置檔案中<target name="test.init"> <mkdir dir="test1/dir11/dir111"/> *1 <mkdir dir="test1/dir11/dir112"/> ... <touch file="test1/dir11/dir111/test"/> <touch file="test1/dir11/dir111/not"/> ... <touch file="test1/dir13/dir131/not2"/> <touch file="test1/dir13/dir132/test"/> <touch file="test1/dir13/dir132/not"/> <touch file="test1/dir13/dir132/not2"/> <mkdir dir="test2"/> <copy todir="test2"> *2 <fileset dir="test1"/> </copy> </target> <target name="testMultipleFiles" depends="use.init,test.init"> *3 <find file="test" location="location.test" delimiter=";"> <path> <fileset dir="test1"/> <fileset dir="test2"/> </path> </find> <delete> *4 <fileset dir="test1"/> <fileset dir="test2"/> </delete> </target>在測試類別中
public void testMultipleFiles() { executeTarget("testMultipleFiles"); String result = getProject().getProperty("location.test"); assertNotNull("Property not set.", result); assertTrue("Only one file found.", result.indexOf(";") > -1); }
現在,我們需要一個目錄結構,可以在不同的目錄中找到具有相同名稱的檔案。因為我們無法確定是否有一個,所以我們在 *1 和 *2 中建立一個。當然,我們會在 *4 中清除它。建立可以在我們的測試目標內或在獨立的目標中完成,這將有助於日後重複使用(*3)。
工作實作修改如下
private List<String> foundFiles = new ArrayList<>(); ... private String delimiter = null; ... public void setDelimiter(String delim) { delimiter = delim; } ... public void execute() { validate(); // find all files for (Path path : paths) { for (File includedFile : path.list()) { String filename = includedFile.replace('\\','/'); filename = filename.substring(filename.lastIndexOf("/")+1); if (file.equals(filename) && !foundFiles.contains(includedFile)) { // 1 foundFiles.add(includedFile); } } } // create the return value (list/single) String rv = null; if (!foundFiles.isEmpty()) { // 2 if (delimiter == null) { // only the first rv = foundFiles.get(0); } else { // create list StringBuilder list = new StringBuilder(); for (String file : foundFiles) { // 3 list.append(it.next()); if (list.length() > 0) list.append(delimiter); // 4 } rv = list.toString(); } } // create the property if (rv != null) getProject().setNewProperty(location, rv); }
演算法會:找出所有檔案,根據使用者的喜好建立回傳值,將該值作為屬性回傳。在 //1 我們會消除重複。//2 確保只有在找到一個檔案時,才會建立回傳值。在 //3 我們會反覆處理所有找到的檔案,而 //4 確保最後一個項目沒有尾隨分隔符號。
好,首先搜尋所有檔案,然後只回傳第一個檔案...您可以自行調整效能 :-)
如果只有建置檔開發人員(而且他只有接下來的幾週時間 :-)才能編寫建置檔,那麼這項任務就毫無用處。因此文件也很重要。您要使用哪種形式的文件,取決於您的喜好。不過在 Ant 內部有一種常見的格式,如果您使用這種格式,將有以下優點:所有任務使用者都知道這種格式,如果您決定貢獻您的任務,就會需要這種格式。因此我們會以這種格式撰寫我們的任務文件。
如果您查看 Java 任務 [5] 的手冊頁面,您會看到它
我們有一個範本
<!DOCTYPE html> <html lang="en"> <head> <title>Taskname Task</title> </head> <body> <h2 id="taskname">Taskname</h2> <h3>Description</h3> <p>Describe the task.</p> <h3>Parameters</h3> <table class="attr"> <tr> <th scope="col">Attribute</th> <th scope="col">Description</th> <th scope="col">Required</th> </tr> do this html row for each attribute (including inherited attributes) <tr> <td>classname</td> <td>the Java class to execute.</td> <td>Either jar or classname</td> </tr> </table> <h3>Parameters specified as nested elements</h3> Describe each nested element (including inherited) <h4>your nested element</h4> <p>description</p> <p><em>since Ant 1.6</em>.</p> <h3>Examples</h3> <pre> A code sample; don't forget to escape the < of the tags with < </pre> What should that example do? </body> </html>
以下是我們任務的範例文件頁面
<!DOCTYPE html> <html lang="en"> <head> <title>Find Task</title> </head> <body> <h2 id="find">Find</h2> <h3>Description</h3> <p>Searches in a given path for a file and returns the absolute to it as property. If delimiter is set this task returns all found locations.</p> <h3>Parameters</h3> <table class="attr"> <tr> <th scope="col">Attribute</th> <th scope="col">Description</th> <th scope="col">Required</th> </tr> <tr> <td>file</td> <td>The name of the file to search.</td> <td>yes</td> </tr> <tr> <td>location</td> <td>The name of the property where to store the location</td> <td>yes</td> </tr> <tr> <td>delimiter</td> <td>A delimiter to use when returning the list</td> <td>only if the list is required</td> </tr> </table> <h3>Parameters specified as nested elements</h3> <h4>path</h4> <p>The path where to search the file.</p> <h3>Examples</h3> <pre> <find file="ant.jar" location="loc"> <path> <fileset dir="${ant.home}"/> <path> </find></pre> Searches in Ant's home directory for a file <samp>ant.jar</samp> and stores its location in property <code>loc</code> (should be <samp>ANT_HOME/bin/ant.jar</samp>). <pre> <find file="ant.jar" location="loc" delimiter=";"> <path> <fileset dir="C:/"/> <path> </find> <echo>ant.jar found in: ${loc}</echo></pre> Searches in Windows C: drive for all <samp>ant.jar</samp> and stores their locations in property <code>loc</code> delimited with <q>;</q>. (should need a long time :-) After that it prints out the result (e.g. <samp>C:/ant-1.5.4/bin/ant.jar;C:/ant-1.6/bin/ant.jar</samp>). </body> </html>
如果我們決定貢獻我們的任務,我們應該做一些事
Ant 任務指南 [6] 提供了更多相關資訊。
現在我們將檢查該指南中說明的「提交新任務前的檢查清單」。
此任務不依賴於任何外部函式庫。因此,我們可以使用它作為核心任務。此任務僅包含一個類別。因此,我們可以使用核心任務的標準套件:org.apache.tools.ant.taskdefs
。實作位於 src/main 目錄中,測試位於 src/testcases 中,測試的建置檔位於 src/etc/testcases 中。
現在我們將我們的成果整合到 Ant 發行版中。因此,我們首先更新我們的 Git 樹。如果您尚未執行此操作,您應該複製 GitHub[7] 上的 Ant 儲存庫,然後建立一個本機複製
git clone https://github.com/your-sig/ant.git
現在我們將建置我們的 Ant 發行版並進行測試。因此,我們可以看到我們的機器上是否有任何測試失敗。(我們可以在後續步驟中忽略這些失敗的測試;這裡使用 Windows 語法,如有需要,請轉換為 UNIX)
ANTREPO> build // 1 ANTREPO> set ANT_HOME=%CD%\dist // 2 ANTREPO> ant test -Dtest.haltonfailure=false // 3
首先,我們必須建置我們的 Ant 發行版 (//1)。在 //2 中,我們將 ANT_HOME
環境變數設定為儲存新建立發行版的目錄 (%CD%
會擴充為 Windows 2000 和更新版本的目前目錄)。在 //3 中,我們讓 Ant 執行所有測試 (強制編譯所有測試),而不會在第一次失敗時停止。
接下來,我們將我們的成果套用在 Ant 來源上。由於我們沒有修改任何內容,所以這是一個相對簡單的步驟。(因為我有一個 Ant 的本地 Git clone,而且通常會貢獻我的成果,所以我從一開始就處理本地副本。優點:如果您修改現有的來源,這個步驟不是必要的,而且可以節省大量工作 :-)。
package org.apache.tools.ant.taskdefs;
testFileNotPresent、
testFilePresent、
test.init和
testMultipleFiles
use.init的依賴性
configureProject("build.xml");
變更為 configureProject("src/etc/testcases/taskdefs/find.xml");
<a href="Tasks/find.html">Find</a><br>
現在,我們的修改已完成,我們將重新測試它
ANTREPO> build ANTREPO> ant run-single-test // 1 -Dtestcase=org.apache.tools.ant.taskdefs.FindTest // 2 -Dtest.haltonfailure=false
由於我們只想測試我們的新類別,因此我們使用單元測試的目標,指定要使用的測試,並設定在第一次失敗時不要停止執行—我們想要看到我們自己的測試的所有失敗(//1 + 2)。
而且 ... 喔,所有測試都失敗了:Ant 無法找到任務或此任務依賴的類別。
好的:在前面的步驟中,我們告訴 Ant 為 <find>
任務使用 Find 類別(請記住 use.init
目標中的 <taskdef>
陳述式)。但現在我們想要將該任務作為核心任務來引入。而且沒有人想要對 javac
、echo
、... 執行 taskdef
。那該怎麼辦?答案是 src/main/.../taskdefs/default.properties。這裡是任務名稱與實作類別之間的對應。因此,我們將 find=org.apache.tools.ant.taskdefs.Find
新增為最後一個核心任務(就在 # optional tasks
行之前)。現在,第二次嘗試
ANTREPO> build // 1 ANTREPO> ant run-single-test -Dtestcase=org.apache.tools.ant.taskdefs.FindTest -Dtest.haltonfailure=false
我們必須重新建置 (//1) Ant,因為測試會在 %ANT_HOME%\lib\ant.jar(更精確地說:在類別路徑上)尋找屬性檔案。而且我們只在來源路徑中修改了它。因此,我們必須重新建置該 jar。但現在所有測試都通過了,而且我們檢查我們的類別是否中斷了其他測試。
ANTREPO> ant test -Dtest.haltonfailure=false
由於測試很多,此步驟需要一點時間。因此在開發期間使用 run-single-test
,僅在最後執行 test
(開發期間有時也可能需要)。我們在此使用 -Dtest.haltonfailure=false,因為可能會發生其他測試失敗,我們必須找出原因。
此測試執行應顯示兩件事:我們的測試將執行,且失敗測試的數量與執行 git clone
(未修改)後的數量相同。
從 Ant 原始碼樹中的其他來源簡單地複製授權文字。
Ant 1.10 使用 Java 8 進行開發,但 Ant 1.9 也在積極維護中。這表示 Ant 1.9 中存在的 Ant 程式碼更新必須能夠在 JDK 5 上執行。(僅針對 Ant 1.10 以上版本的新任務進行處理即可。)因此我們必須測試這一點。您可以從 Oracle [8] 下載較舊的 JDK。
清除 ANT_HOME
變數,刪除 build、bootstrap 和 dist 目錄,並將 JAVA_HOME
指向 JDK 5 安裝目錄。然後使用您的提交建立修補程式,在 Git 中簽出 1.9.x 分支,套用您的修補程式,並執行 build
,設定 ANT_HOME
,然後執行 ant test(如上所述)。
我們的測試應該會通過。
我們必須確保許多事情。使用 4 個空格縮排、空白處在此處和彼處,...(所有內容都在 Ant 任務指南 [6] 中說明,其中包括 Sun 程式碼樣式 [9])。由於有這麼多事情,我們很樂意有一個工具來執行檢查。有一個工具:checkstyle。Checkstyle 可在 Sourceforge [10] 取得,而 Ant 提供 check.xml,這是一個會為我們完成工作的建置檔。
下載它,然後將 checkstyle-*-all.jar 放入您的 %USERPROFILE%\.ant\lib 目錄。儲存在那裡的 jar 都可供 Ant 使用,因此您不必將它新增到您的 %ANT_HOME%\lib 目錄(此功能自 Ant 1.6 起可用)。
因此我們將使用下列指令執行測試
ANTREPO> ant -f check.xml checkstyle htmlreport
我比較喜歡 HTML 報告,因為它有很多訊息,而且我們可以更快瀏覽。開啟 ANTREPO/build/reports/checkstyle/html/index.html,然後瀏覽至 Find.java。現在我們會看到一些錯誤:缺少空白、未使用的匯入、缺少 javadoc。因此我們必須這麼做。
提示:從檔案的底部開始,如此一來報告中的行號將會保持最新,而且您將更容易找到下一個錯誤的位置,而無需重新執行 checkstyle。
根據訊息整理程式碼後,我們刪除報告目錄並執行第二次 checkstyle 執行。現在我們的任務沒有列出。這很好 :-)
最後我們發布該檔案。如 Ant 任務指南 [7] 中所述,我們可以在開發人員郵件清單上公告,建立 BugZilla 條目並開啟 GitHub pull 要求。對於這兩者,我們需要一些資訊
主旨 | 簡短說明 | 在路徑中尋找檔案的任務 |
---|---|---|
本文 | 路徑的更多詳細資料 | 這個新任務會在嵌套的 <path/> 中尋找檔案的出現,並將所有位置儲存為屬性。有關詳細資料,請參閱隨附的手冊。 |
pull 要求參考 | GitHub pull 要求 URL | https://github.com/apache/ant/pull/0 |
傳送包含此資訊的電子郵件非常容易,我想我不用說明。BugZilla 稍微困難一些。但好處是條目不會被遺忘(每週六會產生一份報告)。因此,我將說明這個流程。
首先,您必須擁有 BugZilla 帳戶。因此,開啟 BugZilla 主頁 [11],並追蹤連結 開啟新的 Bugzilla 帳戶 [12],如果您沒有帳戶,請執行其中所述的步驟。
現在,新的任務已註冊到錯誤資料庫中。