Command to generate release notes
diff --git a/pom.xml b/pom.xml
index ad30165..33a926e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -246,7 +246,7 @@
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
- <version>4.3.5</version>
+ <version>4.5.7</version>
<exclusions>
<exclusion>
<artifactId>commons-logging</artifactId>
@@ -294,6 +294,17 @@
<artifactId>tomitribe-util</artifactId>
<version>1.3.18</version>
</dependency>
+ <dependency>
+ <groupId>org.tomitribe.jamira</groupId>
+ <artifactId>jamira-core</artifactId>
+ <version>0.4</version>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.13.2</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</project>
diff --git a/src/main/java/org/apache/openejb/tools/release/Loader.java b/src/main/java/org/apache/openejb/tools/release/Loader.java
index cc2c107..41a927e 100644
--- a/src/main/java/org/apache/openejb/tools/release/Loader.java
+++ b/src/main/java/org/apache/openejb/tools/release/Loader.java
@@ -18,6 +18,7 @@
import org.apache.openejb.tools.release.cmd.Dist;
+import org.apache.openejb.tools.release.cmd.ReleaseNotes;
import java.util.Arrays;
import java.util.Iterator;
@@ -28,6 +29,7 @@
public Iterator<Class<?>> iterator() {
return Arrays.asList(
Dist.class,
+ ReleaseNotes.class,
Object.class
).iterator();
}
diff --git a/src/main/java/org/apache/openejb/tools/release/cmd/ReleaseNotes.java b/src/main/java/org/apache/openejb/tools/release/cmd/ReleaseNotes.java
index 132f2ca..0867223 100644
--- a/src/main/java/org/apache/openejb/tools/release/cmd/ReleaseNotes.java
+++ b/src/main/java/org/apache/openejb/tools/release/cmd/ReleaseNotes.java
@@ -16,19 +16,131 @@
*/
package org.apache.openejb.tools.release.cmd;
-import org.apache.openejb.tools.release.Command;
+import com.atlassian.jira.rest.client.api.SearchRestClient;
+import com.atlassian.jira.rest.client.api.domain.Issue;
+import com.atlassian.jira.rest.client.api.domain.IssueType;
+import com.atlassian.jira.rest.client.api.domain.SearchResult;
+import lombok.Getter;
import org.apache.openejb.tools.release.Release;
+import org.tomitribe.crest.api.Command;
+import org.tomitribe.crest.api.Default;
+import org.tomitribe.crest.api.Option;
+import org.tomitribe.crest.api.PrintOutput;
+import org.tomitribe.jamira.core.Account;
+import org.tomitribe.jamira.core.Client;
import java.lang.reflect.Field;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
/**
* @version $Rev$ $Date$
*/
-@Command
+@Command("release-notes")
public class ReleaseNotes {
+ /**
+ * Generate asciidoc release notes for the specified TomEE version. The resulting
+ * asciidoc can be piped to a file in the `tomee-site-generator` repo. For example:
+ *
+ * release release-notes generate 8.0.7 > tomee-site-generator/src/main/jbake/content/tomee-8.0.7-release-notes.html
+ *
+ * In situations like TomEE 9, we can include release notes for the related TomEE 8
+ * version via the --include-versions flag as follows:
+ *
+ * release release-notes generate 9.0.0-M7 --include-versions=8.0.7
+ *
+ * This tool leverages the Jamira command-line tool and library for logging into
+ * and talking with JIRA. It is expected Jamira has been installed and the setup
+ * commands run so there is an account available for accessing JIRA. See the
+ * description of --account for more details.
+ *
+ * @param version The TomEE version as specified in JIRA. Example "8.0.7"
+ * @param includeVersions Any additional versions that should also be represented in these release notes.
+ * @param account The account to use to log into JIRA. See https://github.com/tomitribe/jamira#setup
+ */
+ @Command
+ public PrintOutput generate(final String version,
+ @Option("include-versions") final String includeVersions,
+ @Option("account") @Default("default") final Account account) throws ExecutionException, InterruptedException {
+
+ final Set<String> versions = new HashSet<>();
+ versions.add(version);
+ if (includeVersions != null) {
+ versions.addAll(Arrays.asList(includeVersions.split(" *, *| ")));
+ }
+
+ final Client client = account.getClient();
+ final SearchRestClient searchClient = client.getSearchClient();
+
+ final Map<String, Issue> issuesByKey = new HashMap<>();
+ for (final String ver : versions) {
+ final String s = "project = TOMEE AND status = Resolved AND fixVersion = " + ver;
+ final SearchResult result = searchClient.searchJql(s).get();
+
+ for (final Issue issue : result.getIssues()) {
+ issuesByKey.put(issue.getKey(), issue);
+ }
+ }
+
+ final List<IssueType> sections = Arrays.asList(
+ client.getIssueType("Dependency upgrade"),
+ client.getIssueType("New Feature"),
+ client.getIssueType("Improvement"),
+ client.getIssueType("Task"),
+ client.getIssueType("Sub-task")
+ );
+
+ return out -> {
+ out.println("= Apache TomEE " + version + " Release Notes\n" +
+ ":index-group: Release Notes\n" +
+ ":jbake-type: page\n" +
+ ":jbake-status: published");
+
+ for (final IssueType section : sections) {
+
+ final List<Issue> issues = issuesByKey.values()
+ .stream().filter(issue -> issue.getIssueType().getName().equals(section.getName()))
+ .collect(Collectors.toList());
+
+ if (issues.size() <= 0) continue;
+
+ out.println();
+ out.printf("== %s%n", section.getName());
+ out.println();
+
+ if (section.getName().equals("Dependency upgrade")) {
+ issues.stream()
+ .map(Upgrade::new)
+ .sorted(Comparator.comparing(Upgrade::getSummary))
+ .forEach(upgrade -> {
+ out.printf(" - link:https://issues.apache.org/jira/browse/%s[%s] %s%n",
+ upgrade.getKey(),
+ upgrade.getKey(),
+ upgrade.getSummary());
+
+ });
+ } else {
+ for (final Issue issue : issues) {
+ out.printf(" - link:https://issues.apache.org/jira/browse/%s[%s] %s%n",
+ issue.getKey(),
+ issue.getKey(),
+ issue.getSummary());
+ }
+ }
+ }
+ };
+ }
+
public static void main(final String[] args) throws Throwable {
final List<String> argsList = new ArrayList<String>();
@@ -46,4 +158,56 @@
org.codehaus.swizzle.jirareport.Main.main((String[]) argsList.toArray(new String[]{}));
}
+
+ @Getter
+ public static class Upgrade {
+ private final Issue issue;
+ private final String summary;
+
+ public Upgrade(final Issue issue) {
+ this.issue = issue;
+ this.summary = normalize(issue.getSummary());
+ }
+
+ public String getKey() {
+ return issue.getKey();
+ }
+
+ public static String normalize(final String summary) {
+ return Replace.string(summary)
+ .first("^(upgrade to|upgrade|update to|update) (.*)", "$2")
+ .all(" to ", " ")
+ .all(" in tomee.*", "")
+ .first("apache ", "")
+ .toString();
+ }
+
+
+ private static class Replace {
+ private String string;
+
+ public Replace(final String string) {
+ this.string = string;
+ }
+
+ public Replace all(final String regex, final String replacement) {
+ string = Pattern.compile(regex, Pattern.CASE_INSENSITIVE).matcher(string).replaceAll(replacement);
+ return this;
+ }
+
+ public Replace first(final String regex, final String replacement) {
+ string = Pattern.compile(regex, Pattern.CASE_INSENSITIVE).matcher(string).replaceFirst(replacement);
+ return this;
+ }
+
+ public static Replace string(final String s) {
+ return new Replace(s);
+ }
+
+ @Override
+ public String toString() {
+ return string;
+ }
+ }
+ }
}
diff --git a/src/test/java/org/apache/openejb/tools/release/cmd/ReleaseNotesTest.java b/src/test/java/org/apache/openejb/tools/release/cmd/ReleaseNotesTest.java
new file mode 100644
index 0000000..2e72ac1
--- /dev/null
+++ b/src/test/java/org/apache/openejb/tools/release/cmd/ReleaseNotesTest.java
@@ -0,0 +1,52 @@
+/*
+ * 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.openejb.tools.release.cmd;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class ReleaseNotesTest {
+
+ @Test
+ public void normalizeDependencySummary() {
+ assertNormalize("BatchEE 0.6", "Upgrade BatchEE to 0.6");
+ assertNormalize("CXF 3.3.10 / 3.4.3", "Upgrade CXF to 3.3.10 / 3.4.3 in TomEE");
+ assertNormalize("CXF 3.3.8", "Update CXF 3.3.8");
+ assertNormalize("CXF 3.4.x (Java 16 support)", "Upgrade CXF 3.4.x (Java 16 support)");
+ assertNormalize("EclipseLink 2.7.7", "Update EclipseLink to 2.7.7");
+ assertNormalize("Implement JAX-RS SSE and add example", "Implement JAX-RS SSE and add example");
+ assertNormalize("Johnzon 1.2.9", "Apache Johnzon 1.2.9");
+ assertNormalize("Johnzon 1.2.9", "Update Johnzon 1.2.9");
+ assertNormalize("MyFaces 2.3.8", "Upgrade MyFaces 2.3.8");
+ assertNormalize("MyFaces 2.3.9", "Upgrade MyFaces to 2.3.9");
+ assertNormalize("OWB 2.0.22", "Update OWB 2.0.22");
+ assertNormalize("OpenSAML V3.4.6", "Update OpenSAML to V3.4.6");
+ assertNormalize("Tomcat 9.0.41", "Upgrade Tomcat 9.0.41");
+ assertNormalize("Tomcat 9.0.43", "Update Tomcat to 9.0.43");
+ assertNormalize("Tomcat 9.0.44", "Upgrade Tomcat to 9.0.44");
+ assertNormalize("Tomcat 9.0.45", "Update Tomcat to 9.0.45");
+ assertNormalize("bcprov-jdk15on 1.67", "Update bcprov-jdk15on to 1.67");
+ assertNormalize("quartz-openejb-shade", "Upgrade quartz-openejb-shade in TomEE 8/9");
+ assertNormalize("xbean 4.18+ (Java 16 support)", "Upgrade xbean to 4.18+ (Java 16 support)");
+ }
+
+ public static void assertNormalize(final String expected, final String input) {
+ assertEquals(expected, ReleaseNotes.Upgrade.normalize(input));
+ }
+
+}