Skip to content

Commit 140b880

Browse files
committed
Markdown added as target language.
* New scala-lang.org site uses jekyll. So it's needed to create markdown release notes. * You still have the option of generating html file by default unless you explicitly mention that you would need markdown file.
1 parent a5396e5 commit 140b880

File tree

5 files changed

+137
-65
lines changed

5 files changed

+137
-65
lines changed

README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,17 @@ For now, it's still mostly manual. What you need to do:
1010

1111
1. Fill in community project list from emails. See the `community-projects.txt` file for the format and how to copy-paste into it.
1212
2. Update the highlights notes in `hand-written.md`.
13-
3. run `sbt -Dfile.encoding=UTF-8 console`, and then the following:
13+
3. run `sbt -Dfile.encoding=UTF-8 console`, and then the following if you want .html output:
1414

1515
scala> MakeReleaseNotes(new java.io.File("~/git/scala"), "v2.9.2", "v2.9.3")
16+
17+
and the following if you want .md as output:
18+
19+
scala> MakeReleaseNotes(new java.io.File("~/git/scala"), "v2.9.2", "v2.9.3")(MarkDown)
1620

1721
where the two strings are the tags to compare.
1822

1923

2024
## Contributing
2125

22-
Feel free to improve. Make sure to sign the Scala CLA.
26+
Feel free to improve. Make sure to sign the Scala CLA.

release-notes.html

Lines changed: 7 additions & 9 deletions
Large diffs are not rendered by default.

src/main/scala/GitInfo.scala

Lines changed: 29 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3,103 +3,93 @@ case class Commit(sha: String, author: String, header: String, body: String) {
33
override def toString = " * " + sha + " (" + author + ") " + header + " - " + body.take(5) + " ..."
44
}
55

