Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

release notes maven plugin (for Jersey) #4290

Merged
merged 1 commit into from
Oct 21, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions tools/jersey-release-notes-maven-plugin/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
[//]: # " Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved. "
[//]: # " "
[//]: # " This program and the accompanying materials are made available under the "
[//]: # " terms of the Eclipse Public License v. 2.0, which is available at "
[//]: # " http://www.eclipse.org/legal/epl-2.0. "
[//]: # " "
[//]: # " This Source Code may also be made available under the following Secondary "
[//]: # " Licenses when the conditions for such availability set forth in the "
[//]: # " Eclipse Public License v. 2.0 are satisfied: GNU General Public License, "
[//]: # " version 2 with the GNU Classpath Exception, which is available at "
[//]: # " https://www.gnu.org/software/classpath/license.html. "
[//]: # " "
[//]: # " SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 "

### Release Notes maven plugin

Runs for post-site mvn target, generates release notes for given template file,
stores generated release notes in target/release-notes/{versionNumber}.html file (path of output file can be changed)

### Input parameters:

- releaseVersion - (String) - version to be used everywhere where it occurs. Like file name, replacement tag, release tag etc.
supplied in for of '2.29.1'
- githubApiUrl - (String) - short relative path to github api to which release notes shall be published (like eclipse-ee4j/jersey)
- githubLogin - (String) - login of github user used to publish release notes to GitHub. Not used in dry run or not publish to GitHub modes.
- githubToken - (String) - token of github user while two factor authentication is used.
Used to publish release notes to GitHub. Not used in dry run or not publish to GitHub modes.
- githubPassword - (String) - password of github user while simple authentication is used.
Used to publish release notes to GitHub. Not used in dry run or not publish to GitHub modes.
- publishToGithub - (Boolean) - whether or not publish generated release notes directly to GitHub (false by default)
- dryRun - (Boolean) - whether to modify anything (false) or not (true). True by default
- templateFilePath - (String) - template HTML file which is used to generate HTML release notes page
- releaseDate - (String) - date of release (like 10-11-2019 or 10-NOV-2019 or any valid date format)
- releaseNotesFilePath - (String) - path for output file to be stored (default target/relese-notes/)
132 changes: 132 additions & 0 deletions tools/jersey-release-notes-maven-plugin/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--

Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved.

This program and the accompanying materials are made available under the
terms of the Eclipse Public License v. 2.0, which is available at
http://www.eclipse.org/legal/epl-2.0.

This Source Code may also be made available under the following Secondary
Licenses when the conditions for such availability set forth in the
Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
version 2 with the GNU Classpath Exception, which is available at
https://www.gnu.org/software/classpath/license.html.

SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0

-->

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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.eclipse.ee4j</groupId>
<artifactId>project</artifactId>
<version>1.0.5</version>
</parent>

<groupId>org.glassfish.jersey.tools.plugins</groupId>
<artifactId>jersey-release-notes-maven-plugin</artifactId>
<packaging>maven-plugin</packaging>
<version>1.0.1</version>
<name>jersey-release-notes-maven-plugin</name>

<description>
Publishes release notes for Jersey to GitHub
</description>

<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
<version>${maven.version}</version>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-core</artifactId>
<version>${maven.version}</version>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-artifact</artifactId>
<version>${maven.version}</version>
</dependency>
<dependency>
<groupId>org.apache.maven.plugin-tools</groupId>
<artifactId>maven-plugin-annotations</artifactId>
<version>3.6.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.kohsuke</groupId>
<artifactId>github-api</artifactId>
<version>1.95</version>
</dependency>
<dependency>
<groupId>org.apache.maven.plugin-testing</groupId>
<artifactId>maven-plugin-testing-harness</artifactId>
<version>3.3.0</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-compat</artifactId>
<version>3.6.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>

</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-plugin-plugin</artifactId>
<version>3.6.0</version>
<configuration>
<skipErrorNoDescriptorsFound>true</skipErrorNoDescriptorsFound>
</configuration>
<executions>
<execution>
<id>default-descriptor</id>
<goals>
<goal>descriptor</goal>
</goals>
<phase>process-classes</phase>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<inherited>true</inherited>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<showWarnings>false</showWarnings>
<fork>false</fork>
</configuration>
</plugin>
</plugins>
</build>

<properties>
<java.version>1.8</java.version>
<maven.version>3.6.2</maven.version>
</properties>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
/*
* Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/

package org.glassfish.jersey.tools.plugins.releasenotes;

import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.kohsuke.github.GHIssue;
senivam marked this conversation as resolved.
Show resolved Hide resolved
import org.kohsuke.github.GHIssueState;
import org.kohsuke.github.GHMilestone;
import org.kohsuke.github.GHRepository;
import org.kohsuke.github.GitHub;
import org.kohsuke.github.PagedIterable;

import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

@Mojo(name = "release-notes", defaultPhase = LifecyclePhase.POST_SITE)
public class ReleaseNotesMojo extends AbstractMojo {

/**
* Version for release notes to be used for generated name and content of release notes
* IMPORTANT - version shall be the same as milestone at GitHub issue tracker
*/
@Parameter(required = true, defaultValue = "2.29.1", property = "releaseVersion")
private String releaseVersion;

/**
* Short path to GitHub issue tracker (like eclipse-ee4j/jersey). Not full url.
*/
@Parameter(required = true, defaultValue = "eclipse-ee4j/jersey", property = "githubApiUrl")
private String githubApiUrl;

/**
* Login to GitHub (related to githubApiPath).
* if DRY_RUN or !publishToGitHub is used the property may be NULL
*/
@Parameter(property = "githubLogin")
private String githubLogin;

/**
* Token for login (if two factor auth is used, empty otherwise)
* if DRY_RUN or !publishToGitHub is used the property may be NULL
*/
@Parameter(property = "githubToken")
private String githubToken;

/**
* GitHub password (if simple auth is used, empty otherwise)
* if DRY_RUN or !publishToGitHub is used the property may be NULL
*/
@Parameter(property = "githubPassword")
private String githubPassword;

/**
* Flag which allows direct publishing of notes to github. (RELEASE TAG)
* Is FALSE by default
*/
@Parameter(required = true, defaultValue = "false", property = "publishToGithub")
private Boolean publishToGithub;

/**
* Dry run mode - no publishing, no creating of release notes file.
* TRUE by default
*/
@Parameter(required = true, defaultValue = "true", property = "dryRun")
private Boolean dryRun;

/**
* Path to HTML template which shall be used for substitution of values to generate release notes
*/
@Parameter(required = true, property = "templateFilePath")
private String templateFilePath;

/**
* Date of release - only used inside HTML file which is generated by template
*/
@Parameter(required = true, property = "releaseDate")
private String releaseDate;

/**
* Path to store generated release notes. The name of file is [releaseVersion].html.
* Default is target/release-notes/
*/
@Parameter(required = true, defaultValue = "target/release-notes", property = "releaseNotesFilePath")
private String releaseNotesFilePath;

private static final String RELEASE_DATE_PATTERN = "@RELEASE_DATE@";
private static final String LATEST_VERSION_PATTERN = "@LATEST_VERSION@";

public void execute() throws MojoExecutionException, MojoFailureException {
validateParameters();
try {
final GitHub github = (dryRun || !publishToGithub) ? GitHub.connectAnonymously() :
(githubPassword != null ? GitHub.connectUsingPassword(githubLogin, githubPassword) :
GitHub.connect(githubLogin, githubToken));
final GHRepository repository = github.getRepository(githubApiUrl);
final PagedIterable<GHMilestone> milestones = repository.listMilestones(GHIssueState.ALL);
for (final GHMilestone milestone : milestones) {
if (releaseVersion.equalsIgnoreCase(milestone.getTitle())) {
getLog().info(String.format("Milestone found for release version: %s", releaseVersion));
processMilestone(releaseVersion, milestone, repository, publishToGithub, dryRun, templateFilePath,
releaseDate, releaseNotesFilePath, getLog());
}
}
} catch (IOException e) {
throw new MojoExecutionException(e.getMessage(), e);
}
}

private static void processMilestone(String releaseVersion, GHMilestone milestone,
GHRepository repository, Boolean publishToGithub,
Boolean dryRun, String templateFilePath, String releaseDate,
String releaseNotesFilePath, Log log
) throws MojoExecutionException {
try {
final String releaseNotes = prepareReleaseNotes(milestone, repository);
log.info("Prepared release notes:");
log.info(releaseNotes);
if (Boolean.TRUE.equals(publishToGithub) && Boolean.FALSE.equals(dryRun)) {
log.info("Publishing release notes to GitHub");
publishReleaseNotes(releaseNotes, releaseVersion, repository);
} else {
log.info("Publishing to GitHub is disabled, skipping");
}
storeReleaseNotes(releaseNotes, templateFilePath, releaseVersion,
releaseDate, releaseNotesFilePath, dryRun, log);
} catch (IOException e) {
throw new MojoExecutionException(e.getMessage(), e);
}
}

private static String prepareReleaseNotes(GHMilestone milestone, GHRepository repository) throws IOException {
final StringBuffer releaseNotes = new StringBuffer();
final String pullRequestFormat = "<li>[<a href='%s'>Pull %d</a>] - %s</li>\n";
final String issueFormat = "<li>[<a href='%s'>Issue %d</a>] - %s</li>\n";
// final List<String> releaseNotesLines = new ArrayList<>();
final List<GHIssue> issues = repository.getIssues(GHIssueState.CLOSED, milestone);
issues.stream().map(issue -> String.format(issue.isPullRequest() ? pullRequestFormat : issueFormat,
issue.getHtmlUrl(), issue.getNumber(), issue.getTitle())).sorted().forEach(releaseNotes::append);
// releaseNotesLines.stream().sorted().forEach(releaseNotes::append);
return releaseNotes.toString();
}

private static void publishReleaseNotes(String releaseNotes, String releaseVersion, GHRepository repository) throws IOException {
repository.createRelease(releaseVersion).name(releaseVersion).body(releaseNotes).create();
}

private static void storeReleaseNotes(String releaseNotes, String templateFilePath,
String releaseVersion, String releaseDate,
String releaseNotesFilePath,
Boolean dryRun, Log log) throws IOException {
if (Files.notExists(Paths.get(templateFilePath))) {
log.warn(String.format("There is no source template file at the given location:%s", templateFilePath));
return;
}
final List<String> notesLines = new ArrayList<>();
final List<String> lines = Files.readAllLines(Paths.get(templateFilePath), Charset.defaultCharset());
for (final String line : lines) {
if (line.contains(RELEASE_DATE_PATTERN)) {
notesLines.add(line.replace(RELEASE_DATE_PATTERN, releaseDate));
} else if (line.contains(LATEST_VERSION_PATTERN)) {
notesLines.add(line.replace(LATEST_VERSION_PATTERN, releaseVersion));
} else if (line.contains("<h2>Previous releases</h2>")) {
notesLines.add("<h2>Pull requests and issues</h2>\n<ul>");
notesLines.add(releaseNotes);
notesLines.add("</ul>");
notesLines.add(line);
} else if (line.contains("<ul>")) {
notesLines.add(line);
notesLines.add(String.format(" <li><a href=\"%s.html\">Jersey %s Release Notes</a></li>", releaseVersion, releaseVersion));
} else {
notesLines.add(line);
}
}
if (Boolean.FALSE.equals(dryRun)) {
log.info(String.format("Storing release notes to file %s/%s.html", releaseNotesFilePath, releaseVersion));
Files.createDirectories(Paths.get(releaseNotesFilePath));
Files.write(Paths.get(String.format("%s/%s.html", releaseNotesFilePath, releaseVersion)), notesLines, Charset.defaultCharset());
} else {
log.info("Prepared release notes are not stored to file due to dryRun mode");
log.info(String.format("File path to store release notes is: %s/%s.html", releaseNotesFilePath, releaseVersion));
}
}

private void validateParameters() throws MojoFailureException {
if (releaseVersion == null) {
throw new MojoFailureException("releaseVersion shall be provided");
}
if (Boolean.FALSE.equals(dryRun) || Boolean.TRUE.equals(publishToGithub)) {
if (githubLogin == null) {
throw new MojoFailureException("githubLogin shall be provided");
}
if (githubPassword == null && githubToken == null) {
throw new MojoFailureException("Either githubPassword or githubToken shall be provided");
}
}
}
}
Loading