Skip to content

Commit

Permalink
pushes notes
Browse files Browse the repository at this point in the history
  • Loading branch information
kolov committed Jul 11, 2017
1 parent c2b26bd commit dbc2e1e
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 34 deletions.
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@ This plugin is under development, the functionality is very basic but usable. In

addSbtPlugin("com.akolov" % "sbt-pantarhei" % "0.1.0")

This makes two sbt tasks available: `printNotesForLatest` and `printNotesAfterLatest`:
This makes the following sbt tasks available:


| Command | Description |
| --------------------------|-------------|
| `printNotesForLatest` | Prints release notes usable for the latest remote tag - that is, form all pull requests _after_ the _previous_ tag, if any, and _before_ the _last_ tag |
| `printNotesAfterLatest` | Prints release notes from the pull requests _after_ the _latest_ tag. These notes will be usable for the _next tag_ |
| `printNotesForLatestTag` | Prints release notes usable for the latest remote tag - that is, form all pull requests _after_ the _previous_ tag, if any, and _before_ the _last_ tag |
| `pushNotesForLatestTag` | Creates or updates release notes for the latest remote tag. |
| `printNotesForNextTag` | Prints release notes from the pull requests _after_ the _latest_ tag. These notes will be usable for the _next tag_ |


The output is in markdown, ready to be copy/pasted as github release notes. Example:
Expand Down
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ addSbtPlugin("io.spray" % "sbt-revolver" % "0.8.0")
addSbtPlugin("com.typesafe.sbt" % "sbt-git" % "0.9.3")

scalacOptions := Seq("-deprecation", "-unchecked")
credentials += Credentials(Path.userHome / ".github" / "token")
credentials += Credentials(Path.userHome / ".github" / "credentials")
resolvers += "Maven.org" at "http://repo1.maven.org/maven2"
pomIncludeRepository := { _ => false }
publishMavenStyle := true
Expand Down
6 changes: 3 additions & 3 deletions src/it/scala/GithubIT.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import java.io.File

import com.akolov.pantarhei.{FutureCommit, Github, NotesMaker}
import com.akolov.pantarhei._
import org.scalatest.WordSpecLike

