mirror of
https://github.com/gitbucket/gitbucket.git
synced 2025-11-03 03:55:58 +01:00
Merge remote-tracking branch 'upstream/master' into pr-implemt-apis
This commit is contained in:
28
CHANGELOG.md
28
CHANGELOG.md
@@ -1,24 +1,24 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
All changes to the project will be documented in this file.
|
All changes to the project will be documented in this file.
|
||||||
|
|
||||||
### 4.29.0 - 29 Sep 2018
|
## 4.29.0 - 29 Sep 2018
|
||||||
- Official Docker image has been available
|
- Official Docker image has been available
|
||||||
- Enhance file edit and delete buttons of the repository viewer
|
- Enhance file edit and delete buttons of the repository viewer
|
||||||
- Fix Patch button to generate patches for all files in the commit
|
- Fix Patch button to generate patches for all files in the commit
|
||||||
- Display confirmation dialog for Transfer Ownership and Garbage collection
|
- Display confirmation dialog for Transfer Ownership and Garbage collection
|
||||||
- Fix wrong url encoding in "Compare & pull request"
|
- Fix wrong url encoding in "Compare & pull request"
|
||||||
|
|
||||||
### 4.28.0 - 1 Sep 2018
|
## 4.28.0 - 1 Sep 2018
|
||||||
- Proxy support for plugin installation
|
- Proxy support for plugin installation
|
||||||
- Fix some bugs around pull requests
|
- Fix some bugs around pull requests
|
||||||
|
|
||||||
### 4.27.0 - 29 Jul 2018
|
## 4.27.0 - 29 Jul 2018
|
||||||
- Create new tag on the browser
|
- Create new tag on the browser
|
||||||
- EditorConfig support
|
- EditorConfig support
|
||||||
- Improve issues / pull requests search
|
- Improve issues / pull requests search
|
||||||
- Some improvements and bug fixes for plugin installation via internet and pull request commenting
|
- Some improvements and bug fixes for plugin installation via internet and pull request commenting
|
||||||
|
|
||||||
### 4.26.0 - 30 Jun 2018
|
## 4.26.0 - 30 Jun 2018
|
||||||
- Installing plugins from the central registry
|
- Installing plugins from the central registry
|
||||||
- Repositories tab in the dashboard
|
- Repositories tab in the dashboard
|
||||||
- Fork dialog enhancement
|
- Fork dialog enhancement
|
||||||
@@ -26,7 +26,7 @@ All changes to the project will be documented in this file.
|
|||||||
- Keep showing incompleted task list
|
- Keep showing incompleted task list
|
||||||
- New notification hooks
|
- New notification hooks
|
||||||
|
|
||||||
### 4.25.0 - 29 May 2018
|
## 4.25.0 - 29 May 2018
|
||||||
- Security improvements
|
- Security improvements
|
||||||
- Show mail address at the profile page
|
- Show mail address at the profile page
|
||||||
- Task list on commit comments
|
- Task list on commit comments
|
||||||
@@ -34,10 +34,10 @@ All changes to the project will be documented in this file.
|
|||||||
- Expose user public keys
|
- Expose user public keys
|
||||||
- Download repository improvements
|
- Download repository improvements
|
||||||
|
|
||||||
### 4.24.1 - 1 May 2018
|
## 4.24.1 - 1 May 2018
|
||||||
- Fix bug in Web API authentication
|
- Fix bug in Web API authentication
|
||||||
|
|
||||||
### 4.24.0 - 30 Apr 2018
|
## 4.24.0 - 30 Apr 2018
|
||||||
- Diff for each review comment on pull requests
|
- Diff for each review comment on pull requests
|
||||||
- Extra mail addresses support
|
- Extra mail addresses support
|
||||||
- Show tags at the commit list
|
- Show tags at the commit list
|
||||||
@@ -45,12 +45,12 @@ All changes to the project will be documented in this file.
|
|||||||
- Renew layout of gitbucket-gist-plugin
|
- Renew layout of gitbucket-gist-plugin
|
||||||
- Web API of gitbucket-ci-plugin
|
- Web API of gitbucket-ci-plugin
|
||||||
|
|
||||||
### 4.23.1 - 10 Apr 2018
|
## 4.23.1 - 10 Apr 2018
|
||||||
- Fix bug that the contents API doesn't work for the repository root
|
- Fix bug that the contents API doesn't work for the repository root
|
||||||
- Fix shutdown problem in Tomcat deployment
|
- Fix shutdown problem in Tomcat deployment
|
||||||
- Render by plugins at the blob view even if it's a binary file
|
- Render by plugins at the blob view even if it's a binary file
|
||||||
|
|
||||||
### 4.23.0 - 31 Mar 2018
|
## 4.23.0 - 31 Mar 2018
|
||||||
- Allow tail slash in URL
|
- Allow tail slash in URL
|
||||||
- Display commit message of tags at the releases page
|
- Display commit message of tags at the releases page
|
||||||
- Add labels property to issues and pull requests API response
|
- Add labels property to issues and pull requests API response
|
||||||
@@ -58,26 +58,26 @@ All changes to the project will be documented in this file.
|
|||||||
- Git authentication with personal access token
|
- Git authentication with personal access token
|
||||||
- Max parallel builds and max stored history in CI plugin became configurable
|
- Max parallel builds and max stored history in CI plugin became configurable
|
||||||
|
|
||||||
### 4.22.0 - 3 Mar 2018
|
## 4.22.0 - 3 Mar 2018
|
||||||
- Pull request merge strategy settings
|
- Pull request merge strategy settings
|
||||||
- Create repository with an empty commit
|
- Create repository with an empty commit
|
||||||
- Improve database viewer
|
- Improve database viewer
|
||||||
- Update maven-repository-plugin
|
- Update maven-repository-plugin
|
||||||
|
|
||||||
### 4.21.2 - 27 Jan 2018
|
## 4.21.2 - 27 Jan 2018
|
||||||
- Bugfix
|
- Bugfix
|
||||||
|
|
||||||
### 4.21.1 - 27 Jan 2018
|
## 4.21.1 - 27 Jan 2018
|
||||||
- Bugfix
|
- Bugfix
|
||||||
|
|
||||||
### 4.21.0 - 27 Jan 2018
|
## 4.21.0 - 27 Jan 2018
|
||||||
- Release page
|
- Release page
|
||||||
- OpenID Connect support
|
- OpenID Connect support
|
||||||
- New database viewer
|
- New database viewer
|
||||||
- Submodule links to web page
|
- Submodule links to web page
|
||||||
- Clarify close/reopen button
|
- Clarify close/reopen button
|
||||||
|
|
||||||
## 4.20.0 - 23 Dec 2017
|
# 4.20.0 - 23 Dec 2017
|
||||||
- Squash and rebase merge strategy for pull requests
|
- Squash and rebase merge strategy for pull requests
|
||||||
- Quick pull request creation
|
- Quick pull request creation
|
||||||
- Download patch from the diff view
|
- Download patch from the diff view
|
||||||
|
|||||||
30
build.sbt
30
build.sbt
@@ -6,7 +6,7 @@ val Name = "gitbucket"
|
|||||||
val GitBucketVersion = "4.30.0-SNAPSHOT"
|
val GitBucketVersion = "4.30.0-SNAPSHOT"
|
||||||
val ScalatraVersion = "2.6.3"
|
val ScalatraVersion = "2.6.3"
|
||||||
val JettyVersion = "9.4.11.v20180605"
|
val JettyVersion = "9.4.11.v20180605"
|
||||||
val JgitVersion = "5.1.2.201810061102-r"
|
val JgitVersion = "5.1.3.201810200350-r"
|
||||||
|
|
||||||
lazy val root = (project in file("."))
|
lazy val root = (project in file("."))
|
||||||
.enablePlugins(SbtTwirl, ScalatraPlugin)
|
.enablePlugins(SbtTwirl, ScalatraPlugin)
|
||||||
@@ -36,40 +36,40 @@ libraryDependencies ++= Seq(
|
|||||||
"org.scalatra" %% "scalatra" % ScalatraVersion,
|
"org.scalatra" %% "scalatra" % ScalatraVersion,
|
||||||
"org.scalatra" %% "scalatra-json" % ScalatraVersion,
|
"org.scalatra" %% "scalatra-json" % ScalatraVersion,
|
||||||
"org.scalatra" %% "scalatra-forms" % ScalatraVersion,
|
"org.scalatra" %% "scalatra-forms" % ScalatraVersion,
|
||||||
"org.json4s" %% "json4s-jackson" % "3.5.3",
|
"org.json4s" %% "json4s-jackson" % "3.5.4",
|
||||||
"commons-io" % "commons-io" % "2.6",
|
"commons-io" % "commons-io" % "2.6",
|
||||||
"io.github.gitbucket" % "solidbase" % "1.0.2",
|
"io.github.gitbucket" % "solidbase" % "1.0.2",
|
||||||
"io.github.gitbucket" % "markedj" % "1.0.15",
|
"io.github.gitbucket" % "markedj" % "1.0.15",
|
||||||
"org.apache.commons" % "commons-compress" % "1.18",
|
"org.apache.commons" % "commons-compress" % "1.18",
|
||||||
"org.apache.commons" % "commons-email" % "1.5",
|
"org.apache.commons" % "commons-email" % "1.5",
|
||||||
"org.apache.httpcomponents" % "httpclient" % "4.5.6",
|
"org.apache.httpcomponents" % "httpclient" % "4.5.6",
|
||||||
"org.apache.sshd" % "apache-sshd" % "2.1.0" exclude ("org.slf4j", "slf4j-jdk14"),
|
"org.apache.sshd" % "apache-sshd" % "1.7.0" exclude ("org.slf4j", "slf4j-jdk14"),
|
||||||
"org.apache.tika" % "tika-core" % "1.19.1",
|
"org.apache.tika" % "tika-core" % "1.19.1",
|
||||||
"com.github.takezoe" %% "blocking-slick-32" % "0.0.10",
|
"com.github.takezoe" %% "blocking-slick-32" % "0.0.11",
|
||||||
"com.novell.ldap" % "jldap" % "2009-10-07",
|
"com.novell.ldap" % "jldap" % "2009-10-07",
|
||||||
"com.h2database" % "h2" % "1.4.196",
|
"com.h2database" % "h2" % "1.4.197",
|
||||||
"org.mariadb.jdbc" % "mariadb-java-client" % "2.3.0",
|
"org.mariadb.jdbc" % "mariadb-java-client" % "2.3.0",
|
||||||
"org.postgresql" % "postgresql" % "42.2.5",
|
"org.postgresql" % "postgresql" % "42.2.5",
|
||||||
"ch.qos.logback" % "logback-classic" % "1.2.3",
|
"ch.qos.logback" % "logback-classic" % "1.2.3",
|
||||||
"com.zaxxer" % "HikariCP" % "2.7.4",
|
"com.zaxxer" % "HikariCP" % "2.7.9",
|
||||||
"com.typesafe" % "config" % "1.3.2",
|
"com.typesafe" % "config" % "1.3.3",
|
||||||
"com.typesafe.akka" %% "akka-actor" % "2.5.8",
|
"com.typesafe.akka" %% "akka-actor" % "2.5.17",
|
||||||
"fr.brouillard.oss.security.xhub" % "xhub4j-core" % "1.0.0",
|
"fr.brouillard.oss.security.xhub" % "xhub4j-core" % "1.0.0",
|
||||||
"com.github.bkromhout" % "java-diff-utils" % "2.1.1",
|
"com.github.bkromhout" % "java-diff-utils" % "2.1.1",
|
||||||
"org.cache2k" % "cache2k-all" % "1.0.1.Final",
|
"org.cache2k" % "cache2k-all" % "1.0.2.Final",
|
||||||
"com.enragedginger" %% "akka-quartz-scheduler" % "1.6.1-akka-2.5.x" exclude ("c3p0", "c3p0"),
|
"com.enragedginger" %% "akka-quartz-scheduler" % "1.7.0-akka-2.5.x" exclude ("c3p0", "c3p0"),
|
||||||
"net.coobird" % "thumbnailator" % "0.4.8",
|
"net.coobird" % "thumbnailator" % "0.4.8",
|
||||||
"com.github.zafarkhaja" % "java-semver" % "0.9.0",
|
"com.github.zafarkhaja" % "java-semver" % "0.9.0",
|
||||||
"com.nimbusds" % "oauth2-oidc-sdk" % "5.45",
|
"com.nimbusds" % "oauth2-oidc-sdk" % "5.64.4",
|
||||||
"org.eclipse.jetty" % "jetty-webapp" % JettyVersion % "provided",
|
"org.eclipse.jetty" % "jetty-webapp" % JettyVersion % "provided",
|
||||||
"javax.servlet" % "javax.servlet-api" % "3.1.0" % "provided",
|
"javax.servlet" % "javax.servlet-api" % "3.1.0" % "provided",
|
||||||
"junit" % "junit" % "4.12" % "test",
|
"junit" % "junit" % "4.12" % "test",
|
||||||
"org.scalatra" %% "scalatra-scalatest" % ScalatraVersion % "test",
|
"org.scalatra" %% "scalatra-scalatest" % ScalatraVersion % "test",
|
||||||
"org.mockito" % "mockito-core" % "2.19.1" % "test",
|
"org.mockito" % "mockito-core" % "2.23.0" % "test",
|
||||||
"com.wix" % "wix-embedded-mysql" % "3.0.0" % "test",
|
"com.wix" % "wix-embedded-mysql" % "3.0.0" % "test",
|
||||||
"ru.yandex.qatools.embed" % "postgresql-embedded" % "2.6" % "test",
|
"ru.yandex.qatools.embed" % "postgresql-embedded" % "2.9" % "test",
|
||||||
"net.i2p.crypto" % "eddsa" % "0.2.0",
|
"net.i2p.crypto" % "eddsa" % "0.3.0",
|
||||||
"is.tagomor.woothee" % "woothee-java" % "1.7.0",
|
"is.tagomor.woothee" % "woothee-java" % "1.8.0",
|
||||||
"org.ec4j.core" % "ec4j-core" % "0.0.1"
|
"org.ec4j.core" % "ec4j-core" % "0.0.1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
sbt.version=1.2.3
|
sbt.version=1.2.6
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
libraryDependencies += "com.eclipsesource.minimal-json" % "minimal-json" % "0.9.4"
|
libraryDependencies += "com.eclipsesource.minimal-json" % "minimal-json" % "0.9.5"
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
scalacOptions ++= Seq("-unchecked", "-deprecation", "-feature")
|
scalacOptions ++= Seq("-unchecked", "-deprecation", "-feature")
|
||||||
|
|
||||||
addSbtPlugin("com.geirsson" % "sbt-scalafmt" % "1.5.0")
|
addSbtPlugin("com.geirsson" % "sbt-scalafmt" % "1.5.0")
|
||||||
addSbtPlugin("com.typesafe.sbt" % "sbt-twirl" % "1.3.13")
|
addSbtPlugin("com.typesafe.sbt" % "sbt-twirl" % "1.3.15")
|
||||||
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.5")
|
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.8")
|
||||||
addSbtPlugin("org.scalatra.sbt" % "sbt-scalatra" % "1.0.1")
|
addSbtPlugin("org.scalatra.sbt" % "sbt-scalatra" % "1.0.1")
|
||||||
addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.1.0")
|
addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.1.2")
|
||||||
addSbtCoursier
|
addSbtCoursier
|
||||||
addSbtPlugin("com.typesafe.sbt" % "sbt-license-report" % "1.2.0")
|
addSbtPlugin("com.typesafe.sbt" % "sbt-license-report" % "1.2.0")
|
||||||
|
|||||||
@@ -360,13 +360,7 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
|||||||
// FileUtils.deleteDirectory(getWikiRepositoryDir(userName, repositoryName))
|
// FileUtils.deleteDirectory(getWikiRepositoryDir(userName, repositoryName))
|
||||||
// FileUtils.deleteDirectory(getTemporaryDir(userName, repositoryName))
|
// FileUtils.deleteDirectory(getTemporaryDir(userName, repositoryName))
|
||||||
// }
|
// }
|
||||||
// Remove from GROUP_MEMBER and COLLABORATOR
|
suspendAccount(account)
|
||||||
removeUserRelatedData(userName)
|
|
||||||
updateAccount(account.copy(isRemoved = true))
|
|
||||||
|
|
||||||
// call hooks
|
|
||||||
PluginRegistry().getAccountHooks.foreach(_.deleted(userName))
|
|
||||||
|
|
||||||
session.invalidate
|
session.invalidate
|
||||||
redirect("/")
|
redirect("/")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ class ApiController
|
|||||||
with WebHookService
|
with WebHookService
|
||||||
with WebHookPullRequestService
|
with WebHookPullRequestService
|
||||||
with WebHookIssueCommentService
|
with WebHookIssueCommentService
|
||||||
|
with WebHookPullRequestReviewCommentService
|
||||||
with WikiService
|
with WikiService
|
||||||
with ActivityService
|
with ActivityService
|
||||||
with PrioritiesService
|
with PrioritiesService
|
||||||
|
|||||||
@@ -12,9 +12,13 @@ class DashboardController
|
|||||||
with PullRequestService
|
with PullRequestService
|
||||||
with RepositoryService
|
with RepositoryService
|
||||||
with AccountService
|
with AccountService
|
||||||
|
with ActivityService
|
||||||
with CommitsService
|
with CommitsService
|
||||||
with LabelsService
|
with LabelsService
|
||||||
with PrioritiesService
|
with PrioritiesService
|
||||||
|
with WebHookService
|
||||||
|
with WebHookPullRequestService
|
||||||
|
with WebHookPullRequestReviewCommentService
|
||||||
with MilestonesService
|
with MilestonesService
|
||||||
with UsersAuthenticator
|
with UsersAuthenticator
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ class IssuesController
|
|||||||
with WritableUsersAuthenticator
|
with WritableUsersAuthenticator
|
||||||
with PullRequestService
|
with PullRequestService
|
||||||
with WebHookIssueCommentService
|
with WebHookIssueCommentService
|
||||||
|
with WebHookPullRequestReviewCommentService
|
||||||
with CommitsService
|
with CommitsService
|
||||||
with PrioritiesService
|
with PrioritiesService
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ class PullRequestsController
|
|||||||
with CommitsService
|
with CommitsService
|
||||||
with ActivityService
|
with ActivityService
|
||||||
with WebHookPullRequestService
|
with WebHookPullRequestService
|
||||||
|
with WebHookPullRequestReviewCommentService
|
||||||
with ReadableUsersAuthenticator
|
with ReadableUsersAuthenticator
|
||||||
with ReferrerAuthenticator
|
with ReferrerAuthenticator
|
||||||
with WritableUsersAuthenticator
|
with WritableUsersAuthenticator
|
||||||
@@ -294,11 +295,12 @@ trait PullRequestsControllerBase extends ControllerBase {
|
|||||||
issueId <- params("id").toIntOpt
|
issueId <- params("id").toIntOpt
|
||||||
loginAccount <- context.loginAccount
|
loginAccount <- context.loginAccount
|
||||||
(issue, pullreq) <- getPullRequest(baseRepository.owner, baseRepository.name, issueId)
|
(issue, pullreq) <- getPullRequest(baseRepository.owner, baseRepository.name, issueId)
|
||||||
|
repository <- getRepository(pullreq.requestUserName, pullreq.requestRepositoryName)
|
||||||
|
remoteRepository <- getRepository(pullreq.userName, pullreq.repositoryName)
|
||||||
owner = pullreq.requestUserName
|
owner = pullreq.requestUserName
|
||||||
name = pullreq.requestRepositoryName
|
name = pullreq.requestRepositoryName
|
||||||
if hasDeveloperRole(owner, name, context.loginAccount)
|
if hasDeveloperRole(owner, name, context.loginAccount)
|
||||||
} yield {
|
} yield {
|
||||||
val repository = getRepository(owner, name).get
|
|
||||||
val branchProtection = getProtectedBranchInfo(owner, name, pullreq.requestBranch)
|
val branchProtection = getProtectedBranchInfo(owner, name, pullreq.requestBranch)
|
||||||
if (branchProtection.needStatusCheck(loginAccount.userName)) {
|
if (branchProtection.needStatusCheck(loginAccount.userName)) {
|
||||||
flash += "error" -> s"branch ${pullreq.requestBranch} is protected need status check."
|
flash += "error" -> s"branch ${pullreq.requestBranch} is protected need status check."
|
||||||
@@ -314,83 +316,19 @@ trait PullRequestsControllerBase extends ControllerBase {
|
|||||||
JGitUtil.getAllCommitIds(git)
|
JGitUtil.getAllCommitIds(git)
|
||||||
}.toSet
|
}.toSet
|
||||||
pullRemote(
|
pullRemote(
|
||||||
owner,
|
repository,
|
||||||
name,
|
|
||||||
pullreq.requestBranch,
|
pullreq.requestBranch,
|
||||||
pullreq.userName,
|
remoteRepository,
|
||||||
pullreq.repositoryName,
|
|
||||||
pullreq.branch,
|
pullreq.branch,
|
||||||
loginAccount,
|
loginAccount,
|
||||||
s"Merge branch '${alias}' into ${pullreq.requestBranch}"
|
s"Merge branch '${alias}' into ${pullreq.requestBranch}",
|
||||||
|
Some(pullreq)
|
||||||
) match {
|
) match {
|
||||||
case None => // conflict
|
case None => // conflict
|
||||||
flash += "error" -> s"Can't automatic merging branch '${alias}' into ${pullreq.requestBranch}."
|
flash += "error" -> s"Can't automatic merging branch '${alias}' into ${pullreq.requestBranch}."
|
||||||
case Some(oldId) =>
|
case Some(oldId) =>
|
||||||
// update pull request
|
// update pull request
|
||||||
updatePullRequests(owner, name, pullreq.requestBranch)
|
updatePullRequests(owner, name, pullreq.requestBranch, loginAccount, "synchronize")
|
||||||
|
|
||||||
using(Git.open(Directory.getRepositoryDir(owner, name))) {
|
|
||||||
git =>
|
|
||||||
// after update branch
|
|
||||||
val newCommitId = git.getRepository.resolve(s"refs/heads/${pullreq.requestBranch}")
|
|
||||||
val commits = git.log
|
|
||||||
.addRange(oldId, newCommitId)
|
|
||||||
.call
|
|
||||||
.iterator
|
|
||||||
.asScala
|
|
||||||
.map(c => new JGitUtil.CommitInfo(c))
|
|
||||||
.toList
|
|
||||||
|
|
||||||
commits.foreach { commit =>
|
|
||||||
if (!existIds.contains(commit.id)) {
|
|
||||||
createIssueComment(owner, name, commit)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// record activity
|
|
||||||
recordPushActivity(owner, name, loginAccount.userName, pullreq.branch, commits)
|
|
||||||
|
|
||||||
// close issue by commit message
|
|
||||||
if (pullreq.requestBranch == repository.repository.defaultBranch) {
|
|
||||||
commits.foreach { commit =>
|
|
||||||
closeIssuesFromMessage(commit.fullMessage, loginAccount.userName, owner, name).foreach {
|
|
||||||
issueId =>
|
|
||||||
getIssue(repository.owner, repository.name, issueId.toString).foreach { issue =>
|
|
||||||
callIssuesWebHook("closed", repository, issue, baseUrl, loginAccount)
|
|
||||||
PluginRegistry().getIssueHooks
|
|
||||||
.foreach(
|
|
||||||
_.closedByCommitComment(issue, repository, commit.fullMessage, loginAccount)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// call web hook
|
|
||||||
callPullRequestWebHookByRequestBranch(
|
|
||||||
"synchronize",
|
|
||||||
repository,
|
|
||||||
pullreq.requestBranch,
|
|
||||||
baseUrl,
|
|
||||||
loginAccount
|
|
||||||
)
|
|
||||||
callWebHookOf(owner, name, WebHook.Push) {
|
|
||||||
for {
|
|
||||||
ownerAccount <- getAccountByUserName(owner)
|
|
||||||
} yield {
|
|
||||||
WebHookService.WebHookPushPayload(
|
|
||||||
git,
|
|
||||||
loginAccount,
|
|
||||||
pullreq.requestBranch,
|
|
||||||
repository,
|
|
||||||
commits,
|
|
||||||
ownerAccount,
|
|
||||||
oldId = oldId,
|
|
||||||
newId = newCommitId
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
flash += "info" -> s"Merge branch '${alias}' into ${pullreq.requestBranch}"
|
flash += "info" -> s"Merge branch '${alias}' into ${pullreq.requestBranch}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -401,119 +339,14 @@ trait PullRequestsControllerBase extends ControllerBase {
|
|||||||
})
|
})
|
||||||
|
|
||||||
post("/:owner/:repository/pull/:id/merge", mergeForm)(writableUsersOnly { (form, repository) =>
|
post("/:owner/:repository/pull/:id/merge", mergeForm)(writableUsersOnly { (form, repository) =>
|
||||||
params("id").toIntOpt.flatMap {
|
params("id").toIntOpt.flatMap { issueId =>
|
||||||
issueId =>
|
|
||||||
val owner = repository.owner
|
val owner = repository.owner
|
||||||
val name = repository.name
|
val name = repository.name
|
||||||
if (repository.repository.options.mergeOptions.split(",").contains(form.strategy)) {
|
|
||||||
LockUtil.lock(s"${owner}/${name}") {
|
|
||||||
getPullRequest(owner, name, issueId).map {
|
|
||||||
case (issue, pullreq) =>
|
|
||||||
using(Git.open(getRepositoryDir(owner, name))) {
|
|
||||||
git =>
|
|
||||||
// mark issue as merged and close.
|
|
||||||
val loginAccount = context.loginAccount.get
|
|
||||||
val commentId = createComment(owner, name, loginAccount.userName, issueId, form.message, "merge")
|
|
||||||
createComment(owner, name, loginAccount.userName, issueId, "Close", "close")
|
|
||||||
updateClosed(owner, name, issueId, true)
|
|
||||||
|
|
||||||
// record activity
|
mergePullRequest(repository, issueId, context.loginAccount.get, form.message, form.strategy) match {
|
||||||
recordMergeActivity(owner, name, loginAccount.userName, issueId, form.message)
|
case Right(objectId) => redirect(s"/${owner}/${name}/pull/${issueId}")
|
||||||
|
case Left(message) => Some(BadRequest())
|
||||||
val (commits, _) = getRequestCompareInfo(
|
|
||||||
owner,
|
|
||||||
name,
|
|
||||||
pullreq.commitIdFrom,
|
|
||||||
pullreq.requestUserName,
|
|
||||||
pullreq.requestRepositoryName,
|
|
||||||
pullreq.commitIdTo
|
|
||||||
)
|
|
||||||
|
|
||||||
val revCommits = using(new RevWalk(git.getRepository)) { revWalk =>
|
|
||||||
commits.flatten.map { commit =>
|
|
||||||
revWalk.parseCommit(git.getRepository.resolve(commit.id))
|
|
||||||
}
|
}
|
||||||
}.reverse
|
|
||||||
|
|
||||||
// merge git repository
|
|
||||||
form.strategy match {
|
|
||||||
case "merge-commit" =>
|
|
||||||
mergePullRequest(
|
|
||||||
git,
|
|
||||||
pullreq.branch,
|
|
||||||
issueId,
|
|
||||||
s"Merge pull request #${issueId} from ${pullreq.requestUserName}/${pullreq.requestBranch}\n\n" + form.message,
|
|
||||||
new PersonIdent(loginAccount.fullName, loginAccount.mailAddress)
|
|
||||||
)
|
|
||||||
case "rebase" =>
|
|
||||||
rebasePullRequest(
|
|
||||||
git,
|
|
||||||
pullreq.branch,
|
|
||||||
issueId,
|
|
||||||
revCommits,
|
|
||||||
new PersonIdent(loginAccount.fullName, loginAccount.mailAddress)
|
|
||||||
)
|
|
||||||
case "squash" =>
|
|
||||||
squashPullRequest(
|
|
||||||
git,
|
|
||||||
pullreq.branch,
|
|
||||||
issueId,
|
|
||||||
s"${issue.title} (#${issueId})\n\n" + form.message,
|
|
||||||
new PersonIdent(loginAccount.fullName, loginAccount.mailAddress)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// close issue by content of pull request
|
|
||||||
val defaultBranch = getRepository(owner, name).get.repository.defaultBranch
|
|
||||||
if (pullreq.branch == defaultBranch) {
|
|
||||||
commits.flatten.foreach { commit =>
|
|
||||||
closeIssuesFromMessage(commit.fullMessage, loginAccount.userName, owner, name).foreach {
|
|
||||||
issueId =>
|
|
||||||
getIssue(owner, name, issueId.toString).foreach { issue =>
|
|
||||||
callIssuesWebHook("closed", repository, issue, baseUrl, loginAccount)
|
|
||||||
PluginRegistry().getIssueHooks
|
|
||||||
.foreach(_.closedByCommitComment(issue, repository, commit.fullMessage, loginAccount))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val issueContent = issue.title + " " + issue.content.getOrElse("")
|
|
||||||
closeIssuesFromMessage(
|
|
||||||
issueContent,
|
|
||||||
loginAccount.userName,
|
|
||||||
owner,
|
|
||||||
name
|
|
||||||
).foreach { issueId =>
|
|
||||||
getIssue(owner, name, issueId.toString).foreach { issue =>
|
|
||||||
callIssuesWebHook("closed", repository, issue, baseUrl, loginAccount)
|
|
||||||
PluginRegistry().getIssueHooks
|
|
||||||
.foreach(_.closedByCommitComment(issue, repository, issueContent, loginAccount))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
closeIssuesFromMessage(form.message, loginAccount.userName, owner, name).foreach { issueId =>
|
|
||||||
getIssue(owner, name, issueId.toString).foreach { issue =>
|
|
||||||
callIssuesWebHook("closed", repository, issue, baseUrl, loginAccount)
|
|
||||||
PluginRegistry().getIssueHooks
|
|
||||||
.foreach(_.closedByCommitComment(issue, repository, issueContent, loginAccount))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
updatePullRequests(owner, name, pullreq.branch)
|
|
||||||
|
|
||||||
// call web hook
|
|
||||||
callPullRequestWebHook("closed", repository, issueId, context.baseUrl, context.loginAccount.get)
|
|
||||||
|
|
||||||
// call hooks
|
|
||||||
PluginRegistry().getPullRequestHooks.foreach { h =>
|
|
||||||
h.addedComment(commentId, form.message, issue, repository)
|
|
||||||
h.merged(issue, repository)
|
|
||||||
}
|
|
||||||
|
|
||||||
redirect(s"/${owner}/${name}/pull/${issueId}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else Some(BadRequest())
|
|
||||||
} getOrElse NotFound()
|
} getOrElse NotFound()
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -731,7 +564,7 @@ trait PullRequestsControllerBase extends ControllerBase {
|
|||||||
recordPullRequestActivity(owner, name, loginUserName, issueId, form.title)
|
recordPullRequestActivity(owner, name, loginUserName, issueId, form.title)
|
||||||
|
|
||||||
// call web hook
|
// call web hook
|
||||||
callPullRequestWebHook("opened", repository, issueId, context.baseUrl, context.loginAccount.get)
|
callPullRequestWebHook("opened", repository, issueId, context.loginAccount.get)
|
||||||
|
|
||||||
getIssue(owner, name, issueId.toString) foreach { issue =>
|
getIssue(owner, name, issueId.toString) foreach { issue =>
|
||||||
// extract references and create refer comment
|
// extract references and create refer comment
|
||||||
|
|||||||
@@ -13,13 +13,11 @@ import gitbucket.core.util.SyntaxSugars._
|
|||||||
import gitbucket.core.util.Implicits._
|
import gitbucket.core.util.Implicits._
|
||||||
import gitbucket.core.util.Directory._
|
import gitbucket.core.util.Directory._
|
||||||
import org.scalatra.forms._
|
import org.scalatra.forms._
|
||||||
import org.apache.commons.io.FileUtils
|
|
||||||
import org.scalatra.i18n.Messages
|
import org.scalatra.i18n.Messages
|
||||||
import org.eclipse.jgit.api.Git
|
import org.eclipse.jgit.api.Git
|
||||||
import org.eclipse.jgit.lib.Constants
|
import org.eclipse.jgit.lib.Constants
|
||||||
import org.eclipse.jgit.lib.ObjectId
|
import org.eclipse.jgit.lib.ObjectId
|
||||||
import gitbucket.core.model.WebHookContentType
|
import gitbucket.core.model.WebHookContentType
|
||||||
import gitbucket.core.plugin.PluginRegistry
|
|
||||||
|
|
||||||
class RepositorySettingsController
|
class RepositorySettingsController
|
||||||
extends RepositorySettingsControllerBase
|
extends RepositorySettingsControllerBase
|
||||||
@@ -148,29 +146,6 @@ trait RepositorySettingsControllerBase extends ControllerBase {
|
|||||||
if (repository.name != form.repositoryName) {
|
if (repository.name != form.repositoryName) {
|
||||||
// Update database
|
// Update database
|
||||||
renameRepository(repository.owner, repository.name, repository.owner, form.repositoryName)
|
renameRepository(repository.owner, repository.name, repository.owner, form.repositoryName)
|
||||||
// Move git repository
|
|
||||||
defining(getRepositoryDir(repository.owner, repository.name)) { dir =>
|
|
||||||
if (dir.isDirectory) {
|
|
||||||
FileUtils.moveDirectory(dir, getRepositoryDir(repository.owner, form.repositoryName))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Move wiki repository
|
|
||||||
defining(getWikiRepositoryDir(repository.owner, repository.name)) { dir =>
|
|
||||||
if (dir.isDirectory) {
|
|
||||||
FileUtils.moveDirectory(dir, getWikiRepositoryDir(repository.owner, form.repositoryName))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Move files directory
|
|
||||||
defining(getRepositoryFilesDir(repository.owner, repository.name)) { dir =>
|
|
||||||
if (dir.isDirectory) {
|
|
||||||
FileUtils.moveDirectory(dir, getRepositoryFilesDir(repository.owner, form.repositoryName))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Delete parent directory
|
|
||||||
FileUtil.deleteDirectoryIfEmpty(getRepositoryFilesDir(repository.owner, repository.name))
|
|
||||||
|
|
||||||
// Call hooks
|
|
||||||
PluginRegistry().getRepositoryHooks.foreach(_.renamed(repository.owner, repository.name, form.repositoryName))
|
|
||||||
}
|
}
|
||||||
flash += "info" -> "Repository settings has been updated."
|
flash += "info" -> "Repository settings has been updated."
|
||||||
redirect(s"/${repository.owner}/${form.repositoryName}/settings/options")
|
redirect(s"/${repository.owner}/${form.repositoryName}/settings/options")
|
||||||
@@ -392,31 +367,7 @@ trait RepositorySettingsControllerBase extends ControllerBase {
|
|||||||
post("/:owner/:repository/settings/transfer", transferForm)(ownerOnly { (form, repository) =>
|
post("/:owner/:repository/settings/transfer", transferForm)(ownerOnly { (form, repository) =>
|
||||||
// Change repository owner
|
// Change repository owner
|
||||||
if (repository.owner != form.newOwner) {
|
if (repository.owner != form.newOwner) {
|
||||||
LockUtil.lock(s"${repository.owner}/${repository.name}") {
|
|
||||||
// Update database
|
|
||||||
renameRepository(repository.owner, repository.name, form.newOwner, repository.name)
|
renameRepository(repository.owner, repository.name, form.newOwner, repository.name)
|
||||||
// Move git repository
|
|
||||||
defining(getRepositoryDir(repository.owner, repository.name)) { dir =>
|
|
||||||
if (dir.isDirectory) {
|
|
||||||
FileUtils.moveDirectory(dir, getRepositoryDir(form.newOwner, repository.name))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Move wiki repository
|
|
||||||
defining(getWikiRepositoryDir(repository.owner, repository.name)) { dir =>
|
|
||||||
if (dir.isDirectory) {
|
|
||||||
FileUtils.moveDirectory(dir, getWikiRepositoryDir(form.newOwner, repository.name))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Move files directory
|
|
||||||
defining(getRepositoryFilesDir(repository.owner, repository.name)) { dir =>
|
|
||||||
if (dir.isDirectory) {
|
|
||||||
FileUtils.moveDirectory(dir, getRepositoryFilesDir(form.newOwner, repository.name))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Call hooks
|
|
||||||
PluginRegistry().getRepositoryHooks.foreach(_.transferred(repository.owner, form.newOwner, repository.name))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
redirect(s"/${form.newOwner}/${repository.name}")
|
redirect(s"/${form.newOwner}/${repository.name}")
|
||||||
})
|
})
|
||||||
@@ -425,19 +376,8 @@ trait RepositorySettingsControllerBase extends ControllerBase {
|
|||||||
* Delete the repository.
|
* Delete the repository.
|
||||||
*/
|
*/
|
||||||
post("/:owner/:repository/settings/delete")(ownerOnly { repository =>
|
post("/:owner/:repository/settings/delete")(ownerOnly { repository =>
|
||||||
LockUtil.lock(s"${repository.owner}/${repository.name}") {
|
|
||||||
// Delete the repository and related files
|
// Delete the repository and related files
|
||||||
deleteRepository(repository.owner, repository.name)
|
deleteRepository(repository.repository)
|
||||||
|
|
||||||
FileUtils.deleteDirectory(getRepositoryDir(repository.owner, repository.name))
|
|
||||||
FileUtils.deleteDirectory(getWikiRepositoryDir(repository.owner, repository.name))
|
|
||||||
FileUtils.deleteDirectory(getTemporaryDir(repository.owner, repository.name))
|
|
||||||
FileUtils.deleteDirectory(getRepositoryFilesDir(repository.owner, repository.name))
|
|
||||||
|
|
||||||
// Call hooks
|
|
||||||
PluginRegistry().getRepositoryHooks.foreach(_.deleted(repository.owner, repository.name))
|
|
||||||
}
|
|
||||||
|
|
||||||
redirect(s"/${repository.owner}")
|
redirect(s"/${repository.owner}")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -7,14 +7,13 @@ import gitbucket.core.plugin.PluginRegistry
|
|||||||
import gitbucket.core.repo.html
|
import gitbucket.core.repo.html
|
||||||
import gitbucket.core.helper
|
import gitbucket.core.helper
|
||||||
import gitbucket.core.service._
|
import gitbucket.core.service._
|
||||||
|
import gitbucket.core.service.RepositoryCommitFileService.CommitFile
|
||||||
import gitbucket.core.util._
|
import gitbucket.core.util._
|
||||||
import gitbucket.core.util.JGitUtil._
|
|
||||||
import gitbucket.core.util.StringUtil._
|
import gitbucket.core.util.StringUtil._
|
||||||
import gitbucket.core.util.SyntaxSugars._
|
import gitbucket.core.util.SyntaxSugars._
|
||||||
import gitbucket.core.util.Implicits._
|
import gitbucket.core.util.Implicits._
|
||||||
import gitbucket.core.util.Directory._
|
import gitbucket.core.util.Directory._
|
||||||
import gitbucket.core.model.{Account, CommitState, CommitStatus, WebHook}
|
import gitbucket.core.model.{Account, CommitState, CommitStatus}
|
||||||
import gitbucket.core.service.WebHookService._
|
|
||||||
import gitbucket.core.view
|
import gitbucket.core.view
|
||||||
import gitbucket.core.view.helpers
|
import gitbucket.core.view.helpers
|
||||||
import org.apache.commons.compress.archivers.{ArchiveEntry, ArchiveOutputStream}
|
import org.apache.commons.compress.archivers.{ArchiveEntry, ArchiveOutputStream}
|
||||||
@@ -24,15 +23,12 @@ import org.apache.commons.compress.compressors.bzip2.BZip2CompressorOutputStream
|
|||||||
import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream
|
import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream
|
||||||
import org.apache.commons.compress.compressors.xz.XZCompressorOutputStream
|
import org.apache.commons.compress.compressors.xz.XZCompressorOutputStream
|
||||||
import org.apache.commons.compress.utils.IOUtils
|
import org.apache.commons.compress.utils.IOUtils
|
||||||
import org.scalatra.forms._
|
|
||||||
import org.apache.commons.io.FileUtils
|
import org.apache.commons.io.FileUtils
|
||||||
import org.ec4j.core.model.PropertyType
|
import org.scalatra.forms._
|
||||||
import org.eclipse.jgit.api.{ArchiveCommand, Git}
|
import org.eclipse.jgit.api.{ArchiveCommand, Git}
|
||||||
import org.eclipse.jgit.archive.{TgzFormat, ZipFormat}
|
import org.eclipse.jgit.archive.{TgzFormat, ZipFormat}
|
||||||
import org.eclipse.jgit.dircache.{DirCache, DirCacheBuilder}
|
|
||||||
import org.eclipse.jgit.errors.MissingObjectException
|
import org.eclipse.jgit.errors.MissingObjectException
|
||||||
import org.eclipse.jgit.lib._
|
import org.eclipse.jgit.lib._
|
||||||
import org.eclipse.jgit.transport.{ReceiveCommand, ReceivePack}
|
|
||||||
import org.eclipse.jgit.treewalk.TreeWalk
|
import org.eclipse.jgit.treewalk.TreeWalk
|
||||||
import org.eclipse.jgit.treewalk.filter.PathFilter
|
import org.eclipse.jgit.treewalk.filter.PathFilter
|
||||||
import org.json4s.jackson.Serialization
|
import org.json4s.jackson.Serialization
|
||||||
@@ -42,6 +38,7 @@ import org.scalatra.i18n.Messages
|
|||||||
class RepositoryViewerController
|
class RepositoryViewerController
|
||||||
extends RepositoryViewerControllerBase
|
extends RepositoryViewerControllerBase
|
||||||
with RepositoryService
|
with RepositoryService
|
||||||
|
with RepositoryCommitFileService
|
||||||
with AccountService
|
with AccountService
|
||||||
with ActivityService
|
with ActivityService
|
||||||
with IssuesService
|
with IssuesService
|
||||||
@@ -64,6 +61,7 @@ class RepositoryViewerController
|
|||||||
*/
|
*/
|
||||||
trait RepositoryViewerControllerBase extends ControllerBase {
|
trait RepositoryViewerControllerBase extends ControllerBase {
|
||||||
self: RepositoryService
|
self: RepositoryService
|
||||||
|
with RepositoryCommitFileService
|
||||||
with AccountService
|
with AccountService
|
||||||
with ActivityService
|
with ActivityService
|
||||||
with IssuesService
|
with IssuesService
|
||||||
@@ -319,13 +317,34 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
|||||||
CommitFile(line.substring(0, i).trim, line.substring(i + 1).trim)
|
CommitFile(line.substring(0, i).trim, line.substring(i + 1).trim)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val newFiles = files.map { file =>
|
||||||
|
file.copy(name = if (form.path.length == 0) file.name else s"${form.path}/${file.name}")
|
||||||
|
}
|
||||||
|
|
||||||
commitFiles(
|
commitFiles(
|
||||||
repository = repository,
|
repository = repository,
|
||||||
branch = form.branch,
|
branch = form.branch,
|
||||||
path = form.path,
|
path = form.path,
|
||||||
files = files,
|
files = files,
|
||||||
message = form.message.getOrElse("Add files via upload")
|
message = form.message.getOrElse("Add files via upload"),
|
||||||
|
loginAccount = context.loginAccount.get
|
||||||
|
) {
|
||||||
|
case (git, headTip, builder, inserter) =>
|
||||||
|
JGitUtil.processTree(git, headTip) { (path, tree) =>
|
||||||
|
if (!newFiles.exists(_.name.contains(path))) {
|
||||||
|
builder.add(JGitUtil.createDirCacheEntry(path, tree.getEntryFileMode, tree.getEntryObjectId))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
newFiles.foreach { file =>
|
||||||
|
val bytes =
|
||||||
|
FileUtils.readFileToByteArray(new File(getTemporaryDir(session.getId), FileUtil.checkFilename(file.id)))
|
||||||
|
builder.add(
|
||||||
|
JGitUtil.createDirCacheEntry(file.name, FileMode.REGULAR_FILE, inserter.insert(Constants.OBJ_BLOB, bytes))
|
||||||
)
|
)
|
||||||
|
builder.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (form.path.length == 0) {
|
if (form.path.length == 0) {
|
||||||
redirect(s"/${repository.owner}/${repository.name}/tree/${form.branch}")
|
redirect(s"/${repository.owner}/${repository.name}/tree/${form.branch}")
|
||||||
@@ -394,7 +413,8 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
|||||||
content = appendNewLine(convertLineSeparator(form.content, form.lineSeparator), form.lineSeparator),
|
content = appendNewLine(convertLineSeparator(form.content, form.lineSeparator), form.lineSeparator),
|
||||||
charset = form.charset,
|
charset = form.charset,
|
||||||
message = form.message.getOrElse(s"Create ${form.newFileName}"),
|
message = form.message.getOrElse(s"Create ${form.newFileName}"),
|
||||||
commit = form.commit
|
commit = form.commit,
|
||||||
|
loginAccount = context.loginAccount.get
|
||||||
)
|
)
|
||||||
|
|
||||||
redirect(
|
redirect(
|
||||||
@@ -417,7 +437,8 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
|||||||
} else {
|
} else {
|
||||||
form.message.getOrElse(s"Rename ${form.oldFileName.get} to ${form.newFileName}")
|
form.message.getOrElse(s"Rename ${form.oldFileName.get} to ${form.newFileName}")
|
||||||
},
|
},
|
||||||
commit = form.commit
|
commit = form.commit,
|
||||||
|
loginAccount = context.loginAccount.get
|
||||||
)
|
)
|
||||||
|
|
||||||
redirect(
|
redirect(
|
||||||
@@ -436,7 +457,8 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
|||||||
content = "",
|
content = "",
|
||||||
charset = "",
|
charset = "",
|
||||||
message = form.message.getOrElse(s"Delete ${form.fileName}"),
|
message = form.message.getOrElse(s"Delete ${form.fileName}"),
|
||||||
commit = form.commit
|
commit = form.commit,
|
||||||
|
loginAccount = context.loginAccount.get
|
||||||
)
|
)
|
||||||
|
|
||||||
println(form.path)
|
println(form.path)
|
||||||
@@ -593,50 +615,17 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
|||||||
post("/:owner/:repository/commit/:id/comment/new", commentForm)(readableUsersOnly { (form, repository) =>
|
post("/:owner/:repository/commit/:id/comment/new", commentForm)(readableUsersOnly { (form, repository) =>
|
||||||
val id = params("id")
|
val id = params("id")
|
||||||
createCommitComment(
|
createCommitComment(
|
||||||
repository.owner,
|
repository,
|
||||||
repository.name,
|
|
||||||
id,
|
id,
|
||||||
context.loginAccount.get.userName,
|
context.loginAccount.get,
|
||||||
form.content,
|
form.content,
|
||||||
form.fileName,
|
form.fileName,
|
||||||
form.oldLineNumber,
|
form.oldLineNumber,
|
||||||
form.newLineNumber,
|
form.newLineNumber,
|
||||||
|
form.diff,
|
||||||
form.issueId
|
form.issueId
|
||||||
)
|
)
|
||||||
|
|
||||||
for {
|
|
||||||
fileName <- form.fileName
|
|
||||||
diff <- form.diff
|
|
||||||
} {
|
|
||||||
saveCommitCommentDiff(
|
|
||||||
repository.owner,
|
|
||||||
repository.name,
|
|
||||||
id,
|
|
||||||
fileName,
|
|
||||||
form.oldLineNumber,
|
|
||||||
form.newLineNumber,
|
|
||||||
diff
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
form.issueId match {
|
|
||||||
case Some(issueId) =>
|
|
||||||
recordCommentPullRequestActivity(
|
|
||||||
repository.owner,
|
|
||||||
repository.name,
|
|
||||||
context.loginAccount.get.userName,
|
|
||||||
issueId,
|
|
||||||
form.content
|
|
||||||
)
|
|
||||||
case None =>
|
|
||||||
recordCommentCommitActivity(
|
|
||||||
repository.owner,
|
|
||||||
repository.name,
|
|
||||||
context.loginAccount.get.userName,
|
|
||||||
id,
|
|
||||||
form.content
|
|
||||||
)
|
|
||||||
}
|
|
||||||
redirect(s"/${repository.owner}/${repository.name}/commit/${id}")
|
redirect(s"/${repository.owner}/${repository.name}/commit/${id}")
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -661,64 +650,18 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
|||||||
ajaxPost("/:owner/:repository/commit/:id/comment/_data/new", commentForm)(readableUsersOnly { (form, repository) =>
|
ajaxPost("/:owner/:repository/commit/:id/comment/_data/new", commentForm)(readableUsersOnly { (form, repository) =>
|
||||||
val id = params("id")
|
val id = params("id")
|
||||||
val commentId = createCommitComment(
|
val commentId = createCommitComment(
|
||||||
repository.owner,
|
repository,
|
||||||
repository.name,
|
|
||||||
id,
|
id,
|
||||||
context.loginAccount.get.userName,
|
context.loginAccount.get,
|
||||||
form.content,
|
form.content,
|
||||||
form.fileName,
|
form.fileName,
|
||||||
form.oldLineNumber,
|
form.oldLineNumber,
|
||||||
form.newLineNumber,
|
form.newLineNumber,
|
||||||
|
form.diff,
|
||||||
form.issueId
|
form.issueId
|
||||||
)
|
)
|
||||||
|
|
||||||
for {
|
|
||||||
fileName <- form.fileName
|
|
||||||
diff <- form.diff
|
|
||||||
} {
|
|
||||||
saveCommitCommentDiff(
|
|
||||||
repository.owner,
|
|
||||||
repository.name,
|
|
||||||
id,
|
|
||||||
fileName,
|
|
||||||
form.oldLineNumber,
|
|
||||||
form.newLineNumber,
|
|
||||||
diff
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
val comment = getCommitComment(repository.owner, repository.name, commentId.toString).get
|
val comment = getCommitComment(repository.owner, repository.name, commentId.toString).get
|
||||||
form.issueId match {
|
|
||||||
case Some(issueId) =>
|
|
||||||
getPullRequest(repository.owner, repository.name, issueId).foreach {
|
|
||||||
case (issue, pullRequest) =>
|
|
||||||
recordCommentPullRequestActivity(
|
|
||||||
repository.owner,
|
|
||||||
repository.name,
|
|
||||||
context.loginAccount.get.userName,
|
|
||||||
issueId,
|
|
||||||
form.content
|
|
||||||
)
|
|
||||||
PluginRegistry().getPullRequestHooks.foreach(_.addedComment(commentId, form.content, issue, repository))
|
|
||||||
callPullRequestReviewCommentWebHook(
|
|
||||||
"create",
|
|
||||||
comment,
|
|
||||||
repository,
|
|
||||||
issue,
|
|
||||||
pullRequest,
|
|
||||||
context.baseUrl,
|
|
||||||
context.loginAccount.get
|
|
||||||
)
|
|
||||||
}
|
|
||||||
case None =>
|
|
||||||
recordCommentCommitActivity(
|
|
||||||
repository.owner,
|
|
||||||
repository.name,
|
|
||||||
context.loginAccount.get.userName,
|
|
||||||
id,
|
|
||||||
form.content
|
|
||||||
)
|
|
||||||
}
|
|
||||||
helper.html
|
helper.html
|
||||||
.commitcomment(comment, hasDeveloperRole(repository.owner, repository.name, context.loginAccount), repository)
|
.commitcomment(comment, hasDeveloperRole(repository.owner, repository.name, context.loginAccount), repository)
|
||||||
})
|
})
|
||||||
@@ -930,185 +873,6 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
|||||||
lazy val isValid: Boolean = fileIds.nonEmpty
|
lazy val isValid: Boolean = fileIds.nonEmpty
|
||||||
}
|
}
|
||||||
|
|
||||||
case class CommitFile(id: String, name: String)
|
|
||||||
|
|
||||||
private def commitFiles(
|
|
||||||
repository: RepositoryService.RepositoryInfo,
|
|
||||||
files: Seq[CommitFile],
|
|
||||||
branch: String,
|
|
||||||
path: String,
|
|
||||||
message: String
|
|
||||||
) = {
|
|
||||||
// prepend path to the filename
|
|
||||||
val newFiles = files.map { file =>
|
|
||||||
file.copy(name = if (path.length == 0) file.name else s"${path}/${file.name}")
|
|
||||||
}
|
|
||||||
|
|
||||||
_commitFile(repository, branch, message) {
|
|
||||||
case (git, headTip, builder, inserter) =>
|
|
||||||
JGitUtil.processTree(git, headTip) { (path, tree) =>
|
|
||||||
if (!newFiles.exists(_.name.contains(path))) {
|
|
||||||
builder.add(JGitUtil.createDirCacheEntry(path, tree.getEntryFileMode, tree.getEntryObjectId))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
newFiles.foreach { file =>
|
|
||||||
val bytes =
|
|
||||||
FileUtils.readFileToByteArray(new File(getTemporaryDir(session.getId), FileUtil.checkFilename(file.id)))
|
|
||||||
builder.add(
|
|
||||||
JGitUtil.createDirCacheEntry(file.name, FileMode.REGULAR_FILE, inserter.insert(Constants.OBJ_BLOB, bytes))
|
|
||||||
)
|
|
||||||
builder.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private def commitFile(
|
|
||||||
repository: RepositoryService.RepositoryInfo,
|
|
||||||
branch: String,
|
|
||||||
path: String,
|
|
||||||
newFileName: Option[String],
|
|
||||||
oldFileName: Option[String],
|
|
||||||
content: String,
|
|
||||||
charset: String,
|
|
||||||
message: String,
|
|
||||||
commit: String
|
|
||||||
) = {
|
|
||||||
|
|
||||||
val newPath = newFileName.map { newFileName =>
|
|
||||||
if (path.length == 0) newFileName else s"${path}/${newFileName}"
|
|
||||||
}
|
|
||||||
val oldPath = oldFileName.map { oldFileName =>
|
|
||||||
if (path.length == 0) oldFileName else s"${path}/${oldFileName}"
|
|
||||||
}
|
|
||||||
|
|
||||||
_commitFile(repository, branch, message) {
|
|
||||||
case (git, headTip, builder, inserter) =>
|
|
||||||
if (headTip.getName == commit) {
|
|
||||||
val permission = JGitUtil
|
|
||||||
.processTree(git, headTip) { (path, tree) =>
|
|
||||||
// Add all entries except the editing file
|
|
||||||
if (!newPath.contains(path) && !oldPath.contains(path)) {
|
|
||||||
builder.add(JGitUtil.createDirCacheEntry(path, tree.getEntryFileMode, tree.getEntryObjectId))
|
|
||||||
}
|
|
||||||
// Retrieve permission if file exists to keep it
|
|
||||||
oldPath.collect { case x if x == path => tree.getEntryFileMode.getBits }
|
|
||||||
}
|
|
||||||
.flatten
|
|
||||||
.headOption
|
|
||||||
|
|
||||||
newPath.foreach { newPath =>
|
|
||||||
builder.add(JGitUtil.createDirCacheEntry(newPath, permission.map { bits =>
|
|
||||||
FileMode.fromBits(bits)
|
|
||||||
} getOrElse FileMode.REGULAR_FILE, inserter.insert(Constants.OBJ_BLOB, content.getBytes(charset))))
|
|
||||||
}
|
|
||||||
builder.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private def _commitFile(repository: RepositoryService.RepositoryInfo, branch: String, message: String)(
|
|
||||||
f: (Git, ObjectId, DirCacheBuilder, ObjectInserter) => Unit
|
|
||||||
) = {
|
|
||||||
|
|
||||||
LockUtil.lock(s"${repository.owner}/${repository.name}") {
|
|
||||||
using(Git.open(getRepositoryDir(repository.owner, repository.name))) { git =>
|
|
||||||
val loginAccount = context.loginAccount.get
|
|
||||||
val builder = DirCache.newInCore.builder()
|
|
||||||
val inserter = git.getRepository.newObjectInserter()
|
|
||||||
val headName = s"refs/heads/${branch}"
|
|
||||||
val headTip = git.getRepository.resolve(headName)
|
|
||||||
|
|
||||||
f(git, headTip, builder, inserter)
|
|
||||||
|
|
||||||
val commitId = JGitUtil.createNewCommit(
|
|
||||||
git,
|
|
||||||
inserter,
|
|
||||||
headTip,
|
|
||||||
builder.getDirCache.writeTree(inserter),
|
|
||||||
headName,
|
|
||||||
loginAccount.fullName,
|
|
||||||
loginAccount.mailAddress,
|
|
||||||
message
|
|
||||||
)
|
|
||||||
|
|
||||||
inserter.flush()
|
|
||||||
inserter.close()
|
|
||||||
|
|
||||||
val receivePack = new ReceivePack(git.getRepository)
|
|
||||||
val receiveCommand = new ReceiveCommand(headTip, commitId, headName)
|
|
||||||
|
|
||||||
// call post commit hook
|
|
||||||
val error = PluginRegistry().getReceiveHooks.flatMap { hook =>
|
|
||||||
hook.preReceive(repository.owner, repository.name, receivePack, receiveCommand, loginAccount.userName)
|
|
||||||
}.headOption
|
|
||||||
|
|
||||||
error match {
|
|
||||||
case Some(error) =>
|
|
||||||
// commit is rejected
|
|
||||||
// TODO Notify commit failure to edited user
|
|
||||||
val refUpdate = git.getRepository.updateRef(headName)
|
|
||||||
refUpdate.setNewObjectId(headTip)
|
|
||||||
refUpdate.setForceUpdate(true)
|
|
||||||
refUpdate.update()
|
|
||||||
|
|
||||||
case None =>
|
|
||||||
// update refs
|
|
||||||
val refUpdate = git.getRepository.updateRef(headName)
|
|
||||||
refUpdate.setNewObjectId(commitId)
|
|
||||||
refUpdate.setForceUpdate(false)
|
|
||||||
refUpdate.setRefLogIdent(new PersonIdent(loginAccount.fullName, loginAccount.mailAddress))
|
|
||||||
refUpdate.update()
|
|
||||||
|
|
||||||
// update pull request
|
|
||||||
updatePullRequests(repository.owner, repository.name, branch)
|
|
||||||
|
|
||||||
// record activity
|
|
||||||
val commitInfo = new CommitInfo(JGitUtil.getRevCommitFromId(git, commitId))
|
|
||||||
recordPushActivity(repository.owner, repository.name, loginAccount.userName, branch, List(commitInfo))
|
|
||||||
|
|
||||||
// create issue comment by commit message
|
|
||||||
createIssueComment(repository.owner, repository.name, commitInfo)
|
|
||||||
|
|
||||||
// close issue by commit message
|
|
||||||
if (branch == repository.repository.defaultBranch) {
|
|
||||||
closeIssuesFromMessage(message, loginAccount.userName, repository.owner, repository.name).foreach {
|
|
||||||
issueId =>
|
|
||||||
getIssue(repository.owner, repository.name, issueId.toString).foreach { issue =>
|
|
||||||
callIssuesWebHook("closed", repository, issue, baseUrl, loginAccount)
|
|
||||||
PluginRegistry().getIssueHooks
|
|
||||||
.foreach(_.closedByCommitComment(issue, repository, message, loginAccount))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// call post commit hook
|
|
||||||
PluginRegistry().getReceiveHooks.foreach { hook =>
|
|
||||||
hook.postReceive(repository.owner, repository.name, receivePack, receiveCommand, loginAccount.userName)
|
|
||||||
}
|
|
||||||
|
|
||||||
//call web hook
|
|
||||||
callPullRequestWebHookByRequestBranch("synchronize", repository, branch, context.baseUrl, loginAccount)
|
|
||||||
val commit = new JGitUtil.CommitInfo(JGitUtil.getRevCommitFromId(git, commitId))
|
|
||||||
callWebHookOf(repository.owner, repository.name, WebHook.Push) {
|
|
||||||
getAccountByUserName(repository.owner).map { ownerAccount =>
|
|
||||||
WebHookPushPayload(
|
|
||||||
git,
|
|
||||||
loginAccount,
|
|
||||||
headName,
|
|
||||||
repository,
|
|
||||||
List(commit),
|
|
||||||
ownerAccount,
|
|
||||||
oldId = headTip,
|
|
||||||
newId = commitId
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val readmeFiles = PluginRegistry().renderableExtensions.map { extension =>
|
private val readmeFiles = PluginRegistry().renderableExtensions.map { extension =>
|
||||||
s"readme.${extension}"
|
s"readme.${extension}"
|
||||||
} ++ Seq("readme.txt", "readme")
|
} ++ Seq("readme.txt", "readme")
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import gitbucket.core.service.RepositoryService.RepositoryInfo
|
|||||||
import gitbucket.core.service.SystemSettingsService.SystemSettings
|
import gitbucket.core.service.SystemSettingsService.SystemSettings
|
||||||
import gitbucket.core.util.SyntaxSugars._
|
import gitbucket.core.util.SyntaxSugars._
|
||||||
import io.github.gitbucket.solidbase.model.Version
|
import io.github.gitbucket.solidbase.model.Version
|
||||||
import org.apache.sshd.server.command.Command
|
import org.apache.sshd.server.Command
|
||||||
import play.twirl.api.Html
|
import play.twirl.api.Html
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import io.github.gitbucket.solidbase.manager.JDBCVersionManager
|
|||||||
import io.github.gitbucket.solidbase.model.Module
|
import io.github.gitbucket.solidbase.model.Module
|
||||||
import org.apache.commons.io.FileUtils
|
import org.apache.commons.io.FileUtils
|
||||||
import org.apache.http.client.methods.HttpGet
|
import org.apache.http.client.methods.HttpGet
|
||||||
import org.apache.sshd.server.command.Command
|
import org.apache.sshd.server.Command
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import play.twirl.api.Html
|
import play.twirl.api.Html
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import gitbucket.core.model.Profile.profile.blockingApi._
|
|||||||
import gitbucket.core.model.Profile.dateColumnType
|
import gitbucket.core.model.Profile.dateColumnType
|
||||||
import gitbucket.core.util.{LDAPUtil, StringUtil}
|
import gitbucket.core.util.{LDAPUtil, StringUtil}
|
||||||
import StringUtil._
|
import StringUtil._
|
||||||
|
import gitbucket.core.plugin.PluginRegistry
|
||||||
import gitbucket.core.service.SystemSettingsService.SystemSettings
|
import gitbucket.core.service.SystemSettingsService.SystemSettings
|
||||||
|
|
||||||
trait AccountService {
|
trait AccountService {
|
||||||
@@ -183,6 +184,15 @@ trait AccountService {
|
|||||||
account
|
account
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def suspendAccount(account: Account)(implicit s: Session): Unit = {
|
||||||
|
// Remove from GROUP_MEMBER and COLLABORATOR
|
||||||
|
removeUserRelatedData(account.userName)
|
||||||
|
updateAccount(account.copy(isRemoved = true))
|
||||||
|
|
||||||
|
// call hooks
|
||||||
|
PluginRegistry().getAccountHooks.foreach(_.deleted(account.userName))
|
||||||
|
}
|
||||||
|
|
||||||
def updateAccount(account: Account)(implicit s: Session): Unit =
|
def updateAccount(account: Account)(implicit s: Session): Unit =
|
||||||
Accounts
|
Accounts
|
||||||
.filter { a =>
|
.filter { a =>
|
||||||
@@ -281,6 +291,15 @@ trait AccountService {
|
|||||||
Collaborators.filter(_.collaboratorName === userName.bind).delete
|
Collaborators.filter(_.collaboratorName === userName.bind).delete
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def removeUser(account: Account)(implicit s: Session): Unit = {
|
||||||
|
// Remove from GROUP_MEMBER and COLLABORATOR
|
||||||
|
removeUserRelatedData(account.userName)
|
||||||
|
updateAccount(account.copy(isRemoved = true))
|
||||||
|
|
||||||
|
// call hooks
|
||||||
|
PluginRegistry().getAccountHooks.foreach(_.deleted(account.userName))
|
||||||
|
}
|
||||||
|
|
||||||
def getGroupNames(userName: String)(implicit s: Session): List[String] = {
|
def getGroupNames(userName: String)(implicit s: Session): List[String] = {
|
||||||
List(userName) ++
|
List(userName) ++
|
||||||
Collaborators.filter(_.collaboratorName === userName.bind).sortBy(_.userName).map(_.userName).list.distinct
|
Collaborators.filter(_.collaboratorName === userName.bind).sortBy(_.userName).map(_.userName).list.distinct
|
||||||
|
|||||||
@@ -360,7 +360,7 @@ trait ActivityService {
|
|||||||
repositoryName,
|
repositoryName,
|
||||||
activityUserName,
|
activityUserName,
|
||||||
"release",
|
"release",
|
||||||
s"[user:${activityUserName}] released ${name} at [repo:${userName}/${repositoryName}]",
|
s"[user:${activityUserName}] released [release:${userName}/${repositoryName}/${name}] at [repo:${userName}/${repositoryName}]",
|
||||||
None,
|
None,
|
||||||
currentDate
|
currentDate
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2,15 +2,20 @@ package gitbucket.core.service
|
|||||||
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
import gitbucket.core.model.CommitComment
|
import gitbucket.core.api.JsonFormat
|
||||||
|
import gitbucket.core.controller.Context
|
||||||
|
import gitbucket.core.model.{Account, CommitComment}
|
||||||
import gitbucket.core.model.Profile._
|
import gitbucket.core.model.Profile._
|
||||||
import gitbucket.core.model.Profile.profile.blockingApi._
|
import gitbucket.core.model.Profile.profile.blockingApi._
|
||||||
import gitbucket.core.model.Profile.dateColumnType
|
import gitbucket.core.model.Profile.dateColumnType
|
||||||
|
import gitbucket.core.plugin.PluginRegistry
|
||||||
|
import gitbucket.core.service.RepositoryService.RepositoryInfo
|
||||||
import gitbucket.core.util.Directory._
|
import gitbucket.core.util.Directory._
|
||||||
import gitbucket.core.util.{FileUtil, StringUtil}
|
import gitbucket.core.util.{FileUtil, StringUtil}
|
||||||
import org.apache.commons.io.FileUtils
|
import org.apache.commons.io.FileUtils
|
||||||
|
|
||||||
trait CommitsService {
|
trait CommitsService {
|
||||||
|
self: ActivityService with PullRequestService with WebHookPullRequestReviewCommentService =>
|
||||||
|
|
||||||
def getCommitComments(owner: String, repository: String, commitId: String, includePullRequest: Boolean)(
|
def getCommitComments(owner: String, repository: String, commitId: String, includePullRequest: Boolean)(
|
||||||
implicit s: Session
|
implicit s: Session
|
||||||
@@ -28,21 +33,21 @@ trait CommitsService {
|
|||||||
None
|
None
|
||||||
|
|
||||||
def createCommitComment(
|
def createCommitComment(
|
||||||
owner: String,
|
repository: RepositoryInfo,
|
||||||
repository: String,
|
|
||||||
commitId: String,
|
commitId: String,
|
||||||
loginUser: String,
|
loginAccount: Account,
|
||||||
content: String,
|
content: String,
|
||||||
fileName: Option[String],
|
fileName: Option[String],
|
||||||
oldLine: Option[Int],
|
oldLine: Option[Int],
|
||||||
newLine: Option[Int],
|
newLine: Option[Int],
|
||||||
|
diff: Option[String],
|
||||||
issueId: Option[Int]
|
issueId: Option[Int]
|
||||||
)(implicit s: Session): Int =
|
)(implicit s: Session, c: JsonFormat.Context, context: Context): Int = {
|
||||||
CommitComments returning CommitComments.map(_.commentId) insert CommitComment(
|
val commentId = CommitComments returning CommitComments.map(_.commentId) insert CommitComment(
|
||||||
userName = owner,
|
userName = repository.owner,
|
||||||
repositoryName = repository,
|
repositoryName = repository.name,
|
||||||
commitId = commitId,
|
commitId = commitId,
|
||||||
commentedUserName = loginUser,
|
commentedUserName = loginAccount.userName,
|
||||||
content = content,
|
content = content,
|
||||||
fileName = fileName,
|
fileName = fileName,
|
||||||
oldLine = oldLine,
|
oldLine = oldLine,
|
||||||
@@ -55,6 +60,56 @@ trait CommitsService {
|
|||||||
originalNewLine = newLine
|
originalNewLine = newLine
|
||||||
)
|
)
|
||||||
|
|
||||||
|
for {
|
||||||
|
fileName <- fileName
|
||||||
|
diff <- diff
|
||||||
|
} {
|
||||||
|
saveCommitCommentDiff(
|
||||||
|
repository.owner,
|
||||||
|
repository.name,
|
||||||
|
commitId,
|
||||||
|
fileName,
|
||||||
|
oldLine,
|
||||||
|
newLine,
|
||||||
|
diff
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val comment = getCommitComment(repository.owner, repository.name, commentId.toString).get
|
||||||
|
issueId match {
|
||||||
|
case Some(issueId) =>
|
||||||
|
getPullRequest(repository.owner, repository.name, issueId).foreach {
|
||||||
|
case (issue, pullRequest) =>
|
||||||
|
recordCommentPullRequestActivity(
|
||||||
|
repository.owner,
|
||||||
|
repository.name,
|
||||||
|
loginAccount.userName,
|
||||||
|
issueId,
|
||||||
|
content
|
||||||
|
)
|
||||||
|
PluginRegistry().getPullRequestHooks.foreach(_.addedComment(commentId, content, issue, repository))
|
||||||
|
callPullRequestReviewCommentWebHook(
|
||||||
|
"create",
|
||||||
|
comment,
|
||||||
|
repository,
|
||||||
|
issue,
|
||||||
|
pullRequest,
|
||||||
|
loginAccount
|
||||||
|
)
|
||||||
|
}
|
||||||
|
case None =>
|
||||||
|
recordCommentCommitActivity(
|
||||||
|
repository.owner,
|
||||||
|
repository.name,
|
||||||
|
loginAccount.userName,
|
||||||
|
commitId,
|
||||||
|
content
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
commentId
|
||||||
|
}
|
||||||
|
|
||||||
def updateCommitCommentPosition(commentId: Int, commitId: String, oldLine: Option[Int], newLine: Option[Int])(
|
def updateCommitCommentPosition(commentId: Int, commitId: String, oldLine: Option[Int], newLine: Option[Int])(
|
||||||
implicit s: Session
|
implicit s: Session
|
||||||
): Unit =
|
): Unit =
|
||||||
|
|||||||
@@ -87,9 +87,9 @@ trait HandleCommentService {
|
|||||||
case "reopen" => "reopened"
|
case "reopen" => "reopened"
|
||||||
}
|
}
|
||||||
if (issue.isPullRequest)
|
if (issue.isPullRequest)
|
||||||
callPullRequestWebHook(webHookAction, repository, issue.issueId, context.baseUrl, loginAccount)
|
callPullRequestWebHook(webHookAction, repository, issue.issueId, loginAccount)
|
||||||
else
|
else
|
||||||
callIssuesWebHook(webHookAction, repository, issue, context.baseUrl, loginAccount)
|
callIssuesWebHook(webHookAction, repository, issue, loginAccount)
|
||||||
}
|
}
|
||||||
|
|
||||||
// call hooks
|
// call hooks
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ trait IssueCreationService {
|
|||||||
createReferComment(owner, name, issue, title + " " + body.getOrElse(""), loginAccount)
|
createReferComment(owner, name, issue, title + " " + body.getOrElse(""), loginAccount)
|
||||||
|
|
||||||
// call web hooks
|
// call web hooks
|
||||||
callIssuesWebHook("opened", repository, issue, context.baseUrl, loginAccount)
|
callIssuesWebHook("opened", repository, issue, loginAccount)
|
||||||
|
|
||||||
// call hooks
|
// call hooks
|
||||||
PluginRegistry().getIssueHooks.foreach(_.created(issue, repository))
|
PluginRegistry().getIssueHooks.foreach(_.created(issue, repository))
|
||||||
|
|||||||
@@ -1,8 +1,16 @@
|
|||||||
package gitbucket.core.service
|
package gitbucket.core.service
|
||||||
|
|
||||||
import gitbucket.core.model.Account
|
import gitbucket.core.api.JsonFormat
|
||||||
|
import gitbucket.core.controller.Context
|
||||||
|
import gitbucket.core.model.{Account, PullRequest, WebHook}
|
||||||
|
import gitbucket.core.plugin.PluginRegistry
|
||||||
|
import gitbucket.core.service.RepositoryService.RepositoryInfo
|
||||||
import gitbucket.core.util.Directory._
|
import gitbucket.core.util.Directory._
|
||||||
|
import gitbucket.core.util.{JGitUtil, LockUtil}
|
||||||
import gitbucket.core.util.SyntaxSugars._
|
import gitbucket.core.util.SyntaxSugars._
|
||||||
|
import gitbucket.core.model.Profile._
|
||||||
|
import gitbucket.core.model.Profile.profile._
|
||||||
|
import gitbucket.core.model.Profile.profile.blockingApi._
|
||||||
import org.eclipse.jgit.merge.{MergeStrategy, Merger, RecursiveMerger}
|
import org.eclipse.jgit.merge.{MergeStrategy, Merger, RecursiveMerger}
|
||||||
import org.eclipse.jgit.api.Git
|
import org.eclipse.jgit.api.Git
|
||||||
import org.eclipse.jgit.transport.RefSpec
|
import org.eclipse.jgit.transport.RefSpec
|
||||||
@@ -13,6 +21,13 @@ import org.eclipse.jgit.revwalk.{RevCommit, RevWalk}
|
|||||||
import scala.collection.JavaConverters._
|
import scala.collection.JavaConverters._
|
||||||
|
|
||||||
trait MergeService {
|
trait MergeService {
|
||||||
|
self: AccountService
|
||||||
|
with ActivityService
|
||||||
|
with IssuesService
|
||||||
|
with RepositoryService
|
||||||
|
with PullRequestService
|
||||||
|
with WebHookPullRequestService =>
|
||||||
|
|
||||||
import MergeService._
|
import MergeService._
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -43,7 +58,13 @@ trait MergeService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** merge the pull request with a merge commit */
|
/** merge the pull request with a merge commit */
|
||||||
def mergePullRequest(git: Git, branch: String, issueId: Int, message: String, committer: PersonIdent): Unit = {
|
def mergePullRequest(
|
||||||
|
git: Git,
|
||||||
|
branch: String,
|
||||||
|
issueId: Int,
|
||||||
|
message: String,
|
||||||
|
committer: PersonIdent
|
||||||
|
): ObjectId = {
|
||||||
new MergeCacheInfo(git, branch, issueId).merge(message, committer)
|
new MergeCacheInfo(git, branch, issueId).merge(message, committer)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,12 +75,18 @@ trait MergeService {
|
|||||||
issueId: Int,
|
issueId: Int,
|
||||||
commits: Seq[RevCommit],
|
commits: Seq[RevCommit],
|
||||||
committer: PersonIdent
|
committer: PersonIdent
|
||||||
): Unit = {
|
): ObjectId = {
|
||||||
new MergeCacheInfo(git, branch, issueId).rebase(committer, commits)
|
new MergeCacheInfo(git, branch, issueId).rebase(committer, commits)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** squash commits in the pull request and append it */
|
/** squash commits in the pull request and append it */
|
||||||
def squashPullRequest(git: Git, branch: String, issueId: Int, message: String, committer: PersonIdent): Unit = {
|
def squashPullRequest(
|
||||||
|
git: Git,
|
||||||
|
branch: String,
|
||||||
|
issueId: Int,
|
||||||
|
message: String,
|
||||||
|
committer: PersonIdent
|
||||||
|
): ObjectId = {
|
||||||
new MergeCacheInfo(git, branch, issueId).squash(message, committer)
|
new MergeCacheInfo(git, branch, issueId).squash(message, committer)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,27 +163,223 @@ trait MergeService {
|
|||||||
tryMergeRemote(userName, repositoryName, branch, requestUserName, requestRepositoryName, requestBranch).left.toOption
|
tryMergeRemote(userName, repositoryName, branch, requestUserName, requestRepositoryName, requestBranch).left.toOption
|
||||||
|
|
||||||
def pullRemote(
|
def pullRemote(
|
||||||
localUserName: String,
|
localRepository: RepositoryInfo,
|
||||||
localRepositoryName: String,
|
|
||||||
localBranch: String,
|
localBranch: String,
|
||||||
remoteUserName: String,
|
remoteRepository: RepositoryInfo,
|
||||||
remoteRepositoryName: String,
|
|
||||||
remoteBranch: String,
|
remoteBranch: String,
|
||||||
loginAccount: Account,
|
loginAccount: Account,
|
||||||
message: String
|
message: String,
|
||||||
): Option[ObjectId] = {
|
pullreq: Option[PullRequest]
|
||||||
|
)(implicit s: Session, c: JsonFormat.Context): Option[ObjectId] = {
|
||||||
|
val localUserName = localRepository.owner
|
||||||
|
val localRepositoryName = localRepository.name
|
||||||
|
val remoteUserName = remoteRepository.owner
|
||||||
|
val remoteRepositoryName = remoteRepository.name
|
||||||
tryMergeRemote(localUserName, localRepositoryName, localBranch, remoteUserName, remoteRepositoryName, remoteBranch).map {
|
tryMergeRemote(localUserName, localRepositoryName, localBranch, remoteUserName, remoteRepositoryName, remoteBranch).map {
|
||||||
case (newTreeId, oldBaseId, oldHeadId) =>
|
case (newTreeId, oldBaseId, oldHeadId) =>
|
||||||
using(Git.open(getRepositoryDir(localUserName, localRepositoryName))) { git =>
|
using(Git.open(getRepositoryDir(localUserName, localRepositoryName))) { git =>
|
||||||
|
val existIds = JGitUtil.getAllCommitIds(git).toSet
|
||||||
|
|
||||||
val committer = new PersonIdent(loginAccount.fullName, loginAccount.mailAddress)
|
val committer = new PersonIdent(loginAccount.fullName, loginAccount.mailAddress)
|
||||||
val newCommit =
|
val newCommit =
|
||||||
Util.createMergeCommit(git.getRepository, newTreeId, committer, message, Seq(oldBaseId, oldHeadId))
|
Util.createMergeCommit(git.getRepository, newTreeId, committer, message, Seq(oldBaseId, oldHeadId))
|
||||||
Util.updateRefs(git.getRepository, s"refs/heads/${localBranch}", newCommit, false, committer, Some("merge"))
|
Util.updateRefs(git.getRepository, s"refs/heads/${localBranch}", newCommit, false, committer, Some("merge"))
|
||||||
|
|
||||||
|
val commits = git.log
|
||||||
|
.addRange(oldBaseId, newCommit)
|
||||||
|
.call
|
||||||
|
.iterator
|
||||||
|
.asScala
|
||||||
|
.map(c => new JGitUtil.CommitInfo(c))
|
||||||
|
.toList
|
||||||
|
|
||||||
|
commits.foreach { commit =>
|
||||||
|
if (!existIds.contains(commit.id)) {
|
||||||
|
createIssueComment(localUserName, localRepositoryName, commit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// record activity
|
||||||
|
recordPushActivity(
|
||||||
|
localUserName,
|
||||||
|
localRepositoryName,
|
||||||
|
loginAccount.userName,
|
||||||
|
localBranch,
|
||||||
|
commits
|
||||||
|
)
|
||||||
|
|
||||||
|
// close issue by commit message
|
||||||
|
if (localBranch == localRepository.repository.defaultBranch) {
|
||||||
|
commits.foreach { commit =>
|
||||||
|
closeIssuesFromMessage(commit.fullMessage, loginAccount.userName, localUserName, localRepositoryName)
|
||||||
|
.foreach { issueId =>
|
||||||
|
getIssue(localRepository.owner, localRepository.name, issueId.toString).foreach { issue =>
|
||||||
|
callIssuesWebHook("closed", localRepository, issue, loginAccount)
|
||||||
|
PluginRegistry().getIssueHooks
|
||||||
|
.foreach(
|
||||||
|
_.closedByCommitComment(issue, localRepository, commit.fullMessage, loginAccount)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pullreq.foreach { pullreq =>
|
||||||
|
callWebHookOf(localRepository.owner, localRepository.name, WebHook.Push) {
|
||||||
|
for {
|
||||||
|
ownerAccount <- getAccountByUserName(localRepository.owner)
|
||||||
|
} yield {
|
||||||
|
WebHookService.WebHookPushPayload(
|
||||||
|
git,
|
||||||
|
loginAccount,
|
||||||
|
pullreq.requestBranch,
|
||||||
|
localRepository,
|
||||||
|
commits,
|
||||||
|
ownerAccount,
|
||||||
|
oldId = oldBaseId,
|
||||||
|
newId = newCommit
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
oldBaseId
|
oldBaseId
|
||||||
}.toOption
|
}.toOption
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def mergePullRequest(
|
||||||
|
repository: RepositoryInfo,
|
||||||
|
issueId: Int,
|
||||||
|
loginAccount: Account,
|
||||||
|
message: String,
|
||||||
|
strategy: String
|
||||||
|
)(implicit s: Session, c: JsonFormat.Context, context: Context): Either[String, ObjectId] = {
|
||||||
|
if (repository.repository.options.mergeOptions.split(",").contains(strategy)) {
|
||||||
|
LockUtil.lock(s"${repository.owner}/${repository.name}") {
|
||||||
|
getPullRequest(repository.owner, repository.name, issueId)
|
||||||
|
.map {
|
||||||
|
case (issue, pullreq) =>
|
||||||
|
using(Git.open(getRepositoryDir(repository.owner, repository.name))) { git =>
|
||||||
|
// mark issue as merged and close.
|
||||||
|
val commentId =
|
||||||
|
createComment(repository.owner, repository.name, loginAccount.userName, issueId, message, "merge")
|
||||||
|
createComment(repository.owner, repository.name, loginAccount.userName, issueId, "Close", "close")
|
||||||
|
updateClosed(repository.owner, repository.name, issueId, true)
|
||||||
|
|
||||||
|
// record activity
|
||||||
|
recordMergeActivity(repository.owner, repository.name, loginAccount.userName, issueId, message)
|
||||||
|
|
||||||
|
val (commits, _) = getRequestCompareInfo(
|
||||||
|
repository.owner,
|
||||||
|
repository.name,
|
||||||
|
pullreq.commitIdFrom,
|
||||||
|
pullreq.requestUserName,
|
||||||
|
pullreq.requestRepositoryName,
|
||||||
|
pullreq.commitIdTo
|
||||||
|
)
|
||||||
|
|
||||||
|
val revCommits = using(new RevWalk(git.getRepository)) { revWalk =>
|
||||||
|
commits.flatten.map { commit =>
|
||||||
|
revWalk.parseCommit(git.getRepository.resolve(commit.id))
|
||||||
|
}
|
||||||
|
}.reverse
|
||||||
|
|
||||||
|
// merge git repository
|
||||||
|
(strategy match {
|
||||||
|
case "merge-commit" =>
|
||||||
|
Some(
|
||||||
|
mergePullRequest(
|
||||||
|
git,
|
||||||
|
pullreq.branch,
|
||||||
|
issueId,
|
||||||
|
s"Merge pull request #${issueId} from ${pullreq.requestUserName}/${pullreq.requestBranch}\n\n" + message,
|
||||||
|
new PersonIdent(loginAccount.fullName, loginAccount.mailAddress)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
case "rebase" =>
|
||||||
|
Some(
|
||||||
|
rebasePullRequest(
|
||||||
|
git,
|
||||||
|
pullreq.branch,
|
||||||
|
issueId,
|
||||||
|
revCommits,
|
||||||
|
new PersonIdent(loginAccount.fullName, loginAccount.mailAddress)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
case "squash" =>
|
||||||
|
Some(
|
||||||
|
squashPullRequest(
|
||||||
|
git,
|
||||||
|
pullreq.branch,
|
||||||
|
issueId,
|
||||||
|
s"${issue.title} (#${issueId})\n\n" + message,
|
||||||
|
new PersonIdent(loginAccount.fullName, loginAccount.mailAddress)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
case _ =>
|
||||||
|
None
|
||||||
|
}) match {
|
||||||
|
case Some(newCommitId) =>
|
||||||
|
// close issue by content of pull request
|
||||||
|
val defaultBranch = getRepository(repository.owner, repository.name).get.repository.defaultBranch
|
||||||
|
if (pullreq.branch == defaultBranch) {
|
||||||
|
commits.flatten.foreach { commit =>
|
||||||
|
closeIssuesFromMessage(
|
||||||
|
commit.fullMessage,
|
||||||
|
loginAccount.userName,
|
||||||
|
repository.owner,
|
||||||
|
repository.name
|
||||||
|
).foreach { issueId =>
|
||||||
|
getIssue(repository.owner, repository.name, issueId.toString).foreach { issue =>
|
||||||
|
callIssuesWebHook("closed", repository, issue, loginAccount)
|
||||||
|
PluginRegistry().getIssueHooks
|
||||||
|
.foreach(_.closedByCommitComment(issue, repository, commit.fullMessage, loginAccount))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val issueContent = issue.title + " " + issue.content.getOrElse("")
|
||||||
|
closeIssuesFromMessage(
|
||||||
|
issueContent,
|
||||||
|
loginAccount.userName,
|
||||||
|
repository.owner,
|
||||||
|
repository.name
|
||||||
|
).foreach { issueId =>
|
||||||
|
getIssue(repository.owner, repository.name, issueId.toString).foreach { issue =>
|
||||||
|
callIssuesWebHook("closed", repository, issue, loginAccount)
|
||||||
|
PluginRegistry().getIssueHooks
|
||||||
|
.foreach(_.closedByCommitComment(issue, repository, issueContent, loginAccount))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
closeIssuesFromMessage(message, loginAccount.userName, repository.owner, repository.name)
|
||||||
|
.foreach { issueId =>
|
||||||
|
getIssue(repository.owner, repository.name, issueId.toString).foreach { issue =>
|
||||||
|
callIssuesWebHook("closed", repository, issue, loginAccount)
|
||||||
|
PluginRegistry().getIssueHooks
|
||||||
|
.foreach(_.closedByCommitComment(issue, repository, issueContent, loginAccount))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updatePullRequests(repository.owner, repository.name, pullreq.branch, loginAccount, "closed")
|
||||||
|
|
||||||
|
// call hooks
|
||||||
|
PluginRegistry().getPullRequestHooks.foreach { h =>
|
||||||
|
h.addedComment(commentId, message, issue, repository)
|
||||||
|
h.merged(issue, repository)
|
||||||
|
}
|
||||||
|
|
||||||
|
Right(newCommitId)
|
||||||
|
case None =>
|
||||||
|
Left("Unknown strategy")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case _ => Left("Unknown error")
|
||||||
|
}
|
||||||
|
.getOrElse(Left("Pull request not found"))
|
||||||
|
}
|
||||||
|
} else Left("Strategy not allowed")
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object MergeService {
|
object MergeService {
|
||||||
@@ -191,13 +414,15 @@ object MergeService {
|
|||||||
force: Boolean,
|
force: Boolean,
|
||||||
committer: PersonIdent,
|
committer: PersonIdent,
|
||||||
refLogMessage: Option[String] = None
|
refLogMessage: Option[String] = None
|
||||||
): Unit = {
|
): ObjectId = {
|
||||||
val refUpdate = repository.updateRef(ref)
|
val refUpdate = repository.updateRef(ref)
|
||||||
refUpdate.setNewObjectId(newObjectId)
|
refUpdate.setNewObjectId(newObjectId)
|
||||||
refUpdate.setForceUpdate(force)
|
refUpdate.setForceUpdate(force)
|
||||||
refUpdate.setRefLogIdent(committer)
|
refUpdate.setRefLogIdent(committer)
|
||||||
refLogMessage.foreach(refUpdate.setRefLogMessage(_, true))
|
refLogMessage.foreach(refUpdate.setRefLogMessage(_, true))
|
||||||
refUpdate.update()
|
refUpdate.update()
|
||||||
|
|
||||||
|
newObjectId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -265,7 +490,7 @@ object MergeService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// update branch from cache
|
// update branch from cache
|
||||||
def merge(message: String, committer: PersonIdent) = {
|
def merge(message: String, committer: PersonIdent): ObjectId = {
|
||||||
if (checkConflict().isDefined) {
|
if (checkConflict().isDefined) {
|
||||||
throw new RuntimeException("This pull request can't merge automatically.")
|
throw new RuntimeException("This pull request can't merge automatically.")
|
||||||
}
|
}
|
||||||
@@ -278,7 +503,7 @@ object MergeService {
|
|||||||
Util.updateRefs(repository, s"refs/heads/${branch}", mergeCommitId, false, committer, Some("merged"))
|
Util.updateRefs(repository, s"refs/heads/${branch}", mergeCommitId, false, committer, Some("merged"))
|
||||||
}
|
}
|
||||||
|
|
||||||
def rebase(committer: PersonIdent, commits: Seq[RevCommit]): Unit = {
|
def rebase(committer: PersonIdent, commits: Seq[RevCommit]): ObjectId = {
|
||||||
if (checkConflict().isDefined) {
|
if (checkConflict().isDefined) {
|
||||||
throw new RuntimeException("This pull request can't merge automatically.")
|
throw new RuntimeException("This pull request can't merge automatically.")
|
||||||
}
|
}
|
||||||
@@ -310,7 +535,7 @@ object MergeService {
|
|||||||
Util.updateRefs(repository, s"refs/heads/${branch}", previousId, false, committer, Some("rebased"))
|
Util.updateRefs(repository, s"refs/heads/${branch}", previousId, false, committer, Some("rebased"))
|
||||||
}
|
}
|
||||||
|
|
||||||
def squash(message: String, committer: PersonIdent): Unit = {
|
def squash(message: String, committer: PersonIdent): ObjectId = {
|
||||||
if (checkConflict().isDefined) {
|
if (checkConflict().isDefined) {
|
||||||
throw new RuntimeException("This pull request can't merge automatically.")
|
throw new RuntimeException("This pull request can't merge automatically.")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import gitbucket.core.model.Profile._
|
|||||||
import gitbucket.core.model.Profile.profile.blockingApi._
|
import gitbucket.core.model.Profile.profile.blockingApi._
|
||||||
import difflib.{Delta, DiffUtils}
|
import difflib.{Delta, DiffUtils}
|
||||||
import gitbucket.core.service.RepositoryService.RepositoryInfo
|
import gitbucket.core.service.RepositoryService.RepositoryInfo
|
||||||
|
import gitbucket.core.api.JsonFormat
|
||||||
import gitbucket.core.util.SyntaxSugars._
|
import gitbucket.core.util.SyntaxSugars._
|
||||||
import gitbucket.core.util.Directory._
|
import gitbucket.core.util.Directory._
|
||||||
import gitbucket.core.util.Implicits._
|
import gitbucket.core.util.Implicits._
|
||||||
@@ -17,7 +18,8 @@ import org.eclipse.jgit.lib.ObjectId
|
|||||||
|
|
||||||
import scala.collection.JavaConverters._
|
import scala.collection.JavaConverters._
|
||||||
|
|
||||||
trait PullRequestService { self: IssuesService with CommitsService =>
|
trait PullRequestService {
|
||||||
|
self: IssuesService with CommitsService with WebHookService with WebHookPullRequestService with RepositoryService =>
|
||||||
import PullRequestService._
|
import PullRequestService._
|
||||||
|
|
||||||
def getPullRequest(owner: String, repository: String, issueId: Int)(
|
def getPullRequest(owner: String, repository: String, issueId: Int)(
|
||||||
@@ -166,7 +168,10 @@ trait PullRequestService { self: IssuesService with CommitsService =>
|
|||||||
/**
|
/**
|
||||||
* Fetch pull request contents into refs/pull/${issueId}/head and update pull request table.
|
* Fetch pull request contents into refs/pull/${issueId}/head and update pull request table.
|
||||||
*/
|
*/
|
||||||
def updatePullRequests(owner: String, repository: String, branch: String)(implicit s: Session): Unit =
|
def updatePullRequests(owner: String, repository: String, branch: String, loginAccount: Account, action: String)(
|
||||||
|
implicit s: Session,
|
||||||
|
c: JsonFormat.Context
|
||||||
|
): Unit = {
|
||||||
getPullRequestsByRequest(owner, repository, branch, Some(false)).foreach { pullreq =>
|
getPullRequestsByRequest(owner, repository, branch, Some(false)).foreach { pullreq =>
|
||||||
if (Repositories.filter(_.byRepository(pullreq.userName, pullreq.repositoryName)).exists.run) {
|
if (Repositories.filter(_.byRepository(pullreq.userName, pullreq.repositoryName)).exists.run) {
|
||||||
// Update the git repository
|
// Update the git repository
|
||||||
@@ -206,6 +211,15 @@ trait PullRequestService { self: IssuesService with CommitsService =>
|
|||||||
|
|
||||||
// Update commit id in the PULL_REQUEST table
|
// Update commit id in the PULL_REQUEST table
|
||||||
updateCommitId(pullreq.userName, pullreq.repositoryName, pullreq.issueId, commitIdTo, commitIdFrom)
|
updateCommitId(pullreq.userName, pullreq.repositoryName, pullreq.issueId, commitIdTo, commitIdFrom)
|
||||||
|
|
||||||
|
// call web hook
|
||||||
|
callPullRequestWebHookByRequestBranch(
|
||||||
|
action,
|
||||||
|
getRepository(owner, repository).get,
|
||||||
|
pullreq.requestBranch,
|
||||||
|
loginAccount
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,188 @@
|
|||||||
|
package gitbucket.core.service
|
||||||
|
import gitbucket.core.api.JsonFormat
|
||||||
|
import gitbucket.core.model.{Account, WebHook}
|
||||||
|
import gitbucket.core.model.Profile._
|
||||||
|
import gitbucket.core.model.Profile.profile.blockingApi._
|
||||||
|
import gitbucket.core.plugin.PluginRegistry
|
||||||
|
import gitbucket.core.service.WebHookService.WebHookPushPayload
|
||||||
|
import gitbucket.core.util.Directory.getRepositoryDir
|
||||||
|
import gitbucket.core.util.JGitUtil.CommitInfo
|
||||||
|
import gitbucket.core.util.{JGitUtil, LockUtil}
|
||||||
|
import gitbucket.core.util.SyntaxSugars.using
|
||||||
|
import org.eclipse.jgit.api.Git
|
||||||
|
import org.eclipse.jgit.dircache.{DirCache, DirCacheBuilder}
|
||||||
|
import org.eclipse.jgit.lib._
|
||||||
|
import org.eclipse.jgit.transport.{ReceiveCommand, ReceivePack}
|
||||||
|
|
||||||
|
trait RepositoryCommitFileService {
|
||||||
|
self: AccountService with ActivityService with IssuesService with PullRequestService with WebHookPullRequestService =>
|
||||||
|
import RepositoryCommitFileService._
|
||||||
|
|
||||||
|
def commitFiles(
|
||||||
|
repository: RepositoryService.RepositoryInfo,
|
||||||
|
files: Seq[CommitFile],
|
||||||
|
branch: String,
|
||||||
|
path: String,
|
||||||
|
message: String,
|
||||||
|
loginAccount: Account
|
||||||
|
)(
|
||||||
|
f: (Git, ObjectId, DirCacheBuilder, ObjectInserter) => Unit
|
||||||
|
)(implicit s: Session, c: JsonFormat.Context) = {
|
||||||
|
// prepend path to the filename
|
||||||
|
_commitFile(repository, branch, message, loginAccount)(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
def commitFile(
|
||||||
|
repository: RepositoryService.RepositoryInfo,
|
||||||
|
branch: String,
|
||||||
|
path: String,
|
||||||
|
newFileName: Option[String],
|
||||||
|
oldFileName: Option[String],
|
||||||
|
content: String,
|
||||||
|
charset: String,
|
||||||
|
message: String,
|
||||||
|
commit: String,
|
||||||
|
loginAccount: Account
|
||||||
|
)(implicit s: Session, c: JsonFormat.Context) = {
|
||||||
|
|
||||||
|
val newPath = newFileName.map { newFileName =>
|
||||||
|
if (path.length == 0) newFileName else s"${path}/${newFileName}"
|
||||||
|
}
|
||||||
|
val oldPath = oldFileName.map { oldFileName =>
|
||||||
|
if (path.length == 0) oldFileName else s"${path}/${oldFileName}"
|
||||||
|
}
|
||||||
|
|
||||||
|
_commitFile(repository, branch, message, loginAccount) {
|
||||||
|
case (git, headTip, builder, inserter) =>
|
||||||
|
if (headTip.getName == commit) {
|
||||||
|
val permission = JGitUtil
|
||||||
|
.processTree(git, headTip) { (path, tree) =>
|
||||||
|
// Add all entries except the editing file
|
||||||
|
if (!newPath.contains(path) && !oldPath.contains(path)) {
|
||||||
|
builder.add(JGitUtil.createDirCacheEntry(path, tree.getEntryFileMode, tree.getEntryObjectId))
|
||||||
|
}
|
||||||
|
// Retrieve permission if file exists to keep it
|
||||||
|
oldPath.collect { case x if x == path => tree.getEntryFileMode.getBits }
|
||||||
|
}
|
||||||
|
.flatten
|
||||||
|
.headOption
|
||||||
|
|
||||||
|
newPath.foreach { newPath =>
|
||||||
|
builder.add(JGitUtil.createDirCacheEntry(newPath, permission.map { bits =>
|
||||||
|
FileMode.fromBits(bits)
|
||||||
|
} getOrElse FileMode.REGULAR_FILE, inserter.insert(Constants.OBJ_BLOB, content.getBytes(charset))))
|
||||||
|
}
|
||||||
|
builder.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private def _commitFile(
|
||||||
|
repository: RepositoryService.RepositoryInfo,
|
||||||
|
branch: String,
|
||||||
|
message: String,
|
||||||
|
loginAccount: Account
|
||||||
|
)(
|
||||||
|
f: (Git, ObjectId, DirCacheBuilder, ObjectInserter) => Unit
|
||||||
|
)(implicit s: Session, c: JsonFormat.Context) = {
|
||||||
|
|
||||||
|
LockUtil.lock(s"${repository.owner}/${repository.name}") {
|
||||||
|
using(Git.open(getRepositoryDir(repository.owner, repository.name))) { git =>
|
||||||
|
val builder = DirCache.newInCore.builder()
|
||||||
|
val inserter = git.getRepository.newObjectInserter()
|
||||||
|
val headName = s"refs/heads/${branch}"
|
||||||
|
val headTip = git.getRepository.resolve(headName)
|
||||||
|
|
||||||
|
f(git, headTip, builder, inserter)
|
||||||
|
|
||||||
|
val commitId = JGitUtil.createNewCommit(
|
||||||
|
git,
|
||||||
|
inserter,
|
||||||
|
headTip,
|
||||||
|
builder.getDirCache.writeTree(inserter),
|
||||||
|
headName,
|
||||||
|
loginAccount.fullName,
|
||||||
|
loginAccount.mailAddress,
|
||||||
|
message
|
||||||
|
)
|
||||||
|
|
||||||
|
inserter.flush()
|
||||||
|
inserter.close()
|
||||||
|
|
||||||
|
val receivePack = new ReceivePack(git.getRepository)
|
||||||
|
val receiveCommand = new ReceiveCommand(headTip, commitId, headName)
|
||||||
|
|
||||||
|
// call post commit hook
|
||||||
|
val error = PluginRegistry().getReceiveHooks.flatMap { hook =>
|
||||||
|
hook.preReceive(repository.owner, repository.name, receivePack, receiveCommand, loginAccount.userName)
|
||||||
|
}.headOption
|
||||||
|
|
||||||
|
error match {
|
||||||
|
case Some(error) =>
|
||||||
|
// commit is rejected
|
||||||
|
// TODO Notify commit failure to edited user
|
||||||
|
val refUpdate = git.getRepository.updateRef(headName)
|
||||||
|
refUpdate.setNewObjectId(headTip)
|
||||||
|
refUpdate.setForceUpdate(true)
|
||||||
|
refUpdate.update()
|
||||||
|
|
||||||
|
case None =>
|
||||||
|
// update refs
|
||||||
|
val refUpdate = git.getRepository.updateRef(headName)
|
||||||
|
refUpdate.setNewObjectId(commitId)
|
||||||
|
refUpdate.setForceUpdate(false)
|
||||||
|
refUpdate.setRefLogIdent(new PersonIdent(loginAccount.fullName, loginAccount.mailAddress))
|
||||||
|
refUpdate.update()
|
||||||
|
|
||||||
|
// update pull request
|
||||||
|
updatePullRequests(repository.owner, repository.name, branch, loginAccount, "synchronize")
|
||||||
|
|
||||||
|
// record activity
|
||||||
|
val commitInfo = new CommitInfo(JGitUtil.getRevCommitFromId(git, commitId))
|
||||||
|
recordPushActivity(repository.owner, repository.name, loginAccount.userName, branch, List(commitInfo))
|
||||||
|
|
||||||
|
// create issue comment by commit message
|
||||||
|
createIssueComment(repository.owner, repository.name, commitInfo)
|
||||||
|
|
||||||
|
// close issue by commit message
|
||||||
|
if (branch == repository.repository.defaultBranch) {
|
||||||
|
closeIssuesFromMessage(message, loginAccount.userName, repository.owner, repository.name).foreach {
|
||||||
|
issueId =>
|
||||||
|
getIssue(repository.owner, repository.name, issueId.toString).foreach { issue =>
|
||||||
|
callIssuesWebHook("closed", repository, issue, loginAccount)
|
||||||
|
PluginRegistry().getIssueHooks
|
||||||
|
.foreach(_.closedByCommitComment(issue, repository, message, loginAccount))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// call post commit hook
|
||||||
|
PluginRegistry().getReceiveHooks.foreach { hook =>
|
||||||
|
hook.postReceive(repository.owner, repository.name, receivePack, receiveCommand, loginAccount.userName)
|
||||||
|
}
|
||||||
|
|
||||||
|
val commit = new JGitUtil.CommitInfo(JGitUtil.getRevCommitFromId(git, commitId))
|
||||||
|
callWebHookOf(repository.owner, repository.name, WebHook.Push) {
|
||||||
|
getAccountByUserName(repository.owner).map { ownerAccount =>
|
||||||
|
WebHookPushPayload(
|
||||||
|
git,
|
||||||
|
loginAccount,
|
||||||
|
headName,
|
||||||
|
repository,
|
||||||
|
List(commit),
|
||||||
|
ownerAccount,
|
||||||
|
oldId = headTip,
|
||||||
|
newId = commitId
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
object RepositoryCommitFileService {
|
||||||
|
case class CommitFile(id: String, name: String)
|
||||||
|
}
|
||||||
@@ -1,16 +1,25 @@
|
|||||||
package gitbucket.core.service
|
package gitbucket.core.service
|
||||||
|
|
||||||
|
import gitbucket.core.api.JsonFormat
|
||||||
import gitbucket.core.controller.Context
|
import gitbucket.core.controller.Context
|
||||||
import gitbucket.core.util._
|
import gitbucket.core.util._
|
||||||
import gitbucket.core.util.SyntaxSugars._
|
import gitbucket.core.util.SyntaxSugars._
|
||||||
import gitbucket.core.model.{Account, Collaborator, Repository, RepositoryOptions, Role, ReleaseTag}
|
import gitbucket.core.model.{CommitComments => _, Session => _, _}
|
||||||
import gitbucket.core.model.Profile._
|
import gitbucket.core.model.Profile._
|
||||||
import gitbucket.core.model.Profile.profile.blockingApi._
|
import gitbucket.core.model.Profile.profile.blockingApi._
|
||||||
import gitbucket.core.model.Profile.dateColumnType
|
import gitbucket.core.model.Profile.dateColumnType
|
||||||
import gitbucket.core.util.JGitUtil.FileInfo
|
import gitbucket.core.plugin.PluginRegistry
|
||||||
|
import gitbucket.core.service.WebHookService.WebHookPushPayload
|
||||||
|
import gitbucket.core.util.Directory.{getRepositoryDir, getRepositoryFilesDir, getTemporaryDir, getWikiRepositoryDir}
|
||||||
|
import gitbucket.core.util.JGitUtil.{CommitInfo, FileInfo}
|
||||||
|
import org.apache.commons.io.FileUtils
|
||||||
import org.eclipse.jgit.api.Git
|
import org.eclipse.jgit.api.Git
|
||||||
|
import org.eclipse.jgit.dircache.{DirCache, DirCacheBuilder}
|
||||||
|
import org.eclipse.jgit.lib.{Repository => _, _}
|
||||||
|
import org.eclipse.jgit.transport.{ReceiveCommand, ReceivePack}
|
||||||
|
|
||||||
trait RepositoryService { self: AccountService =>
|
trait RepositoryService {
|
||||||
|
self: AccountService =>
|
||||||
import RepositoryService._
|
import RepositoryService._
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -68,6 +77,7 @@ trait RepositoryService { self: AccountService =>
|
|||||||
(Repositories filter { t =>
|
(Repositories filter { t =>
|
||||||
t.byRepository(oldUserName, oldRepositoryName)
|
t.byRepository(oldUserName, oldRepositoryName)
|
||||||
} firstOption).foreach { repository =>
|
} firstOption).foreach { repository =>
|
||||||
|
LockUtil.lock(s"${repository.userName}/${repository.repositoryName}") {
|
||||||
Repositories insert repository.copy(userName = newUserName, repositoryName = newRepositoryName)
|
Repositories insert repository.copy(userName = newUserName, repositoryName = newRepositoryName)
|
||||||
|
|
||||||
val webHooks = RepositoryWebHooks.filter(_.byRepository(oldUserName, oldRepositoryName)).list
|
val webHooks = RepositoryWebHooks.filter(_.byRepository(oldUserName, oldRepositoryName)).list
|
||||||
@@ -117,7 +127,7 @@ trait RepositoryService { self: AccountService =>
|
|||||||
.update(newUserName, newRepositoryName)
|
.update(newUserName, newRepositoryName)
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteRepository(oldUserName, oldRepositoryName)
|
deleteRepositoryOnModel(oldUserName, oldRepositoryName)
|
||||||
|
|
||||||
RepositoryWebHooks.insertAll(
|
RepositoryWebHooks.insertAll(
|
||||||
webHooks.map(_.copy(userName = newUserName, repositoryName = newRepositoryName)): _*
|
webHooks.map(_.copy(userName = newUserName, repositoryName = newRepositoryName)): _*
|
||||||
@@ -139,12 +149,17 @@ trait RepositoryService { self: AccountService =>
|
|||||||
newMilestones.find(_.title == milestones.find(_.milestoneId == id).get.title).get.milestoneId
|
newMilestones.find(_.title == milestones.find(_.milestoneId == id).get.title).get.milestoneId
|
||||||
},
|
},
|
||||||
priorityId = x.priorityId.map { id =>
|
priorityId = x.priorityId.map { id =>
|
||||||
newPriorities.find(_.priorityName == priorities.find(_.priorityId == id).get.priorityName).get.priorityId
|
newPriorities
|
||||||
|
.find(_.priorityName == priorities.find(_.priorityId == id).get.priorityName)
|
||||||
|
.get
|
||||||
|
.priorityId
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}: _*)
|
}: _*)
|
||||||
|
|
||||||
PullRequests.insertAll(pullRequests.map(_.copy(userName = newUserName, repositoryName = newRepositoryName)): _*)
|
PullRequests.insertAll(
|
||||||
|
pullRequests.map(_.copy(userName = newUserName, repositoryName = newRepositoryName)): _*
|
||||||
|
)
|
||||||
IssueComments.insertAll(
|
IssueComments.insertAll(
|
||||||
issueComments.map(_.copy(userName = newUserName, repositoryName = newRepositoryName)): _*
|
issueComments.map(_.copy(userName = newUserName, repositoryName = newRepositoryName)): _*
|
||||||
)
|
)
|
||||||
@@ -223,7 +238,10 @@ trait RepositoryService { self: AccountService =>
|
|||||||
s"[branch:${oldUserName}/${oldRepositoryName}#",
|
s"[branch:${oldUserName}/${oldRepositoryName}#",
|
||||||
s"[branch:${newUserName}/${newRepositoryName}#"
|
s"[branch:${newUserName}/${newRepositoryName}#"
|
||||||
)
|
)
|
||||||
.replace(s"[tag:${oldUserName}/${oldRepositoryName}#", s"[tag:${newUserName}/${newRepositoryName}#")
|
.replace(
|
||||||
|
s"[tag:${oldUserName}/${oldRepositoryName}#",
|
||||||
|
s"[tag:${newUserName}/${newRepositoryName}#"
|
||||||
|
)
|
||||||
.replace(
|
.replace(
|
||||||
s"[pullreq:${oldUserName}/${oldRepositoryName}#",
|
s"[pullreq:${oldUserName}/${oldRepositoryName}#",
|
||||||
s"[pullreq:${newUserName}/${newRepositoryName}#"
|
s"[pullreq:${newUserName}/${newRepositoryName}#"
|
||||||
@@ -238,11 +256,53 @@ trait RepositoryService { self: AccountService =>
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
// Move git repository
|
||||||
|
defining(getRepositoryDir(oldUserName, oldRepositoryName)) { dir =>
|
||||||
|
if (dir.isDirectory) {
|
||||||
|
FileUtils.moveDirectory(dir, getRepositoryDir(newUserName, newRepositoryName))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Move wiki repository
|
||||||
|
defining(getWikiRepositoryDir(oldUserName, oldRepositoryName)) { dir =>
|
||||||
|
if (dir.isDirectory) {
|
||||||
|
FileUtils.moveDirectory(dir, getWikiRepositoryDir(newUserName, newRepositoryName))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Move files directory
|
||||||
|
defining(getRepositoryFilesDir(oldUserName, oldRepositoryName)) { dir =>
|
||||||
|
if (dir.isDirectory) {
|
||||||
|
FileUtils.moveDirectory(dir, getRepositoryFilesDir(newUserName, newRepositoryName))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Delete parent directory
|
||||||
|
FileUtil.deleteDirectoryIfEmpty(getRepositoryFilesDir(oldUserName, oldRepositoryName))
|
||||||
|
|
||||||
|
// Call hooks
|
||||||
|
if (oldUserName == newUserName) {
|
||||||
|
PluginRegistry().getRepositoryHooks.foreach(_.renamed(oldUserName, oldRepositoryName, newRepositoryName))
|
||||||
|
} else {
|
||||||
|
PluginRegistry().getRepositoryHooks.foreach(_.transferred(oldUserName, newUserName, newRepositoryName))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def deleteRepository(userName: String, repositoryName: String)(implicit s: Session): Unit = {
|
def deleteRepository(repository: Repository)(implicit s: Session): Unit = {
|
||||||
|
LockUtil.lock(s"${repository.userName}/${repository.repositoryName}") {
|
||||||
|
deleteRepositoryOnModel(repository.userName, repository.repositoryName)
|
||||||
|
|
||||||
|
FileUtils.deleteDirectory(getRepositoryDir(repository.userName, repository.repositoryName))
|
||||||
|
FileUtils.deleteDirectory(getWikiRepositoryDir(repository.userName, repository.repositoryName))
|
||||||
|
FileUtils.deleteDirectory(getTemporaryDir(repository.userName, repository.repositoryName))
|
||||||
|
FileUtils.deleteDirectory(getRepositoryFilesDir(repository.userName, repository.repositoryName))
|
||||||
|
|
||||||
|
// Call hooks
|
||||||
|
PluginRegistry().getRepositoryHooks.foreach(_.deleted(repository.userName, repository.repositoryName))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private def deleteRepositoryOnModel(userName: String, repositoryName: String)(implicit s: Session): Unit = {
|
||||||
Activities.filter(_.byRepository(userName, repositoryName)).delete
|
Activities.filter(_.byRepository(userName, repositoryName)).delete
|
||||||
Collaborators.filter(_.byRepository(userName, repositoryName)).delete
|
Collaborators.filter(_.byRepository(userName, repositoryName)).delete
|
||||||
CommitComments.filter(_.byRepository(userName, repositoryName)).delete
|
CommitComments.filter(_.byRepository(userName, repositoryName)).delete
|
||||||
@@ -718,7 +778,6 @@ trait RepositoryService { self: AccountService =>
|
|||||||
}
|
}
|
||||||
|
|
||||||
object RepositoryService {
|
object RepositoryService {
|
||||||
|
|
||||||
case class RepositoryInfo(
|
case class RepositoryInfo(
|
||||||
owner: String,
|
owner: String,
|
||||||
name: String,
|
name: String,
|
||||||
|
|||||||
@@ -311,7 +311,6 @@ trait WebHookPullRequestService extends WebHookService {
|
|||||||
action: String,
|
action: String,
|
||||||
repository: RepositoryService.RepositoryInfo,
|
repository: RepositoryService.RepositoryInfo,
|
||||||
issue: Issue,
|
issue: Issue,
|
||||||
baseUrl: String,
|
|
||||||
sender: Account
|
sender: Account
|
||||||
)(implicit s: Session, context: JsonFormat.Context): Unit = {
|
)(implicit s: Session, context: JsonFormat.Context): Unit = {
|
||||||
callWebHookOf(repository.owner, repository.name, WebHook.Issues) {
|
callWebHookOf(repository.owner, repository.name, WebHook.Issues) {
|
||||||
@@ -341,7 +340,6 @@ trait WebHookPullRequestService extends WebHookService {
|
|||||||
action: String,
|
action: String,
|
||||||
repository: RepositoryService.RepositoryInfo,
|
repository: RepositoryService.RepositoryInfo,
|
||||||
issueId: Int,
|
issueId: Int,
|
||||||
baseUrl: String,
|
|
||||||
sender: Account
|
sender: Account
|
||||||
)(implicit s: Session, c: JsonFormat.Context): Unit = {
|
)(implicit s: Session, c: JsonFormat.Context): Unit = {
|
||||||
import WebHookService._
|
import WebHookService._
|
||||||
@@ -404,7 +402,6 @@ trait WebHookPullRequestService extends WebHookService {
|
|||||||
action: String,
|
action: String,
|
||||||
requestRepository: RepositoryService.RepositoryInfo,
|
requestRepository: RepositoryService.RepositoryInfo,
|
||||||
requestBranch: String,
|
requestBranch: String,
|
||||||
baseUrl: String,
|
|
||||||
sender: Account
|
sender: Account
|
||||||
)(implicit s: Session, c: JsonFormat.Context): Unit = {
|
)(implicit s: Session, c: JsonFormat.Context): Unit = {
|
||||||
import WebHookService._
|
import WebHookService._
|
||||||
@@ -450,7 +447,6 @@ trait WebHookPullRequestReviewCommentService extends WebHookService {
|
|||||||
repository: RepositoryService.RepositoryInfo,
|
repository: RepositoryService.RepositoryInfo,
|
||||||
issue: Issue,
|
issue: Issue,
|
||||||
pullRequest: PullRequest,
|
pullRequest: PullRequest,
|
||||||
baseUrl: String,
|
|
||||||
sender: Account
|
sender: Account
|
||||||
)(implicit s: Session, c: JsonFormat.Context): Unit = {
|
)(implicit s: Session, c: JsonFormat.Context): Unit = {
|
||||||
import WebHookService._
|
import WebHookService._
|
||||||
|
|||||||
@@ -221,6 +221,7 @@ class CommitLogHook(owner: String, repository: String, pusher: String, baseUrl:
|
|||||||
with PrioritiesService
|
with PrioritiesService
|
||||||
with MilestonesService
|
with MilestonesService
|
||||||
with WebHookPullRequestService
|
with WebHookPullRequestService
|
||||||
|
with WebHookPullRequestReviewCommentService
|
||||||
with CommitsService {
|
with CommitsService {
|
||||||
|
|
||||||
private val logger = LoggerFactory.getLogger(classOf[CommitLogHook])
|
private val logger = LoggerFactory.getLogger(classOf[CommitLogHook])
|
||||||
@@ -299,7 +300,7 @@ class CommitLogHook(owner: String, repository: String, pusher: String, baseUrl:
|
|||||||
getAccountByUserName(pusher).foreach { pusherAccount =>
|
getAccountByUserName(pusher).foreach { pusherAccount =>
|
||||||
closeIssuesFromMessage(commit.fullMessage, pusher, owner, repository).foreach { issueId =>
|
closeIssuesFromMessage(commit.fullMessage, pusher, owner, repository).foreach { issueId =>
|
||||||
getIssue(owner, repository, issueId.toString).foreach { issue =>
|
getIssue(owner, repository, issueId.toString).foreach { issue =>
|
||||||
callIssuesWebHook("closed", repositoryInfo, issue, baseUrl, pusherAccount)
|
callIssuesWebHook("closed", repositoryInfo, issue, pusherAccount)
|
||||||
PluginRegistry().getIssueHooks
|
PluginRegistry().getIssueHooks
|
||||||
.foreach(_.closedByCommitComment(issue, repositoryInfo, commit.fullMessage, pusherAccount))
|
.foreach(_.closedByCommitComment(issue, repositoryInfo, commit.fullMessage, pusherAccount))
|
||||||
}
|
}
|
||||||
@@ -319,7 +320,7 @@ class CommitLogHook(owner: String, repository: String, pusher: String, baseUrl:
|
|||||||
}.isDefined) {
|
}.isDefined) {
|
||||||
markMergeAndClosePullRequest(pusher, owner, repository, pull)
|
markMergeAndClosePullRequest(pusher, owner, repository, pull)
|
||||||
getAccountByUserName(pusher).foreach { pusherAccount =>
|
getAccountByUserName(pusher).foreach { pusherAccount =>
|
||||||
callPullRequestWebHook("closed", repositoryInfo, pull.issueId, baseUrl, pusherAccount)
|
callPullRequestWebHook("closed", repositoryInfo, pull.issueId, pusherAccount)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -346,15 +347,8 @@ class CommitLogHook(owner: String, repository: String, pusher: String, baseUrl:
|
|||||||
command.getType match {
|
command.getType match {
|
||||||
case ReceiveCommand.Type.CREATE | ReceiveCommand.Type.UPDATE |
|
case ReceiveCommand.Type.CREATE | ReceiveCommand.Type.UPDATE |
|
||||||
ReceiveCommand.Type.UPDATE_NONFASTFORWARD =>
|
ReceiveCommand.Type.UPDATE_NONFASTFORWARD =>
|
||||||
updatePullRequests(owner, repository, branchName)
|
|
||||||
getAccountByUserName(pusher).foreach { pusherAccount =>
|
getAccountByUserName(pusher).foreach { pusherAccount =>
|
||||||
callPullRequestWebHookByRequestBranch(
|
updatePullRequests(owner, repository, branchName, pusherAccount, "synchronize")
|
||||||
"synchronize",
|
|
||||||
repositoryInfo,
|
|
||||||
branchName,
|
|
||||||
baseUrl,
|
|
||||||
pusherAccount
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
case _ =>
|
case _ =>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import gitbucket.core.service.{AccountService, DeployKeyService, RepositoryServi
|
|||||||
import gitbucket.core.servlet.{CommitLogHook, Database}
|
import gitbucket.core.servlet.{CommitLogHook, Database}
|
||||||
import gitbucket.core.util.{SyntaxSugars, Directory}
|
import gitbucket.core.util.{SyntaxSugars, Directory}
|
||||||
import org.apache.sshd.server.{Environment, ExitCallback, SessionAware}
|
import org.apache.sshd.server.{Environment, ExitCallback, SessionAware}
|
||||||
import org.apache.sshd.server.command.{Command, CommandFactory}
|
import org.apache.sshd.server.{Command, CommandFactory}
|
||||||
import org.apache.sshd.server.session.ServerSession
|
import org.apache.sshd.server.session.ServerSession
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import java.io.{File, InputStream, OutputStream}
|
import java.io.{File, InputStream, OutputStream}
|
||||||
@@ -16,7 +16,7 @@ import org.eclipse.jgit.api.Git
|
|||||||
import Directory._
|
import Directory._
|
||||||
import gitbucket.core.ssh.PublicKeyAuthenticator.AuthType
|
import gitbucket.core.ssh.PublicKeyAuthenticator.AuthType
|
||||||
import org.eclipse.jgit.transport.{ReceivePack, UploadPack}
|
import org.eclipse.jgit.transport.{ReceivePack, UploadPack}
|
||||||
import org.apache.sshd.server.shell.UnknownCommand
|
import org.apache.sshd.server.scp.UnknownCommand
|
||||||
import org.eclipse.jgit.errors.RepositoryNotFoundException
|
import org.eclipse.jgit.errors.RepositoryNotFoundException
|
||||||
|
|
||||||
object GitCommand {
|
object GitCommand {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package gitbucket.core.ssh
|
|||||||
import gitbucket.core.service.SystemSettingsService.SshAddress
|
import gitbucket.core.service.SystemSettingsService.SshAddress
|
||||||
import org.apache.sshd.common.Factory
|
import org.apache.sshd.common.Factory
|
||||||
import org.apache.sshd.server.{Environment, ExitCallback}
|
import org.apache.sshd.server.{Environment, ExitCallback}
|
||||||
import org.apache.sshd.server.command.Command
|
import org.apache.sshd.server.Command
|
||||||
import java.io.{OutputStream, InputStream}
|
import java.io.{OutputStream, InputStream}
|
||||||
import org.eclipse.jgit.lib.Constants
|
import org.eclipse.jgit.lib.Constants
|
||||||
|
|
||||||
|
|||||||
@@ -232,6 +232,12 @@ object helpers extends AvatarImageProvider with LinkConverter with RequestCache
|
|||||||
s"""<a href="${context.path}/${m.group(1)}/${m.group(2)}/commit/${m.group(3)}">${m.group(1)}/${m
|
s"""<a href="${context.path}/${m.group(1)}/${m.group(2)}/commit/${m.group(3)}">${m.group(1)}/${m
|
||||||
.group(2)}@${m.group(3).substring(0, 7)}</a>"""
|
.group(2)}@${m.group(3).substring(0, 7)}</a>"""
|
||||||
)
|
)
|
||||||
|
.replaceAll(
|
||||||
|
"\\[release:([^\\s]+?)/([^\\s]+?)/([^\\s]+?)\\]",
|
||||||
|
(m: Match) =>
|
||||||
|
s"""<a href="${context.path}/${m.group(1)}/${m.group(2)}/releases/${encodeRefName(m.group(3))}">${m
|
||||||
|
.group(3)}</a>"""
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -40,10 +40,6 @@
|
|||||||
<label class="col-md-2">Version</label>
|
<label class="col-md-2">Version</label>
|
||||||
<span class="col-md-10">@plugin.pluginVersion</span>
|
<span class="col-md-10">@plugin.pluginVersion</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
|
||||||
<label class="col-md-2">Name</label>
|
|
||||||
<span class="col-md-10">@plugin.pluginName</span>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label class="col-md-2">Description</label>
|
<label class="col-md-2">Description</label>
|
||||||
<span class="col-md-10 muted">@plugin.description</span>
|
<span class="col-md-10 muted">@plugin.description</span>
|
||||||
|
|||||||
@@ -12,7 +12,9 @@ import org.scalatest.FunSpec
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class MergeServiceSpec extends FunSpec {
|
class MergeServiceSpec extends FunSpec {
|
||||||
val service = new MergeService {}
|
val service = new MergeService with AccountService with ActivityService with IssuesService with LabelsService
|
||||||
|
with MilestonesService with RepositoryService with PrioritiesService with PullRequestService with CommitsService
|
||||||
|
with WebHookPullRequestService with WebHookPullRequestReviewCommentService {}
|
||||||
val branch = "master"
|
val branch = "master"
|
||||||
val issueId = 10
|
val issueId = 10
|
||||||
def initRepository(owner: String, name: String): File = {
|
def initRepository(owner: String, name: String): File = {
|
||||||
|
|||||||
@@ -9,11 +9,15 @@ class PullRequestServiceSpec
|
|||||||
with PullRequestService
|
with PullRequestService
|
||||||
with IssuesService
|
with IssuesService
|
||||||
with AccountService
|
with AccountService
|
||||||
|
with ActivityService
|
||||||
with RepositoryService
|
with RepositoryService
|
||||||
with CommitsService
|
with CommitsService
|
||||||
with LabelsService
|
with LabelsService
|
||||||
with MilestonesService
|
with MilestonesService
|
||||||
with PrioritiesService {
|
with PrioritiesService
|
||||||
|
with WebHookService
|
||||||
|
with WebHookPullRequestService
|
||||||
|
with WebHookPullRequestReviewCommentService {
|
||||||
|
|
||||||
def swap(r: (Issue, PullRequest)) = (r._2 -> r._1)
|
def swap(r: (Issue, PullRequest)) = (r._2 -> r._1)
|
||||||
|
|
||||||
|
|||||||
@@ -43,8 +43,10 @@ trait ServiceSpecBase {
|
|||||||
|
|
||||||
def user(name: String)(implicit s: Session): Account = AccountService.getAccountByUserName(name).get
|
def user(name: String)(implicit s: Session): Account = AccountService.getAccountByUserName(name).get
|
||||||
|
|
||||||
lazy val dummyService = new RepositoryService with AccountService with IssuesService with PullRequestService
|
lazy val dummyService = new RepositoryService with AccountService with ActivityService with IssuesService
|
||||||
with CommitsService with CommitStatusService with LabelsService with MilestonesService with PrioritiesService() {}
|
with PullRequestService with CommitsService with CommitStatusService with LabelsService with MilestonesService
|
||||||
|
with PrioritiesService with WebHookService with WebHookPullRequestService
|
||||||
|
with WebHookPullRequestReviewCommentService {}
|
||||||
|
|
||||||
def generateNewUserWithDBRepository(userName: String, repositoryName: String)(implicit s: Session): Account = {
|
def generateNewUserWithDBRepository(userName: String, repositoryName: String)(implicit s: Session): Account = {
|
||||||
val ac = AccountService.getAccountByUserName(userName).getOrElse(generateNewAccount(userName))
|
val ac = AccountService.getAccountByUserName(userName).getOrElse(generateNewAccount(userName))
|
||||||
|
|||||||
@@ -5,8 +5,9 @@ import org.scalatest.FunSuite
|
|||||||
import gitbucket.core.model.WebHookContentType
|
import gitbucket.core.model.WebHookContentType
|
||||||
|
|
||||||
class WebHookServiceSpec extends FunSuite with ServiceSpecBase {
|
class WebHookServiceSpec extends FunSuite with ServiceSpecBase {
|
||||||
lazy val service = new WebHookPullRequestService with AccountService with RepositoryService with PullRequestService
|
lazy val service = new WebHookPullRequestService with AccountService with ActivityService with RepositoryService
|
||||||
with IssuesService with CommitsService with LabelsService with MilestonesService with PrioritiesService
|
with PullRequestService with IssuesService with CommitsService with LabelsService with MilestonesService
|
||||||
|
with PrioritiesService with WebHookPullRequestReviewCommentService
|
||||||
|
|
||||||
test("WebHookPullRequestService.getPullRequestsByRequestForWebhook") {
|
test("WebHookPullRequestService.getPullRequestsByRequestForWebhook") {
|
||||||
withTestDB { implicit session =>
|
withTestDB { implicit session =>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package gitbucket.core.ssh
|
package gitbucket.core.ssh
|
||||||
|
|
||||||
import org.apache.sshd.server.shell.UnknownCommand
|
import org.apache.sshd.server.scp.UnknownCommand
|
||||||
import org.scalatest.FunSpec
|
import org.scalatest.FunSpec
|
||||||
|
|
||||||
class GitCommandFactorySpec extends FunSpec {
|
class GitCommandFactorySpec extends FunSpec {
|
||||||
|
|||||||
Reference in New Issue
Block a user