add create/update a file. closes #2112

This commit is contained in:
KOUNOIKE
2019-02-09 20:30:09 +09:00
parent d608b171de
commit ff0c7f6a50
4 changed files with 104 additions and 28 deletions

View File

@@ -0,0 +1,13 @@
package gitbucket.core.api
/**
* https://developer.github.com/v3/repos/contents/#create-a-file
*/
case class CreateAFile(
message: String,
content: String,
sha: Option[String],
branch: Option[String],
committer: Option[ApiPusher],
author: Option[ApiPusher]
)

View File

@@ -32,6 +32,7 @@ class ApiController
with CommitsService
with CommitStatusService
with RepositoryCreationService
with RepositoryCommitFileService
with IssueCreationService
with HandleCommentService
with MergeService

View File

@@ -1,7 +1,7 @@
package gitbucket.core.controller.api
import gitbucket.core.api.{ApiContents, JsonFormat}
import gitbucket.core.api.{ApiContents, ApiError, CreateAFile, JsonFormat}
import gitbucket.core.controller.ControllerBase
import gitbucket.core.service.{AccountService, ProtectedBranchService, RepositoryService}
import gitbucket.core.service.{RepositoryCommitFileService, RepositoryService}
import gitbucket.core.util.Directory.getRepositoryDir
import gitbucket.core.util.JGitUtil.{FileInfo, getContentFromId, getFileList}
import gitbucket.core.util._
@@ -11,7 +11,7 @@ import gitbucket.core.util.Implicits._
import org.eclipse.jgit.api.Git
trait ApiRepositoryContentsControllerBase extends ControllerBase {
self: ReferrerAuthenticator =>
self: ReferrerAuthenticator with WritableUsersAuthenticator with RepositoryCommitFileService =>
/*
* i. Get the README
@@ -101,16 +101,48 @@ trait ApiRepositoryContentsControllerBase extends ControllerBase {
}
}
/*
* iii. Create a file
* iii. Create a file or iv. Update a file
* https://developer.github.com/v3/repos/contents/#create-a-file
* https://developer.github.com/v3/repos/contents/#update-a-file
* if sha is presented, update a file else create a file.
* requested #2112
*/
/*
* iv. Update a file
* https://developer.github.com/v3/repos/contents/#update-a-file
* requested #2112
*/
put("/api/v3/repos/:owner/:repository/contents/*")(writableUsersOnly { repository =>
JsonFormat(for {
data <- extractFromJsonBody[CreateAFile]
} yield {
val branch = data.branch.getOrElse(repository.repository.defaultBranch)
val commit = using(Git.open(getRepositoryDir(repository.owner, repository.name))) { git =>
val revCommit = JGitUtil.getRevCommitFromId(git, git.getRepository.resolve(branch))
revCommit.name
}
val paths = multiParams("splat").head.split("/")
val path = paths.take(paths.size - 1).toList.mkString("/")
if (data.sha.isDefined && data.sha.get != commit) {
ApiError("The blob SHA is not matched.", Some("https://developer.github.com/v3/repos/contents/#update-a-file"))
} else {
val objectId = commitFile(
repository,
branch,
path,
Some(paths.last),
if (data.sha.isDefined) {
Some(paths.last)
} else {
None
},
StringUtil.base64Decode(data.content),
data.message,
commit,
context.loginAccount.get,
data.committer.map(_.name).getOrElse(context.loginAccount.get.fullName),
data.committer.map(_.email).getOrElse(context.loginAccount.get.mailAddress)
)
ApiContents("file", paths.last, path, objectId.name, None, None)(RepositoryName(repository))
}
})
})
/*
* v. Delete a file

View File

@@ -29,7 +29,7 @@ trait RepositoryCommitFileService {
f: (Git, ObjectId, DirCacheBuilder, ObjectInserter) => Unit
)(implicit s: Session, c: JsonFormat.Context) = {
// prepend path to the filename
_commitFile(repository, branch, message, loginAccount)(f)
_commitFile(repository, branch, message, loginAccount, loginAccount.fullName, loginAccount.mailAddress)(f)
}
def commitFile(
@@ -43,7 +43,35 @@ trait RepositoryCommitFileService {
message: String,
commit: String,
loginAccount: Account
)(implicit s: Session, c: JsonFormat.Context) = {
)(implicit s: Session, c: JsonFormat.Context): ObjectId = {
commitFile(
repository,
branch,
path,
newFileName,
oldFileName,
if (content.nonEmpty) { content.getBytes(charset) } else { Array.emptyByteArray },
message,
commit,
loginAccount,
loginAccount.fullName,
loginAccount.mailAddress
)
}
def commitFile(
repository: RepositoryService.RepositoryInfo,
branch: String,
path: String,
newFileName: Option[String],
oldFileName: Option[String],
content: Array[Byte],
message: String,
commit: String,
loginAccount: Account,
fullName: String,
mailAddress: String
)(implicit s: Session, c: JsonFormat.Context): ObjectId = {
val newPath = newFileName.map { newFileName =>
if (path.length == 0) newFileName else s"${path}/${newFileName}"
@@ -52,7 +80,7 @@ trait RepositoryCommitFileService {
if (path.length == 0) oldFileName else s"${path}/${oldFileName}"
}
_commitFile(repository, branch, message, loginAccount) {
_commitFile(repository, branch, message, loginAccount, fullName, mailAddress) {
case (git, headTip, builder, inserter) =>
if (headTip.getName == commit) {
val permission = JGitUtil
@@ -70,7 +98,7 @@ trait RepositoryCommitFileService {
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))))
} getOrElse FileMode.REGULAR_FILE, inserter.insert(Constants.OBJ_BLOB, content)))
}
builder.finish()
}
@@ -81,10 +109,12 @@ trait RepositoryCommitFileService {
repository: RepositoryService.RepositoryInfo,
branch: String,
message: String,
loginAccount: Account
loginAccount: Account,
committerName: String,
committerMailAddress: String
)(
f: (Git, ObjectId, DirCacheBuilder, ObjectInserter) => Unit
)(implicit s: Session, c: JsonFormat.Context) = {
)(implicit s: Session, c: JsonFormat.Context): ObjectId = {
LockUtil.lock(s"${repository.owner}/${repository.name}") {
using(Git.open(getRepositoryDir(repository.owner, repository.name))) { git =>
@@ -101,8 +131,8 @@ trait RepositoryCommitFileService {
headTip,
builder.getDirCache.writeTree(inserter),
headName,
loginAccount.fullName,
loginAccount.mailAddress,
committerName,
committerMailAddress,
message
)
@@ -114,7 +144,7 @@ trait RepositoryCommitFileService {
// call post commit hook
val error = PluginRegistry().getReceiveHooks.flatMap { hook =>
hook.preReceive(repository.owner, repository.name, receivePack, receiveCommand, loginAccount.userName)
hook.preReceive(repository.owner, repository.name, receivePack, receiveCommand, committerName)
}.headOption
error match {
@@ -131,7 +161,7 @@ trait RepositoryCommitFileService {
val refUpdate = git.getRepository.updateRef(headName)
refUpdate.setNewObjectId(commitId)
refUpdate.setForceUpdate(false)
refUpdate.setRefLogIdent(new PersonIdent(loginAccount.fullName, loginAccount.mailAddress))
refUpdate.setRefLogIdent(new PersonIdent(committerName, committerMailAddress))
refUpdate.update()
// update pull request
@@ -139,26 +169,25 @@ trait RepositoryCommitFileService {
// record activity
val commitInfo = new CommitInfo(JGitUtil.getRevCommitFromId(git, commitId))
recordPushActivity(repository.owner, repository.name, loginAccount.userName, branch, List(commitInfo))
recordPushActivity(repository.owner, repository.name, committerName, 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))
}
closeIssuesFromMessage(message, committerName, 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)
hook.postReceive(repository.owner, repository.name, receivePack, receiveCommand, committerName)
}
val commit = new JGitUtil.CommitInfo(JGitUtil.getRevCommitFromId(git, commitId))
@@ -177,6 +206,7 @@ trait RepositoryCommitFileService {
}
}
}
commitId
}
}
}