diff --git a/src/main/resources/update/3_10.sql b/src/main/resources/update/3_10.sql new file mode 100644 index 0000000..721690a --- /dev/null +++ b/src/main/resources/update/3_10.sql @@ -0,0 +1,25 @@ +DROP TABLE IF EXISTS PROTECTED_BRANCH; + +CREATE TABLE PROTECTED_BRANCH( + USER_NAME VARCHAR(100) NOT NULL, + REPOSITORY_NAME VARCHAR(100) NOT NULL, + BRANCH VARCHAR(100) NOT NULL, + STATUS_CHECK_ADMIN BOOLEAN NOT NULL DEFAULT false +); + +ALTER TABLE PROTECTED_BRANCH ADD CONSTRAINT IDX_PROTECTED_BRANCH_PK PRIMARY KEY (USER_NAME, REPOSITORY_NAME, BRANCH); +ALTER TABLE PROTECTED_BRANCH ADD CONSTRAINT IDX_PROTECTED_BRANCH_FK0 FOREIGN KEY (USER_NAME, REPOSITORY_NAME) REFERENCES REPOSITORY (USER_NAME, REPOSITORY_NAME) + ON DELETE CASCADE ON UPDATE CASCADE; + + +DROP TABLE IF EXISTS PROTECTED_BRANCH_REQUIRE_CONTEXT; +CREATE TABLE PROTECTED_BRANCH_REQUIRE_CONTEXT( + USER_NAME VARCHAR(100) NOT NULL, + REPOSITORY_NAME VARCHAR(100) NOT NULL, + BRANCH VARCHAR(100) NOT NULL, + CONTEXT VARCHAR(255) NOT NULL +); + +ALTER TABLE PROTECTED_BRANCH_REQUIRE_CONTEXT ADD CONSTRAINT IDX_PROTECTED_BRANCH_REQUIRE_CONTEXT_PK PRIMARY KEY (USER_NAME, REPOSITORY_NAME, BRANCH, CONTEXT); +ALTER TABLE PROTECTED_BRANCH_REQUIRE_CONTEXT ADD CONSTRAINT IDX_PROTECTED_BRANCH_REQUIRE_CONTEXT_FK0 FOREIGN KEY (USER_NAME, REPOSITORY_NAME, BRANCH) REFERENCES PROTECTED_BRANCH (USER_NAME, REPOSITORY_NAME, BRANCH) + ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/src/main/scala/gitbucket/core/model/BasicTemplate.scala b/src/main/scala/gitbucket/core/model/BasicTemplate.scala index db3e1b4..1d91cc4 100644 --- a/src/main/scala/gitbucket/core/model/BasicTemplate.scala +++ b/src/main/scala/gitbucket/core/model/BasicTemplate.scala @@ -54,4 +54,10 @@ byRepository(userName, repositoryName) && (this.commitId === commitId) } + + trait BranchTemplate extends BasicTemplate{ self: Table[_] => + val branch = column[String]("BRANCH") + def byBranch(owner: String, repository: String, branchName: String) = byRepository(owner, repository) && (branch === branchName.bind) + def byBranch(owner: Column[String], repository: Column[String], branchName: Column[String]) = byRepository(owner, repository) && (this.branch === branchName) + } } diff --git a/src/main/scala/gitbucket/core/model/Profile.scala b/src/main/scala/gitbucket/core/model/Profile.scala index e173630..0badf86 100644 --- a/src/main/scala/gitbucket/core/model/Profile.scala +++ b/src/main/scala/gitbucket/core/model/Profile.scala @@ -50,5 +50,6 @@ with WebHookComponent with WebHookEventComponent with PluginComponent + with ProtectedBranchComponent object Profile extends CoreProfile diff --git a/src/main/scala/gitbucket/core/model/ProtectedBranch.scala b/src/main/scala/gitbucket/core/model/ProtectedBranch.scala new file mode 100644 index 0000000..dcc26c4 --- /dev/null +++ b/src/main/scala/gitbucket/core/model/ProtectedBranch.scala @@ -0,0 +1,37 @@ +package gitbucket.core.model + +import scala.slick.lifted.MappedTo +import scala.slick.jdbc._ + +trait ProtectedBranchComponent extends TemplateComponent { self: Profile => + import profile.simple._ + import self._ + + lazy val ProtectedBranches = TableQuery[ProtectedBranches] + class ProtectedBranches(tag: Tag) extends Table[ProtectedBranch](tag, "PROTECTED_BRANCH") with BranchTemplate { + val statusCheckAdmin = column[Boolean]("STATUS_CHECK_ADMIN") + def * = (userName, repositoryName, branch, statusCheckAdmin) <> (ProtectedBranch.tupled, ProtectedBranch.unapply) + def byPrimaryKey(userName: String, repositoryName: String, branch: String) = byBranch(userName, repositoryName, branch) + def byPrimaryKey(userName: Column[String], repositoryName: Column[String], branch: Column[String]) = byBranch(userName, repositoryName, branch) + } + + lazy val ProtectedBrancheContexts = TableQuery[ProtectedBrancheContexts] + class ProtectedBrancheContexts(tag: Tag) extends Table[ProtectedBranchContext](tag, "PROTECTED_BRANCH_REQUIRE_CONTEXT") with BranchTemplate { + val context = column[String]("CONTEXT") + def * = (userName, repositoryName, branch, context) <> (ProtectedBranchContext.tupled, ProtectedBranchContext.unapply) + } +} + + +case class ProtectedBranch( + userName: String, + repositoryName: String, + branch: String, + statusCheckAdmin: Boolean) + + +case class ProtectedBranchContext( + userName: String, + repositoryName: String, + branch: String, + context: String) diff --git a/src/main/scala/gitbucket/core/service/ProtectedBrancheService.scala b/src/main/scala/gitbucket/core/service/ProtectedBrancheService.scala index 89a1955..40f398e 100644 --- a/src/main/scala/gitbucket/core/service/ProtectedBrancheService.scala +++ b/src/main/scala/gitbucket/core/service/ProtectedBrancheService.scala @@ -1,6 +1,6 @@ package gitbucket.core.service -import gitbucket.core.model.{Collaborator, Repository, Account, CommitState, CommitStatus} +import gitbucket.core.model.{Collaborator, Repository, Account, CommitState, CommitStatus, ProtectedBranch, ProtectedBranchContext} import gitbucket.core.model.Profile._ import gitbucket.core.util.JGitUtil import profile.simple._ @@ -10,38 +10,40 @@ import org.eclipse.jgit.lib.ObjectId -object MockDB{ - val data:scala.collection.mutable.Map[(String,String,String),(Boolean, Seq[String])] = scala.collection.mutable.Map(("root", "test58", "hoge2") -> (false, Seq.empty)) -} - trait ProtectedBrancheService { import ProtectedBrancheService._ - private def getProtectedBranchInfoOpt(owner: String, repository: String, branch: String)(implicit session: Session): Option[ProtectedBranchInfo] = { - // TODO: mock - MockDB.data.get((owner, repository, branch)).map{ case (includeAdministrators, contexts) => - new ProtectedBranchInfo(owner, repository, true, contexts, includeAdministrators) - } - } - def getProtectedBranchInfo(owner: String, repository: String, branch: String)(implicit session: Session): ProtectedBranchInfo = { + private def getProtectedBranchInfoOpt(owner: String, repository: String, branch: String)(implicit session: Session): Option[ProtectedBranchInfo] = + ProtectedBranches + .leftJoin(ProtectedBrancheContexts) + .on{ case (pb, c) => pb.byBranch(c.userName, c.repositoryName, c.branch) } + .map{ case (pb, c) => pb -> c.context.? } + .filter(_._1.byPrimaryKey(owner, repository, branch)) + .list + .groupBy(_._1) + .map(p => p._1 -> p._2.flatMap(_._2)) + .map{ case (t1, contexts) => + new ProtectedBranchInfo(t1.userName, t1.repositoryName, true, contexts, t1.statusCheckAdmin) + }.headOption + + def getProtectedBranchInfo(owner: String, repository: String, branch: String)(implicit session: Session): ProtectedBranchInfo = getProtectedBranchInfoOpt(owner, repository, branch).getOrElse(ProtectedBranchInfo.disabled(owner, repository)) - } + def isProtectedBranchNeedStatusCheck(owner: String, repository: String, branch: String, user: String)(implicit session: Session): Boolean = getProtectedBranchInfo(owner, repository, branch).needStatusCheck(user) - def getProtectedBranchList(owner: String, repository: String)(implicit session: Session): List[String] = { - // TODO: mock - MockDB.data.filter{ - case ((owner, repository, _), _) => true - case _ => false - }.map{ case ((_, _, branch), _) => branch }.toList - } + + def getProtectedBranchList(owner: String, repository: String)(implicit session: Session): List[String] = + ProtectedBranches.filter(_.byRepository(owner, repository)).map(_.branch).list + def enableBranchProtection(owner: String, repository: String, branch:String, includeAdministrators: Boolean, contexts: Seq[String])(implicit session: Session): Unit = { - // TODO: mock - MockDB.data.put((owner, repository, branch), includeAdministrators -> contexts) + disableBranchProtection(owner, repository, branch) + ProtectedBranches.insert(new ProtectedBranch(owner, repository, branch, includeAdministrators)) + contexts.map{ context => + ProtectedBrancheContexts.insert(new ProtectedBranchContext(owner, repository, branch, context)) + } } - def disableBranchProtection(owner: String, repository: String, branch:String)(implicit session: Session): Unit = { - // TODO: mock - MockDB.data.remove((owner, repository, branch)) - } + + def disableBranchProtection(owner: String, repository: String, branch:String)(implicit session: Session): Unit = + ProtectedBranches.filter(_.byPrimaryKey(owner, repository, branch)).delete def getBranchProtectedReason(owner: String, repository: String, receivePack: ReceivePack, command: ReceiveCommand, pusher: String)(implicit session: Session): Option[String] = { val branch = command.getRefName.stripPrefix("refs/heads/") diff --git a/src/main/scala/gitbucket/core/service/RepositoryService.scala b/src/main/scala/gitbucket/core/service/RepositoryService.scala index ffef183..fd2549c 100644 --- a/src/main/scala/gitbucket/core/service/RepositoryService.scala +++ b/src/main/scala/gitbucket/core/service/RepositoryService.scala @@ -46,18 +46,20 @@ (Repositories filter { t => t.byRepository(oldUserName, oldRepositoryName) } firstOption).map { repository => Repositories insert repository.copy(userName = newUserName, repositoryName = newRepositoryName) - val webHooks = WebHooks .filter(_.byRepository(oldUserName, oldRepositoryName)).list - val webHookEvents = WebHookEvents .filter(_.byRepository(oldUserName, oldRepositoryName)).list - val milestones = Milestones .filter(_.byRepository(oldUserName, oldRepositoryName)).list - val issueId = IssueId .filter(_.byRepository(oldUserName, oldRepositoryName)).list - val issues = Issues .filter(_.byRepository(oldUserName, oldRepositoryName)).list - val pullRequests = PullRequests .filter(_.byRepository(oldUserName, oldRepositoryName)).list - val labels = Labels .filter(_.byRepository(oldUserName, oldRepositoryName)).list - val issueComments = IssueComments .filter(_.byRepository(oldUserName, oldRepositoryName)).list - val issueLabels = IssueLabels .filter(_.byRepository(oldUserName, oldRepositoryName)).list - val commitComments = CommitComments.filter(_.byRepository(oldUserName, oldRepositoryName)).list - val commitStatuses = CommitStatuses.filter(_.byRepository(oldUserName, oldRepositoryName)).list - val collaborators = Collaborators .filter(_.byRepository(oldUserName, oldRepositoryName)).list + val webHooks = WebHooks .filter(_.byRepository(oldUserName, oldRepositoryName)).list + val webHookEvents = WebHookEvents .filter(_.byRepository(oldUserName, oldRepositoryName)).list + val milestones = Milestones .filter(_.byRepository(oldUserName, oldRepositoryName)).list + val issueId = IssueId .filter(_.byRepository(oldUserName, oldRepositoryName)).list + val issues = Issues .filter(_.byRepository(oldUserName, oldRepositoryName)).list + val pullRequests = PullRequests .filter(_.byRepository(oldUserName, oldRepositoryName)).list + val labels = Labels .filter(_.byRepository(oldUserName, oldRepositoryName)).list + val issueComments = IssueComments .filter(_.byRepository(oldUserName, oldRepositoryName)).list + val issueLabels = IssueLabels .filter(_.byRepository(oldUserName, oldRepositoryName)).list + val commitComments = CommitComments .filter(_.byRepository(oldUserName, oldRepositoryName)).list + val commitStatuses = CommitStatuses .filter(_.byRepository(oldUserName, oldRepositoryName)).list + val collaborators = Collaborators .filter(_.byRepository(oldUserName, oldRepositoryName)).list + val protectedBranches = ProtectedBranches .filter(_.byRepository(oldUserName, oldRepositoryName)).list + val protectedBrancheContexts = ProtectedBrancheContexts .filter(_.byRepository(oldUserName, oldRepositoryName)).list Repositories.filter { t => (t.originUserName === oldUserName.bind) && (t.originRepositoryName === oldRepositoryName.bind) @@ -90,11 +92,13 @@ } )} :_*) - PullRequests .insertAll(pullRequests .map(_.copy(userName = newUserName, repositoryName = newRepositoryName)) :_*) - IssueComments .insertAll(issueComments .map(_.copy(userName = newUserName, repositoryName = newRepositoryName)) :_*) - Labels .insertAll(labels .map(_.copy(userName = newUserName, repositoryName = newRepositoryName)) :_*) - CommitComments.insertAll(commitComments.map(_.copy(userName = newUserName, repositoryName = newRepositoryName)) :_*) - CommitStatuses.insertAll(commitStatuses.map(_.copy(userName = newUserName, repositoryName = newRepositoryName)) :_*) + PullRequests .insertAll(pullRequests .map(_.copy(userName = newUserName, repositoryName = newRepositoryName)) :_*) + IssueComments .insertAll(issueComments .map(_.copy(userName = newUserName, repositoryName = newRepositoryName)) :_*) + Labels .insertAll(labels .map(_.copy(userName = newUserName, repositoryName = newRepositoryName)) :_*) + CommitComments .insertAll(commitComments.map(_.copy(userName = newUserName, repositoryName = newRepositoryName)) :_*) + CommitStatuses .insertAll(commitStatuses.map(_.copy(userName = newUserName, repositoryName = newRepositoryName)) :_*) + ProtectedBranches .insertAll(protectedBranches.map(_.copy(userName = newUserName, repositoryName = newRepositoryName)) :_*) + ProtectedBrancheContexts.insertAll(protectedBrancheContexts.map(_.copy(userName = newUserName, repositoryName = newRepositoryName)) :_*) // Update source repository of pull requests PullRequests.filter { t =>