6-
76
/** Gobal functions for dealing with git. */
87
object GitHelper {
98
def processGitCommits(gitDir: java.io.File, previousTag: String, currentTag: String): IndexedSeq[Commit] = {
109
import sys.process._
1110
val gitFormat = "%h %s" // sha and subject
12-
val log = Process(Seq("git", "--no-pager", "log", s"${previousTag}..${currentTag}","--format=format:"+gitFormat,"--no-merges", "--topo-order"), gitDir).lines
11+
val log = Process(Seq("git", "--no-pager", "log", s"${previousTag}..${currentTag}", "--format=format:" + gitFormat, "--no-merges", "--topo-order"), gitDir).lines
1312

1413
log.par.map(_.split(" ", 2)).collect {
1514
case Array(sha, title) =>
16-
val (author :: body) = Process(Seq("git", "--no-pager", "show", sha ,"--format=format:%aN%n%b","--quiet"), gitDir).lines.toList
15+
val (author :: body) = Process(Seq("git", "--no-pager", "show", sha, "--format=format:%aN%n%b", "--quiet"), gitDir).lines.toList
1716
Commit(sha, author, title, body.mkString("\n"))
1817
}.toVector
1918
}
2019

2120
def hasFixins(msg: String): Boolean = (
2221
(msg contains "SI-") /*&& ((msg.toLowerCase contains "fix") || (msg.toLowerCase contains "close"))*/
2322
)
24-
23+
2524
val siPattern = java.util.regex.Pattern.compile("(SI-[0-9]+)")
2625

27-
def fixLinks(commit: Commit): String = {
26+
def fixLinks(commit: Commit)(implicit targetLanguage: TargetLanguage): String = {
2827
val searchString = commit.body + commit.header
2928
val m = siPattern matcher searchString
3029
val issues = new collection.mutable.ArrayBuffer[String]
31-
while(m.find()) {
30+
while (m.find()) {
3231
issues += (m group 1)
3332
}
34-
issues map (si => """<a href="https://issues.scala-lang.org/browse/%s">%s</a>""" format (si, si)) mkString ", "
33+
issues map (si => targetLanguage.createHyperLink(s"https://issues.scala-lang.org/browse/$si", si)) mkString ", "
3534
}
3635

3736
def htmlEncode(s: String) = org.apache.commons.lang3.StringEscapeUtils.escapeHtml4(s)
3837
}
3938

40-
class GitInfo(gitDir: java.io.File, val previousTag: String, val currentTag: String) {
39+
class GitInfo(gitDir: java.io.File, val previousTag: String, val currentTag: String)(implicit targetLanguage: TargetLanguage) {
4140
import GitHelper._
4241
val commits = processGitCommits(gitDir, previousTag, currentTag)
4342

4443
val authors: Seq[(String, Int)] = {
45-
val grouped: Vector[(String,Int)] = (commits groupBy (_.author)).map { case (a,c) => a -> c.length }{collection.breakOut}
44+
val grouped: Vector[(String, Int)] = (commits groupBy (_.author)).map { case (a, c) => a -> c.length } { collection.breakOut }
4645
(grouped sortBy (_._2)).reverse
4746
}
4847

4948
val fixCommits =
50-
for {
51-
commit <- commits
52-
searchString = commit.body + commit.header
53-
if hasFixins(searchString)
54-
} yield commit
49+
for {
50+
commit <- commits
51+
searchString = commit.body + commit.header
52+
if hasFixins(searchString)
53+
} yield commit
5554

56-
private def commitShaLink(sha: String) =
57-
s"""<a href="https://github.com/scala/scala/commit/${sha}">${sha}</a>"""
55+
private def commitShaLink(sha: String) =
56+
targetLanguage.createHyperLink(s"https://github.com/scala/scala/commit/${sha}", sha)
5857

59-
private def blankLine(): String = "<p>&nbsp;</p>"
60-
private def header4(msg: String): String = s"<h4>$msg</h4>"
58+
private def blankLine(): String = targetLanguage.blankLine()
59+
private def header4(msg: String): String = targetLanguage.header4(msg)
6160

6261
def renderCommitterList: String = {
6362
val sb = new StringBuffer
6463
sb append blankLine()
6564
sb append header4("A big thank you to all the contributors!")
66-
sb append """|<table border="0" cellspacing="0" cellpadding="1">
67-
| <thead><tr><th>#</th><th align="left">Author</th></tr></thead>
68-
|<tbody>""".stripMargin
69-
for((author, count) <- authors)
70-
sb append s"""<tr><td align="right">${count} &nbsp;</td><td>${htmlEncode(author)}</td></tr>"""
71-
sb append """</tbody></table>"""
65+
sb append targetLanguage.tableHeader("#", "Author")
66+
for ((author, count) <- authors)
67+
sb append targetLanguage.tableRow(count.toString, author)
68+
sb append targetLanguage.tableEnd
7269
sb.toString
7370
}
7471

7572
def renderCommitList: String = {
7673
val sb = new StringBuffer
7774
sb append blankLine()
7875
sb append header4("Complete commit list!")
79-
sb append """<table border="0" cellspacing="0" cellpadding="1">
80-
<thead><tr><th>sha</th><th align="left">Title</th></tr></thead>
81-
<tbody>"""
82-
for(commit <- commits)
83-
sb append s"""<tr><td align="right">${commitShaLink(commit.sha)}&nbsp;</td><td>${htmlEncode(commit.header)}</td></tr>"""
84-
sb append """</tbody>
85-
</table>"""
76+
sb append targetLanguage.tableHeader("sha", "Title")
77+
for (commit <- commits)
78+
sb append targetLanguage.tableRow(commitShaLink(commit.sha), commit.header)
79+
sb append targetLanguage.tableEnd
8680
sb.toString
8781
}
8882

8983
def renderFixedIssues: String = {
9084
val sb = new StringBuffer
9185
sb append blankLine()
9286
sb append header4(s"Commits and the issues they fixed since ${previousTag}")
93-
sb append ("""<table border="0" cellspacing="0" cellpading="1">
94-
<thead><tr><th>Issue(s)</th><th>Commit</th><th>Message</th></tr></thead>
95-
<tbody>""")
96-
for(commit <- fixCommits)
97-
sb append s"""<tr><td>${fixLinks(commit)}&nbsp;</td><td>${commitShaLink(commit.sha)}&nbsp;</td><td>${htmlEncode(commit.header)}</td></tr>"""
98-
sb append """</tbody>
99-
</table>"""
87+
sb append targetLanguage.tableHeader("Issue(s)", "Commit", "Message")
88+
for (commit <- fixCommits)
89+
sb append targetLanguage.tableRow(fixLinks(commit), commitShaLink(commit.sha), commit.header)
90+
sb append targetLanguage.tableEnd
10091
sb append blankLine()
10192
sb.toString
10293
}
10394

104-
10595
}

src/main/scala/MakeReleaseNotes.scala

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,56 @@
11

22

33
import java.io.BufferedReader
4+
import scala.io.Source
45
object MakeReleaseNotes {
5-
6-
7-
def apply(scalaDir: java.io.File, previousTag: String, currentTag: String): Unit = {
8-
val out = new java.io.File("release-notes.html")
6+
7+
def apply(scalaDir: java.io.File, previousTag: String, currentTag: String)(implicit targetLanguage: TargetLanguage = Html): Unit = {
8+
val out = targetLanguage match {
9+
case Html => new java.io.File("release-notes.html")
10+
case MarkDown => new java.io.File(s"release-notes-${currentTag}.md")
11+
}
912
val buf = new java.io.BufferedWriter(new java.io.FileWriter(out))
1013
try buf.write(makeReleaseNotes(scalaDir, previousTag, currentTag))
1114
finally buf.close()
1215
}
13-
14-
15-
16+
1617
def parseHandWrittenNotes(file: java.io.File = new java.io.File("hand-written.md")): String = {
1718
import org.pegdown._
1819
val parser = new PegDownProcessor
19-
20+
2021
val in = new java.io.BufferedReader(new java.io.FileReader(file))
21-
def read(buf: StringBuffer): String =
22+
def read(buf: StringBuffer): String =
2223
in.readLine match {
2324
case null => buf.toString
24-
case line =>
25+
case line =>
2526
buf append s"${line}\n"
2627
read(buf)
2728
}
2829
val content =
2930
try read(new StringBuffer)
3031
finally in.close()
31-
32+
3233
parser markdownToHtml content
3334
}
34-
35-
def makeReleaseNotes(scalaDir: java.io.File, previousTag: String, currentTag: String): String = {
35+
36+
def makeReleaseNotes(scalaDir: java.io.File, previousTag: String, currentTag: String)(implicit targetLanguage: TargetLanguage): String = {
37+
def rawHandWrittenNotes(file: java.io.File = new java.io.File(s"history/hand-written-${currentTag drop 1}.md")): String = {
38+
val src = Source.fromFile(file)
39+
val lines = src.getLines
40+
// if you don't have the next line, sub-bullets would be screwed!
41+
// please take this case into account and comment out 2 next lines and uncomment the line after!
42+
val newLines = lines.map(x => if (x.startsWith(" *")) "\n" + x else x)
43+
newLines.mkString("\n")
44+
// lines.mkString("\n")
45+
}
3646
val info = new GitInfo(scalaDir, previousTag, currentTag)
3747
// val communityProjects = CommunityProjects.loadHtmlFromFile()
38-
import info.{currentTag => _, _}
48+
import info.{ currentTag => _, _ }
3949
// <h3> Known issues </h3>
4050
// ${JiraIssues.makeOpenIssuesString}
4151

42-
s"""<html>
52+
targetLanguage match {
53+
case Html => s"""<html>
4354
<head>
4455
<meta charset="UTF-8">
4556
<title>${currentTag} - Release notes</title>
@@ -53,5 +64,18 @@ object MakeReleaseNotes {
5364
${renderCommitList}
5465
</body>
5566
</html>"""
67+
case MarkDown => s"""---
68+
layout: news
69+
post-type: announcement
70+
title: "Scala ${currentTag drop 1} is now available!"
71+
---
72+
${rawHandWrittenNotes()}
73+
74+
${renderCommitterList}
75+
${renderFixedIssues}
76+
${renderCommitList}
77+
"""
78+
}
79+
5680
}
5781
}

src/main/scala/TargetLanguage.scala

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
sealed trait TargetLanguage {
2+
def createHyperLink(link: String, content: String): String
3+
def blankLine(): String
4+
def header4(msg: String): String
5+
def tableHeader(firstColumn: String, secondColumn: String): String
6+
def tableRow(firstColumn: String, secondColumn: String): String
7+
def tableHeader(firstColumn: String, secondColumn: String, thirdColumn: String): String
8+
def tableRow(firstColumn: String, secondColumn: String, thirdColumn: String): String
9+
def tableEnd: String
10+
}
11+
case object MarkDown extends TargetLanguage {
12+
def createHyperLink(link: String, content: String): String =
13+
s"[$link]($content)"
14+
def blankLine(): String = "\n"
15+
def header4(msg: String): String = s"#### $msg\n"
16+
def tableHeader(firstColumn: String, secondColumn: String): String =
17+
s"""
18+
${markdownEncode(firstColumn)} | $secondColumn
19+
---: | ---
20+
"""
21+
def tableRow(firstColumn: String, secondColumn: String): String = s"${firstColumn} | <notextile>${escapeHtml(secondColumn)}</notextile>\n"
22+
def tableHeader(firstColumn: String, secondColumn: String, thirdColumn: String): String =
23+
s"""
24+
$firstColumn | $secondColumn | $thirdColumn
25+
--- | --- | ---
26+
"""
27+
def tableRow(firstColumn: String, secondColumn: String, thirdColumn: String): String = s"$firstColumn | $secondColumn | <notextile>${escapeHtml(thirdColumn)}</notextile>\n"
28+
def tableEnd: String = "\n"
29+
30+
def markdownEncode(s: String): String = s.flatMap {
31+
case c if (List('*', '`', '[', ']', '#').contains(c)) => "\\" + c
32+
case x => x.toString
33+
}
34+
35+
def escapeHtml(s: String): String = Html.htmlEncode(s).flatMap {
36+
case '|' => "&#124;" // it would destroy tables!
37+
case c => c.toString
38+
}
39+
}
40+
case object Html extends TargetLanguage {
41+
def createHyperLink(link: String, content: String): String =
42+
s"""<a href="$link">$content</a>"""
43+
def blankLine(): String = "<p>&nbsp;</p>"
44+
def header4(msg: String): String = s"<h4>$msg</h4>"
45+
def tableHeader(firstColumn: String, secondColumn: String): String = s"""|<table border="0" cellspacing="0" cellpadding="1">
46+
| <thead><tr><th>$firstColumn</th><th align="left">$secondColumn</th></tr></thead>
47+
|<tbody>""".stripMargin
48+
def tableRow(firstColumn: String, secondColumn: String): String = s"""<tr><td align="right">${firstColumn} &nbsp;</td><td>${htmlEncode(secondColumn)}</td></tr>"""
49+
def tableHeader(firstColumn: String, secondColumn: String, thirdColumn: String): String = s"""<table border="0" cellspacing="0" cellpading="1">
50+
<thead><tr><th>$firstColumn</th><th>$secondColumn</th><th>$thirdColumn</th></tr></thead>
51+
<tbody>"""
52+
def tableRow(firstColumn: String, secondColumn: String, thirdColumn: String): String = s"""<tr><td>${firstColumn}&nbsp;</td><td>${secondColumn}&nbsp;</td><td>${htmlEncode(thirdColumn)}</td></tr>"""
53+
def tableEnd: String = "</tbody></table>"
54+
55+
def htmlEncode(s: String) = org.apache.commons.lang3.StringEscapeUtils.escapeHtml4(s)
56+
}

0 commit comments

Comments
 (0)