Merge pull request #2266 from kounoike/pr-release-api
Add release API feature.
commit 81acfaa42461b63730848dbe96efdab095a4f6ce
2 parents c489a7e + 9de4029
@Naoki Takezoe Naoki Takezoe authored on 21 Feb 2019
GitHub committed on 21 Feb 2019
Showing 8 changed files
View
43
src/main/scala/gitbucket/core/api/ApiRelease.scala 0 → 100644
package gitbucket.core.api
import gitbucket.core.model.{Account, ReleaseAsset, ReleaseTag}
import gitbucket.core.util.RepositoryName
 
case class ApiReleaseAsset(name: String, size: Long)(tag: String, fileName: String, repositoryName: RepositoryName) {
val label = name
val file_id = fileName
val browser_download_url = ApiPath(
s"/api/v3/repos/${repositoryName.fullName}/releases/${tag}/assets/${fileName}"
)
}
 
object ApiReleaseAsset {
def apply(asset: ReleaseAsset, repositoryName: RepositoryName): ApiReleaseAsset =
ApiReleaseAsset(asset.label, asset.size)(asset.tag, asset.fileName, repositoryName)
}
 
case class ApiRelease(
name: String,
tag_name: String,
body: Option[String],
author: ApiUser,
assets: Seq[ApiReleaseAsset]
)
 
object ApiRelease {
def apply(
release: ReleaseTag,
assets: Seq[ReleaseAsset],
author: Account,
repositoryName: RepositoryName
): ApiRelease =
ApiRelease(
release.name,
release.tag,
release.content,
ApiUser(author),
assets.map { asset =>
ApiReleaseAsset(asset, repositoryName)
}
)
}
View
11
src/main/scala/gitbucket/core/api/CreateARelease.scala 0 → 100644
package gitbucket.core.api
 
case class CreateARelease(
tag_name: String,
target_commitish: Option[String],
name: Option[String],
body: Option[String],
draft: Option[Boolean],
prerelease: Option[Boolean]
)
View
2
■■■
src/main/scala/gitbucket/core/api/JsonFormat.scala
FieldSerializer[ApiCommits.Commit]() +
FieldSerializer[ApiCommits.Tree]() +
FieldSerializer[ApiCommits.Stats]() +
FieldSerializer[ApiCommits.File]() +
FieldSerializer[ApiRelease]() +
FieldSerializer[ApiReleaseAsset]() +
ApiBranchProtection.enforcementLevelSerializer
 
