mirror of
https://github.com/gitbucket/gitbucket.git
synced 2025-11-07 22:15:51 +01:00
Merge pull request #1696 from gitbucket/api_repository_ssh_url
Add ssh_url to web hook request and API response
This commit is contained in:
@@ -1,6 +1,13 @@
|
|||||||
package gitbucket.core.api
|
package gitbucket.core.api
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* path for api url. if set path '/repos/aa/bb' then, expand 'http://server:post/repos/aa/bb' when converted to json.
|
* Path for API url.
|
||||||
|
* If set path '/repos/aa/bb' then, expand 'http://server:port/repos/aa/bb' when converted to json.
|
||||||
*/
|
*/
|
||||||
case class ApiPath(path: String)
|
case class ApiPath(path: String)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Path for git repository via SSH.
|
||||||
|
* If set path '/aa/bb.git' then, expand 'git@server:port/aa/bb.git' when converted to json.
|
||||||
|
*/
|
||||||
|
case class SshPath(path: String)
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ case class ApiRepository(
|
|||||||
val http_url = ApiPath(s"/git/${full_name}.git")
|
val http_url = ApiPath(s"/git/${full_name}.git")
|
||||||
val clone_url = ApiPath(s"/git/${full_name}.git")
|
val clone_url = ApiPath(s"/git/${full_name}.git")
|
||||||
val html_url = ApiPath(s"/${full_name}")
|
val html_url = ApiPath(s"/${full_name}")
|
||||||
|
val ssh_url = Some(SshPath(s":${full_name}.git"))
|
||||||
}
|
}
|
||||||
|
|
||||||
object ApiRepository{
|
object ApiRepository{
|
||||||
@@ -55,12 +56,13 @@ object ApiRepository{
|
|||||||
|
|
||||||
def forDummyPayload(owner: ApiUser): ApiRepository =
|
def forDummyPayload(owner: ApiUser): ApiRepository =
|
||||||
ApiRepository(
|
ApiRepository(
|
||||||
name="dummy",
|
name = "dummy",
|
||||||
full_name=s"${owner.login}/dummy",
|
full_name = s"${owner.login}/dummy",
|
||||||
description="",
|
description = "",
|
||||||
watchers=0,
|
watchers = 0,
|
||||||
forks=0,
|
forks = 0,
|
||||||
`private`=false,
|
`private` = false,
|
||||||
default_branch="master",
|
default_branch = "master",
|
||||||
owner=owner)(true)
|
owner = owner
|
||||||
|
)(true)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import scala.util.Try
|
|||||||
|
|
||||||
object JsonFormat {
|
object JsonFormat {
|
||||||
|
|
||||||
case class Context(baseUrl: String)
|
case class Context(baseUrl: String, sshUrl: Option[String])
|
||||||
|
|
||||||
val parserISO = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss'Z'")
|
val parserISO = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss'Z'")
|
||||||
|
|
||||||
@@ -40,21 +40,24 @@ object JsonFormat {
|
|||||||
FieldSerializer[ApiCommits.File]() +
|
FieldSerializer[ApiCommits.File]() +
|
||||||
ApiBranchProtection.enforcementLevelSerializer
|
ApiBranchProtection.enforcementLevelSerializer
|
||||||
|
|
||||||
def apiPathSerializer(c: Context) = new CustomSerializer[ApiPath](format =>
|
def apiPathSerializer(c: Context) = new CustomSerializer[ApiPath](_ => ({
|
||||||
(
|
case JString(s) if s.startsWith(c.baseUrl) => ApiPath(s.substring(c.baseUrl.length))
|
||||||
{
|
case JString(s) => throw new MappingException("Can't convert " + s + " to ApiPath")
|
||||||
case JString(s) if s.startsWith(c.baseUrl) => ApiPath(s.substring(c.baseUrl.length))
|
}, {
|
||||||
case JString(s) => throw new MappingException("Can't convert " + s + " to ApiPath")
|
case ApiPath(path) => JString(c.baseUrl + path)
|
||||||
},
|
}))
|
||||||
{
|
|
||||||
case ApiPath(path) => JString(c.baseUrl + path)
|
def sshPathSerializer(c: Context) = new CustomSerializer[SshPath](_ => ({
|
||||||
}
|
case JString(s) if c.sshUrl.exists(sshUrl => s.startsWith(sshUrl)) => SshPath(s.substring(c.sshUrl.get.length))
|
||||||
)
|
case JString(s) => throw new MappingException("Can't convert " + s + " to ApiPath")
|
||||||
)
|
}, {
|
||||||
|
case SshPath(path) => c.sshUrl.map { sshUrl => JString(sshUrl + path) } getOrElse JNothing
|
||||||
|
}))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* convert object to json string
|
* convert object to json string
|
||||||
*/
|
*/
|
||||||
def apply(obj: AnyRef)(implicit c: Context): String = Serialization.write(obj)(jsonFormats + apiPathSerializer(c))
|
def apply(obj: AnyRef)(implicit c: Context): String =
|
||||||
|
Serialization.write(obj)(jsonFormats + apiPathSerializer(c) + sshPathSerializer(c))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -140,17 +140,16 @@ object SystemSettingsService {
|
|||||||
ldapAuthentication: Boolean,
|
ldapAuthentication: Boolean,
|
||||||
ldap: Option[Ldap],
|
ldap: Option[Ldap],
|
||||||
skinName: String){
|
skinName: String){
|
||||||
def baseUrl(request: HttpServletRequest): String = baseUrl.fold(request.baseUrl)(_.stripSuffix("/"))
|
|
||||||
|
|
||||||
def sshAddress:Option[SshAddress] =
|
def baseUrl(request: HttpServletRequest): String = baseUrl.fold {
|
||||||
for {
|
val url = request.getRequestURL.toString
|
||||||
host <- sshHost if ssh
|
val len = url.length - (request.getRequestURI.length - request.getContextPath.length)
|
||||||
}
|
url.substring(0, len).stripSuffix("/")
|
||||||
yield SshAddress(
|
} (_.stripSuffix("/"))
|
||||||
host,
|
|
||||||
sshPort.getOrElse(DefaultSshPort),
|
def sshAddress:Option[SshAddress] = sshHost.collect { case host if ssh =>
|
||||||
"git"
|
SshAddress(host, sshPort.getOrElse(DefaultSshPort), "git")
|
||||||
)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case class Ldap(
|
case class Ldap(
|
||||||
|
|||||||
@@ -156,9 +156,13 @@ class GitBucketReceivePackFactory extends ReceivePackFactory[HttpServletRequest]
|
|||||||
|
|
||||||
logger.debug("repository:" + owner + "/" + repository)
|
logger.debug("repository:" + owner + "/" + repository)
|
||||||
|
|
||||||
|
val settings = loadSystemSettings()
|
||||||
|
val baseUrl = settings.baseUrl(request)
|
||||||
|
val sshUrl = settings.sshAddress.map { x => s"${x.genericUser}@${x.host}:${x.port}" }
|
||||||
|
|
||||||
if(!repository.endsWith(".wiki")){
|
if(!repository.endsWith(".wiki")){
|
||||||
defining(request) { implicit r =>
|
defining(request) { implicit r =>
|
||||||
val hook = new CommitLogHook(owner, repository, pusher, baseUrl)
|
val hook = new CommitLogHook(owner, repository, pusher, baseUrl, sshUrl)
|
||||||
receivePack.setPreReceiveHook(hook)
|
receivePack.setPreReceiveHook(hook)
|
||||||
receivePack.setPostReceiveHook(hook)
|
receivePack.setPostReceiveHook(hook)
|
||||||
}
|
}
|
||||||
@@ -166,7 +170,7 @@ class GitBucketReceivePackFactory extends ReceivePackFactory[HttpServletRequest]
|
|||||||
|
|
||||||
if(repository.endsWith(".wiki")){
|
if(repository.endsWith(".wiki")){
|
||||||
defining(request) { implicit r =>
|
defining(request) { implicit r =>
|
||||||
receivePack.setPostReceiveHook(new WikiCommitHook(owner, repository.stripSuffix(".wiki"), pusher, baseUrl))
|
receivePack.setPostReceiveHook(new WikiCommitHook(owner, repository.stripSuffix(".wiki"), pusher, baseUrl, sshUrl))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -178,7 +182,7 @@ class GitBucketReceivePackFactory extends ReceivePackFactory[HttpServletRequest]
|
|||||||
|
|
||||||
import scala.collection.JavaConverters._
|
import scala.collection.JavaConverters._
|
||||||
|
|
||||||
class CommitLogHook(owner: String, repository: String, pusher: String, baseUrl: String)
|
class CommitLogHook(owner: String, repository: String, pusher: String, baseUrl: String, sshUrl: Option[String])
|
||||||
extends PostReceiveHook with PreReceiveHook
|
extends PostReceiveHook with PreReceiveHook
|
||||||
with RepositoryService with AccountService with IssuesService with ActivityService with PullRequestService with WebHookService
|
with RepositoryService with AccountService with IssuesService with ActivityService with PullRequestService with WebHookService
|
||||||
with WebHookPullRequestService with CommitsService {
|
with WebHookPullRequestService with CommitsService {
|
||||||
@@ -219,7 +223,7 @@ class CommitLogHook(owner: String, repository: String, pusher: String, baseUrl:
|
|||||||
val pushedIds = scala.collection.mutable.Set[String]()
|
val pushedIds = scala.collection.mutable.Set[String]()
|
||||||
commands.asScala.foreach { command =>
|
commands.asScala.foreach { command =>
|
||||||
logger.debug(s"commandType: ${command.getType}, refName: ${command.getRefName}")
|
logger.debug(s"commandType: ${command.getType}, refName: ${command.getRefName}")
|
||||||
implicit val apiContext = api.JsonFormat.Context(baseUrl)
|
implicit val apiContext = api.JsonFormat.Context(baseUrl, sshUrl)
|
||||||
val refName = command.getRefName.split("/")
|
val refName = command.getRefName.split("/")
|
||||||
val branchName = refName.drop(2).mkString("/")
|
val branchName = refName.drop(2).mkString("/")
|
||||||
val commits = if (refName(1) == "tags") {
|
val commits = if (refName(1) == "tags") {
|
||||||
@@ -320,7 +324,7 @@ class CommitLogHook(owner: String, repository: String, pusher: String, baseUrl:
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class WikiCommitHook(owner: String, repository: String, pusher: String, baseUrl: String)
|
class WikiCommitHook(owner: String, repository: String, pusher: String, baseUrl: String, sshUrl: Option[String])
|
||||||
extends PostReceiveHook with WebHookService with AccountService with RepositoryService {
|
extends PostReceiveHook with WebHookService with AccountService with RepositoryService {
|
||||||
|
|
||||||
private val logger = LoggerFactory.getLogger(classOf[WikiCommitHook])
|
private val logger = LoggerFactory.getLogger(classOf[WikiCommitHook])
|
||||||
@@ -329,7 +333,7 @@ class WikiCommitHook(owner: String, repository: String, pusher: String, baseUrl:
|
|||||||
Database() withTransaction { implicit session =>
|
Database() withTransaction { implicit session =>
|
||||||
try {
|
try {
|
||||||
commands.asScala.headOption.foreach { command =>
|
commands.asScala.headOption.foreach { command =>
|
||||||
implicit val apiContext = api.JsonFormat.Context(baseUrl)
|
implicit val apiContext = api.JsonFormat.Context(baseUrl, sshUrl)
|
||||||
val refName = command.getRefName.split("/")
|
val refName = command.getRefName.split("/")
|
||||||
val commitIds = if (refName(1) == "tags") {
|
val commitIds = if (refName(1) == "tags") {
|
||||||
None
|
None
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ class DefaultGitUploadPack(owner: String, repoName: String) extends DefaultGitCo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DefaultGitReceivePack(owner: String, repoName: String, baseUrl: String) extends DefaultGitCommand(owner, repoName)
|
class DefaultGitReceivePack(owner: String, repoName: String, baseUrl: String, sshUrl: Option[String]) extends DefaultGitCommand(owner, repoName)
|
||||||
with RepositoryService with AccountService with DeployKeyService {
|
with RepositoryService with AccountService with DeployKeyService {
|
||||||
|
|
||||||
override protected def runTask(authType: AuthType): Unit = {
|
override protected def runTask(authType: AuthType): Unit = {
|
||||||
@@ -169,7 +169,7 @@ class DefaultGitReceivePack(owner: String, repoName: String, baseUrl: String) ex
|
|||||||
val repository = git.getRepository
|
val repository = git.getRepository
|
||||||
val receive = new ReceivePack(repository)
|
val receive = new ReceivePack(repository)
|
||||||
if (!repoName.endsWith(".wiki")) {
|
if (!repoName.endsWith(".wiki")) {
|
||||||
val hook = new CommitLogHook(owner, repoName, userName(authType), baseUrl)
|
val hook = new CommitLogHook(owner, repoName, userName(authType), baseUrl, sshUrl)
|
||||||
receive.setPreReceiveHook(hook)
|
receive.setPreReceiveHook(hook)
|
||||||
receive.setPostReceiveHook(hook)
|
receive.setPostReceiveHook(hook)
|
||||||
}
|
}
|
||||||
@@ -216,7 +216,7 @@ class PluginGitReceivePack(repoName: String, routing: GitRepositoryRouting) exte
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class GitCommandFactory(baseUrl: String) extends CommandFactory {
|
class GitCommandFactory(baseUrl: String, sshUrl: Option[String]) extends CommandFactory {
|
||||||
private val logger = LoggerFactory.getLogger(classOf[GitCommandFactory])
|
private val logger = LoggerFactory.getLogger(classOf[GitCommandFactory])
|
||||||
|
|
||||||
override def createCommand(command: String): Command = {
|
override def createCommand(command: String): Command = {
|
||||||
@@ -227,7 +227,7 @@ class GitCommandFactory(baseUrl: String) extends CommandFactory {
|
|||||||
case SimpleCommandRegex ("upload" , repoName) if(pluginRepository(repoName)) => new PluginGitUploadPack (repoName, routing(repoName))
|
case SimpleCommandRegex ("upload" , repoName) if(pluginRepository(repoName)) => new PluginGitUploadPack (repoName, routing(repoName))
|
||||||
case SimpleCommandRegex ("receive", repoName) if(pluginRepository(repoName)) => new PluginGitReceivePack(repoName, routing(repoName))
|
case SimpleCommandRegex ("receive", repoName) if(pluginRepository(repoName)) => new PluginGitReceivePack(repoName, routing(repoName))
|
||||||
case DefaultCommandRegex("upload" , owner, repoName) => new DefaultGitUploadPack (owner, repoName)
|
case DefaultCommandRegex("upload" , owner, repoName) => new DefaultGitUploadPack (owner, repoName)
|
||||||
case DefaultCommandRegex("receive", owner, repoName) => new DefaultGitReceivePack(owner, repoName, baseUrl)
|
case DefaultCommandRegex("receive", owner, repoName) => new DefaultGitReceivePack(owner, repoName, baseUrl, sshUrl)
|
||||||
case _ => new UnknownCommand(command)
|
case _ => new UnknownCommand(command)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ object SshServer {
|
|||||||
provider.setOverwriteAllowed(false)
|
provider.setOverwriteAllowed(false)
|
||||||
server.setKeyPairProvider(provider)
|
server.setKeyPairProvider(provider)
|
||||||
server.setPublickeyAuthenticator(new PublicKeyAuthenticator(sshAddress.genericUser))
|
server.setPublickeyAuthenticator(new PublicKeyAuthenticator(sshAddress.genericUser))
|
||||||
server.setCommandFactory(new GitCommandFactory(baseUrl))
|
server.setCommandFactory(new GitCommandFactory(baseUrl, Some(s"${sshAddress.genericUser}@${sshAddress.host}:${sshAddress.port}")))
|
||||||
server.setShellFactory(new NoShell(sshAddress))
|
server.setShellFactory(new NoShell(sshAddress))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,8 @@ object Implicits {
|
|||||||
// Convert to slick session.
|
// Convert to slick session.
|
||||||
implicit def request2Session(implicit request: HttpServletRequest): JdbcBackend#Session = Database.getSession(request)
|
implicit def request2Session(implicit request: HttpServletRequest): JdbcBackend#Session = Database.getSession(request)
|
||||||
|
|
||||||
implicit def context2ApiJsonFormatContext(implicit context: Context): JsonFormat.Context = JsonFormat.Context(context.baseUrl)
|
implicit def context2ApiJsonFormatContext(implicit context: Context): JsonFormat.Context =
|
||||||
|
JsonFormat.Context(context.baseUrl, context.settings.sshAddress.map { x => s"${x.genericUser}@${x.host}:${x.port}" })
|
||||||
|
|
||||||
implicit class RichSeq[A](private val seq: Seq[A]) extends AnyVal {
|
implicit class RichSeq[A](private val seq: Seq[A]) extends AnyVal {
|
||||||
|
|
||||||
@@ -77,11 +78,6 @@ object Implicits {
|
|||||||
|
|
||||||
def gitRepositoryPath: String = request.getRequestURI.replaceFirst("^" + quote(request.getContextPath) + "/git/", "/")
|
def gitRepositoryPath: String = request.getRequestURI.replaceFirst("^" + quote(request.getContextPath) + "/git/", "/")
|
||||||
|
|
||||||
def baseUrl:String = {
|
|
||||||
val url = request.getRequestURL.toString
|
|
||||||
val len = url.length - (request.getRequestURI.length - request.getContextPath.length)
|
|
||||||
url.substring(0, len).stripSuffix("/")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit class RichSession(private val session: HttpSession) extends AnyVal {
|
implicit class RichSession(private val session: HttpSession) extends AnyVal {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class JsonFormatSpec extends FunSuite {
|
|||||||
}
|
}
|
||||||
val sha1 = "6dcb09b5b57875f334f61aebed695e2e4193db5e"
|
val sha1 = "6dcb09b5b57875f334f61aebed695e2e4193db5e"
|
||||||
val repo1Name = RepositoryName("octocat/Hello-World")
|
val repo1Name = RepositoryName("octocat/Hello-World")
|
||||||
implicit val context = JsonFormat.Context("http://gitbucket.exmple.com")
|
implicit val context = JsonFormat.Context("http://gitbucket.exmple.com", None)
|
||||||
|
|
||||||
val apiUser = ApiUser(
|
val apiUser = ApiUser(
|
||||||
login = "octocat",
|
login = "octocat",
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import org.scalatest.FunSpec
|
|||||||
|
|
||||||
class GitCommandFactorySpec extends FunSpec {
|
class GitCommandFactorySpec extends FunSpec {
|
||||||
|
|
||||||
val factory = new GitCommandFactory("http://localhost:8080")
|
val factory = new GitCommandFactory("http://localhost:8080", None)
|
||||||
|
|
||||||
describe("createCommand") {
|
describe("createCommand") {
|
||||||
it("should return GitReceivePack when command is git-receive-pack"){
|
it("should return GitReceivePack when command is git-receive-pack"){
|
||||||
|
|||||||
Reference in New Issue
Block a user