diff --git a/src/main/resources/update/gitbucket-core_4.22.xml b/src/main/resources/update/gitbucket-core_4.22.xml
new file mode 100644
index 0000000..98a3b3d
--- /dev/null
+++ b/src/main/resources/update/gitbucket-core_4.22.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/src/main/scala/gitbucket/core/GitBucketCoreModule.scala b/src/main/scala/gitbucket/core/GitBucketCoreModule.scala
index 2f3df19..0fd6742 100644
--- a/src/main/scala/gitbucket/core/GitBucketCoreModule.scala
+++ b/src/main/scala/gitbucket/core/GitBucketCoreModule.scala
@@ -53,5 +53,8 @@
new LiquibaseMigration("update/gitbucket-core_4.21.xml")
),
new Version("4.21.1"),
- new Version("4.21.2")
+ new Version("4.21.2"),
+ new Version("4.22.0",
+ new LiquibaseMigration("update/gitbucket-core_4.22.xml")
+ )
)
diff --git a/src/main/scala/gitbucket/core/controller/PullRequestsController.scala b/src/main/scala/gitbucket/core/controller/PullRequestsController.scala
index 18fef96..395b4f9 100644
--- a/src/main/scala/gitbucket/core/controller/PullRequestsController.scala
+++ b/src/main/scala/gitbucket/core/controller/PullRequestsController.scala
@@ -17,6 +17,7 @@
import org.eclipse.jgit.api.Git
import org.eclipse.jgit.lib.PersonIdent
import org.eclipse.jgit.revwalk.RevWalk
+import org.scalatra.BadRequest
import scala.collection.JavaConverters._
@@ -248,67 +249,69 @@
params("id").toIntOpt.flatMap { issueId =>
val owner = repository.owner
val name = repository.name
- 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)
+ 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
- recordMergeActivity(owner, name, loginAccount.userName, issueId, form.message)
+ // record activity
+ recordMergeActivity(owner, name, loginAccount.userName, issueId, form.message)
- val (commits, _) = getRequestCompareInfo(owner, name, pullreq.commitIdFrom,
- pullreq.requestUserName, pullreq.requestRepositoryName, pullreq.commitIdTo)
+ 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))
+ 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))
}
- }.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)
+ // 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)
+ }
+ closeIssuesFromMessage(issue.title + " " + issue.content.getOrElse(""), loginAccount.userName, owner, name)
+ closeIssuesFromMessage(form.message, loginAccount.userName, owner, name)
}
- closeIssuesFromMessage(issue.title + " " + issue.content.getOrElse(""), loginAccount.userName, owner, name)
- closeIssuesFromMessage(form.message, loginAccount.userName, owner, name)
+
+ 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}")
}
-
- 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()
})
diff --git a/src/main/scala/gitbucket/core/controller/RepositorySettingsController.scala b/src/main/scala/gitbucket/core/controller/RepositorySettingsController.scala
index b1e5b3d..ffe98c1 100644
--- a/src/main/scala/gitbucket/core/controller/RepositorySettingsController.scala
+++ b/src/main/scala/gitbucket/core/controller/RepositorySettingsController.scala
@@ -39,20 +39,29 @@
externalIssuesUrl: Option[String],
wikiOption: String,
externalWikiUrl: Option[String],
- allowFork: Boolean
+ allowFork: Boolean,
+ mergeOptions: Seq[String]
)
val optionsForm = mapping(
- "repositoryName" -> trim(label("Repository Name" , text(required, maxlength(100), repository, renameRepositoryName))),
- "description" -> trim(label("Description" , optional(text()))),
- "isPrivate" -> trim(label("Repository Type" , boolean())),
- "issuesOption" -> trim(label("Issues Option" , text(required, featureOption))),
- "externalIssuesUrl" -> trim(label("External Issues URL", optional(text(maxlength(200))))),
- "wikiOption" -> trim(label("Wiki Option" , text(required, featureOption))),
- "externalWikiUrl" -> trim(label("External Wiki URL" , optional(text(maxlength(200))))),
- "allowFork" -> trim(label("Allow Forking" , boolean()))
+ "repositoryName" -> trim(label("Repository Name" , text(required, maxlength(100), repository, renameRepositoryName))),
+ "description" -> trim(label("Description" , optional(text()))),
+ "isPrivate" -> trim(label("Repository Type" , boolean())),
+ "issuesOption" -> trim(label("Issues Option" , text(required, featureOption))),
+ "externalIssuesUrl" -> trim(label("External Issues URL", optional(text(maxlength(200))))),
+ "wikiOption" -> trim(label("Wiki Option" , text(required, featureOption))),
+ "externalWikiUrl" -> trim(label("External Wiki URL" , optional(text(maxlength(200))))),
+ "allowFork" -> trim(label("Allow Forking" , boolean())),
+ "mergeOptions" -> new ValueType[Seq[String]]{
+ override def convert(name: String, params: Map[String, Seq[String]], messages: Messages): Seq[String] =
+ params.get("mergeOptions").getOrElse(Nil)
+ override def validate(name: String, params: Map[String, Seq[String]], messages: Messages): Seq[(String, String)] =
+ if(params.get("mergeOptions").getOrElse(Nil).isEmpty) Seq("mergeOptions" -> "At least one option must be enabled.") else Nil
+ },
)(OptionsForm.apply)
+
+
// for default branch
case class DefaultBranchForm(defaultBranch: String)
@@ -118,7 +127,8 @@
form.externalIssuesUrl,
form.wikiOption,
form.externalWikiUrl,
- form.allowFork
+ form.allowFork,
+ form.mergeOptions
)
// Change repository name
if(repository.name != form.repositoryName){
diff --git a/src/main/scala/gitbucket/core/model/Repository.scala b/src/main/scala/gitbucket/core/model/Repository.scala
index 66cb641..1e06a39 100644
--- a/src/main/scala/gitbucket/core/model/Repository.scala
+++ b/src/main/scala/gitbucket/core/model/Repository.scala
@@ -22,11 +22,12 @@
val wikiOption = column[String]("WIKI_OPTION")
val externalWikiUrl = column[String]("EXTERNAL_WIKI_URL")
val allowFork = column[Boolean]("ALLOW_FORK")
+ val mergeOptions = column[String]("MERGE_OPTIONS")
def * = (
(userName, repositoryName, isPrivate, description.?, defaultBranch,
registeredDate, updatedDate, lastActivityDate, originUserName.?, originRepositoryName.?, parentUserName.?, parentRepositoryName.?),
- (issuesOption, externalIssuesUrl.?, wikiOption, externalWikiUrl.?, allowFork)
+ (issuesOption, externalIssuesUrl.?, wikiOption, externalWikiUrl.?, allowFork, mergeOptions)
).shaped <> (
{ case (repository, options) =>
Repository(
@@ -88,5 +89,6 @@
externalIssuesUrl: Option[String],
wikiOption: String,
externalWikiUrl: Option[String],
- allowFork: Boolean
+ allowFork: Boolean,
+ mergeOptions: String
)
diff --git a/src/main/scala/gitbucket/core/service/RepositoryService.scala b/src/main/scala/gitbucket/core/service/RepositoryService.scala
index 5997629..34bb954 100644
--- a/src/main/scala/gitbucket/core/service/RepositoryService.scala
+++ b/src/main/scala/gitbucket/core/service/RepositoryService.scala
@@ -46,7 +46,8 @@
externalIssuesUrl = None,
wikiOption = "PUBLIC", // TODO DISABLE for the forked repository?
externalWikiUrl = None,
- allowFork = true
+ allowFork = true,
+ mergeOptions = "merge-commit,squash,rebase"
)
)
@@ -362,14 +363,34 @@
/**
* Save repository options.
*/
- def saveRepositoryOptions(userName: String, repositoryName: String,
- description: Option[String], isPrivate: Boolean,
- issuesOption: String, externalIssuesUrl: Option[String],
- wikiOption: String, externalWikiUrl: Option[String],
- allowFork: Boolean)(implicit s: Session): Unit =
+ def saveRepositoryOptions(userName: String, repositoryName: String, description: Option[String], isPrivate: Boolean,
+ issuesOption: String, externalIssuesUrl: Option[String], wikiOption: String, externalWikiUrl: Option[String],
+ allowFork: Boolean, mergeOptions: Seq[String])(implicit s: Session): Unit = {
+
Repositories.filter(_.byRepository(userName, repositoryName))
- .map { r => (r.description.?, r.isPrivate, r.issuesOption, r.externalIssuesUrl.?, r.wikiOption, r.externalWikiUrl.?, r.allowFork, r.updatedDate) }
- .update (description, isPrivate, issuesOption, externalIssuesUrl, wikiOption, externalWikiUrl, allowFork, currentDate)
+ .map { r => (
+ r.description.?,
+ r.isPrivate,
+ r.issuesOption,
+ r.externalIssuesUrl.?,
+ r.wikiOption,
+ r.externalWikiUrl.?,
+ r.allowFork,
+ r.mergeOptions,
+ r.updatedDate
+ ) }
+ .update (
+ description,
+ isPrivate,
+ issuesOption,
+ externalIssuesUrl,
+ wikiOption,
+ externalWikiUrl,
+ allowFork,
+ mergeOptions.mkString(","),
+ currentDate
+ )
+ }
def saveRepositoryDefaultBranch(userName: String, repositoryName: String,
defaultBranch: String)(implicit s: Session): Unit =
diff --git a/src/main/twirl/gitbucket/core/pulls/mergeguide.scala.html b/src/main/twirl/gitbucket/core/pulls/mergeguide.scala.html
index 3332c1f..e80e60c 100644
--- a/src/main/twirl/gitbucket/core/pulls/mergeguide.scala.html
+++ b/src/main/twirl/gitbucket/core/pulls/mergeguide.scala.html
@@ -143,34 +143,48 @@
diff --git a/src/main/twirl/gitbucket/core/settings/options.scala.html b/src/main/twirl/gitbucket/core/settings/options.scala.html
index 7589425..4e39f8e 100644
--- a/src/main/twirl/gitbucket/core/settings/options.scala.html
+++ b/src/main/twirl/gitbucket/core/settings/options.scala.html
@@ -112,6 +112,38 @@
+
+
Merge strategy
+
+ Select pull request merge strategies which are available in this repository. At least one option must be enabled.
+
+
+