Skip to content

Instantly share code, notes, and snippets.

@fbricon
Last active August 31, 2020 17:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fbricon/4028e0e2dda01acd0e7bd0f3e3c2ed63 to your computer and use it in GitHub Desktop.
Save fbricon/4028e0e2dda01acd0e7bd0f3e3c2ed63 to your computer and use it in GitHub Desktop.
Generate changelogs
//usr/bin/env jbang "$0" "$@" ; exit $?
//DEPS com.google.code.gson:gson:2.8.6
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Stream;
import com.google.gson.Gson;
/**
* Generate changelog for a release. Requires
* <a href="https://github.com/maxandersen/jbang">j'bang</a> to be installed.
* <p>
* Execute with:
* <ul>
* <li><code>jbang GenerateChangelog.java repo1/milestone/number1 repoN/milestone/numberN ...</code></li>
* <li>eg. <code>jbang GenerateChangelog.java
* https://github.com/eclipse/lemminx/milestone/14
* https://github.com/eclipse/lemminx/milestone/13
*
* </ul>
* </p>
*/
public class GenerateChangelog {
private static final Map<String, List<Issue>> labeledIssues = new LinkedHashMap<>();
public static void main(String[] args) throws Exception {
for (String repo : args) {
String url = repo.replace("https://github.com/", "https://api.github.com/repos/")
.replace("/milestone/", "/issues?state=closed&milestone=");
fillIssues(url);
}
// Performance
generateIssues("performance -", labeledIssues.get("performance"));
// enhancement
generateIssues("enhancement -", labeledIssues.get("enhancement"));
// Bug Fixes
generateIssues("bug fix -", labeledIssues.get("bug"));
// Performance
generateIssues("build -", labeledIssues.get("build"));
// Other
generateIssues("other -", labeledIssues.get("other"));
System.exit(0);
}
private static void generateIssues(String title, List<Issue> list) {
if (list == null) {
return;
}
for (Issue issue : list) {
String url = issue.html_url;
String number = url.substring(url.lastIndexOf("/") + 1);
String line = " * " + title + " " + issue.title + ". See [#" + number + "](" + url + ").";
generateLine(line);
}
}
private static void generateLine(String line) {
System.out.println(line);
}
private static void fillIssues(String url) throws Exception {
int page = 1;
boolean hasMore = true;
do {
String pageUrl = url+"&page="+(page++);
System.out.println("Fetching issues from " + pageUrl);
URL u = new URL(pageUrl);
URLConnection connection = u.openConnection();
try (InputStream in = connection.getInputStream()) {
Reader reader = new InputStreamReader(in, "UTF-8");
Issue[] issues = new Gson().fromJson(reader, Issue[].class);
hasMore = issues.length == 30;
Stream.of(issues).filter(Issue::isValid).forEach(i -> {
labeledIssues.computeIfAbsent(i.getMainLabel(), k -> new ArrayList<>()).add(i);
});
}
} while (hasMore);
}
static class Label {
public String name;
}
static class Issue {
private static String[] SIGNIFICANT_LABELS = { "build", "enhancement", "bug", "performance", "other" };
String html_url;
String title;
Label[] labels;
public String getMainLabel() {
String mainLabel = findLabel(SIGNIFICANT_LABELS);
return mainLabel == null ? "other" : mainLabel;
}
public String findLabel(String... names) {
if (labels != null) {
for (Label label : labels) {
for (String name : names) {
if (Objects.equals(label.name, name)) {
return name;
}
}
}
}
return null;
}
public boolean isValid() {
return findLabel("invalid") == null;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment