diff --git a/src/main/scala/app/RepositoryViewerController.scala b/src/main/scala/app/RepositoryViewerController.scala index e710d06..821900c 100644 --- a/src/main/scala/app/RepositoryViewerController.scala +++ b/src/main/scala/app/RepositoryViewerController.scala @@ -24,6 +24,7 @@ class RepositoryViewerController extends RepositoryViewerControllerBase with RepositoryService with AccountService with ActivityService with IssuesService with WebHookService with CommitsService with ReadableUsersAuthenticator with ReferrerAuthenticator with CollaboratorsAuthenticator with PullRequestService with CommitStatusService + with WebHookPullRequestService /** @@ -31,7 +32,8 @@ */ trait RepositoryViewerControllerBase extends ControllerBase { 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("tar.gz", new TgzFormat) @@ -562,6 +564,7 @@ closeIssuesFromMessage(message, loginAccount.userName, repository.owner, repository.name) // call web hook + callPullRequestWebHookByRequestBranch("synchronize", repository, branch, context.baseUrl, loginAccount) val commit = new JGitUtil.CommitInfo(JGitUtil.getRevCommitFromId(git, commitId)) callWebHookOf(repository.owner, repository.name, "push") { getAccountByUserName(repository.owner).map{ ownerAccount => diff --git a/src/main/scala/service/PullRequestService.scala b/src/main/scala/service/PullRequestService.scala index 1f09d7f..19c20d9 100644 --- a/src/main/scala/service/PullRequestService.scala +++ b/src/main/scala/service/PullRequestService.scala @@ -2,7 +2,7 @@ import model.Profile._ import profile.simple._ -import model.{PullRequest, Issue} +import model.{PullRequest, Issue, WebHook, Account} import util.JGitUtil trait PullRequestService { self: IssuesService => diff --git a/src/main/scala/service/WebHookService.scala b/src/main/scala/service/WebHookService.scala index c03ce95..83c40ac 100644 --- a/src/main/scala/service/WebHookService.scala +++ b/src/main/scala/service/WebHookService.scala @@ -116,6 +116,40 @@ } } } + + 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 { diff --git a/src/main/scala/servlet/GitRepositoryServlet.scala b/src/main/scala/servlet/GitRepositoryServlet.scala index a4e94ed..9ebb4ac 100644 --- a/src/main/scala/servlet/GitRepositoryServlet.scala +++ b/src/main/scala/servlet/GitRepositoryServlet.scala @@ -97,7 +97,8 @@ class CommitLogHook(owner: String, repository: String, pusher: String, baseUrl: String)(implicit session: Session) 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 var existIds: Seq[String] = Nil @@ -121,6 +122,7 @@ val pushedIds = scala.collection.mutable.Set[String]() commands.asScala.foreach { command => logger.debug(s"commandType: ${command.getType}, refName: ${command.getRefName}") + implicit val apiContext = api.JsonFormat.Context(baseUrl) val refName = command.getRefName.split("/") val branchName = refName.drop(2).mkString("/") val commits = if (refName(1) == "tags") { @@ -137,8 +139,10 @@ countIssue(IssueSearchCondition(state = "open"), false, owner -> repository) + countIssue(IssueSearchCondition(state = "closed"), false, owner -> repository) + val repositoryInfo = getRepository(owner, repository, baseUrl).get + // 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 => if (!existIds.contains(commit.id) && !pushedIds.contains(commit.id)) { if (issueCount > 0) { @@ -175,16 +179,17 @@ ReceiveCommand.Type.UPDATE | ReceiveCommand.Type.UPDATE_NONFASTFORWARD => updatePullRequests(owner, repository, branchName) + getAccountByUserName(pusher).map{ pusherAccount => + callPullRequestWebHookByRequestBranch("synchronize", repositoryInfo, branchName, baseUrl, pusherAccount) + } case _ => } } // call web hook - implicit val apiContext = api.JsonFormat.Context(baseUrl) callWebHookOf(owner, repository, "push"){ for(pusherAccount <- getAccountByUserName(pusher); - ownerAccount <- getAccountByUserName(owner); - repositoryInfo <- getRepository(owner, repository, baseUrl)) yield { + ownerAccount <- getAccountByUserName(owner)) yield { WebHookPushPayload(git, pusherAccount, command.getRefName, repositoryInfo, newCommits, ownerAccount) } } diff --git a/src/test/scala/service/AccessTokenServiceSpec.scala b/src/test/scala/service/AccessTokenServiceSpec.scala index fcdd695..dccb287 100644 --- a/src/test/scala/service/AccessTokenServiceSpec.scala +++ b/src/test/scala/service/AccessTokenServiceSpec.scala @@ -6,11 +6,6 @@ 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 { "generateAccessToken" in { withTestDB { implicit session => AccessTokenService.generateAccessToken("root", "note") must be like{ diff --git a/src/test/scala/service/CommitStateServiceSpec.scala b/src/test/scala/service/CommitStateServiceSpec.scala index 24ea41d..a868e13 100644 --- a/src/test/scala/service/CommitStateServiceSpec.scala +++ b/src/test/scala/service/CommitStateServiceSpec.scala @@ -6,10 +6,6 @@ import profile.simple._ class CommitStatusServiceSpec extends Specification with ServiceSpecBase with CommitStatusService 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 fixture1 = CommitStatus( userName = "root", diff --git a/src/test/scala/service/RepositoryServiceSpec.scala b/src/test/scala/service/RepositoryServiceSpec.scala index b3a5faa..33c74bc 100644 --- a/src/test/scala/service/RepositoryServiceSpec.scala +++ b/src/test/scala/service/RepositoryServiceSpec.scala @@ -5,10 +5,6 @@ import model.Profile._ import profile.simple._ 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 { "renameRepository can rename CommitState" in { withTestDB { implicit session => val tester = generateNewAccount("tester") diff --git a/src/test/scala/service/ServiceSpecBase.scala b/src/test/scala/service/ServiceSpecBase.scala index a87bb58..cc9dd05 100644 --- a/src/test/scala/service/ServiceSpecBase.scala +++ b/src/test/scala/service/ServiceSpecBase.scala @@ -8,6 +8,7 @@ import org.apache.commons.io.FileUtils import scala.util.Random import java.io.File +import model._ trait ServiceSpecBase { @@ -24,4 +25,41 @@ } } + 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 + } } diff --git a/src/test/scala/service/WebHookServiceSpec.scala b/src/test/scala/service/WebHookServiceSpec.scala new file mode 100644 index 0000000..c23f708 --- /dev/null +++ b/src/test/scala/service/WebHookServiceSpec.scala @@ -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") + } } + } +} \ No newline at end of file