Enhance Git Reference APIs (#2937)

This commit is contained in:
Naoki Takezoe
2021-12-06 17:16:33 +09:00
committed by GitHub
parent aba428bba1
commit d6a191d95b
10 changed files with 92 additions and 55 deletions

View File

@@ -39,11 +39,11 @@ object ApiRef {
): ApiRef =
ApiRef(
ref = s"refs/tags/${tagInfo.name}",
url = ApiPath(s"/api/v3/repos/${repositoryName.fullName}/refs/tags/${tagInfo.name}"),
url = ApiPath(s"/api/v3/repos/${repositoryName.fullName}/git/refs/tags/${tagInfo.name}"),
`object` = ApiRefCommit(
sha = tagInfo.id,
url = ApiPath(s"/api/v3/repos/${repositoryName.fullName}/git/tags/${tagInfo.id}"), // TODO This URL is not yet available?
`type` = "commit"
sha = tagInfo.objectId,
url = ApiPath(s"/api/v3/repos/${repositoryName.fullName}/git/tags/${tagInfo.objectId}"), // TODO This URL is not yet available?
`type` = "tag"
)
)
}

View File

@@ -138,7 +138,7 @@ trait ReleaseControllerBase extends ControllerBase {
get("/:owner/:repository/changelog/*...*")(writableUsersOnly { repository =>
val Seq(previousTag, currentTag) = multiParams("splat")
val previousTagId = repository.tags.collectFirst { case x if x.name == previousTag => x.id }.getOrElse("")
val previousTagId = repository.tags.collectFirst { case x if x.name == previousTag => x.commitId }.getOrElse("")
val commitLog = Using.resource(Git.open(getRepositoryDir(repository.owner, repository.name))) { git =>
val commits = JGitUtil.getCommitLog(git, previousTagId, currentTag).reverse

View File

@@ -1,10 +1,10 @@
package gitbucket.core.controller.api
import gitbucket.core.api.{ApiRef, CreateARef, JsonFormat, UpdateARef}
import gitbucket.core.api.{ApiError, ApiRef, CreateARef, JsonFormat, UpdateARef}
import gitbucket.core.controller.ControllerBase
import gitbucket.core.service.RepositoryService.RepositoryInfo
import gitbucket.core.util.Directory.getRepositoryDir
import gitbucket.core.util.Implicits._
import gitbucket.core.util.{ReferrerAuthenticator, RepositoryName}
import gitbucket.core.util.{ReferrerAuthenticator, RepositoryName, WritableUsersAuthenticator}
import org.eclipse.jgit.api.Git
import org.eclipse.jgit.lib.ObjectId
import org.eclipse.jgit.lib.RefUpdate.Result
@@ -15,10 +15,23 @@ import scala.jdk.CollectionConverters._
import scala.util.Using
trait ApiGitReferenceControllerBase extends ControllerBase {
self: ReferrerAuthenticator =>
self: ReferrerAuthenticator with WritableUsersAuthenticator =>
private val logger = LoggerFactory.getLogger(classOf[ApiGitReferenceControllerBase])
get("/api/v3/repos/:owner/:repository/git/refs")(referrersOnly { repository =>
val result = Using.resource(Git.open(getRepositoryDir(repository.owner, repository.name))) { git =>
val refs = git
.getRepository()
.getRefDatabase()
.getRefsByPrefix("refs")
.asScala
refs.map(ApiRef.fromRef(RepositoryName(s"${repository.owner}/${repository.name}"), _))
}
JsonFormat(result)
})
/*
* i. Get a reference
* https://docs.github.com/en/free-pro-team@latest/rest/reference/git#get-a-reference
@@ -35,34 +48,6 @@ trait ApiGitReferenceControllerBase extends ControllerBase {
getRef(revstr, repository)
})
protected def getRef(revstr: String, repository: RepositoryInfo): String = {
logger.debug(s"getRef: path '${revstr}'")
val name = RepositoryName(repository)
val result = JsonFormat(revstr match {
case tags if tags == "tags" =>
repository.tags.map(ApiRef.fromTag(name, _))
case other =>
Using.resource(Git.open(getRepositoryDir(repository.owner, repository.name))) { git =>
git.getRepository().findRef(other) match {
case null =>
val refs = git
.getRepository()
.getRefDatabase()
.getRefsByPrefix("refs/")
.asScala
refs.map(ApiRef.fromRef(name, _))
case hit =>
ApiRef.fromRef(name, hit)
}
}
})
logger.debug(s"json result: $result")
result
}
/*
* ii. Get all references
* https://docs.github.com/en/free-pro-team@latest/rest/reference/git#list-matching-references
@@ -96,7 +81,7 @@ trait ApiGitReferenceControllerBase extends ControllerBase {
* iv. Update a reference
* https://docs.github.com/en/free-pro-team@latest/rest/reference/git#update-a-reference
*/
patch("/api/v3/repos/:owner/:repository/git/refs/*")(referrersOnly { repository =>
patch("/api/v3/repos/:owner/:repository/git/refs/*")(writableUsersOnly { repository =>
val refName = multiParams("splat").mkString("/")
extractFromJsonBody[UpdateARef].map {
data =>
@@ -123,7 +108,7 @@ trait ApiGitReferenceControllerBase extends ControllerBase {
* v. Delete a reference
* https://docs.github.com/en/free-pro-team@latest/rest/reference/git#delete-a-reference
*/
delete("/api/v3/repos/:owner/:repository/git/refs/*")(referrersOnly { repository =>
delete("/api/v3/repos/:owner/:repository/git/refs/*")(writableUsersOnly { _ =>
val refName = multiParams("splat").mkString("/")
Using.resource(Git.open(getRepositoryDir(params("owner"), params("repository")))) { git =>
val ref = git.getRepository.findRef(refName)
@@ -140,4 +125,34 @@ trait ApiGitReferenceControllerBase extends ControllerBase {
}
}
})
private def notFound(): ApiError = {
response.setStatus(404)
ApiError("Not Found")
}
protected def getRef(revstr: String, repository: RepositoryInfo): AnyRef = {
logger.debug(s"getRef: path '${revstr}'")
val name = RepositoryName(repository)
val result = JsonFormat(revstr match {
case "tags" => repository.tags.map(ApiRef.fromTag(name, _))
case x if x.startsWith("tags/") =>
val tagName = x.substring("tags/".length)
repository.tags.find(_.name == tagName) match {
case Some(tagInfo) => ApiRef.fromTag(name, tagInfo)
case None => notFound()
}
case other =>
Using.resource(Git.open(getRepositoryDir(repository.owner, repository.name))) { git =>
git.getRepository().findRef(other) match {
case null => notFound()
case ref => ApiRef.fromRef(name, ref)
}
}
})
logger.debug(s"json result: $result")
result
}
}

View File

@@ -579,7 +579,7 @@ trait PullRequestService {
case (oldGit, newGit) =>
if (originRepository.branchList.contains(originId)) {
val forkedId2 =
forkedRepository.tags.collectFirst { case x if x.name == forkedId => x.id }.getOrElse(forkedId)
forkedRepository.tags.collectFirst { case x if x.name == forkedId => x.commitId }.getOrElse(forkedId)
val originId2 = JGitUtil.getForkedCommitId(
oldGit,
@@ -596,9 +596,9 @@ trait PullRequestService {
} else {
val originId2 =
originRepository.tags.collectFirst { case x if x.name == originId => x.id }.getOrElse(originId)
originRepository.tags.collectFirst { case x if x.name == originId => x.commitId }.getOrElse(originId)
val forkedId2 =
forkedRepository.tags.collectFirst { case x if x.name == forkedId => x.id }.getOrElse(forkedId)
forkedRepository.tags.collectFirst { case x if x.name == forkedId => x.commitId }.getOrElse(forkedId)
(Option(oldGit.getRepository.resolve(originId2)), Option(newGit.getRepository.resolve(forkedId2)))
}

View File

@@ -228,10 +228,11 @@ object JGitUtil {
*
* @param name the tag name
* @param time the tagged date
* @param id the commit id
* @param commitId the commit id
* @param message the message of the tagged commit
* @param objectId the tag object id
*/
case class TagInfo(name: String, time: Date, id: String, message: String)
case class TagInfo(name: String, time: Date, commitId: String, message: String, objectId: String)
/**
* The submodule data
@@ -347,7 +348,8 @@ object JGitUtil {
ref.getName.stripPrefix("refs/tags/"),
revCommit.getCommitterIdent.getWhen,
revCommit.getName,
revCommit.getShortMessage
revCommit.getShortMessage,
ref.getObjectId.getName
)
)
} catch {

View File

@@ -16,7 +16,7 @@
<td>
<div class="col-md-2 text-right">
<a href="@helpers.url(repository)/tree/@helpers.urlEncode(tag.name)" class="strong"><i class="octicon octicon-tag"></i>@tag.name</a><br>
<a href="@helpers.url(repository)/commit/@tag.id" class="monospace muted"><i class="octicon octicon-git-commit"></i>@tag.id.substring(0, 7)</a><br>
<a href="@helpers.url(repository)/commit/@tag.commitId" class="monospace muted"><i class="octicon octicon-git-commit"></i>@tag.commitId.substring(0, 7)</a><br>
<span class="muted">@gitbucket.core.helper.html.datetimeago(tag.time)</span>
</div>
<div class="col-md-10" style="border-left: 1px solid #eee">

View File

@@ -10,7 +10,7 @@
@defining(repository.tags.find(_.name == release.tag)){ tag =>
@tag.map { tag =>
<a href="@helpers.url(repository)/tree/@helpers.urlEncode(tag.name)" class="strong"><i class="octicon octicon-tag"></i>@tag.name</a><br>
<a href="@helpers.url(repository)/commit/@tag.id" class="monospace muted"><i class="octicon octicon-git-commit"></i>@tag.id.substring(0, 7)</a><br>
<a href="@helpers.url(repository)/commit/@tag.commitId" class="monospace muted"><i class="octicon octicon-git-commit"></i>@tag.commitId.substring(0, 7)</a><br>
<span class="muted">@gitbucket.core.helper.html.datetimeago(tag.time)</span>
}
}

View File

@@ -52,6 +52,8 @@ class TestingGitBucketServer(val port: Int = 19999) extends AutoCloseable {
def client(login: String, password: String): GitHub =
GitHub.connectToEnterprise(s"http://localhost:${port}/api/v3", login, password)
def getDirectory(): File = dir
private def addStatisticsHandler(handler: Handler) = { // The graceful shutdown is implemented via the statistics handler.
// See the following: https://bugs.eclipse.org/bugs/show_bug.cgi?id=420142
val statisticsHandler = new StatisticsHandler

View File

@@ -2,11 +2,14 @@ package gitbucket.core.api
import gitbucket.core.TestingGitBucketServer
import org.apache.commons.io.IOUtils
import org.eclipse.jgit.api.Git
import org.scalatest.funsuite.AnyFunSuite
import scala.util.Using
import org.kohsuke.github.GHCommitState
import java.io.File
/**
* Need to run `sbt package` before running this test.
*/
@@ -145,13 +148,16 @@ class ApiIntegrationTest extends AnyFunSuite {
assert(ref.getObject.getType == "commit")
}
// // get tag v1.0
// {
// val ref = repo.getRef("heads/tags/v1.0")
// assert(ref.getRef == "heads/tags/v1.0")
// assert(ref.getUrl == "tbd")
// assert(ref.getObject.getType == "tag")
// }
// get tag v1.0
{
Using.resource(Git.open(new File(server.getDirectory(), "repositories/root/create_status_test"))) { git =>
git.tag().setName("v1.0").call()
}
val ref = repo.getRef("tags/v1.0")
assert(ref.getRef == "refs/tags/v1.0")
assert(ref.getUrl.toString == "http://localhost:19999/api/v3/repos/root/create_status_test/git/refs/tags/v1.0")
assert(ref.getObject.getType == "tag")
}
}
}

View File

@@ -83,8 +83,20 @@ object ApiSpecModels {
milestoneCount = 1,
branchList = Seq("master", "develop"),
tags = Seq(
TagInfo(name = "v1.0", time = date("2015-05-05T23:40:27Z"), id = "id1", message = "1.0 released"),
TagInfo(name = "v2.0", time = date("2016-05-05T23:40:27Z"), id = "id2", message = "2.0 released")
TagInfo(
name = "v1.0",
time = date("2015-05-05T23:40:27Z"),
commitId = "id1",
message = "1.0 released",
objectId = "id1"
),
TagInfo(
name = "v2.0",
time = date("2016-05-05T23:40:27Z"),
commitId = "id2",
message = "2.0 released",
objectId = "id2"
)
),
managers = Seq("myboss")
)