You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by kr...@apache.org on 2010/10/27 11:42:02 UTC

svn commit: r1027878 - in /db/derby/code/trunk/java/build/org/apache/derbyBuild: GeneratorBase.java JiraIssue.java ReleaseNotesGenerator.java ReportParser.java

Author: kristwaa
Date: Wed Oct 27 09:42:02 2010
New Revision: 1027878

URL: http://svn.apache.org/viewvc?rev=1027878&view=rev
Log:
DERBY-4857 (partial): Utilize the SOAP API to fetch JIRA issue list for release notes generation

Modified the existing release notes generator to be able to parse the file
generated by the new JIRA SOAP client.
Removed deprecated class ReportParser.

Note that the description on how to run the ant target is incorrect until a
follow-up patch is committed/applied.

Patch file: derby-4857-3b-jirasoap_relnotesgen_changes.diff

Removed:
    db/derby/code/trunk/java/build/org/apache/derbyBuild/ReportParser.java
Modified:
    db/derby/code/trunk/java/build/org/apache/derbyBuild/GeneratorBase.java
    db/derby/code/trunk/java/build/org/apache/derbyBuild/JiraIssue.java
    db/derby/code/trunk/java/build/org/apache/derbyBuild/ReleaseNotesGenerator.java

Modified: db/derby/code/trunk/java/build/org/apache/derbyBuild/GeneratorBase.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/build/org/apache/derbyBuild/GeneratorBase.java?rev=1027878&r1=1027877&r2=1027878&view=diff
==============================================================================
--- db/derby/code/trunk/java/build/org/apache/derbyBuild/GeneratorBase.java (original)
+++ db/derby/code/trunk/java/build/org/apache/derbyBuild/GeneratorBase.java Wed Oct 27 09:42:02 2010
@@ -86,7 +86,7 @@ public class GeneratorBase extends Task 
     protected ElementFacade summary;
     // Bug list file
     protected String bugListFileName;
-    protected TagReader bugListDoc;
+    protected List bugList;
 
     // Output file
     private String outputFileName;
@@ -149,7 +149,6 @@ public class GeneratorBase extends Task 
      */
     public void setBugListFileName(String bugListFileName) throws Exception {
         this.bugListFileName = bugListFileName;
-        bugListDoc = new TagReader( new FileInputStream(bugListFileName) );
     }
 
     /**

Modified: db/derby/code/trunk/java/build/org/apache/derbyBuild/JiraIssue.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/build/org/apache/derbyBuild/JiraIssue.java?rev=1027878&r1=1027877&r2=1027878&view=diff
==============================================================================
--- db/derby/code/trunk/java/build/org/apache/derbyBuild/JiraIssue.java (original)
+++ db/derby/code/trunk/java/build/org/apache/derbyBuild/JiraIssue.java Wed Oct 27 09:42:02 2010
@@ -1,90 +1,139 @@
-/*  Derby - Class org.apache.derbyBuild.JiraIssue
-Licensed to the Apache Software Foundation (ASF) under one or more
-contributor license agreements.  See the NOTICE file distributed with
-this work for additional information regarding copyright ownership.
-The ASF licenses this file to You under the Apache License, Version 2.0
-(the "License"); you may not use this file except in compliance with
-the License.  You may obtain a copy of the License at
-http://www.apache.org/licenses/LICENSE-2.0
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
+/*
+
+   Derby - Class org.apache.derbyBuild.JiraIssue
+
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to you under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
  */
-package org.apache.derbyBuild;
 
