mirror of
https://github.com/gitbucket/gitbucket.git
synced 2025-11-15 09:55:49 +01:00
Merge branch 'feature/file-upload-to-repo' of https://github.com/devagorilla/gitbucket into devagorilla-feature/file-upload-to-repo
This commit is contained in:
@@ -21,7 +21,7 @@ import io.github.gitbucket.scalatra.forms._
|
|||||||
import org.apache.commons.io.IOUtils
|
import org.apache.commons.io.IOUtils
|
||||||
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
|
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.revwalk.RevCommit
|
import org.eclipse.jgit.revwalk.RevCommit
|
||||||
@@ -547,6 +547,149 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Upload file to a branch.
|
||||||
|
*/
|
||||||
|
post("/:owner/:repository/files/upload")(writableUsersOnly { repository =>
|
||||||
|
defining(repository.owner, repository.name){ case (owner, name) =>
|
||||||
|
(for {
|
||||||
|
data <- extractFromJsonBody[UploadFiles] if data.isValid
|
||||||
|
} yield {
|
||||||
|
Directory.getAttachedDir(owner, name) match {
|
||||||
|
case dir if (dir.exists && dir.isDirectory) =>
|
||||||
|
val _commitFiles = data.fileIds.map { case (fileName, id) =>
|
||||||
|
dir.listFiles.find(_.getName.startsWith(id + ".")).map { file =>
|
||||||
|
CommitFile(id, fileName, using(new FileInputStream(file))(IOUtils.toByteArray))
|
||||||
|
}
|
||||||
|
}.toList
|
||||||
|
|
||||||
|
val finalCommitFiles = _commitFiles.flatten
|
||||||
|
if(finalCommitFiles.size == data.fileIds.size) {
|
||||||
|
commitFiles(
|
||||||
|
repository,
|
||||||
|
files = finalCommitFiles,
|
||||||
|
branch = data.branch,
|
||||||
|
path = data.path,
|
||||||
|
message = data.message)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
org.scalatra.NotAcceptable(
|
||||||
|
s"""{"message":
|
||||||
|
|"$repository doesn't contain all the files you specified in the body"}""".stripMargin)
|
||||||
|
}
|
||||||
|
|
||||||
|
case _ => org.scalatra.NotFound(s"""{"message": "$repository doesn't contain any attached files"}""")
|
||||||
|
}
|
||||||
|
|
||||||
|
}) getOrElse
|
||||||
|
org.scalatra.NotAcceptable("""{"message": "FileIds can't be an empty list"}""")
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
case class UploadFiles(branch: String, path: String, fileIds : Map[String,String], message: String) {
|
||||||
|
lazy val isValid: Boolean = fileIds.size > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
case class CommitFile(fileId: String, name: String, fileBytes: Array[Byte])
|
||||||
|
|
||||||
|
private def commitFiles(repository: RepositoryService.RepositoryInfo,
|
||||||
|
files: List[CommitFile],
|
||||||
|
branch: String, path: String, message: String) = {
|
||||||
|
|
||||||
|
_commitFile(repository, branch, path, message) { case (git, headTip, builder, inserter) =>
|
||||||
|
JGitUtil.processTree(git, headTip) { (path, tree) =>
|
||||||
|
builder.add(JGitUtil.createDirCacheEntry(path, tree.getEntryFileMode, tree.getEntryObjectId))
|
||||||
|
}
|
||||||
|
|
||||||
|
files.foreach { item =>
|
||||||
|
val fileName = item.name
|
||||||
|
val bytes = item.fileBytes
|
||||||
|
builder.add(JGitUtil.createDirCacheEntry(fileName,
|
||||||
|
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) = {
|
||||||
|
|
||||||
|
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, path, message){ case (git, headTip, builder, inserter) =>
|
||||||
|
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, path: 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.userName, loginAccount.mailAddress, message)
|
||||||
|
|
||||||
|
inserter.flush()
|
||||||
|
inserter.close()
|
||||||
|
|
||||||
|
// 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
|
||||||
|
closeIssuesFromMessage(message, loginAccount.userName, repository.owner, repository.name)
|
||||||
|
|
||||||
|
//call web hook
|
||||||
|
callPullRequestWebHookByRequestBranch("synchronize", repository, branch, context.baseUrl, loginAccount)
|
||||||
|
val commit = new JGitUtil.CommitInfo(JGitUtil.getRevCommitFromId(git, commitId))
|
||||||
|
callWebHookOf(repository.owner, repository.name, 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")
|
||||||
@@ -597,84 +740,13 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private def commitFile(repository: RepositoryService.RepositoryInfo,
|
|
||||||
branch: String, path: String, newFileName: Option[String], oldFileName: Option[String],
|
|
||||||
content: String, charset: String, message: 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}" }
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
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()
|
|
||||||
|
|
||||||
val commitId = JGitUtil.createNewCommit(git, inserter, headTip, builder.getDirCache.writeTree(inserter),
|
|
||||||
headName, loginAccount.fullName, loginAccount.mailAddress, message)
|
|
||||||
|
|
||||||
inserter.flush()
|
|
||||||
inserter.close()
|
|
||||||
|
|
||||||
// update refs
|
|
||||||
val refUpdate = git.getRepository.updateRef(headName)
|
|
||||||
refUpdate.setNewObjectId(commitId)
|
|
||||||
refUpdate.setForceUpdate(false)
|
|
||||||
refUpdate.setRefLogIdent(new PersonIdent(loginAccount.fullName, loginAccount.mailAddress))
|
|
||||||
//refUpdate.setRefLogMessage("merged", true)
|
|
||||||
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
|
|
||||||
closeIssuesFromMessage(message, loginAccount.userName, repository.owner, repository.name)
|
|
||||||
|
|
||||||
// call web hook
|
|
||||||
callPullRequestWebHookByRequestBranch("synchronize", repository, branch, context.baseUrl, loginAccount)
|
|
||||||
val commit = new JGitUtil.CommitInfo(JGitUtil.getRevCommitFromId(git, commitId))
|
|
||||||
callWebHookOf(repository.owner, repository.name, WebHook.Push) {
|
|
||||||
getAccountByUserName(repository.owner).map{ ownerAccount =>
|
|
||||||
WebHookPushPayload(git, loginAccount, headName, repository, List(commit), ownerAccount,
|
|
||||||
oldId = headTip, newId = commitId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private def archiveRepository(name: String, suffix: String, repository: RepositoryService.RepositoryInfo): Unit = {
|
private def archiveRepository(name: String, suffix: String, repository: RepositoryService.RepositoryInfo): Unit = {
|
||||||
val revision = name.stripSuffix(suffix)
|
val revision = name.stripSuffix(suffix)
|
||||||
|
|
||||||
using(Git.open(getRepositoryDir(repository.owner, repository.name))){ git =>
|
using(Git.open(getRepositoryDir(repository.owner, repository.name))){ git =>
|
||||||
val oid = git.getRepository.resolve(revision)
|
val oid = git.getRepository.resolve(revision)
|
||||||
val revCommit = JGitUtil.getRevCommitFromId(git, oid)
|
val revCommit = JGitUtil.getRevCommitFromId(git, oid)
|
||||||
val sha1 = oid.getName()
|
val sha1 = oid.getName()
|
||||||
val repositorySuffix = (if(sha1.startsWith(revision)) sha1 else revision).replace('/','-')
|
val repositorySuffix = (if(sha1.startsWith(revision)) sha1 else revision).replace('/','-')
|
||||||
val filename = repository.name + "-" + repositorySuffix + suffix
|
val filename = repository.name + "-" + repositorySuffix + suffix
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user