mirror of
https://github.com/gitbucket/gitbucket.git
synced 2025-11-05 04:56:02 +01:00
add webhook pull_request synchronize action
This commit is contained in:
@@ -24,6 +24,7 @@ import api._
|
|||||||
class RepositoryViewerController extends RepositoryViewerControllerBase
|
class RepositoryViewerController extends RepositoryViewerControllerBase
|
||||||
with RepositoryService with AccountService with ActivityService with IssuesService with WebHookService with CommitsService
|
with RepositoryService with AccountService with ActivityService with IssuesService with WebHookService with CommitsService
|
||||||
with ReadableUsersAuthenticator with ReferrerAuthenticator with CollaboratorsAuthenticator with PullRequestService with CommitStatusService
|
with ReadableUsersAuthenticator with ReferrerAuthenticator with CollaboratorsAuthenticator with PullRequestService with CommitStatusService
|
||||||
|
with WebHookPullRequestService
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -31,7 +32,8 @@ class RepositoryViewerController extends RepositoryViewerControllerBase
|
|||||||
*/
|
*/
|
||||||
trait RepositoryViewerControllerBase extends ControllerBase {
|
trait RepositoryViewerControllerBase extends ControllerBase {
|
||||||
self: RepositoryService with AccountService with ActivityService with IssuesService with WebHookService with CommitsService
|
self: RepositoryService with AccountService with ActivityService with IssuesService with WebHookService with CommitsService
|
||||||
with ReadableUsersAuthenticator with ReferrerAuthenticator with CollaboratorsAuthenticator with PullRequestService with CommitStatusService =>
|
with ReadableUsersAuthenticator with ReferrerAuthenticator with CollaboratorsAuthenticator with PullRequestService with CommitStatusService
|
||||||
|
with WebHookPullRequestService =>
|
||||||
|
|
||||||
ArchiveCommand.registerFormat("zip", new ZipFormat)
|
ArchiveCommand.registerFormat("zip", new ZipFormat)
|
||||||
ArchiveCommand.registerFormat("tar.gz", new TgzFormat)
|
ArchiveCommand.registerFormat("tar.gz", new TgzFormat)
|
||||||
@@ -562,6 +564,7 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
|||||||
closeIssuesFromMessage(message, loginAccount.userName, repository.owner, repository.name)
|
closeIssuesFromMessage(message, loginAccount.userName, repository.owner, repository.name)
|
||||||
|
|
||||||
// call web hook
|
// call web hook
|
||||||
|
callPullRequestWebHookByRequestBranch("synchronize", repository, branch, context.baseUrl, loginAccount)
|
||||||
val commit = new JGitUtil.CommitInfo(JGitUtil.getRevCommitFromId(git, commitId))
|
val commit = new JGitUtil.CommitInfo(JGitUtil.getRevCommitFromId(git, commitId))
|
||||||
callWebHookOf(repository.owner, repository.name, "push") {
|
callWebHookOf(repository.owner, repository.name, "push") {
|
||||||
getAccountByUserName(repository.owner).map{ ownerAccount =>
|
getAccountByUserName(repository.owner).map{ ownerAccount =>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package service
|
|||||||
|
|
||||||
import model.Profile._
|
import model.Profile._
|
||||||
import profile.simple._
|
import profile.simple._
|
||||||
import model.{PullRequest, Issue}
|
import model.{PullRequest, Issue, WebHook, Account}
|
||||||
import util.JGitUtil
|
import util.JGitUtil
|
||||||
|
|
||||||
trait PullRequestService { self: IssuesService =>
|
trait PullRequestService { self: IssuesService =>
|
||||||
|
|||||||
@@ -116,6 +116,40 @@ trait WebHookPullRequestService extends WebHookService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def getPullRequestsByRequestForWebhook(userName:String, repositoryName:String, branch:String)
|
||||||
|
(implicit s: Session): Map[(Issue, PullRequest, Account, Account), List[WebHook]] =
|
||||||
|
(for{
|
||||||
|
is <- Issues if is.closed === false.bind
|
||||||
|
pr <- PullRequests if pr.byPrimaryKey(is.userName, is.repositoryName, is.issueId)
|
||||||
|
if pr.requestUserName === userName.bind
|
||||||
|
if pr.requestRepositoryName === repositoryName.bind
|
||||||
|
if pr.requestBranch === branch.bind
|
||||||
|
bu <- Accounts if bu.userName === pr.userName
|
||||||
|
ru <- Accounts if ru.userName === pr.requestUserName
|
||||||
|
wh <- WebHooks if wh.byRepository(is.userName , is.repositoryName)
|
||||||
|
} yield {
|
||||||
|
((is, pr, bu, ru), wh)
|
||||||
|
}).list.groupBy(_._1).mapValues(_.map(_._2))
|
||||||
|
|
||||||
|
def callPullRequestWebHookByRequestBranch(action: String, requestRepository: RepositoryService.RepositoryInfo, requestBranch: String, baseUrl: String, sender: model.Account)(implicit s: Session, context:JsonFormat.Context): Unit = {
|
||||||
|
import WebHookService._
|
||||||
|
for{
|
||||||
|
((issue, pullRequest, baseOwner, headOwner), webHooks) <- getPullRequestsByRequestForWebhook(requestRepository.owner, requestRepository.name, requestBranch)
|
||||||
|
baseRepo <- getRepository(pullRequest.userName, pullRequest.repositoryName, baseUrl)
|
||||||
|
} yield {
|
||||||
|
val payload = WebHookPullRequestPayload(
|
||||||
|
action = action,
|
||||||
|
issue = issue,
|
||||||
|
pullRequest = pullRequest,
|
||||||
|
headRepository = requestRepository,
|
||||||
|
headOwner = headOwner,
|
||||||
|
baseRepository = baseRepo,
|
||||||
|
baseOwner = baseOwner,
|
||||||
|
sender = sender)
|
||||||
|
callWebHook("pull_request", webHooks, payload)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trait WebHookIssueCommentService extends WebHookPullRequestService {
|
trait WebHookIssueCommentService extends WebHookPullRequestService {
|
||||||
|
|||||||
@@ -97,7 +97,8 @@ 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)(implicit session: Session)
|
||||||
extends PostReceiveHook with PreReceiveHook
|
extends PostReceiveHook with PreReceiveHook
|
||||||
with RepositoryService with AccountService with IssuesService with ActivityService with PullRequestService with WebHookService {
|
with RepositoryService with AccountService with IssuesService with ActivityService with PullRequestService with WebHookService
|
||||||
|
with WebHookPullRequestService {
|
||||||
|
|
||||||
private val logger = LoggerFactory.getLogger(classOf[CommitLogHook])
|
private val logger = LoggerFactory.getLogger(classOf[CommitLogHook])
|
||||||
private var existIds: Seq[String] = Nil
|
private var existIds: Seq[String] = Nil
|
||||||
@@ -121,6 +122,7 @@ class CommitLogHook(owner: String, repository: String, pusher: String, baseUrl:
|
|||||||
val pushedIds = scala.collection.mutable.Set[String]()
|
val pushedIds = scala.collection.mutable.Set[String]()
|
||||||
commands.asScala.foreach { command =>
|
commands.asScala.foreach { command =>
|
||||||
logger.debug(s"commandType: ${command.getType}, refName: ${command.getRefName}")
|
logger.debug(s"commandType: ${command.getType}, refName: ${command.getRefName}")
|
||||||
|
implicit val apiContext = api.JsonFormat.Context(baseUrl)
|
||||||
val refName = command.getRefName.split("/")
|
val refName = command.getRefName.split("/")
|
||||||
val branchName = refName.drop(2).mkString("/")
|
val branchName = refName.drop(2).mkString("/")
|
||||||
val commits = if (refName(1) == "tags") {
|
val commits = if (refName(1) == "tags") {
|
||||||
@@ -137,8 +139,10 @@ class CommitLogHook(owner: String, repository: String, pusher: String, baseUrl:
|
|||||||
countIssue(IssueSearchCondition(state = "open"), false, owner -> repository) +
|
countIssue(IssueSearchCondition(state = "open"), false, owner -> repository) +
|
||||||
countIssue(IssueSearchCondition(state = "closed"), false, owner -> repository)
|
countIssue(IssueSearchCondition(state = "closed"), false, owner -> repository)
|
||||||
|
|
||||||
|
val repositoryInfo = getRepository(owner, repository, baseUrl).get
|
||||||
|
|
||||||
// Extract new commit and apply issue comment
|
// Extract new commit and apply issue comment
|
||||||
val defaultBranch = getRepository(owner, repository, baseUrl).get.repository.defaultBranch
|
val defaultBranch = repositoryInfo.repository.defaultBranch
|
||||||
val newCommits = commits.flatMap { commit =>
|
val newCommits = commits.flatMap { commit =>
|
||||||
if (!existIds.contains(commit.id) && !pushedIds.contains(commit.id)) {
|
if (!existIds.contains(commit.id) && !pushedIds.contains(commit.id)) {
|
||||||
if (issueCount > 0) {
|
if (issueCount > 0) {
|
||||||
@@ -175,16 +179,17 @@ class CommitLogHook(owner: String, repository: String, pusher: String, baseUrl:
|
|||||||
ReceiveCommand.Type.UPDATE |
|
ReceiveCommand.Type.UPDATE |
|
||||||
ReceiveCommand.Type.UPDATE_NONFASTFORWARD =>
|
ReceiveCommand.Type.UPDATE_NONFASTFORWARD =>
|
||||||
updatePullRequests(owner, repository, branchName)
|
updatePullRequests(owner, repository, branchName)
|
||||||
|
getAccountByUserName(pusher).map{ pusherAccount =>
|
||||||
|
callPullRequestWebHookByRequestBranch("synchronize", repositoryInfo, branchName, baseUrl, pusherAccount)
|
||||||
|
}
|
||||||
case _ =>
|
case _ =>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// call web hook
|
// call web hook
|
||||||
implicit val apiContext = api.JsonFormat.Context(baseUrl)
|
|
||||||
callWebHookOf(owner, repository, "push"){
|
callWebHookOf(owner, repository, "push"){
|
||||||
for(pusherAccount <- getAccountByUserName(pusher);
|
for(pusherAccount <- getAccountByUserName(pusher);
|
||||||
ownerAccount <- getAccountByUserName(owner);
|
ownerAccount <- getAccountByUserName(owner)) yield {
|
||||||
repositoryInfo <- getRepository(owner, repository, baseUrl)) yield {
|
|
||||||
WebHookPushPayload(git, pusherAccount, command.getRefName, repositoryInfo, newCommits, ownerAccount)
|
WebHookPushPayload(git, pusherAccount, command.getRefName, repositoryInfo, newCommits, ownerAccount)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,11 +6,6 @@ import model._
|
|||||||
|
|
||||||
class AccessTokenServiceSpec extends Specification with ServiceSpecBase {
|
class AccessTokenServiceSpec extends Specification with ServiceSpecBase {
|
||||||
|
|
||||||
def generateNewAccount(name:String)(implicit s:Session):Account = {
|
|
||||||
AccountService.createAccount(name, name, name, s"${name}@example.com", false, None)
|
|
||||||
AccountService.getAccountByUserName(name).get
|
|
||||||
}
|
|
||||||
|
|
||||||
"AccessTokenService" should {
|
"AccessTokenService" should {
|
||||||
"generateAccessToken" in { withTestDB { implicit session =>
|
"generateAccessToken" in { withTestDB { implicit session =>
|
||||||
AccessTokenService.generateAccessToken("root", "note") must be like{
|
AccessTokenService.generateAccessToken("root", "note") must be like{
|
||||||
|
|||||||
@@ -6,10 +6,6 @@ import model.Profile._
|
|||||||
import profile.simple._
|
import profile.simple._
|
||||||
class CommitStatusServiceSpec extends Specification with ServiceSpecBase with CommitStatusService
|
class CommitStatusServiceSpec extends Specification with ServiceSpecBase with CommitStatusService
|
||||||
with RepositoryService with AccountService{
|
with RepositoryService with AccountService{
|
||||||
def generateNewAccount(name:String)(implicit s:Session):Account = {
|
|
||||||
createAccount(name, name, name, s"${name}@example.com", false, None)
|
|
||||||
getAccountByUserName(name).get
|
|
||||||
}
|
|
||||||
val now = new java.util.Date()
|
val now = new java.util.Date()
|
||||||
val fixture1 = CommitStatus(
|
val fixture1 = CommitStatus(
|
||||||
userName = "root",
|
userName = "root",
|
||||||
|
|||||||
@@ -5,10 +5,6 @@ import model._
|
|||||||
import model.Profile._
|
import model.Profile._
|
||||||
import profile.simple._
|
import profile.simple._
|
||||||
class RepositoryServiceSpec extends Specification with ServiceSpecBase with RepositoryService with AccountService{
|
class RepositoryServiceSpec extends Specification with ServiceSpecBase with RepositoryService with AccountService{
|
||||||
def generateNewAccount(name:String)(implicit s:Session):Account = {
|
|
||||||
createAccount(name, name, name, s"${name}@example.com", false, None)
|
|
||||||
getAccountByUserName(name).get
|
|
||||||
}
|
|
||||||
"RepositoryService" should {
|
"RepositoryService" should {
|
||||||
"renameRepository can rename CommitState" in { withTestDB { implicit session =>
|
"renameRepository can rename CommitState" in { withTestDB { implicit session =>
|
||||||
val tester = generateNewAccount("tester")
|
val tester = generateNewAccount("tester")
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import java.sql.DriverManager
|
|||||||
import org.apache.commons.io.FileUtils
|
import org.apache.commons.io.FileUtils
|
||||||
import scala.util.Random
|
import scala.util.Random
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import model._
|
||||||
|
|
||||||
trait ServiceSpecBase {
|
trait ServiceSpecBase {
|
||||||
|
|
||||||
@@ -24,4 +25,41 @@ trait ServiceSpecBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def generateNewAccount(name:String)(implicit s:Session):Account = {
|
||||||
|
AccountService.createAccount(name, name, name, s"${name}@example.com", false, None)
|
||||||
|
AccountService.getAccountByUserName(name).get
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy val dummyService = new RepositoryService with AccountService with IssuesService with PullRequestService (){}
|
||||||
|
|
||||||
|
def generateNewUserWithDBRepository(userName:String, repositoryName:String)(implicit s:Session):Account = {
|
||||||
|
val ac = generateNewAccount(userName)
|
||||||
|
dummyService.createRepository(repositoryName, userName, None, false)
|
||||||
|
ac
|
||||||
|
}
|
||||||
|
def generateNewPullRequest(base:String, request:String)(implicit s:Session):(Issue, PullRequest) = {
|
||||||
|
val Array(baseUserName, baseRepositoryName, baesBranch)=base.split("/")
|
||||||
|
val Array(requestUserName, requestRepositoryName, requestBranch)=request.split("/")
|
||||||
|
val issueId = dummyService.createIssue(
|
||||||
|
owner = baseUserName,
|
||||||
|
repository = baseRepositoryName,
|
||||||
|
loginUser = requestUserName,
|
||||||
|
title = "issue title",
|
||||||
|
content = None,
|
||||||
|
assignedUserName = None,
|
||||||
|
milestoneId = None,
|
||||||
|
isPullRequest = true)
|
||||||
|
|
||||||
|
dummyService.createPullRequest(
|
||||||
|
originUserName = baseUserName,
|
||||||
|
originRepositoryName = baseRepositoryName,
|
||||||
|
issueId = issueId,
|
||||||
|
originBranch = baesBranch,
|
||||||
|
requestUserName = requestUserName,
|
||||||
|
requestRepositoryName = requestRepositoryName,
|
||||||
|
requestBranch = requestBranch,
|
||||||
|
commitIdFrom = baesBranch,
|
||||||
|
commitIdTo = requestBranch)
|
||||||
|
dummyService.getPullRequest(baseUserName, baseRepositoryName, issueId).get
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
43
src/test/scala/service/WebHookServiceSpec.scala
Normal file
43
src/test/scala/service/WebHookServiceSpec.scala
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import org.specs2.mutable.Specification
|
||||||
|
import java.util.Date
|
||||||
|
import model._
|
||||||
|
|
||||||
|
class WebHookServiceSpec extends Specification with ServiceSpecBase {
|
||||||
|
lazy val service = new WebHookPullRequestService with AccountService with RepositoryService with PullRequestService with IssuesService
|
||||||
|
|
||||||
|
"WebHookPullRequestService.getPullRequestsByRequestForWebhook" should {
|
||||||
|
"find from request branch" in { withTestDB { implicit session =>
|
||||||
|
val user1 = generateNewUserWithDBRepository("user1","repo1")
|
||||||
|
val user2 = generateNewUserWithDBRepository("user2","repo2")
|
||||||
|
val user3 = generateNewUserWithDBRepository("user3","repo3")
|
||||||
|
val (issue1, pullreq1) = generateNewPullRequest("user1/repo1/master1", "user2/repo2/master2")
|
||||||
|
val (issue3, pullreq3) = generateNewPullRequest("user3/repo3/master3", "user2/repo2/master2")
|
||||||
|
val (issue32, pullreq32) = generateNewPullRequest("user3/repo3/master32", "user2/repo2/master2")
|
||||||
|
generateNewPullRequest("user2/repo2/master2", "user1/repo1/master2")
|
||||||
|
service.addWebHookURL("user1", "repo1", "webhook1-1")
|
||||||
|
service.addWebHookURL("user1", "repo1", "webhook1-2")
|
||||||
|
service.addWebHookURL("user2", "repo2", "webhook2-1")
|
||||||
|
service.addWebHookURL("user2", "repo2", "webhook2-2")
|
||||||
|
service.addWebHookURL("user3", "repo3", "webhook3-1")
|
||||||
|
service.addWebHookURL("user3", "repo3", "webhook3-2")
|
||||||
|
|
||||||
|
service.getPullRequestsByRequestForWebhook("user1","repo1","master1") must_== Map.empty
|
||||||
|
|
||||||
|
var r = service.getPullRequestsByRequestForWebhook("user2","repo2","master2").mapValues(_.map(_.url).toSet)
|
||||||
|
r.size must_== 3
|
||||||
|
r((issue1, pullreq1, user1, user2)) must_== Set("webhook1-1","webhook1-2")
|
||||||
|
r((issue3, pullreq3, user3, user2)) must_== Set("webhook3-1","webhook3-2")
|
||||||
|
r((issue32, pullreq32, user3, user2)) must_== Set("webhook3-1","webhook3-2")
|
||||||
|
|
||||||
|
// when closed, it not founds.
|
||||||
|
service.updateClosed("user1","repo1",issue1.issueId, true)
|
||||||
|
|
||||||
|
var r2 = service.getPullRequestsByRequestForWebhook("user2","repo2","master2").mapValues(_.map(_.url).toSet)
|
||||||
|
r2.size must_== 2
|
||||||
|
r2((issue3, pullreq3, user3, user2)) must_== Set("webhook3-1","webhook3-2")
|
||||||
|
r2((issue32, pullreq32, user3, user2)) must_== Set("webhook3-1","webhook3-2")
|
||||||
|
} }
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user