import scala.io.Source
Expand All @@ -9,7 +9,7 @@ class GithubIT extends WordSpecLike {


val PW = "password="
val token = Source.fromFile(s"/Users/assen/.github/token")
val token = Source.fromFile(s"/Users/assen/.github/credentials")
.getLines()
.toList
.find {
Expand All @@ -23,7 +23,7 @@ class GithubIT extends WordSpecLike {

"The Notes Plugin" should {
"make RN" in {
new NotesMaker(new File("/Users/assen/projects/sbt-pantarhei"), token).makeNotes(FutureCommit)
new NotesMaker(new File("/Users/assen/projects/sbt-pantarhei"), token).makeNotes(LatestComit, PushNotes)
}
}
"The class Github" should {
Expand Down
23 changes: 18 additions & 5 deletions src/main/scala/Domain.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,21 @@ case class PullRequest(title: String, htmlUrl: String, number: Int, createdAt: S

case class Commit(sha: String, url: String)

case class CommitInfo(message: String, author: CommitPerson)
case class CommitInfo( message: String, author: CommitPerson)

case class CommitPerson(name: String, email: String, date: String)

case class CommitRecord(htmlUrl: String, commit: CommitInfo)
case class CommitRecord(sha: String, htmlUrl: String, commit: CommitInfo)

case class Release(tagName: String, body: String)
case class ReleaseRequest(tagName: String, name: String, body: String)

case class ReleaseResponse(id: Int, tagName: String, name: String, body: String)

case class Tag(tagName: String, commit: Commit)

case class CommitterInfo(name: String, email: String, date: String)


object MyJsonProtocol extends DefaultJsonProtocol {

implicit val pullRequestFormat: RootJsonFormat[PullRequest] = jsonFormat(
Expand Down Expand Up @@ -47,12 +50,22 @@ object MyJsonProtocol extends DefaultJsonProtocol {

implicit val commitRecordFormat: RootJsonFormat[CommitRecord] = jsonFormat(
CommitRecord,
"sha",
"html_url",
"commit")

implicit val releaseFormat: RootJsonFormat[Release] = jsonFormat(
Release,
implicit val releaseRequestFormat: RootJsonFormat[ReleaseRequest] = jsonFormat(
ReleaseRequest,
"tag_name",
"name",
"body"
)

implicit val releaseResponseFormat: RootJsonFormat[ReleaseResponse] = jsonFormat(
ReleaseResponse,
"id",
"tag_name",
"name",
"body"
)
implicit val tagFormat: RootJsonFormat[Tag] = jsonFormat(
Expand Down
28 changes: 24 additions & 4 deletions src/main/scala/Github.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import scalaj.http._

class Github(remoteUrl: String, val token: String) {


val (host, owner, repository) = Github.parseUrl(remoteUrl)
val apiUrl = s"https://api.github.com/repos/$owner/$repository"
val home = System.getProperty("user.home")
Expand All @@ -16,7 +15,7 @@ class Github(remoteUrl: String, val token: String) {
val response: HttpResponse[String] = Http(s"$apiUrl/pulls")
.param("state", "all")
.params(since match {
case None => Map[String,String]()
case None => Map[String, String]()
case Some(date) => Map("since" -> date)
})
.header("Accept", "application/vnd.github.v3+json")
Expand All @@ -37,7 +36,7 @@ class Github(remoteUrl: String, val token: String) {
.elements.map(e => commitRecordFormat.read(e))
}

def getLatestRelease(): Option[Release] = {
def getLatestRelease(): Option[ReleaseResponse] = {
val response: HttpResponse[String] = Http(s"$apiUrl/releases/latest")
.header("Accept", "application/vnd.github.v3+json")
.header("Authorization", s"token $token")
Expand All @@ -46,7 +45,7 @@ class Github(remoteUrl: String, val token: String) {
if (response.code == 404)
return None
else if (response.code == 200)
return Some(response.body.parseJson.convertTo[Release])
return Some(response.body.parseJson.convertTo[ReleaseResponse])
else throw new Exception(s"Error: $response.body")
}

Expand All @@ -69,6 +68,27 @@ class Github(remoteUrl: String, val token: String) {
response.body.parseJson.convertTo[CommitRecord]
}

def pushReleaseNotes(tag: Tag, body: String) = {
val response: HttpResponse[String] = Http(s"$apiUrl/releases")
.postData(releaseRequestFormat.write(ReleaseRequest(tag.tagName, "release name", body)).toString)
.header("Accept", "application/vnd.github.v3+json")
.header("Authorization", s"token $token")
.asString

response.body.parseJson.convertTo[ReleaseResponse]
}

def editReleaseNotes(release: ReleaseResponse, body: String) = {
val response: HttpResponse[String] = Http(s"$apiUrl/releases/${release.id}")
.postData(releaseRequestFormat.write(ReleaseRequest(release.tagName, "release name", body)).toString)
.method("PATCH")
.header("Accept", "application/vnd.github.v3+json")
.header("Authorization", s"token $token")
.asString

response.body.parseJson.convertTo[ReleaseResponse]
}


}

Expand Down
65 changes: 47 additions & 18 deletions src/main/scala/NotesMaker.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,33 @@ import sbt._

object NotesMaker extends sbt.AutoPlugin {

lazy val printNotesAfterLatest = taskKey[Unit]("Create release notes af pull requests after the latest tag")
lazy val printNotesForLatest = taskKey[Unit]("Create release notes af pull requests for the latest tag")
lazy val printNotesForNextTag = taskKey[Unit]("Create and print release notes af pull requests after the latest tag")
lazy val printNotesForLatestTag = taskKey[Unit]("Create and print release notes af pull requests for the latest tag")
lazy val pushNotesForLatestTag = taskKey[Unit]("Create and push release notes af pull requests for the latest tag")

override def trigger: PluginTrigger = AllRequirements


override def projectSettings = Seq(
printNotesAfterLatest := {
printNotesForNextTag := {
val baseDirectory = Keys.baseDirectory.value
val credentials = Keys.credentials.value
processNotes(baseDirectory, credentials, FutureCommit)
processNotes(baseDirectory, credentials, FutureCommit, PrintNotes)
},
printNotesForLatest := {
printNotesForLatestTag := {
val baseDirectory = Keys.baseDirectory.value
val credentials = Keys.credentials.value
processNotes(baseDirectory, credentials, LatestComit)
processNotes(baseDirectory, credentials, LatestComit, PrintNotes)
},
pushNotesForLatestTag := {
val baseDirectory = Keys.baseDirectory.value
val credentials = Keys.credentials.value
processNotes(baseDirectory, credentials, LatestComit, PushNotes)
}
)

def processNotes(baseDirectory: java.io.File, credentials: Seq[Credentials], target: Target): Unit = {
def processNotes(baseDirectory: java.io.File, credentials: Seq[Credentials],
target: Target, action: Action): Unit = {
val githubCredentials = credentials.map(Credentials.toDirect).find(c => c.realm.toLowerCase == "github")
.orElse(
Credentials.loadCredentials(new File(System.getProperty("user.home") + "/.github/credentials")) match {
Expand All @@ -39,7 +46,8 @@ object NotesMaker extends sbt.AutoPlugin {
return ()
}

new NotesMaker(baseDirectory, githubCredentials.get.passwd).makeNotes(target)
new NotesMaker(baseDirectory, githubCredentials.get.passwd)
.makeNotes(target, action)
}
}

Expand All @@ -59,7 +67,7 @@ class NotesMaker(baseDir: java.io.File, token: String) {
def this(lowerBound: Option[Tag], upperBound: Option[Tag]) = this(lowerBound, upperBound, None)
}

def makeNotes(target: Target): Unit = {
def makeNotes(target: Target, action: Action): Unit = {
val tags = github.tags

val parameters = target match {
Expand All @@ -84,7 +92,7 @@ class NotesMaker(baseDir: java.io.File, token: String) {
return ()
}
case Parameters(lower, upper, _) => {
printNotes(lower, upper)
printNotes(lower, upper, action)
}
}
}
Expand All @@ -93,7 +101,7 @@ class NotesMaker(baseDir: java.io.File, token: String) {

def dateStrToTicks(dateStr: String) = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").parse(dateStr).getTime()

def printNotes(lowerBound: Option[Tag], upperBound: Option[Tag]): Unit = {
def printNotes(lowerBound: Option[Tag], upperBound: Option[Tag], action: Action): Unit = {
(lowerBound, upperBound) match {
case (Some(l), Some(u)) => println(s"Preparing release notes from pull requests between tags ${l.tagName} and ${u.tagName}\n")
case (None, Some(u)) => println(s"Preparing release notes from pull requests before tag ${u.tagName}\n")
Expand All @@ -116,22 +124,43 @@ class NotesMaker(baseDir: java.io.File, token: String) {
println("No pull requests were found since last tag")
}

pullRequests.foreach { pr =>
println(s"[PR #${pr.number}](${pr.htmlUrl}) ${pr.title}")
val body = pullRequests.foldLeft("") { (txt, pr) =>
val commits = github.getPRCommits(pr.number)
commits.foreach { record =>
println(s"* [${record.commit.message}](${record.htmlUrl})")
}
println
txt + s"[PR #${pr.number}](${pr.htmlUrl}) ${pr.title}\n" +
commits.foldLeft("") { (txt, record) =>
txt + s"* ${record.commit.message} _[${record.sha.substring(0, 7)}](${record.htmlUrl})_\n"
} + "\n"
}

println(body)

if (action == PushNotes) {
github.getLatestRelease().find(_.tagName == upperBound.get.tagName) match {
case Some(release) => {
println(s"Patching release ${release.id} for tag ${upperBound.get.tagName}")
github.editReleaseNotes(release, body)
}
case None => {
println(s"Ceealting release for tag ${upperBound.get.tagName}")
github.pushReleaseNotes(upperBound.get, body)
}
}
}

}
}

class Target
sealed trait Target

case object LatestComit extends Target

case object FutureCommit extends Target

sealed trait Action

case object PushNotes extends Action

case object PrintNotes extends Action



0 comments on commit dbc2e1e

Please sign in to comment.