diff --git a/src/main/scala/gitbucket/core/controller/WikiController.scala b/src/main/scala/gitbucket/core/controller/WikiController.scala
index 49cc97d..b32deb0 100644
--- a/src/main/scala/gitbucket/core/controller/WikiController.scala
+++ b/src/main/scala/gitbucket/core/controller/WikiController.scala
@@ -1,8 +1,10 @@
package gitbucket.core.controller
+import gitbucket.core.model.{WebHook, WebHookEvent}
import gitbucket.core.service.RepositoryService.RepositoryInfo
+import gitbucket.core.service.WebHookService.WebHookGollumPayload
import gitbucket.core.wiki.html
-import gitbucket.core.service.{AccountService, ActivityService, RepositoryService, WikiService}
+import gitbucket.core.service._
import gitbucket.core.util._
import gitbucket.core.util.StringUtil._
import gitbucket.core.util.SyntaxSugars._
@@ -13,11 +15,12 @@
import org.scalatra.i18n.Messages
class WikiController extends WikiControllerBase
- with WikiService with RepositoryService with AccountService with ActivityService
+ with WikiService with RepositoryService with AccountService with ActivityService with WebHookService
with ReadableUsersAuthenticator with ReferrerAuthenticator
trait WikiControllerBase extends ControllerBase {
- self: WikiService with RepositoryService with ActivityService with ReadableUsersAuthenticator with ReferrerAuthenticator =>
+ self: WikiService with RepositoryService with AccountService with ActivityService with WebHookService
+ with ReadableUsersAuthenticator with ReferrerAuthenticator =>
case class WikiPageEditForm(pageName: String, content: String, message: Option[String], currentPageName: String, id: String)
@@ -136,6 +139,11 @@
).map { commitId =>
updateLastActivityDate(repository.owner, repository.name)
recordEditWikiPageActivity(repository.owner, repository.name, loginAccount.userName, form.pageName, commitId)
+ callWebHookOf(repository.owner, repository.name, WebHook.Gollum){
+ getAccountByUserName(repository.owner).map { repositoryUser =>
+ WebHookGollumPayload("edited", form.pageName, commitId, repository, repositoryUser, loginAccount)
+ }
+ }
}
if(notReservedPageName(form.pageName)) {
redirect(s"/${repository.owner}/${repository.name}/wiki/${StringUtil.urlEncode(form.pageName)}")
@@ -155,11 +163,24 @@
post("/:owner/:repository/wiki/_new", newForm)(readableUsersOnly { (form, repository) =>
if(isEditable(repository)){
defining(context.loginAccount.get){ loginAccount =>
- saveWikiPage(repository.owner, repository.name, form.currentPageName, form.pageName,
- form.content, loginAccount, form.message.getOrElse(""), None)
-
- updateLastActivityDate(repository.owner, repository.name)
- recordCreateWikiPageActivity(repository.owner, repository.name, loginAccount.userName, form.pageName)
+ saveWikiPage(
+ repository.owner,
+ repository.name,
+ form.currentPageName,
+ form.pageName,
+ form.content,
+ loginAccount,
+ form.message.getOrElse(""),
+ None
+ ).map { commitId =>
+ updateLastActivityDate(repository.owner, repository.name)
+ recordCreateWikiPageActivity(repository.owner, repository.name, loginAccount.userName, form.pageName)
+ callWebHookOf(repository.owner, repository.name, WebHook.Gollum){
+ getAccountByUserName(repository.owner).map { repositoryUser =>
+ WebHookGollumPayload("created", form.pageName, commitId, repository, repositoryUser, loginAccount)
+ }
+ }
+ }
if(notReservedPageName(form.pageName)) {
redirect(s"/${repository.owner}/${repository.name}/wiki/${StringUtil.urlEncode(form.pageName)}")
diff --git a/src/main/scala/gitbucket/core/service/WebHookService.scala b/src/main/scala/gitbucket/core/service/WebHookService.scala
index 2f060de..35fe847 100644
--- a/src/main/scala/gitbucket/core/service/WebHookService.scala
+++ b/src/main/scala/gitbucket/core/service/WebHookService.scala
@@ -8,7 +8,7 @@
import gitbucket.core.model.Profile.profile.blockingApi._
import org.apache.http.client.utils.URLEncodedUtils
import gitbucket.core.util.JGitUtil.CommitInfo
-import gitbucket.core.util.RepositoryName
+import gitbucket.core.util.{RepositoryName, StringUtil}
import gitbucket.core.service.RepositoryService.RepositoryInfo
import org.apache.http.NameValuePair
import org.apache.http.client.entity.UrlEncodedFormEntity
@@ -18,7 +18,7 @@
import org.slf4j.LoggerFactory
import scala.concurrent._
-import scala.util.{Success, Failure}
+import scala.util.{Failure, Success}
import org.apache.http.HttpRequest
import org.apache.http.HttpResponse
import gitbucket.core.model.WebHookContentType
@@ -42,7 +42,7 @@
def getWebHooksByEvent(owner: String, repository: String, event: WebHook.Event)(implicit s: Session): List[WebHook] =
WebHooks.filter(_.byRepository(owner, repository))
.join(WebHookEvents).on { (wh, whe) => whe.byWebHook(wh) }
- .filter { case (wh, whe) => whe.event === event.bind}
+ .filter { case (wh, whe) => whe.event === event.bind }
.map{ case (wh, whe) => wh }
.list.distinct
@@ -160,7 +160,7 @@
import WebHookService._
// https://developer.github.com/v3/activity/events/types/#issuesevent
def callIssuesWebHook(action: String, repository: RepositoryService.RepositoryInfo, issue: Issue, baseUrl: String, sender: Account)
- (implicit s: Session, context:JsonFormat.Context): Unit = {
+ (implicit s: Session, context: JsonFormat.Context): Unit = {
callWebHookOf(repository.owner, repository.name, WebHook.Issues){
val users = getAccountsByUserNames(Set(repository.owner, issue.openedUserName), Set(sender))
for{
@@ -178,7 +178,7 @@
}
def callPullRequestWebHook(action: String, repository: RepositoryService.RepositoryInfo, issueId: Int, baseUrl: String, sender: Account)
- (implicit s: Session, context:JsonFormat.Context): Unit = {
+ (implicit s: Session, c: JsonFormat.Context): Unit = {
import WebHookService._
callWebHookOf(repository.owner, repository.name, WebHook.PullRequest){
for{
@@ -224,7 +224,7 @@
}).list.groupBy(_._1).mapValues(_.map(_._2))
def callPullRequestWebHookByRequestBranch(action: String, requestRepository: RepositoryService.RepositoryInfo, requestBranch: String, baseUrl: String, sender: Account)
- (implicit s: Session, context:JsonFormat.Context): Unit = {
+ (implicit s: Session, c: JsonFormat.Context): Unit = {
import WebHookService._
for{
((issue, issueUser, pullRequest, baseOwner, headOwner), webHooks) <- getPullRequestsByRequestForWebhook(requestRepository.owner, requestRepository.name, requestBranch)
@@ -246,12 +246,13 @@
callWebHook(WebHook.PullRequest, webHooks, payload)
}
}
+
}
trait WebHookPullRequestReviewCommentService extends WebHookService {
self: AccountService with RepositoryService with PullRequestService with IssuesService with CommitsService =>
def callPullRequestReviewCommentWebHook(action: String, comment: CommitComment, repository: RepositoryService.RepositoryInfo, issueId: Int, baseUrl: String, sender: Account)
- (implicit s: Session, context:JsonFormat.Context): Unit = {
+ (implicit s: Session, c: JsonFormat.Context): Unit = {
import WebHookService._
callWebHookOf(repository.owner, repository.name, WebHook.PullRequestReviewComment){
for{
@@ -285,7 +286,7 @@
import WebHookService._
def callIssueCommentWebHook(repository: RepositoryService.RepositoryInfo, issue: Issue, issueCommentId: Int, sender: Account)
- (implicit s: Session, context:JsonFormat.Context): Unit = {
+ (implicit s: Session, c: JsonFormat.Context): Unit = {
callWebHookOf(repository.owner, repository.name, WebHook.IssueComment){
for{
issueComment <- getComment(repository.owner, repository.name, issueCommentId.toString())
@@ -470,4 +471,53 @@
sender = senderPayload)
}
}
+
+ // https://developer.github.com/v3/activity/events/types/#gollumevent
+ case class WebHookGollumPayload(
+ pages: Seq[WebHookGollumPagePayload],
+ repository: ApiRepository,
+ sender: ApiUser
+ ) extends WebHookPayload
+
+ case class WebHookGollumPagePayload(
+ page_name: String,
+ title: String,
+ summary: Option[String] = None,
+ action: String, // created or edited
+ sha: String, // SHA of the latest commit
+ html_url: ApiPath
+ )
+
+ object WebHookGollumPayload {
+ def apply(
+ action: String,
+ pageName: String,
+ sha: String,
+ repository: RepositoryInfo,
+ repositoryUser: Account,
+ sender: Account
+ ): WebHookGollumPayload = apply(Seq((action, pageName, sha)), repository, repositoryUser, sender)
+
+ def apply(
+ pages: Seq[(String, String, String)],
+ repository: RepositoryInfo,
+ repositoryUser: Account,
+ sender: Account
+ ): WebHookGollumPayload = {
+ WebHookGollumPayload(
+ pages = pages.map { case (action, pageName, sha) =>
+ WebHookGollumPagePayload(
+ action = action,
+ page_name = pageName,
+ title = pageName,
+ sha = sha,
+ html_url = ApiPath(s"/${RepositoryName(repository).fullName}/wiki/${StringUtil.urlDecode(pageName)}")
+ )
+ },
+ repository = ApiRepository(repository, repositoryUser),
+ sender = ApiUser(sender)
+ )
+ }
+ }
+
}
diff --git a/src/main/scala/gitbucket/core/servlet/GitRepositoryServlet.scala b/src/main/scala/gitbucket/core/servlet/GitRepositoryServlet.scala
index c4ffe41..a6af98b 100644
--- a/src/main/scala/gitbucket/core/servlet/GitRepositoryServlet.scala
+++ b/src/main/scala/gitbucket/core/servlet/GitRepositoryServlet.scala
@@ -1,6 +1,7 @@
package gitbucket.core.servlet
import java.io.File
+import java.util
import java.util.Date
import gitbucket.core.api
@@ -22,6 +23,7 @@
import javax.servlet.ServletConfig
import javax.servlet.http.{HttpServletRequest, HttpServletResponse}
+import org.eclipse.jgit.diff.DiffEntry.ChangeType
import org.json4s.jackson.Serialization._
@@ -161,6 +163,12 @@
receivePack.setPostReceiveHook(hook)
}
}
+
+ if(repository.endsWith(".wiki")){
+ defining(request) { implicit r =>
+ receivePack.setPostReceiveHook(new WikiCommitHook(owner, repository.replaceFirst("\\.wiki$", ""), pusher, baseUrl))
+ }
+ }
}
}
@@ -170,7 +178,7 @@
import scala.collection.JavaConverters._
-class CommitLogHook(owner: String, repository: String, pusher: String, baseUrl: String)/*(implicit session: Session)*/
+class CommitLogHook(owner: String, repository: String, pusher: String, baseUrl: String)
extends PostReceiveHook with PreReceiveHook
with RepositoryService with AccountService with IssuesService with ActivityService with PullRequestService with WebHookService
with WebHookPullRequestService with CommitsService {
@@ -185,9 +193,10 @@
// call pre-commit hook
PluginRegistry().getReceiveHooks
.flatMap(_.preReceive(owner, repository, receivePack, command, pusher))
- .headOption.foreach { error =>
- command.setResult(ReceiveCommand.Result.REJECTED_OTHER_REASON, error)
- }
+ .headOption
+ .foreach { error =>
+ command.setResult(ReceiveCommand.Result.REJECTED_OTHER_REASON, error)
+ }
}
using(Git.open(Directory.getRepositoryDir(owner, repository))) { git =>
existIds = JGitUtil.getAllCommitIds(git)
@@ -285,8 +294,10 @@
// call web hook
callWebHookOf(owner, repository, WebHook.Push) {
- for (pusherAccount <- getAccountByUserName(pusher);
- ownerAccount <- getAccountByUserName(owner)) yield {
+ for {
+ pusherAccount <- getAccountByUserName(pusher)
+ ownerAccount <- getAccountByUserName(owner)
+ } yield {
WebHookPushPayload(git, pusherAccount, command.getRefName, repositoryInfo, newCommits, ownerAccount,
newId = command.getNewId(), oldId = command.getOldId())
}
@@ -309,6 +320,67 @@
}
+class WikiCommitHook(owner: String, repository: String, pusher: String, baseUrl: String)
+ extends PostReceiveHook with WebHookService with AccountService with RepositoryService {
+
+ private val logger = LoggerFactory.getLogger(classOf[WikiCommitHook])
+
+ override def onPostReceive(receivePack: ReceivePack, commands: util.Collection[ReceiveCommand]): Unit = {
+ Database() withTransaction { implicit session =>
+ try {
+ commands.asScala.headOption.foreach { command =>
+ implicit val apiContext = api.JsonFormat.Context(baseUrl)
+ val refName = command.getRefName.split("/")
+ val commitIds = if (refName(1) == "tags") {
+ None
+ } else {
+ command.getType match {
+ case ReceiveCommand.Type.DELETE => None
+ case _ => Some((command.getOldId.getName, command.getNewId.name))
+ }
+ }
+
+ commitIds.map { case (oldCommitId, newCommitId) =>
+ val commits = using(Git.open(Directory.getWikiRepositoryDir(owner, repository))) { git =>
+ JGitUtil.getCommitLog(git, oldCommitId, newCommitId).flatMap { commit =>
+ val diffs = JGitUtil.getDiffs(git, commit.id, false)
+ diffs._1.collect { case diff if diff.newPath.toLowerCase.endsWith(".md") =>
+ val action = if(diff.changeType == ChangeType.ADD) "created" else "edited"
+ val fileName = diff.newPath
+ println(action + " - " + fileName + " - " + commit.id)
+ (action, fileName, commit.id)
+ }
+ }
+ }
+
+ val pages = commits
+ .groupBy { case (action, fileName, commitId) => fileName }
+ .map { case (fileName, commits) =>
+ (commits.head._1, fileName, commits.last._3)
+ }
+
+ callWebHookOf(owner, repository, WebHook.Gollum) {
+ for {
+ pusherAccount <- getAccountByUserName(pusher)
+ repositoryUser <- getAccountByUserName(owner)
+ repositoryInfo <- getRepository(owner, repository)
+ } yield {
+ WebHookGollumPayload(pages.toSeq, repositoryInfo, repositoryUser, pusherAccount)
+ }
+ }
+ }
+ }
+ } catch {
+ case ex: Exception => {
+ logger.error(ex.toString, ex)
+ throw ex
+ }
+ }
+ }
+ }
+
+}
+
object GitLfs {
case class BatchRequest(
diff --git a/src/main/scala/gitbucket/core/util/RepositoryName.scala b/src/main/scala/gitbucket/core/util/RepositoryName.scala
index e7d293d..9f0825b 100644
--- a/src/main/scala/gitbucket/core/util/RepositoryName.scala
+++ b/src/main/scala/gitbucket/core/util/RepositoryName.scala
@@ -1,7 +1,7 @@
package gitbucket.core.util
// TODO Move to gitbucket.core.api package?
-case class RepositoryName(owner:String, name:String){
+case class RepositoryName(owner: String, name: String){
val fullName = s"${owner}/${name}"
}
diff --git a/src/main/twirl/gitbucket/core/settings/edithooks.scala.html b/src/main/twirl/gitbucket/core/settings/edithooks.scala.html
index 812b929..35c4172 100644
--- a/src/main/twirl/gitbucket/core/settings/edithooks.scala.html
+++ b/src/main/twirl/gitbucket/core/settings/edithooks.scala.html
@@ -55,7 +55,9 @@
+ -->
+