def apiPathSerializer(c: Context) =
new CustomSerializer[ApiPath](
View
2
■■■
src/main/scala/gitbucket/core/controller/ApiController.scala
with ApiIssueControllerBase
with ApiIssueLabelControllerBase
with ApiOrganizationControllerBase
with ApiPullRequestControllerBase
with ApiReleaseControllerBase
with ApiRepositoryBranchControllerBase
with ApiRepositoryCollaboratorControllerBase
with ApiRepositoryCommitControllerBase
with ApiRepositoryContentsControllerBase
with MilestonesService
with PullRequestService
with CommitsService
with CommitStatusService
with ReleaseService
with RepositoryCreationService
with RepositoryCommitFileService
with IssueCreationService
with HandleCommentService
View
185
src/main/scala/gitbucket/core/controller/api/ApiReleaseControllerBase.scala 0 → 100644
package gitbucket.core.controller.api
import java.io.{ByteArrayInputStream, File}
 
import gitbucket.core.api._
import gitbucket.core.controller.ControllerBase
import gitbucket.core.service.{AccountService, ReleaseService}
import gitbucket.core.util.Directory.getReleaseFilesDir
import gitbucket.core.util.{FileUtil, ReferrerAuthenticator, RepositoryName, WritableUsersAuthenticator}
import gitbucket.core.util.Implicits._
import gitbucket.core.util.SyntaxSugars.defining
import org.apache.commons.io.FileUtils
import org.scalatra.{Created, NoContent}
 
trait ApiReleaseControllerBase extends ControllerBase {
self: AccountService with ReleaseService with ReferrerAuthenticator with WritableUsersAuthenticator =>
 
/**
* i. List releases for a repository
* https://developer.github.com/v3/repos/releases/#list-releases-for-a-repository
*/
get("/api/v3/repos/:owner/:repository/releases")(referrersOnly { repository =>
val releases = getReleases(repository.owner, repository.name)
JsonFormat(releases.map { rel =>
val assets = getReleaseAssets(repository.owner, repository.name, rel.tag)
ApiRelease(rel, assets, getAccountByUserName(rel.author).get, RepositoryName(repository))
})
})
 
/**
* ii. Get a single release
* https://developer.github.com/v3/repos/releases/#get-a-single-release
* GitBucket doesn't have release id
*/
/**
* iii. Get the latest release
* https://developer.github.com/v3/repos/releases/#get-the-latest-release
*/
get("/api/v3/repos/:owner/:repository/releases/latest")(referrersOnly { repository =>
getReleases(repository.owner, repository.name).lastOption
.map { release =>
val assets = getReleaseAssets(repository.owner, repository.name, release.tag)
JsonFormat(ApiRelease(release, assets, getAccountByUserName(release.author).get, RepositoryName(repository)))
}
.getOrElse {
NotFound()
}
})
 
/**
* iv. Get a release by tag name
* https://developer.github.com/v3/repos/releases/#get-a-release-by-tag-name
*/
get("/api/v3/repos/:owner/:repository/releases/tags/:tag")(referrersOnly { repository =>
val tag = params("tag")
getRelease(repository.owner, repository.name, tag)
.map { release =>
val assets = getReleaseAssets(repository.owner, repository.name, tag)
JsonFormat(ApiRelease(release, assets, getAccountByUserName(release.author).get, RepositoryName(repository)))
}
.getOrElse {
NotFound()
}
})
 
/**
* v. Create a release
* https://developer.github.com/v3/repos/releases/#create-a-release
*/
post("/api/v3/repos/:owner/:repository/releases")(writableUsersOnly { repository =>
(for {
data <- extractFromJsonBody[CreateARelease]
} yield {
createRelease(
repository.owner,
repository.name,
data.name.getOrElse(data.tag_name),
data.body,
data.tag_name,
context.loginAccount.get
)
val release = getRelease(repository.owner, repository.name, data.tag_name).get
val assets = getReleaseAssets(repository.owner, repository.name, data.tag_name)
JsonFormat(ApiRelease(release, assets, context.loginAccount.get, RepositoryName(repository)))
})
})
 
/**
* vi. Edit a release
* https://developer.github.com/v3/repos/releases/#edit-a-release
* Incompatiblity info: GitHub API requires :release_id, but GitBucket API requires :tag_name
*/
patch("/api/v3/repos/:owner/:repository/releases/:tag")(writableUsersOnly { repository =>
(for {
data <- extractFromJsonBody[CreateARelease]
} yield {
val tag = params("tag")
updateRelease(repository.owner, repository.name, tag, data.name.getOrElse(data.tag_name), data.body)
val release = getRelease(repository.owner, repository.name, data.tag_name).get
val assets = getReleaseAssets(repository.owner, repository.name, data.tag_name)
JsonFormat(ApiRelease(release, assets, context.loginAccount.get, RepositoryName(repository)))
})
})
 
/**
* vii. Delete a release
* https://developer.github.com/v3/repos/releases/#delete-a-release
* Incompatiblity info: GitHub API requires :release_id, but GitBucket API requires :tag_name
*/
delete("/api/v3/repos/:owner/:repository/releases/:tag")(writableUsersOnly { repository =>
val tag = params("tag")
deleteRelease(repository.owner, repository.name, tag)
NoContent()
})
 
/**
* viii. List assets for a release
* https://developer.github.com/v3/repos/releases/#list-assets-for-a-release
*/
/**
* ix. Upload a release asset
* https://developer.github.com/v3/repos/releases/#upload-a-release-asset
*/
post("/api/v3/repos/:owner/:repository/releases/:tag/assets")(writableUsersOnly { repository =>
val name = params("name")
val tag = params("tag")
getRelease(repository.owner, repository.name, tag)
.map {
release =>
defining(FileUtil.generateFileId) { fileId =>
val buf = new Array[Byte](request.inputStream.available())
request.inputStream.read(buf)
FileUtils.writeByteArrayToFile(
new File(
getReleaseFilesDir(repository.owner, repository.name),
FileUtil.checkFilename(tag + "/" + fileId)
),
buf
)
createReleaseAsset(
repository.owner,
repository.name,
tag,
fileId,
name,
request.contentLength.getOrElse(0),
context.loginAccount.get
)
getReleaseAsset(repository.owner, repository.name, tag, fileId)
.map { asset =>
JsonFormat(ApiReleaseAsset(asset, RepositoryName(repository)))
}
.getOrElse {
ApiError("Unknown error")
}
}
}
.getOrElse(NotFound())
})
 
/**
* x. Get a single release asset
* https://developer.github.com/v3/repos/releases/#get-a-single-release-asset
* Incompatibility info: GitHub requires only asset_id, but GitBucket requires tag and fileId(file_id).
*/
get("/api/v3/repos/:owner/:repository/releases/:tag/assets/:fileId")(referrersOnly { repository =>
val tag = params("tag")
val fileId = params("fileId")
getReleaseAsset(repository.owner, repository.name, tag, fileId)
.map { asset =>
JsonFormat(ApiReleaseAsset(asset, RepositoryName(repository)))
}
.getOrElse(NotFound())
})
 
/*
* xi. Edit a release asset
* https://developer.github.com/v3/repos/releases/#edit-a-release-asset
*/
 
/*
* xii. Delete a release asset
* https://developer.github.com/v3/repos/releases/#edit-a-release-asset
*/
}
View
src/main/scala/gitbucket/core/service/ReleaseService.scala
View
src/test/scala/gitbucket/core/api/ApiSpecModels.scala
View
src/test/scala/gitbucket/core/api/JsonFormatSpec.scala