mirror of
https://github.com/gitbucket/gitbucket.git
synced 2025-11-02 19:45:57 +01:00
Enhance Git Reference APIs (#2937)
This commit is contained in:
@@ -39,11 +39,11 @@ object ApiRef {
|
|||||||
): ApiRef =
|
): ApiRef =
|
||||||
ApiRef(
|
ApiRef(
|
||||||
ref = s"refs/tags/${tagInfo.name}",
|
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(
|
`object` = ApiRefCommit(
|
||||||
sha = tagInfo.id,
|
sha = tagInfo.objectId,
|
||||||
url = ApiPath(s"/api/v3/repos/${repositoryName.fullName}/git/tags/${tagInfo.id}"), // TODO This URL is not yet available?
|
url = ApiPath(s"/api/v3/repos/${repositoryName.fullName}/git/tags/${tagInfo.objectId}"), // TODO This URL is not yet available?
|
||||||
`type` = "commit"
|
`type` = "tag"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ trait ReleaseControllerBase extends ControllerBase {
|
|||||||
|
|
||||||
get("/:owner/:repository/changelog/*...*")(writableUsersOnly { repository =>
|
get("/:owner/:repository/changelog/*...*")(writableUsersOnly { repository =>
|
||||||
val Seq(previousTag, currentTag) = multiParams("splat")
|
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 commitLog = Using.resource(Git.open(getRepositoryDir(repository.owner, repository.name))) { git =>
|
||||||
val commits = JGitUtil.getCommitLog(git, previousTagId, currentTag).reverse
|
val commits = JGitUtil.getCommitLog(git, previousTagId, currentTag).reverse
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package gitbucket.core.controller.api
|
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.controller.ControllerBase
|
||||||
import gitbucket.core.service.RepositoryService.RepositoryInfo
|
import gitbucket.core.service.RepositoryService.RepositoryInfo
|
||||||
import gitbucket.core.util.Directory.getRepositoryDir
|
import gitbucket.core.util.Directory.getRepositoryDir
|
||||||
import gitbucket.core.util.Implicits._
|
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.api.Git
|
||||||
import org.eclipse.jgit.lib.ObjectId
|
import org.eclipse.jgit.lib.ObjectId
|
||||||
import org.eclipse.jgit.lib.RefUpdate.Result
|
import org.eclipse.jgit.lib.RefUpdate.Result
|
||||||
@@ -15,10 +15,23 @@ import scala.jdk.CollectionConverters._
|
|||||||
import scala.util.Using
|
import scala.util.Using
|
||||||
|
|
||||||
trait ApiGitReferenceControllerBase extends ControllerBase {
|
trait ApiGitReferenceControllerBase extends ControllerBase {
|
||||||
self: ReferrerAuthenticator =>
|
self: ReferrerAuthenticator with WritableUsersAuthenticator =>
|
||||||
|
|
||||||
private val logger = LoggerFactory.getLogger(classOf[ApiGitReferenceControllerBase])
|
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
|
* i. Get a reference
|
||||||
* https://docs.github.com/en/free-pro-team@latest/rest/reference/git#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)
|
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
|
* ii. Get all references
|
||||||
* https://docs.github.com/en/free-pro-team@latest/rest/reference/git#list-matching-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
|
* iv. Update a reference
|
||||||
* https://docs.github.com/en/free-pro-team@latest/rest/reference/git#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("/")
|
val refName = multiParams("splat").mkString("/")
|
||||||
extractFromJsonBody[UpdateARef].map {
|
extractFromJsonBody[UpdateARef].map {
|
||||||
data =>
|
data =>
|
||||||
@@ -123,7 +108,7 @@ trait ApiGitReferenceControllerBase extends ControllerBase {
|
|||||||
* v. Delete a reference
|
* v. Delete a reference
|
||||||
* https://docs.github.com/en/free-pro-team@latest/rest/reference/git#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("/")
|
val refName = multiParams("splat").mkString("/")
|
||||||
Using.resource(Git.open(getRepositoryDir(params("owner"), params("repository")))) { git =>
|
Using.resource(Git.open(getRepositoryDir(params("owner"), params("repository")))) { git =>
|
||||||
val ref = git.getRepository.findRef(refName)
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -579,7 +579,7 @@ trait PullRequestService {
|
|||||||
case (oldGit, newGit) =>
|
case (oldGit, newGit) =>
|
||||||
if (originRepository.branchList.contains(originId)) {
|
if (originRepository.branchList.contains(originId)) {
|
||||||
val forkedId2 =
|
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(
|
val originId2 = JGitUtil.getForkedCommitId(
|
||||||
oldGit,
|
oldGit,
|
||||||
@@ -596,9 +596,9 @@ trait PullRequestService {
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
val originId2 =
|
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 =
|
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)))
|
(Option(oldGit.getRepository.resolve(originId2)), Option(newGit.getRepository.resolve(forkedId2)))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -228,10 +228,11 @@ object JGitUtil {
|
|||||||
*
|
*
|
||||||
* @param name the tag name
|
* @param name the tag name
|
||||||
* @param time the tagged date
|
* @param time the tagged date
|
||||||
* @param id the commit id
|
* @param commitId the commit id
|
||||||
* @param message the message of the tagged commit
|
* @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
|
* The submodule data
|
||||||
@@ -347,7 +348,8 @@ object JGitUtil {
|
|||||||
ref.getName.stripPrefix("refs/tags/"),
|
ref.getName.stripPrefix("refs/tags/"),
|
||||||
revCommit.getCommitterIdent.getWhen,
|
revCommit.getCommitterIdent.getWhen,
|
||||||
revCommit.getName,
|
revCommit.getName,
|
||||||
revCommit.getShortMessage
|
revCommit.getShortMessage,
|
||||||
|
ref.getObjectId.getName
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
} catch {
|
} catch {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
<td>
|
<td>
|
||||||
<div class="col-md-2 text-right">
|
<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)/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>
|
<span class="muted">@gitbucket.core.helper.html.datetimeago(tag.time)</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-10" style="border-left: 1px solid #eee">
|
<div class="col-md-10" style="border-left: 1px solid #eee">
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
@defining(repository.tags.find(_.name == release.tag)){ tag =>
|
@defining(repository.tags.find(_.name == release.tag)){ tag =>
|
||||||
@tag.map { 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)/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>
|
<span class="muted">@gitbucket.core.helper.html.datetimeago(tag.time)</span>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,6 +52,8 @@ class TestingGitBucketServer(val port: Int = 19999) extends AutoCloseable {
|
|||||||
def client(login: String, password: String): GitHub =
|
def client(login: String, password: String): GitHub =
|
||||||
GitHub.connectToEnterprise(s"http://localhost:${port}/api/v3", login, password)
|
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.
|
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
|
// See the following: https://bugs.eclipse.org/bugs/show_bug.cgi?id=420142
|
||||||
val statisticsHandler = new StatisticsHandler
|
val statisticsHandler = new StatisticsHandler
|
||||||
|
|||||||
@@ -2,11 +2,14 @@ package gitbucket.core.api
|
|||||||
|
|
||||||
import gitbucket.core.TestingGitBucketServer
|
import gitbucket.core.TestingGitBucketServer
|
||||||
import org.apache.commons.io.IOUtils
|
import org.apache.commons.io.IOUtils
|
||||||
|
import org.eclipse.jgit.api.Git
|
||||||
import org.scalatest.funsuite.AnyFunSuite
|
import org.scalatest.funsuite.AnyFunSuite
|
||||||
|
|
||||||
import scala.util.Using
|
import scala.util.Using
|
||||||
import org.kohsuke.github.GHCommitState
|
import org.kohsuke.github.GHCommitState
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Need to run `sbt package` before running this test.
|
* Need to run `sbt package` before running this test.
|
||||||
*/
|
*/
|
||||||
@@ -145,13 +148,16 @@ class ApiIntegrationTest extends AnyFunSuite {
|
|||||||
assert(ref.getObject.getType == "commit")
|
assert(ref.getObject.getType == "commit")
|
||||||
}
|
}
|
||||||
|
|
||||||
// // get tag v1.0
|
// get tag v1.0
|
||||||
// {
|
{
|
||||||
// val ref = repo.getRef("heads/tags/v1.0")
|
Using.resource(Git.open(new File(server.getDirectory(), "repositories/root/create_status_test"))) { git =>
|
||||||
// assert(ref.getRef == "heads/tags/v1.0")
|
git.tag().setName("v1.0").call()
|
||||||
// assert(ref.getUrl == "tbd")
|
}
|
||||||
// assert(ref.getObject.getType == "tag")
|
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")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -83,8 +83,20 @@ object ApiSpecModels {
|
|||||||
milestoneCount = 1,
|
milestoneCount = 1,
|
||||||
branchList = Seq("master", "develop"),
|
branchList = Seq("master", "develop"),
|
||||||
tags = Seq(
|
tags = Seq(
|
||||||
TagInfo(name = "v1.0", time = date("2015-05-05T23:40:27Z"), id = "id1", message = "1.0 released"),
|
TagInfo(
|
||||||
TagInfo(name = "v2.0", time = date("2016-05-05T23:40:27Z"), id = "id2", message = "2.0 released")
|
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")
|
managers = Seq("myboss")
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user