Skip to content

Commit 97f630e

Browse files
committed
Merge pull request #12 from rtyley/set-subject-prefix
Allow setting a custom subject prefix on patch emails
2 parents 16c2e78 + c7e5647 commit 97f630e

8 files changed

Lines changed: 109 additions & 32 deletions

File tree

app/controllers/Application.scala

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,13 @@ import lib.model.{PatchBomb, PatchCommit, Patch}
1414
import org.eclipse.jgit.lib.ObjectId
1515
import org.kohsuke.github._
1616
import play.api.Logger
17+
import play.api.data.Form
18+
import play.api.data.Forms._
1719
import play.api.libs.json.Json
20+
import play.api.libs.json.Json._
1821
import play.api.mvc._
1922
import views.html.pullRequestSent
23+
import play.api.i18n.Messages.Implicits._
2024

2125
import scala.collection.convert.wrapAll._
2226
import scala.concurrent.ExecutionContext.Implicits.global
@@ -25,6 +29,8 @@ import scala.util.Try
2529

2630
object Application extends Controller {
2731

32+
import play.api.Play.current
33+
2834
def index = Action { implicit req =>
2935
Ok(views.html.index())
3036
}
@@ -41,6 +47,13 @@ object Application extends Controller {
4147
def reviewPullRequest(prId: PullRequestId) = githubPRAction(prId).async { implicit req =>
4248
val myself = req.gitHub.getMyself
4349

50+
val settings = (for {
51+
data <- req.session.get(prId.slug)
52+
s <- Json.parse(data).validate[PRMailSettings].asOpt
53+
} yield s).getOrElse(PRMailSettings("PATCH"))
54+
55+
req.session.get(prId.slug).map(Json.parse).map(fromJson[PRMailSettings](_).asOpt)
56+
implicit val form = mailSettingsForm.fill(settings)
4457
for (proposedMailByType <- proposedMailByTypeFor(req)) yield {
4558
Ok(views.html.reviewPullRequest(req.pr, myself, proposedMailByType))
4659
}
@@ -70,22 +83,30 @@ object Application extends Controller {
7083
}
7184
}
7285

73-
def mailPullRequest(prId: PullRequestId, mailType: MailType) = (githubPRAction(prId) andThen mailChecks(mailType)).async {
86+
val mailSettingsForm = Form(
87+
mapping(
88+
"subjectPrefix" -> default(text(maxLength = 20), "PATCH")
89+
)(PRMailSettings.apply)(PRMailSettings.unapply)
90+
)
91+
92+
def mailPullRequest(prId: PullRequestId, mailType: MailType) = (githubPRAction(prId) andThen mailChecks(mailType)).async(parse.form(mailSettingsForm)) {
7493
implicit req =>
7594
val mailingList = Project.byRepoId(req.repo.id).mailingList
7695

7796
val addresses = mailType.addressing(mailingList, req.user)
7897

98+
val settings = req.body
99+
79100
for (patchCommits <- req.patchCommitsF) yield {
80-
val patchBomb = PatchBomb(patchCommits, addresses, "PATCH", mailType.subjectPrefix, mailType.footer(req.pr))
101+
val patchBomb = PatchBomb(patchCommits, addresses, settings.subjectPrefix, mailType.subjectPrefix, mailType.footer(req.pr))
81102
for (initialMessageId <- ses.send(patchBomb.emails.head)) {
82103
for (email <- patchBomb.emails.drop(1)) {
83104
ses.send(email.inReplyTo(initialMessageId))
84105
}
85106

86107
mailType.afterSending(req.pr, initialMessageId)
87108
}
88-
Ok(pullRequestSent(req.pr, req.user, mailType))
109+
Ok(pullRequestSent(req.pr, req.user, mailType)).addingToSession(prId.slug -> Json.toJson(settings).toString)
89110
}
90111
}
91112

app/lib/PRMailSettings.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package lib
2+
3+
import play.api.libs.json.Json
4+
5+
case class PRMailSettings(subjectPrefix: String)
6+
7+
object PRMailSettings {
8+
implicit val formats = Json.format[PRMailSettings]
9+
}
10+
Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,17 @@
11
@(addresses: lib.Email.Addresses)
2-
<dl class="dl-horizontal">
3-
<dt>From:</dt><dd>@addresses.from</dd>
4-
@if(addresses.to.nonEmpty){<dt>To:</dt><dd>@addresses.to.mkString(", ")</dd>}
5-
@if(addresses.cc.nonEmpty){<dt>Cc:</dt><dd>@addresses.cc.mkString(", ")</dd>}
6-
@if(addresses.bcc.nonEmpty){<dt>Bcc:</dt><dd>@addresses.bcc.mkString(", ")</dd>}
7-
@for(replyTo <- addresses.replyTo) {<dt>Reply-To:</dt><dd>@replyTo</dd>}
8-
</dl>
2+
@display(label: String, ids: Seq[String]) = {
3+
@if(ids.nonEmpty) {
4+
<label class="col-sm-4 control-label">@label</label>
5+
<div class="col-sm-8">
6+
<p class="form-control-static">@ids.mkString(", ")</p>
7+
</div>
8+
}
9+
}
10+
11+
<div class="form-group">
12+
@display("From", Seq(addresses.from))
13+
@display("To", addresses.to)
14+
@display("Cc", addresses.cc)
15+
@display("Bcc", addresses.bcc)
16+
@display("Reply-To", addresses.replyTo.toSeq)
17+
</div>
Lines changed: 34 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,40 @@
1-
@(mailType: lib.MailType, proposedMail: lib.ProposedMail, isDefault: Boolean, btnClass: String)(implicit req: GHPRRequest[_])
1+
@(mailType: lib.MailType, proposedMail: lib.ProposedMail, isDefault: Boolean, btnClass: String
2+
)(implicit req: GHPRRequest[_], prMailSettings: Form[lib.PRMailSettings], messages: Messages)
23
@import helper._
3-
4+
@implicitFieldConstructor = @{ b3.horizontal.fieldConstructor("col-md-4", "col-md-8") }
45

56
<div role="tabpanel" class="tab-pane @if(isDefault) { fade in active }" id="mail-@mailType.slug">
6-
@fragments.emailAddresses(proposedMail.addresses)
7-
@if(proposedMail.errors.nonEmpty) {
8-
<div class="alert alert-warning" role="alert">
9-
<ul>
10-
@for(error <- proposedMail.errors) {
11-
<li>@error</li>
12-
}
13-
</ul>
14-
</div>
15-
}
16-
17-
@form(routes.Application.mailPullRequest(req.pr.id, mailType)) {
7+
@b3.form(routes.Application.mailPullRequest(req.pr.id, mailType)) {
188
@CSRF.formField
19-
<button
20-
class="btn @btnClass btn-lg"
21-
value="send"
22-
@if(proposedMail.errors.nonEmpty) { disabled="disabled" }
23-
>Send</button>
9+
10+
@if(proposedMail.errors.nonEmpty) {
11+
<div class="alert alert-warning" role="alert">
12+
<ul>
13+
@for(error <- proposedMail.errors) {
14+
<li>@error</li>
15+
}
16+
</ul>
17+
</div>
18+
}
19+
20+
@fragments.emailAddresses(proposedMail.addresses)
21+
22+
@b3.inputWrapped("text", prMailSettings("subjectPrefix"), '_label -> "Subject prefix", 'placeholder -> "PATCH", 'maxlength -> "20") { input =>
23+
<div class="input-group">
24+
<span class="input-group-addon">[</span>
25+
@input
26+
<span class="input-group-addon">]</span>
27+
</div>
28+
}
29+
30+
<div class="form-group">
31+
<div class="col-sm-offset-4 col-sm-8">
32+
<button
33+
class="btn @btnClass btn-lg"
34+
value="send"
35+
@if(proposedMail.errors.nonEmpty) { disabled="disabled" }
36+
>Send</button>
37+
</div>
38+
</div>
2439
}
2540
</div>

app/views/fragments/sendTabs.scala.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
@(defaultMailTab: lib.MailType, proposedMailByType: Map[lib.MailType,lib.ProposedMail])(implicit req: GHPRRequest[_])
1+
@(defaultMailTab: lib.MailType, proposedMailByType: Map[lib.MailType,lib.ProposedMail]
2+
)(implicit req: GHPRRequest[_], prMailSettings: Form[lib.PRMailSettings], messages: Messages)
23
@import lib.MailType
34
@import MailType.{Live, Preview}
45

app/views/reviewPullRequest.scala.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
@(pullRequest: org.kohsuke.github.GHPullRequest, user: org.kohsuke.github.GHMyself, proposedMailByType: Map[lib.MailType,lib.ProposedMail])(implicit req: GHPRRequest[_])
1+
@(pullRequest: org.kohsuke.github.GHPullRequest, user: org.kohsuke.github.GHMyself, proposedMailByType: Map[lib.MailType,lib.ProposedMail]
2+
)(implicit req: GHPRRequest[_], prMailSettings: Form[lib.PRMailSettings], messages: Messages)
23
@main {
34
<div class="row">
45
<ol class="breadcrumb">

build.sbt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,18 @@ TwirlKeys.templateImports ++= Seq(
2626

2727
routesImport ++= Seq("lib._","com.madgag.github._","controllers.Binders._","org.eclipse.jgit.lib.ObjectId")
2828

29-
resolvers += Resolver.sonatypeRepo("releases")
29+
resolvers ++= Seq(
30+
Resolver.sonatypeRepo("releases"),
31+
Resolver.sonatypeRepo("snapshots")
32+
)
3033

3134
libraryDependencies ++= Seq(
3235
cache,
3336
filters,
3437
"com.madgag" %% "play-git-hub" % "1.1",
3538
"com.typesafe.akka" %% "akka-agent" % "2.3.2",
3639
"org.webjars" % "bootstrap" % "3.3.4",
40+
"com.adrianhurt" %% "play-bootstrap3" % "0.4.4-P24-SNAPSHOT",
3741
"org.webjars.bower" % "octicons" % "2.2.3",
3842
"com.lihaoyi" %% "fastparse" % "0.1.7",
3943
"com.github.nscala-time" %% "nscala-time" % "2.0.0",

notes.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,19 @@
1+
In http://git-scm.com/docs/git-format-patch :
2+
3+
--subject-prefix=<Subject-Prefix>
4+
Instead of the standard [PATCH] prefix in the subject line, instead use [<Subject-Prefix>]. This allows for useful naming of a patch series, and can be combined with the --numbered option.
5+
6+
[PATCH v2 ...]
7+
[RFC/PATCH ...]
8+
[WIP/PATCH v4 6/8]
9+
[PATCH]
10+
[RFC/WIP PATCH 06/11]
11+
[PATCH/WIP 4/8]
12+
13+
Matthieu Moy said: I found no way to specify a version like [PATCH v2 ...]. Similarly, there could be a way to say [RFC/PATCH ...].
14+
15+
16+
117
Potential features TODO:
218

319
* When closing a PR 'cos it's been posted, link to http://mid.gmane.org/1234567890.1234567890@example.com so we can see the discussion.

0 commit comments

Comments
 (0)