-import org.w3c.dom.*;
-import java.io.InputStream;
-import java.util.*;
+package org.apache.derbyBuild;
 
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
 
 /**
- *
- * An issue from a JIRA report. The constructor of this class parses text produced by
- * a JIRA report. This parsing logic probably has to be rewritten for every release because
- * the format of the JIRA reports is not stable.
- *
+ * An issue from JIRA.
  */
 class JiraIssue {
-    private static final String RELEASE_NOTE_NAME = "releaseNote.html";
+    public static final long NO_RELEASE_NOTE = -1;
+    public static final long MISSING_RELEASE_NOTE = -2;
+    private static final String ATTACHMENT_BASE =
+        "https://issues.apache.org/jira/secure/attachment/";
+    private static final String ATTACHMENT_NAME = "releaseNote.html";
+
+    // States for parsing source from the Derby JIRA SOAP client.
+    private static final int STATE_ADD_RESET = -1;
+    private static final int STATE_ADD_KEY = 0;
+    private static final int STATE_ADD_SUMMARY = 1;
+    private static final int STATE_ADD_FIXVERSIONS = 2;
+    private static final int STATE_ADD_RELEASENOTE = 3;
 
+    // JIRA issue information
     private String key;
     private String title;
-    private long releaseNoteAttachmentID = ReportParser.NO_RELEASE_NOTE;
-    private HashSet fixVersionSet;
+    private long releaseNoteAttachmentID = NO_RELEASE_NOTE;
+    private List fixVersions;
 
-    /**
-     * Create an object instance from a TagReader.
-     */
-    public JiraIssue(  ReportParser rp, TagReader tr ) throws Exception
-    {
-        key = rp.parseKey( tr );
-        title = rp.parseTitle( tr );
-        fixVersionSet = rp.parseFixedVersions( tr );
-        releaseNoteAttachmentID = rp.getReleaseNoteAttachmentID( tr );
+    public JiraIssue(String key, String title, List fixVersions,
+                     long releaseNoteAttachmentID) {
+        this.key = key;
+        this.title = title;
+        this.fixVersions = fixVersions;
+        this.releaseNoteAttachmentID = releaseNoteAttachmentID;
     }
 
     /**
-     * Factory method which extracts a list of JiraIssue objects from a Jira
-     * report (supplied as an XML Document). Issues with a fixVersion contained
-     * in the exclude list will be omitted from the list.
-     * @param masterReport a TagReader holding the JIRA report of all the fixed bugs
-     * @param excludeReleaseIDList list of fixVersions that disqualifies an issue
-     * @param parser a class to parse content in the master report
-     * @return a List of JiraIssue objects
-     * @throws java.lang.Exception
-     */
-    public static List createJiraIssueList
-        ( TagReader masterReport, List excludeReleaseIDList, ReportParser parser ) throws Exception
-    {
-        int issueCount = 0;
-
+     * Factory method which extracts a list of JiraIssue objects from a data
+     * file generated by the Derby JIRA SOAP client.
+     *
+     * @param source the source file (generated by the Derby JIRA SOAP client)
+     * @return A List of {@code JiraIssue} objects.
+     * @throws Exception if something goes wrong
+     */
+    public static List createJiraIssueList(String source)
+            throws IOException {
         ArrayList jiraIssues = new ArrayList();
 
-        while( true )
-        {
-            TagReader nextIssue = parser.parseNextIssue( masterReport );
-            if ( nextIssue == null ) { break; }
-
-            JiraIssue candidate = new JiraIssue( parser, nextIssue );
-
-            boolean skip = false;
-            for (Iterator ex = excludeReleaseIDList.iterator(); ex.hasNext();)
-            {
-                String rid = (String) ex.next();
-                if (candidate.isFixedIn(rid))
-                {
-                    //System.out.println("Already fixed: "+candidate.getKey()+ " (in "+rid+")");
-                    skip=true;
-                    break;
-                }
+        BufferedReader in = new BufferedReader(new FileReader(source));
+        String line;
+        System.out.println("--- Creating Jira issue list");
+        while ((line = in.readLine()) != null && line.startsWith("//")) {
+            System.out.println(line);
+        }
+
+        ArrayList comments = new ArrayList();
+        int state = STATE_ADD_KEY;
+        String key = null;
+        String summary = null;
+        String[] fixVersions = null;
+        long attachmentId = NO_RELEASE_NOTE;
+        do {
+            if (line.startsWith("//")) {
+                comments.add(line.trim());
+                continue;
             }
-            if (!skip)
-            {
-                //System.out.println("adding: " + candidate.getKey());
-                jiraIssues.add(candidate);
+            if (line.startsWith("---")) {
+                continue;
             }
+
+            if (state == STATE_ADD_KEY) {
+                key = line.trim();
+                if (!key.startsWith("DERBY-")) {
+                    throw new IllegalStateException(
+                            "invalid JIRA key for Derby: " + key);
+                }
+                key = key.split("-")[1];
+                // Sanity check
+                Integer.parseInt(key);
+            } else if (state == STATE_ADD_SUMMARY) {
+                summary = line.trim();
+            } else if (state == STATE_ADD_FIXVERSIONS) {
+                line = line.trim();
+                fixVersions = line.split(",");
+            } else if (state == STATE_ADD_RELEASENOTE) {
+                line = line.trim();
+                if (line.equals("null")) {
+                    attachmentId = NO_RELEASE_NOTE;
+                } else  if (line.equals("missing")) {
+                    attachmentId = MISSING_RELEASE_NOTE;
+                } else {
+                    attachmentId = Long.parseLong(line);
+                }
+                // We now have all the information we need.
+                jiraIssues.add(new JiraIssue(key, summary,
+                        Arrays.asList(fixVersions), attachmentId));
+                state = STATE_ADD_RESET;
+            }
+            state++;
+        } while ((line = in.readLine()) != null);
+        if (state != STATE_ADD_KEY) {
+            throw new IllegalStateException("illegal state, check source " +
+                    "file for correctness (state=" + state + ")");
+        }
+        // Print the last few comments for information (by convention).
+        int size = comments.size();
+        if (size > 2) {
+            System.out.println(comments.get(size -3));
+            System.out.println(comments.get(size -2));
+            System.out.println(comments.get(size -1));
         }
 
         return jiraIssues;
@@ -115,7 +164,15 @@ class JiraIssue {
      * @return true iff this issue has a release note attached
      */
     public boolean hasReleaseNote() {
-        return (releaseNoteAttachmentID > ReportParser.NO_RELEASE_NOTE);
+        return (releaseNoteAttachmentID != NO_RELEASE_NOTE &&
+                releaseNoteAttachmentID != MISSING_RELEASE_NOTE);
+    }
+
+    /**
+     * @return true iff this issue is missing a release note
+     */
+    public boolean hasMissingReleaseNote() {
+        return (releaseNoteAttachmentID == MISSING_RELEASE_NOTE);
     }
 
     /**
@@ -124,7 +181,7 @@ class JiraIssue {
      * @return true iff issue has version as fixVersion
      */
     public boolean isFixedIn(String version) {
-        return fixVersionSet.contains(version);
+        return fixVersions.contains(version);
     }
 
     /**
@@ -138,9 +195,7 @@ class JiraIssue {
      * @return Full URL to the latest release note
      */
     public String getReleaseNoteAddress() {
-        return "https://issues.apache.org/jira/secure/attachment/" +
-                releaseNoteAttachmentID + "/releaseNote.html";
+        return ATTACHMENT_BASE +
+                releaseNoteAttachmentID + "/" + ATTACHMENT_NAME;
     }
 }
-
-

Modified: db/derby/code/trunk/java/build/org/apache/derbyBuild/ReleaseNotesGenerator.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/build/org/apache/derbyBuild/ReleaseNotesGenerator.java?rev=1027878&r1=1027877&r2=1027878&view=diff
==============================================================================
--- db/derby/code/trunk/java/build/org/apache/derbyBuild/ReleaseNotesGenerator.java (original)
+++ db/derby/code/trunk/java/build/org/apache/derbyBuild/ReleaseNotesGenerator.java Wed Oct 27 09:42:02 2010
@@ -31,35 +31,50 @@ import org.apache.tools.ant.BuildExcepti
  * <p>
  * This tool generates Release Notes for a Derby release. See the USAGE
  * constant for details on how to run this tool standalone. It is recommended
- * that you freshly regenerate your BUG_LIST and NOTES_LIST just before
- * you run this tool.
+ * that you freshly regenerate your BUG_LIST just before you run this tool.
  * </p>
  *
  * <p>
- * The tool is designed to be run from Derby's ant build scripts. To run under
- * ant, do the following:
+ * The tool is designed to be run from Derby's ant build scripts. The build
+ * script will integrate the various steps of generating the release notes into
+ * a single ant target. This includes generating the issue list by querying
+ * the Apache JIRA instance. For this reason, the properties below must be
+ * specified when invoking the ant target. You can specify them in
+ * <tt>ant.properties</tt>, or on the command line.<br/>
+ * To run under ant, do the following:
  * </p>
  *
  * <ul>
- * <li>Define the "relnotes.src.reports" variable in your ant.properties. This
- * variable points at the directory which holds your xml JIRA reports.</li>
- * <li>Put your xml JIRA reports in that directory. They should have the
- * following names:
- *  <ul>
- *  <li>fixedBugsList.xml - This is the list of issues addressed
- * by the release.</li>
- *  <li>releaseNotesList.xml - This is the list of issues which have detailed
- *  release notes.</li>
- *  </ul>
- * </li>
- * <li>Then cd to tools/release and run ant thusly: "ant genrelnotes"</li>
+ *      <li>Make sure the Maven 2 executable is in your path.</li>
+ *      <li>Fill in information in <tt>releaseSummary.xml</tt>.<br/>
+ *          See <tt>tools/release/templates/releaseSummaryTemplate.xml</tt>
+ *          for details.</li>
+ *      <li>Define <tt>jira.user</tt>.<br/>
+ *          This variable is your JIRA user name.</li>
+ *      <li>Define <tt>jira.password</tt>.<br/>
+ *          This variable is your JIRA password.</li>
+ *      <li>Define <tt>jira.filter.id</tt>.<br/>
+ *          This variable holds the id for the manually created JIRA filter
+ *          that will select the issues addressed by the release. The id
+ *          consists of digits only.</li>
+ *      <li>Define <tt>release.version</tt>.<br/>
+ *          The version of the release, i.e. "10.7.1.0".</li>
+ *      <li>Define <tt>relnotes.src.reports</tt>.<br/>
+ *          This variable points at the directory which holds the list of JIRA
+ *          issues addressed by the release. The file, called
+ *          <tt>fixedBugsList.txt</tt>, will be generated when you invoke the
+ *          ant target.</li>
+ *      <li>cd into <tt>tools/release</tt> and run ant thusly:
+ *          <tt>ant [properties] genrelnotes</tt></li>
  * </ul>
- *
- * <p>For more information on this tool, please see the JIRA which introduced it:
+ * Running the ant target successfully requires a working Internet connection
+ * to the Apache JIRA instance, as well as a valid JIRA username/password and
+ * the id of an existing JIRA filter.
  * </p>
- *
- * <p>
- * <a href="http://issues.apache.org/jira/browse/DERBY-2570">DERBY-2570</a>
+ * <p>For more information on this tool, please see the JIRAs which introduced it:
+ * <ul> <li><a href="http://issues.apache.org/jira/browse/DERBY-4857">DERBY-4857</a></li>
+ *      <li><a href="http://issues.apache.org/jira/browse/DERBY-2570">DERBY-2570</a></li>
+ * </ul>
  * </p>
  */
 public class ReleaseNotesGenerator extends GeneratorBase {
@@ -72,12 +87,11 @@ public class ReleaseNotesGenerator exten
     private static  final   String  USAGE =
         "Usage:\n" +
         "\n" +
-        "  java org.apache.derbyBuild.ReleaseNotesGenerator SUMMARY BUG_LIST NOTES_LIST OUTPUT_PAMPHLET\n" +
+        "  java org.apache.derbyBuild.ReleaseNotesGenerator SUMMARY BUG_LIST OUTPUT_PAMPHLET\n" +
         "\n" +
         "    where\n" +
         "                  SUMMARY                    Summary, a filled-in copy of releaseSummaryTemplate.xml.\n" +
-        "                  BUG_LIST                     An xml JIRA report of issues addressed by this release.\n" +
-        "                  NOTES_LIST                An xml JIRA report listing issues which have detailed releaseNotes.html attachments.\n" +
+        "                  BUG_LIST                   A report of issues addressed by this release, generated by the Derby JIRA SOAP client.\n" +
         "                  OUTPUT_PAMPHLET  The output file to generate, typically RELEASE-NOTES.html.\n" +
         "\n" +
         "The ReleaseNoteGenerator attempts to connect to issues.apache.org in\n" +
@@ -85,14 +99,13 @@ public class ReleaseNotesGenerator exten
         "individual JIRAs. Before running this program, make sure that you can\n" +
         "ping issues.apache.org.\n" +
         "\n" +
-        "The ReleaseNoteGenerator assumes that the two JIRA reports contain\n" +
-        "key, title, and attachments elements for each Derby issue. For each\n" +
-        "issue in NOTES_LIST, the ReleaseNotesGenerator looks through the\n" +
-        "attachments block in that report and grabs the latest reported\n" +
-        "releaseNote.html.\n" +
+        "The ReleaseNoteGenerator assumes that the JIRA report contains\n" +
+        "key, title, fix versions and attachment id elements for each Derby\n" +
+        "issue. For each issue in with an attachment id element the\n" +
+        "ReleaseNotesGenerator grabs the (latest) releaseNote.html file.\n" +
         "\n" +
         "For this reason, it is recommended that you freshly generate BUG_LIST\n" +
-        "and NOTES_LIST just before you run this tool.\n"
+        "just before you run this tool.\n"
         ;
 
 
@@ -132,7 +145,6 @@ public class ReleaseNotesGenerator exten
     /////////////////////////////////////////////////////////////////////////
 
     private ReleaseNoteReader releaseNoteReader = new ReleaseNoteReader(docBldr);
-    private ReportParser reportParser = ReportParser.makeReportParser();
     // set on the command line or by ant
 
     private ArrayList missingReleaseNotes = new ArrayList();
@@ -171,6 +183,7 @@ public class ReleaseNotesGenerator exten
             beginOutput();
             buildOverview();
             buildNewFeatures();
+            parseBugsList();
             buildFixedBugsList();
             buildReleaseNoteIssuesList();
             buildEnvironment();
@@ -263,6 +276,32 @@ public class ReleaseNotesGenerator exten
     //
     //////////////////////////////////
 
+    private void parseBugsList()
+            throws Exception {
+        bugList = JiraIssue.createJiraIssueList(bugListFileName);
+        // Parse the file for the release version and the previous version to
+        // carry out sanity checks.
+        BufferedReader in = new BufferedReader(new InputStreamReader(
+                new FileInputStream(bugListFileName), "UTF-8"));
+        String line;
+        String prevVer = null;
+        while ((line = in.readLine()) != null) {
+            if (line.startsWith("// Previous release:")) {
+                prevVer = line.split(":")[1].trim();
+                break;
+            }
+        }
+        in.close();
+        if (prevVer == null) {
+            System.out.println(
+                    "WARNING: Skipped previous release version sanity check.");
+        } else if (!prevVer.equals(previousReleaseID)) {
+            throw new IllegalStateException("previous release version " +
+                    "mismatch between releaseSummary.xml and bug list: " +
+                    previousReleaseID + " != " + prevVer);
+        }
+    }
+
     /**
      * Build the Bug List section.
      * @param gs state
@@ -284,10 +323,7 @@ public class ReleaseNotesGenerator exten
             (bugListSection, DEFAULT_TABLE_BORDER_WIDTH,
             new String[] { ISSUE_ID_HEADLINE, DESCRIPTION_HEADLINE });
 
-        bugListDoc.reset();
-        
-        for ( Iterator i = JiraIssue.createJiraIssueList( bugListDoc, excludeReleaseIDList, reportParser ).iterator(); i.hasNext(); )
-        {
+        for ( Iterator i=bugList.iterator(); i.hasNext(); ) {
             JiraIssue issue = (JiraIssue) i.next();
             //println("Fixed: "+ issue.getKey());
             Element row = insertRow(table);
@@ -324,10 +360,7 @@ public class ReleaseNotesGenerator exten
         addParagraph(issuesSection, deltaStatement);
         Element toc = createList(issuesSection);
 
-        bugListDoc.reset();
-        
-        for ( Iterator i = JiraIssue.createJiraIssueList( bugListDoc, excludeReleaseIDList, reportParser ).iterator(); i.hasNext(); )
-        {
+        for (Iterator i=bugList.iterator(); i.hasNext(); ) {
             JiraIssue issue = (JiraIssue) i.next();
             if (issue.hasReleaseNote()) {
                 Node summaryText = null;
@@ -357,6 +390,8 @@ public class ReleaseNotesGenerator exten
                 Element issueSection = createSection(issuesSection,
                         ISSUE_DETAIL_LEVEL, toc, key, paragraph);
                 cloneChildren(details, issueSection);
+            } else if (issue.hasMissingReleaseNote()) {
+                missingReleaseNotes.add(issue);
             }
         }
     }