move api classes to api package

This commit is contained in:
nazoking
2015-02-26 18:37:41 +09:00
parent 9221bfa045
commit 579ed19949
24 changed files with 788 additions and 428 deletions

View File

@@ -0,0 +1,26 @@
package api
import model.Account
import model.CommitStatus
import model.CommitState
/**
* https://developer.github.com/v3/repos/statuses/#get-the-combined-status-for-a-specific-ref
*/
case class ApiCombinedCommitStatus(
state: String,
sha: String,
total_count: Int,
statuses: Iterable[ApiCommitStatus],
repository: ApiRepository){
// val commit_url = ApiPath(s"/api/v3/repos/${repository.full_name}/${sha}")
val url = ApiPath(s"/api/v3/repos/${repository.full_name}/commits/${sha}/status")
}
object ApiCombinedCommitStatus {
def apply(sha:String, statuses: Iterable[(CommitStatus, Account)], repository:ApiRepository): ApiCombinedCommitStatus = ApiCombinedCommitStatus(
state = CommitState.combine(statuses.map(_._1.state).toSet).name,
sha = sha,
total_count= statuses.size,
statuses = statuses.map{ case (s, a)=> ApiCommitStatus(s, ApiUser(a)) },
repository = repository)
}

View File

@@ -0,0 +1,24 @@
package api
import java.util.Date
import model.IssueComment
/**
* https://developer.github.com/v3/issues/comments/
*/
case class ApiComment(
id: Int,
user: ApiUser,
body: String,
created_at: Date,
updated_at: Date)
object ApiComment{
def apply(comment: IssueComment, user: ApiUser): ApiComment =
ApiComment(
id = comment.commentId,
user = user,
body = comment.content,
created_at = comment.registeredDate,
updated_at = comment.updatedDate)
}

View File

@@ -0,0 +1,41 @@
package api
import java.util.Date
import org.eclipse.jgit.diff.DiffEntry
import util.JGitUtil
import util.JGitUtil.CommitInfo
import org.eclipse.jgit.api.Git
import util.RepositoryName
/**
* https://developer.github.com/v3/repos/commits/
*/
case class ApiCommit(
id: String,
message: String,
timestamp: Date,
added: List[String],
removed: List[String],
modified: List[String],
author: ApiPersonIdent,
committer: ApiPersonIdent)(repositoryName:RepositoryName){
val url = ApiPath(s"/api/v3/${repositoryName.fullName}/commits/${id}")
val html_url = ApiPath(s"/${repositoryName.fullName}/commit/${id}")
}
object ApiCommit{
def apply(git: Git, repositoryName: RepositoryName, commit: CommitInfo): ApiCommit = {
val diffs = JGitUtil.getDiffs(git, commit.id, false)
ApiCommit(
id = commit.id,
message = commit.fullMessage,
timestamp = commit.commitTime,
added = diffs._1.collect { case x if(x.changeType == DiffEntry.ChangeType.ADD) => x.newPath },
removed = diffs._1.collect { case x if(x.changeType == DiffEntry.ChangeType.DELETE) => x.oldPath },
modified = diffs._1.collect { case x if(x.changeType != DiffEntry.ChangeType.ADD &&
x.changeType != DiffEntry.ChangeType.DELETE) => x.newPath },
author = ApiPersonIdent.author(commit),
committer = ApiPersonIdent.committer(commit)
)(repositoryName)
}
}

View File

@@ -0,0 +1,41 @@
package api
import util.JGitUtil.CommitInfo
import ApiCommitListItem._
import util.RepositoryName
/**
* https://developer.github.com/v3/repos/commits/
*/
case class ApiCommitListItem(
sha: String,
commit: Commit,
author: Option[ApiUser],
committer: Option[ApiUser],
parents: Seq[Parent])(repositoryName: RepositoryName) {
val url = ApiPath(s"/api/v3/repos/${repositoryName.fullName}/commits/${sha}")
}
object ApiCommitListItem {
def apply(commit: CommitInfo, repositoryName: RepositoryName): ApiCommitListItem = ApiCommitListItem(
sha = commit.id,
commit = Commit(
message = commit.fullMessage,
author = ApiPersonIdent.author(commit),
committer = ApiPersonIdent.committer(commit)
)(commit.id, repositoryName),
author = None,
committer = None,
parents = commit.parents.map(Parent(_)(repositoryName)))(repositoryName)
case class Parent(sha: String)(repositoryName: RepositoryName){
val url = ApiPath(s"/api/v3/repos/${repositoryName.fullName}/commits/${sha}")
}
case class Commit(
message: String,
author: ApiPersonIdent,
committer: ApiPersonIdent)(sha:String, repositoryName: RepositoryName) {
val url = ApiPath(s"/api/v3/repos/${repositoryName.fullName}/git/commits/${sha}")
}
}

View File

@@ -0,0 +1,35 @@
package api
import java.util.Date
import model.CommitStatus
import util.RepositoryName
/**
* https://developer.github.com/v3/repos/statuses/#create-a-status
* https://developer.github.com/v3/repos/statuses/#list-statuses-for-a-specific-ref
*/
case class ApiCommitStatus(
created_at: Date,
updated_at: Date,
state: String,
target_url: Option[String],
description: Option[String],
id: Int,
context: String,
creator: ApiUser
)(sha: String,repositoryName: RepositoryName) {
val url = ApiPath(s"/api/v3/repos/${repositoryName.fullName}/commits/${sha}/statuses")
}
object ApiCommitStatus {
def apply(status: CommitStatus, creator:ApiUser): ApiCommitStatus = ApiCommitStatus(
created_at = status.registeredDate,
updated_at = status.updatedDate,
state = status.state.name,
target_url = status.targetUrl,
description= status.description,
id = status.commitStatusId,
context = status.context,
creator = creator
)(status.commitId, RepositoryName(status))
}

View File

@@ -0,0 +1,29 @@
package api
import java.util.Date
import model.Issue
/**
* https://developer.github.com/v3/issues/
*/
case class ApiIssue(
number: Int,
title: String,
user: ApiUser,
// labels,
state: String,
created_at: Date,
updated_at: Date,
body: String)
object ApiIssue{
def apply(issue: Issue, user: ApiUser): ApiIssue =
ApiIssue(
number = issue.issueId,
title = issue.title,
user = user,
state = if(issue.closed){ "closed" }else{ "open" },
body = issue.content.getOrElse(""),
created_at = issue.registeredDate,
updated_at = issue.updatedDate)
}

View File

@@ -0,0 +1,6 @@
package api
/**
* path for api url. if set path '/repos/aa/bb' then, expand 'http://server:post/repos/aa/bb' when converted to json.
*/
case class ApiPath(path: String)

View File

@@ -0,0 +1,22 @@
package api
import java.util.Date
import util.JGitUtil.CommitInfo
case class ApiPersonIdent(
name: String,
email: String,
date: Date)
object ApiPersonIdent {
def author(commit: CommitInfo): ApiPersonIdent =
ApiPersonIdent(
name = commit.authorName,
email = commit.authorEmailAddress,
date = commit.authorTime)
def committer(commit: CommitInfo): ApiPersonIdent =
ApiPersonIdent(
name = commit.committerName,
email = commit.committerEmailAddress,
date = commit.commitTime)
}

View File

@@ -0,0 +1,58 @@
package api
import java.util.Date
import model.{Issue, PullRequest}
import ApiPullRequest._
/**
* https://developer.github.com/v3/pulls/
*/
case class ApiPullRequest(
number: Int,
updated_at: Date,
created_at: Date,
head: ApiPullRequest.Commit,
base: ApiPullRequest.Commit,
mergeable: Option[Boolean],
title: String,
body: String,
user: ApiUser) {
val html_url = ApiPath(s"${base.repo.html_url.path}/pull/${number}")
//val diff_url = ApiPath(s"${base.repo.html_url.path}/pull/${number}.diff")
//val patch_url = ApiPath(s"${base.repo.html_url.path}/pull/${number}.patch")
val url = ApiPath(s"${base.repo.url.path}/pulls/${number}")
//val issue_url = ApiPath(s"${base.repo.url.path}/issues/${number}")
val commits_url = ApiPath(s"${base.repo.url.path}/pulls/${number}/commits")
val review_comments_url = ApiPath(s"${base.repo.url.path}/pulls/${number}/comments")
val review_comment_url = ApiPath(s"${base.repo.url.path}/pulls/comments/{number}")
val comments_url = ApiPath(s"${base.repo.url.path}/issues/${number}/comments")
val statuses_url = ApiPath(s"${base.repo.url.path}/statuses/${head.sha}")
}
object ApiPullRequest{
def apply(issue: Issue, pullRequest: PullRequest, headRepo: ApiRepository, baseRepo: ApiRepository, user: ApiUser): ApiPullRequest = ApiPullRequest(
number = issue.issueId,
updated_at = issue.updatedDate,
created_at = issue.registeredDate,
head = Commit(
sha = pullRequest.commitIdTo,
ref = pullRequest.requestBranch,
repo = headRepo)(issue.userName),
base = Commit(
sha = pullRequest.commitIdFrom,
ref = pullRequest.branch,
repo = baseRepo)(issue.userName),
mergeable = None, // TODO: need check mergeable.
title = issue.title,
body = issue.content.getOrElse(""),
user = user
)
case class Commit(
sha: String,
ref: String,
repo: ApiRepository)(baseOwner:String){
val label = if( baseOwner == repo.owner.login ){ ref }else{ s"${repo.owner.login}:${ref}" }
val user = repo.owner
}
}

View File

@@ -0,0 +1,48 @@
package api
import util.JGitUtil.CommitInfo
import service.RepositoryService.RepositoryInfo
import model.{Account, Repository}
// https://developer.github.com/v3/repos/
case class ApiRepository(
name: String,
full_name: String,
description: String,
watchers: Int,
forks: Int,
`private`: Boolean,
default_branch: String,
owner: ApiUser) {
val forks_count = forks
val watchers_coun = watchers
val url = ApiPath(s"/api/v3/repos/${full_name}")
val http_url = ApiPath(s"/git/${full_name}.git")
val clone_url = ApiPath(s"/git/${full_name}.git")
val html_url = ApiPath(s"/${full_name}")
}
object ApiRepository{
def apply(
repository: Repository,
owner: ApiUser,
forkedCount: Int =0,
watchers: Int = 0): ApiRepository =
ApiRepository(
name = repository.repositoryName,
full_name = s"${repository.userName}/${repository.repositoryName}",
description = repository.description.getOrElse(""),
watchers = 0,
forks = forkedCount,
`private` = repository.isPrivate,
default_branch = repository.defaultBranch,
owner = owner
)
def apply(repositoryInfo: RepositoryInfo, owner: ApiUser): ApiRepository =
ApiRepository(repositoryInfo.repository, owner, forkedCount=repositoryInfo.forkedCount)
def apply(repositoryInfo: RepositoryInfo, owner: Account): ApiRepository =
this(repositoryInfo.repository, ApiUser(owner))
}

View File

@@ -0,0 +1,33 @@
package api
import java.util.Date
import model.Account
case class ApiUser(
login: String,
email: String,
`type`: String,
site_admin: Boolean,
created_at: Date) {
val url = ApiPath(s"/api/v3/users/${login}")
val html_url = ApiPath(s"/${login}")
// val followers_url = ApiPath(s"/api/v3/users/${login}/followers")
// val following_url = ApiPath(s"/api/v3/users/${login}/following{/other_user}")
// val gists_url = ApiPath(s"/api/v3/users/${login}/gists{/gist_id}")
// val starred_url = ApiPath(s"/api/v3/users/${login}/starred{/owner}{/repo}")
// val subscriptions_url = ApiPath(s"/api/v3/users/${login}/subscriptions")
// val organizations_url = ApiPath(s"/api/v3/users/${login}/orgs")
// val repos_url = ApiPath(s"/api/v3/users/${login}/repos")
// val events_url = ApiPath(s"/api/v3/users/${login}/events{/privacy}")
// val received_events_url = ApiPath(s"/api/v3/users/${login}/received_events")
}
object ApiUser{
def apply(user: Account): ApiUser = ApiUser(
login = user.fullName,
email = user.mailAddress,
`type` = if(user.isGroupAccount){ "Organization" }else{ "User" },
site_admin = user.isAdmin,
created_at = user.registeredDate
)
}

View File

@@ -0,0 +1,7 @@
package api
/**
* https://developer.github.com/v3/issues/comments/#create-a-comment
* api form
*/
case class CreateAComment(body: String)

View File

@@ -0,0 +1,26 @@
package api
import model.CommitState
/**
* https://developer.github.com/v3/repos/statuses/#create-a-status
* api form
*/
case class CreateAStatus(
/* state is Required. The state of the status. Can be one of pending, success, error, or failure. */
state: String,
/* context is a string label to differentiate this status from the status of other systems. Default: "default" */
context: Option[String],
/* The target URL to associate with this status. This URL will be linked from the GitHub UI to allow users to easily see the source of the Status. */
target_url: Option[String],
/* description is a short description of the status.*/
description: Option[String]
) {
def isValid: Boolean = {
CommitState.valueOf(state).isDefined &&
// only http
target_url.filterNot(f => "\\Ahttps?://".r.findPrefixOf(f).isDefined && f.length<255).isEmpty &&
context.filterNot(f => f.length<255).isEmpty &&
description.filterNot(f => f.length<1000).isEmpty
}
}

View File

@@ -0,0 +1,37 @@
package api
import org.json4s._
import org.json4s.jackson.Serialization
import scala.util.Try
import org.joda.time.format._
import org.joda.time.DateTime
import org.joda.time.DateTimeZone
import java.util.Date
object JsonFormat {
case class Context(baseUrl:String)
val parserISO = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss'Z'")
val jsonFormats = Serialization.formats(NoTypeHints) + new CustomSerializer[Date](format =>
(
{ case JString(s) => Try(parserISO.parseDateTime(s)).toOption.map(_.toDate)
.getOrElse(throw new MappingException("Can't convert " + s + " to Date")) },
{ case x: Date => JString(parserISO.print(new DateTime(x).withZone(DateTimeZone.UTC))) }
)
) + FieldSerializer[ApiUser]() + FieldSerializer[ApiPullRequest]() + FieldSerializer[ApiRepository]() +
FieldSerializer[ApiCommitListItem.Parent]() + FieldSerializer[ApiCommitListItem]() + FieldSerializer[ApiCommitListItem.Commit]() +
FieldSerializer[ApiCommitStatus]() + FieldSerializer[ApiCommit]() + FieldSerializer[ApiCombinedCommitStatus]() +
FieldSerializer[ApiPullRequest.Commit]()
def apiPathSerializer(c: Context) = new CustomSerializer[ApiPath](format =>
(
{
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)
}
)
)
/**
* convert object to json string
*/
def apply(obj: AnyRef)(implicit c: Context): String = Serialization.write(obj)(jsonFormats + apiPathSerializer(c))
}

View File

@@ -15,6 +15,7 @@ import org.eclipse.jgit.lib.{FileMode, Constants}
import org.eclipse.jgit.dircache.DirCache
import model.GroupMember
import service.WebHookService._
import api._
class AccountController extends AccountControllerBase
with AccountService with RepositoryService with ActivityService with WikiService with LabelsService with SshKeyService
@@ -156,7 +157,7 @@ trait AccountControllerBase extends AccountManagementControllerBase {
*/
get("/api/v3/users/:userName") {
getAccountByUserName(params("userName")).map { account =>
apiJson(WebHookApiUser(account))
JsonFormat(ApiUser(account))
} getOrElse NotFound
}
@@ -165,7 +166,7 @@ trait AccountControllerBase extends AccountManagementControllerBase {
*/
get("/api/v3/user") {
context.loginAccount.map { account =>
apiJson(WebHookApiUser(account))
JsonFormat(ApiUser(account))
} getOrElse NotFound
}

View File

@@ -11,6 +11,7 @@ import org.scalatra.Ok
import model.Issue
import service.WebHookService._
import scala.util.Try
import api._
class IssuesController extends IssuesControllerBase
with IssuesService with RepositoryService with AccountService with LabelsService with MilestonesService with ActivityService
@@ -83,7 +84,7 @@ trait IssuesControllerBase extends ControllerBase {
issueId <- params("id").toIntOpt
comments = getCommentsForApi(repository.owner, repository.name, issueId.toInt)
} yield {
apiJson(comments.map{ case (issueComment, user) => WebHookComment(issueComment, WebHookApiUser(user)) })
JsonFormat(comments.map{ case (issueComment, user) => ApiComment(issueComment, ApiUser(user)) })
}).getOrElse(NotFound)
})
@@ -187,7 +188,7 @@ trait IssuesControllerBase extends ControllerBase {
(issue, id) <- handleComment(issueId, Some(body), repository)()
issueComment <- getComment(repository.owner, repository.name, id.toString())
} yield {
apiJson(WebHookComment(issueComment, WebHookApiUser(context.loginAccount.get)))
JsonFormat(ApiComment(issueComment, ApiUser(context.loginAccount.get)))
}) getOrElse NotFound
})

View File

@@ -19,7 +19,7 @@ import service.WebHookService._
import util.JGitUtil.DiffInfo
import util.JGitUtil.CommitInfo
import model.{PullRequest, Issue, CommitState}
import api._
class PullRequestsController extends PullRequestsControllerBase
with RepositoryService with AccountService with IssuesService with PullRequestService with MilestonesService with LabelsService
@@ -80,13 +80,13 @@ trait PullRequestsControllerBase extends ControllerBase {
val condition = IssueSearchCondition(request)
val baseOwner = getAccountByUserName(repository.owner).get
val issues:List[(model.Issue, model.Account, Int, model.PullRequest, model.Repository, model.Account)] = searchPullRequestByApi(condition, (page - 1) * PullRequestLimit, PullRequestLimit, repository.owner -> repository.name)
apiJson(issues.map{case (issue, issueUser, commentCount, pullRequest, headRepo, headOwner) =>
WebHookPullRequest(
JsonFormat(issues.map{case (issue, issueUser, commentCount, pullRequest, headRepo, headOwner) =>
ApiPullRequest(
issue,
pullRequest,
WebHookRepository(headRepo, WebHookApiUser(headOwner)),
WebHookRepository(repository, WebHookApiUser(baseOwner)),
WebHookApiUser(issueUser)) })
ApiRepository(headRepo, ApiUser(headOwner)),
ApiRepository(repository, ApiUser(baseOwner)),
ApiUser(issueUser)) })
})
get("/:owner/:repository/pull/:id")(referrersOnly { repository =>
@@ -127,12 +127,12 @@ trait PullRequestsControllerBase extends ControllerBase {
issueUser <- users.get(issue.userName)
headRepo <- getRepository(pullRequest.requestUserName, pullRequest.requestRepositoryName, baseUrl)
} yield {
apiJson(WebHookPullRequest(
JsonFormat(ApiPullRequest(
issue,
pullRequest,
WebHookRepository(headRepo, WebHookApiUser(headOwner)),
WebHookRepository(repository, WebHookApiUser(baseOwner)),
WebHookApiUser(issueUser)))
ApiRepository(headRepo, ApiUser(headOwner)),
ApiRepository(repository, ApiUser(baseOwner)),
ApiUser(issueUser)))
}).getOrElse(NotFound)
})
@@ -147,9 +147,9 @@ trait PullRequestsControllerBase extends ControllerBase {
using(Git.open(getRepositoryDir(owner, name))){ git =>
val oldId = git.getRepository.resolve(pullreq.commitIdFrom)
val newId = git.getRepository.resolve(pullreq.commitIdTo)
val repoFullName = s"${owner}/${name}"
val commits = git.log.addRange(oldId, newId).call.iterator.asScala.map(c => WebHookCommitListItem(new CommitInfo(c), repoFullName)).toList
apiJson(commits)
val repoFullName = util.RepositoryName(repository)
val commits = git.log.addRange(oldId, newId).call.iterator.asScala.map(c => ApiCommitListItem(new CommitInfo(c), repoFullName)).toList
JsonFormat(commits)
}
}
} getOrElse NotFound

View File

@@ -19,6 +19,7 @@ import org.eclipse.jgit.dircache.DirCache
import org.eclipse.jgit.revwalk.RevCommit
import service.WebHookService._
import model.CommitState
import api._
class RepositoryViewerController extends RepositoryViewerControllerBase
with RepositoryService with AccountService with ActivityService with IssuesService with WebHookService with CommitsService
@@ -110,7 +111,7 @@ trait RepositoryViewerControllerBase extends ControllerBase {
* https://developer.github.com/v3/repos/#get
*/
get("/api/v3/repos/:owner/:repository")(referrersOnly { repository =>
apiJson(WebHookRepository(repository, WebHookApiUser(getAccountByUserName(repository.owner).get)))
JsonFormat(ApiRepository(repository, ApiUser(getAccountByUserName(repository.owner).get)))
})
/**
@@ -158,7 +159,7 @@ trait RepositoryViewerControllerBase extends ControllerBase {
state, data.target_url, data.description, new java.util.Date(), creator)
status <- getCommitStatus(repository.owner, repository.name, statusId)
} yield {
apiJson(WebHookCommitStatus(status, WebHookApiUser(creator)))
JsonFormat(ApiCommitStatus(status, ApiUser(creator)))
}) getOrElse NotFound
})
@@ -172,8 +173,8 @@ trait RepositoryViewerControllerBase extends ControllerBase {
ref <- params.get("ref")
sha <- JGitUtil.getShaByRef(repository.owner, repository.name, ref)
} yield {
apiJson(getCommitStatuesWithCreator(repository.owner, repository.name, sha).map{ case(status, creator) =>
WebHookCommitStatus(status, WebHookApiUser(creator))
JsonFormat(getCommitStatuesWithCreator(repository.owner, repository.name, sha).map{ case(status, creator) =>
ApiCommitStatus(status, ApiUser(creator))
})
}) getOrElse NotFound
})
@@ -190,7 +191,7 @@ trait RepositoryViewerControllerBase extends ControllerBase {
sha <- JGitUtil.getShaByRef(repository.owner, repository.name, ref)
} yield {
val statuses = getCommitStatuesWithCreator(repository.owner, repository.name, sha)
apiJson(WebHookCombinedCommitStatus(sha, statuses, WebHookRepository(repository, owner)))
JsonFormat(ApiCombinedCommitStatus(sha, statuses, ApiRepository(repository, owner)))
}) getOrElse NotFound
})

View File

@@ -397,5 +397,4 @@ object RepositoryService {
}
case class RepositoryTreeNode(owner: String, name: String, children: List[RepositoryTreeNode])
}

View File

@@ -6,13 +6,13 @@ import model.{WebHook, Account, Issue, PullRequest, IssueComment, Repository, Co
import org.slf4j.LoggerFactory
import service.RepositoryService.RepositoryInfo
import util.JGitUtil
import org.eclipse.jgit.diff.DiffEntry
import util.JGitUtil.CommitInfo
import org.eclipse.jgit.api.Git
import org.apache.http.message.BasicNameValuePair
import org.apache.http.client.entity.UrlEncodedFormEntity
import org.apache.http.NameValuePair
import java.util.Date
import api._
trait WebHookService {
import WebHookService._
@@ -28,25 +28,21 @@ trait WebHookService {
def deleteWebHookURL(owner: String, repository: String, url :String)(implicit s: Session): Unit =
WebHooks.filter(_.byPrimaryKey(owner, repository, url)).delete
def callWebHookOf(owner: String, repository: String, eventName: String)(makePayload: => Option[WebHookPayload])(implicit s: Session, c: ApiContext): Unit = {
def callWebHookOf(owner: String, repository: String, eventName: String)(makePayload: => Option[WebHookPayload])(implicit s: Session, c: JsonFormat.Context): Unit = {
val webHookURLs = getWebHookURLs(owner, repository)
if(webHookURLs.nonEmpty){
makePayload.map(callWebHook(eventName, webHookURLs, _))
}
}
def apiJson(obj: AnyRef)(implicit c: ApiContext): String = {
org.json4s.jackson.Serialization.write(obj)(jsonFormats + apiPathSerializer(c))
}
def callWebHook(eventName: String, webHookURLs: List[WebHook], payload: WebHookPayload)(implicit c: ApiContext): Unit = {
def callWebHook(eventName: String, webHookURLs: List[WebHook], payload: WebHookPayload)(implicit c: JsonFormat.Context): Unit = {
import org.apache.http.client.methods.HttpPost
import org.apache.http.impl.client.HttpClientBuilder
import scala.concurrent._
import ExecutionContext.Implicits.global
if(webHookURLs.nonEmpty){
val json = apiJson(payload)
val json = JsonFormat(payload)
val httpClient = HttpClientBuilder.create.build
webHookURLs.foreach { webHookUrl =>
@@ -81,7 +77,7 @@ trait WebHookPullRequestService extends WebHookService {
import WebHookService._
// https://developer.github.com/v3/activity/events/types/#issuesevent
def callIssuesWebHook(action: String, repository: RepositoryService.RepositoryInfo, issue: Issue, baseUrl: String, sender: model.Account)(implicit s: Session, context:ApiContext): Unit = {
def callIssuesWebHook(action: String, repository: RepositoryService.RepositoryInfo, issue: Issue, baseUrl: String, sender: model.Account)(implicit s: Session, context:JsonFormat.Context): Unit = {
callWebHookOf(repository.owner, repository.name, "issues"){
val users = getAccountsByUserNames(Set(repository.owner, issue.userName), Set(sender))
for{
@@ -91,14 +87,14 @@ trait WebHookPullRequestService extends WebHookService {
WebHookIssuesPayload(
action = action,
number = issue.issueId,
repository = WebHookRepository(repository, WebHookApiUser(repoOwner)),
issue = WebHookIssue(issue, WebHookApiUser(issueUser)),
sender = WebHookApiUser(sender))
repository = ApiRepository(repository, ApiUser(repoOwner)),
issue = ApiIssue(issue, ApiUser(issueUser)),
sender = ApiUser(sender))
}
}
}
def callPullRequestWebHook(action: String, repository: RepositoryService.RepositoryInfo, issueId: Int, baseUrl: String, sender: model.Account)(implicit s: Session, context:ApiContext): Unit = {
def callPullRequestWebHook(action: String, repository: RepositoryService.RepositoryInfo, issueId: Int, baseUrl: String, sender: model.Account)(implicit s: Session, context:JsonFormat.Context): Unit = {
import WebHookService._
callWebHookOf(repository.owner, repository.name, "pull_request"){
for{
@@ -126,7 +122,7 @@ trait WebHookIssueCommentService extends WebHookPullRequestService {
self: AccountService with RepositoryService with PullRequestService with IssuesService =>
import WebHookService._
def callIssueCommentWebHook(repository: RepositoryService.RepositoryInfo, issue: Issue, issueCommentId: Int, sender: model.Account)(implicit s: Session, context:ApiContext): Unit = {
def callIssueCommentWebHook(repository: RepositoryService.RepositoryInfo, issue: Issue, issueCommentId: Int, sender: model.Account)(implicit s: Session, context:JsonFormat.Context): Unit = {
callWebHookOf(repository.owner, repository.name, "issue_comment"){
for{
issueComment <- getComment(repository.owner, repository.name, issueCommentId.toString())
@@ -149,58 +145,26 @@ trait WebHookIssueCommentService extends WebHookPullRequestService {
}
object WebHookService {
case class ApiContext(baseUrl:String)
case class ApiPath(path:String)
import org.json4s._
import org.json4s.jackson.Serialization
val jsonFormats = {
import scala.util.Try
import org.joda.time.format._
import org.joda.time.DateTime
import org.joda.time.DateTimeZone
val parserISO = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss'Z'")
Serialization.formats(NoTypeHints) + new CustomSerializer[Date](format =>
(
{ case JString(s) => Try(parserISO.parseDateTime(s)).toOption.map(_.toDate)
.getOrElse(throw new MappingException("Can't convert " + s + " to Date")) },
{ case x: Date => JString(parserISO.print(new DateTime(x).withZone(DateTimeZone.UTC))) }
)
) + FieldSerializer[WebHookApiUser]() + FieldSerializer[WebHookPullRequest]() + FieldSerializer[WebHookRepository]() +
FieldSerializer[WebHookCommitListItemParent]() + FieldSerializer[WebHookCommitListItem]() + FieldSerializer[WebHookCommitListItemCommit]() +
FieldSerializer[WebHookCommitStatus]() + FieldSerializer[WebHookCombinedCommitStatus]()
}
def apiPathSerializer(c:ApiContext) = new CustomSerializer[ApiPath](format =>
(
{
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) }
)
)
trait WebHookPayload
// https://developer.github.com/v3/activity/events/types/#pushevent
case class WebHookPushPayload(
pusher: WebHookApiUser,
pusher: ApiUser,
ref: String,
commits: List[WebHookCommit],
repository: WebHookRepository
commits: List[ApiCommit],
repository: ApiRepository
) extends WebHookPayload
object WebHookPushPayload {
def apply(git: Git, pusher: Account, refName: String, repositoryInfo: RepositoryInfo,
commits: List[CommitInfo], repositoryOwner: Account): WebHookPushPayload =
WebHookPushPayload(
WebHookApiUser(pusher),
ApiUser(pusher),
refName,
commits.map{ commit => WebHookCommit(git, repositoryInfo, commit) },
WebHookRepository(
commits.map{ commit => ApiCommit(git, util.RepositoryName(repositoryInfo), commit) },
ApiRepository(
repositoryInfo,
owner= WebHookApiUser(repositoryOwner)
owner= ApiUser(repositoryOwner)
)
)
}
@@ -209,17 +173,17 @@ object WebHookService {
case class WebHookIssuesPayload(
action: String,
number: Int,
repository: WebHookRepository,
issue: WebHookIssue,
sender: WebHookApiUser) extends WebHookPayload
repository: ApiRepository,
issue: ApiIssue,
sender: ApiUser) extends WebHookPayload
// https://developer.github.com/v3/activity/events/types/#pullrequestevent
case class WebHookPullRequestPayload(
action: String,
number: Int,
repository: WebHookRepository,
pull_request: WebHookPullRequest,
sender: WebHookApiUser
repository: ApiRepository,
pull_request: ApiPullRequest,
sender: ApiUser
) extends WebHookPayload
object WebHookPullRequestPayload{
@@ -231,10 +195,10 @@ object WebHookService {
baseRepository: RepositoryInfo,
baseOwner: Account,
sender: model.Account): WebHookPullRequestPayload = {
val headRepoPayload = WebHookRepository(headRepository, headOwner)
val baseRepoPayload = WebHookRepository(baseRepository, baseOwner)
val senderPayload = WebHookApiUser(sender)
val pr = WebHookPullRequest(issue, pullRequest, headRepoPayload, baseRepoPayload, senderPayload)
val headRepoPayload = ApiRepository(headRepository, headOwner)
val baseRepoPayload = ApiRepository(baseRepository, baseOwner)
val senderPayload = ApiUser(sender)
val pr = ApiPullRequest(issue, pullRequest, headRepoPayload, baseRepoPayload, senderPayload)
WebHookPullRequestPayload(
action = action,
number = issue.issueId,
@@ -248,10 +212,10 @@ object WebHookService {
// https://developer.github.com/v3/activity/events/types/#issuecommentevent
case class WebHookIssueCommentPayload(
action: String,
repository: WebHookRepository,
issue: WebHookIssue,
comment: WebHookComment,
sender: WebHookApiUser
repository: ApiRepository,
issue: ApiIssue,
comment: ApiComment,
sender: ApiUser
) extends WebHookPayload
object WebHookIssueCommentPayload{
@@ -265,341 +229,9 @@ object WebHookService {
sender: Account): WebHookIssueCommentPayload =
WebHookIssueCommentPayload(
action = "created",
repository = WebHookRepository(repository, repositoryUser),
issue = WebHookIssue(issue, WebHookApiUser(issueUser)),
comment = WebHookComment(comment, WebHookApiUser(commentUser)),
sender = WebHookApiUser(sender))
}
case class WebHookCommit(
id: String,
message: String,
timestamp: Date,
url: String,
added: List[String],
removed: List[String],
modified: List[String],
author: WebHookCommitUser,
committer: WebHookCommitUser)
object WebHookCommit{
def apply(git: Git, repositoryInfo: RepositoryInfo, commit: CommitInfo): WebHookCommit = {
val diffs = JGitUtil.getDiffs(git, commit.id, false)
val commitUrl = repositoryInfo.httpUrl.replaceFirst("/git/", "/").stripSuffix(".git") + "/commit/" + commit.id
WebHookCommit(
id = commit.id,
message = commit.fullMessage,
timestamp = commit.commitTime,
url = commitUrl,
added = diffs._1.collect { case x if(x.changeType == DiffEntry.ChangeType.ADD) => x.newPath },
removed = diffs._1.collect { case x if(x.changeType == DiffEntry.ChangeType.DELETE) => x.oldPath },
modified = diffs._1.collect { case x if(x.changeType != DiffEntry.ChangeType.ADD &&
x.changeType != DiffEntry.ChangeType.DELETE) => x.newPath },
author = WebHookCommitUser.author(commit),
committer = WebHookCommitUser.committer(commit)
)
}
}
case class WebHookApiUser(
login: String,
email: String,
`type`: String,
site_admin: Boolean,
created_at: Date) {
val url = ApiPath(s"/api/v3/users/${login}")
val html_url = ApiPath(s"/${login}")
// val followers_url = ApiPath(s"/api/v3/users/${login}/followers")
// val following_url = ApiPath(s"/api/v3/users/${login}/following{/other_user}")
// val gists_url = ApiPath(s"/api/v3/users/${login}/gists{/gist_id}")
// val starred_url = ApiPath(s"/api/v3/users/${login}/starred{/owner}{/repo}")
// val subscriptions_url = ApiPath(s"/api/v3/users/${login}/subscriptions")
// val organizations_url = ApiPath(s"/api/v3/users/${login}/orgs")
// val repos_url = ApiPath(s"/api/v3/users/${login}/repos")
// val events_url = ApiPath(s"/api/v3/users/${login}/events{/privacy}")
// val received_events_url = ApiPath(s"/api/v3/users/${login}/received_events")
}
object WebHookApiUser{
def apply(user: Account): WebHookApiUser = WebHookApiUser(
login = user.fullName,
email = user.mailAddress,
`type` = if(user.isGroupAccount){ "Organization" }else{ "User" },
site_admin = user.isAdmin,
created_at = user.registeredDate
)
}
case class WebHookCommitUser(
name: String,
email: String,
date: Date)
object WebHookCommitUser {
def author(commit: CommitInfo): WebHookCommitUser =
WebHookCommitUser(
name = commit.authorName,
email = commit.authorEmailAddress,
date = commit.authorTime)
def committer(commit: CommitInfo): WebHookCommitUser =
WebHookCommitUser(
name = commit.committerName,
email = commit.committerEmailAddress,
date = commit.commitTime)
}
// https://developer.github.com/v3/repos/
case class WebHookRepository(
name: String,
full_name: String,
description: String,
watchers: Int,
forks: Int,
`private`: Boolean,
default_branch: String,
owner: WebHookApiUser) {
val forks_count = forks
val watchers_coun = watchers
val url = ApiPath(s"/api/v3/repos/${full_name}")
val http_url = ApiPath(s"/git/${full_name}.git")
val clone_url = ApiPath(s"/git/${full_name}.git")
val html_url = ApiPath(s"/${full_name}")
}
object WebHookRepository{
def apply(
repository: Repository,
owner: WebHookApiUser,
forkedCount: Int =0,
watchers: Int = 0): WebHookRepository =
WebHookRepository(
name = repository.repositoryName,
full_name = s"${repository.userName}/${repository.repositoryName}",
description = repository.description.getOrElse(""),
watchers = 0,
forks = forkedCount,
`private` = repository.isPrivate,
default_branch = repository.defaultBranch,
owner = owner
)
def apply(repositoryInfo: RepositoryInfo, owner: WebHookApiUser): WebHookRepository =
WebHookRepository(repositoryInfo.repository, owner, forkedCount=repositoryInfo.forkedCount)
def apply(repositoryInfo: RepositoryInfo, owner: Account): WebHookRepository =
this(repositoryInfo.repository, WebHookApiUser(owner))
}
// https://developer.github.com/v3/pulls/
case class WebHookPullRequest(
number: Int,
updated_at: Date,
created_at: Date,
head: WebHookPullRequestCommit,
base: WebHookPullRequestCommit,
mergeable: Option[Boolean],
title: String,
body: String,
user: WebHookApiUser) {
val html_url = ApiPath(s"${base.repo.html_url.path}/pull/${number}")
//val diff_url = ApiPath("${base.repo.html_url.path}/pull/${number}.diff")
//val patch_url = ApiPath("${base.repo.html_url.path}/pull/${number}.patch")
val url = ApiPath(s"${base.repo.url.path}/pulls/${number}")
//val issue_url = ApiPath("${base.repo.url.path}/issues/${number}")
//val commits_url = ApiPath("${base.repo.url.path}/pulls/${number}/commits")
//val review_comments_url = ApiPath("${base.repo.url.path}/pulls/${number}/comments")
//val review_comment_url = ApiPath("${base.repo.url.path}/pulls/comments/{number}")
//val comments_url = ApiPath("${base.repo.url.path}/issues/${number}/comments")
val statuses_url = ApiPath(s"${base.repo.url.path}/statuses/${head.sha}")
}
object WebHookPullRequest{
def apply(issue: Issue, pullRequest: PullRequest, headRepo: WebHookRepository, baseRepo: WebHookRepository, user: WebHookApiUser): WebHookPullRequest = WebHookPullRequest(
number = issue.issueId,
updated_at = issue.updatedDate,
created_at = issue.registeredDate,
head = WebHookPullRequestCommit(
sha = pullRequest.commitIdTo,
ref = pullRequest.requestBranch,
repo = headRepo),
base = WebHookPullRequestCommit(
sha = pullRequest.commitIdFrom,
ref = pullRequest.branch,
repo = baseRepo),
mergeable = None, // TODO: need check mergeable.
title = issue.title,
body = issue.content.getOrElse(""),
user = user
)
}
case class WebHookPullRequestCommit(
label: String,
sha: String,
ref: String,
repo: WebHookRepository,
user: WebHookApiUser)
object WebHookPullRequestCommit{
def apply(sha: String,
ref: String,
repo: WebHookRepository): WebHookPullRequestCommit =
WebHookPullRequestCommit(
label = s"${repo.owner.login}:${ref}",
sha = sha,
ref = ref,
repo = repo,
user = repo.owner)
}
// https://developer.github.com/v3/issues/
case class WebHookIssue(
number: Int,
title: String,
user: WebHookApiUser,
// labels,
state: String,
created_at: Date,
updated_at: Date,
body: String)
object WebHookIssue{
def apply(issue: Issue, user: WebHookApiUser): WebHookIssue =
WebHookIssue(
number = issue.issueId,
title = issue.title,
user = user,
state = if(issue.closed){ "closed" }else{ "open" },
body = issue.content.getOrElse(""),
created_at = issue.registeredDate,
updated_at = issue.updatedDate)
}
// https://developer.github.com/v3/issues/comments/
case class WebHookComment(
id: Int,
user: WebHookApiUser,
body: String,
created_at: Date,
updated_at: Date)
object WebHookComment{
def apply(comment: IssueComment, user: WebHookApiUser): WebHookComment =
WebHookComment(
id = comment.commentId,
user = user,
body = comment.content,
created_at = comment.registeredDate,
updated_at = comment.updatedDate)
}
// https://developer.github.com/v3/issues/comments/#create-a-comment
case class CreateAComment(body: String)
// https://developer.github.com/v3/repos/commits/
case class WebHookCommitListItemParent(sha: String)(repoFullName:String){
val url = ApiPath(s"/api/v3/repos/${repoFullName}/commits/${sha}")
}
case class WebHookCommitListItemCommit(
message: String,
author: WebHookCommitUser,
committer: WebHookCommitUser)(sha:String, repoFullName: String) {
val url = ApiPath(s"/api/v3/repos/${repoFullName}/git/commits/${sha}")
}
case class WebHookCommitListItem(
sha: String,
commit: WebHookCommitListItemCommit,
author: Option[WebHookApiUser],
committer: Option[WebHookApiUser],
parents: Seq[WebHookCommitListItemParent])(repoFullName: String) {
val url = ApiPath(s"/api/v3/repos/${repoFullName}/commits/${sha}")
}
object WebHookCommitListItem {
def apply(commit: CommitInfo, repoFullName:String): WebHookCommitListItem = WebHookCommitListItem(
sha = commit.id,
commit = WebHookCommitListItemCommit(
message = commit.fullMessage,
author = WebHookCommitUser.author(commit),
committer = WebHookCommitUser.committer(commit)
)(commit.id, repoFullName),
author = None,
committer = None,
parents = commit.parents.map(WebHookCommitListItemParent(_)(repoFullName)))(repoFullName)
}
/**
* https://developer.github.com/v3/repos/statuses/#create-a-status
*/
case class CreateAStatus(
/* state is Required. The state of the status. Can be one of pending, success, error, or failure. */
state: String,
/* context is a string label to differentiate this status from the status of other systems. Default: "default" */
context: Option[String],
/* The target URL to associate with this status. This URL will be linked from the GitHub UI to allow users to easily see the source of the Status. */
target_url: Option[String],
/* description is a short description of the status.*/
description: Option[String]
) {
def isValid: Boolean = {
CommitState.valueOf(state).isDefined &&
target_url.filterNot(f => "\\Ahttps?://".r.findPrefixOf(f).isDefined && f.length<255).isEmpty &&
context.filterNot(f => f.length<255).isEmpty &&
description.filterNot(f => f.length<1000).isEmpty
}
}
/**
* https://developer.github.com/v3/repos/statuses/#create-a-status
* https://developer.github.com/v3/repos/statuses/#list-statuses-for-a-specific-ref
*/
case class WebHookCommitStatus(
created_at: Date,
updated_at: Date,
state: String,
target_url: Option[String],
description: Option[String],
id: Int,
context: String,
creator: WebHookApiUser
)(sha: String, repoFullName: String) {
def url = ApiPath(s"/api/v3/repos/${repoFullName}/commits/${sha}/statuses")
}
object WebHookCommitStatus {
def apply(status: CommitStatus, creator:WebHookApiUser): WebHookCommitStatus = WebHookCommitStatus(
created_at = status.registeredDate,
updated_at = status.updatedDate,
state = status.state.name,
target_url = status.targetUrl,
description= status.description,
id = status.commitStatusId,
context = status.context,
creator = creator
)(status.commitId, s"${status.userName}/${status.repositoryName}")
}
/**
* https://developer.github.com/v3/repos/statuses/#get-the-combined-status-for-a-specific-ref
*/
case class WebHookCombinedCommitStatus(
state: String,
sha: String,
total_count: Int,
statuses: Iterable[WebHookCommitStatus],
repository: WebHookRepository){
// val commit_url = ApiPath(s"/api/v3/repos/${repository.full_name}/${sha}")
val url = ApiPath(s"/api/v3/repos/${repository.full_name}/commits/${sha}/status")
}
object WebHookCombinedCommitStatus {
def apply(sha:String, statuses: Iterable[(CommitStatus, Account)], repository:WebHookRepository): WebHookCombinedCommitStatus = WebHookCombinedCommitStatus(
state = CommitState.combine(statuses.map(_._1.state).toSet).name,
sha = sha,
total_count= statuses.size,
statuses = statuses.map{ case (s, a)=> WebHookCommitStatus(s, WebHookApiUser(a)) },
repository = repository)
repository = ApiRepository(repository, repositoryUser),
issue = ApiIssue(issue, ApiUser(issueUser)),
comment = ApiComment(comment, ApiUser(commentUser)),
sender = ApiUser(sender))
}
}

View File

@@ -180,7 +180,7 @@ class CommitLogHook(owner: String, repository: String, pusher: String, baseUrl:
}
// call web hook
implicit val apiContext = ApiContext(baseUrl)
implicit val apiContext = api.JsonFormat.Context(baseUrl)
callWebHookOf(owner, repository, "push"){
for(pusherAccount <- getAccountByUserName(pusher);
ownerAccount <- getAccountByUserName(owner);

View File

@@ -14,7 +14,7 @@ object Implicits {
// Convert to slick session.
implicit def request2Session(implicit request: HttpServletRequest): JdbcBackend#Session = Database.getSession(request)
implicit def context2ApiContext(implicit context: app.Context): service.WebHookService.ApiContext = service.WebHookService.ApiContext(context.baseUrl)
implicit def context2ApiJsonFormatContext(implicit context: app.Context): api.JsonFormat.Context = api.JsonFormat.Context(context.baseUrl)
implicit class RichSeq[A](seq: Seq[A]) {

View File

@@ -0,0 +1,18 @@
package util
case class RepositoryName(owner:String, name:String){
val fullName = s"${owner}/${name}"
}
object RepositoryName{
def apply(fullName: String): RepositoryName = {
fullName.split("/").toList match {
case owner :: name :: Nil => RepositoryName(owner, name)
case _ => throw new IllegalArgumentException(s"${fullName} is not repositoryName (only 'owner/name')")
}
}
def apply(repository: model.Repository): RepositoryName = RepositoryName(repository.userName, repository.repositoryName)
def apply(repository: util.JGitUtil.RepositoryInfo): RepositoryName = RepositoryName(repository.owner, repository.name)
def apply(repository: service.RepositoryService.RepositoryInfo): RepositoryName = RepositoryName(repository.owner, repository.name)
def apply(repository: model.CommitStatus): RepositoryName = RepositoryName(repository.userName, repository.repositoryName)
}

View File

@@ -0,0 +1,275 @@
package api
import org.specs2.mutable.Specification
import java.util.{Date, Calendar, TimeZone}
import util.RepositoryName
import org.json4s.jackson.JsonMethods.{pretty, parse}
import org.json4s._
import org.specs2.matcher._
class JsonFormatSpec extends Specification {
val date1 = {
val d = Calendar.getInstance(TimeZone.getTimeZone("UTC"))
d.set(2011,3,14,16,0,49)
d.getTime
}
val sha1 = "6dcb09b5b57875f334f61aebed695e2e4193db5e"
val repo1Name = RepositoryName("octocat/Hello-World")
implicit val context = JsonFormat.Context("http://gitbucket.exmple.com")
val apiUser = ApiUser(
login= "octocat",
email= "octocat@example.com",
`type`= "User",
site_admin= false,
created_at= date1)
val apiUserJson = """{
"login":"octocat",
"email":"octocat@example.com",
"type":"User",
"site_admin":false,
"created_at":"2011-04-14T16:00:49Z",
"url":"http://gitbucket.exmple.com/api/v3/users/octocat",
"html_url":"http://gitbucket.exmple.com/octocat"
}"""
val repository = ApiRepository(
name = repo1Name.name,
full_name = repo1Name.fullName,
description = "This your first repo!",
watchers = 0,
forks = 0,
`private` = false,
default_branch = "master",
owner = apiUser)
val repositoryJson = s"""{
"name" : "Hello-World",
"full_name" : "octocat/Hello-World",
"description" : "This your first repo!",
"watchers" : 0,
"forks" : 0,
"private" : false,
"default_branch" : "master",
"owner" : $apiUserJson,
"forks_count" : 0,
"watchers_coun" : 0,
"url" : "${context.baseUrl}/api/v3/repos/octocat/Hello-World",
"http_url" : "${context.baseUrl}/git/octocat/Hello-World.git",
"clone_url" : "${context.baseUrl}/git/octocat/Hello-World.git",
"html_url" : "${context.baseUrl}/octocat/Hello-World"
}"""
val apiCommitStatus = ApiCommitStatus(
created_at = date1,
updated_at = date1,
state = "success",
target_url = Some("https://ci.example.com/1000/output"),
description = Some("Build has completed successfully"),
id = 1,
context = "Default",
creator = apiUser
)(sha1, repo1Name)
val apiCommitStatusJson = s"""{
"created_at":"2011-04-14T16:00:49Z",
"updated_at":"2011-04-14T16:00:49Z",
"state":"success",
"target_url":"https://ci.example.com/1000/output",
"description":"Build has completed successfully",
"id":1,
"context":"Default",
"creator":$apiUserJson,
"url": "http://gitbucket.exmple.com/api/v3/repos/octocat/Hello-World/commits/6dcb09b5b57875f334f61aebed695e2e4193db5e/statuses"
}"""
val apiComment = ApiComment(
id =1,
user = apiUser,
body= "Me too",
created_at= date1,
updated_at= date1)
val apiCommentJson = s"""{
"id": 1,
"body": "Me too",
"user": $apiUserJson,
"created_at": "2011-04-14T16:00:49Z",
"updated_at": "2011-04-14T16:00:49Z"
}"""
val apiPersonIdent = ApiPersonIdent("Monalisa Octocat","support@example.com",date1)
val apiPersonIdentJson = """ {
"name": "Monalisa Octocat",
"email": "support@example.com",
"date": "2011-04-14T16:00:49Z"
}"""
val apiCommitListItem = ApiCommitListItem(
sha = sha1,
commit = ApiCommitListItem.Commit(
message = "Fix all the bugs",
author = apiPersonIdent,
committer = apiPersonIdent
)(sha1, repo1Name),
author = Some(apiUser),
committer= Some(apiUser),
parents= Seq(ApiCommitListItem.Parent("6dcb09b5b57875f334f61aebed695e2e4193db5e")(repo1Name)))(repo1Name)
val apiCommitListItemJson = s"""{
"url": "${context.baseUrl}/api/v3/repos/octocat/Hello-World/commits/6dcb09b5b57875f334f61aebed695e2e4193db5e",
"sha": "6dcb09b5b57875f334f61aebed695e2e4193db5e",
"commit": {
"url": "${context.baseUrl}/api/v3/repos/octocat/Hello-World/git/commits/6dcb09b5b57875f334f61aebed695e2e4193db5e",
"author": $apiPersonIdentJson,
"committer": $apiPersonIdentJson,
"message": "Fix all the bugs"
},
"author": $apiUserJson,
"committer": $apiUserJson,
"parents": [
{
"url": "${context.baseUrl}/api/v3/repos/octocat/Hello-World/commits/6dcb09b5b57875f334f61aebed695e2e4193db5e",
"sha": "6dcb09b5b57875f334f61aebed695e2e4193db5e"
}
]
}"""
val apiCombinedCommitStatus = ApiCombinedCommitStatus(
state = "success",
sha = sha1,
total_count = 2,
statuses = List(apiCommitStatus),
repository = repository)
val apiCombinedCommitStatusJson = s"""{
"state": "success",
"sha": "$sha1",
"total_count": 2,
"statuses": [ $apiCommitStatusJson ],
"repository": $repositoryJson,
"url": "${context.baseUrl}/api/v3/repos/octocat/Hello-World/commits/$sha1/status"
}"""
val apiIssue = ApiIssue(
number = 1347,
title = "Found a bug",
user = apiUser,
state = "open",
body = "I'm having a problem with this.",
created_at = date1,
updated_at = date1)
val apiIssueJson = s"""{
"number": 1347,
"state": "open",
"title": "Found a bug",
"body": "I'm having a problem with this.",
"user": $apiUserJson,
"created_at": "2011-04-14T16:00:49Z",
"updated_at": "2011-04-14T16:00:49Z"
}"""
val apiPullRequest = ApiPullRequest(
number = 1347,
updated_at = date1,
created_at = date1,
head = ApiPullRequest.Commit(
sha = sha1,
ref = "new-topic",
repo = repository)("octocat"),
base = ApiPullRequest.Commit(
sha = sha1,
ref = "master",
repo = repository)("octocat"),
mergeable = None,
title = "new-feature",
body = "Please pull these awesome changes",
user = apiUser
)
val apiPullRequestJson = s"""{
"url": "${context.baseUrl}/api/v3/repos/octocat/Hello-World/pulls/1347",
"html_url": "${context.baseUrl}/octocat/Hello-World/pull/1347",
// "diff_url": "${context.baseUrl}/octocat/Hello-World/pull/1347.diff",
// "patch_url": "${context.baseUrl}/octocat/Hello-World/pull/1347.patch",
// "issue_url": "${context.baseUrl}/api/v3/repos/octocat/Hello-World/issues/1347",
"commits_url": "${context.baseUrl}/api/v3/repos/octocat/Hello-World/pulls/1347/commits",
"review_comments_url": "${context.baseUrl}/api/v3/repos/octocat/Hello-World/pulls/1347/comments",
"review_comment_url": "${context.baseUrl}/api/v3/repos/octocat/Hello-World/pulls/comments/{number}",
"comments_url": "${context.baseUrl}/api/v3/repos/octocat/Hello-World/issues/1347/comments",
"statuses_url": "${context.baseUrl}/api/v3/repos/octocat/Hello-World/statuses/6dcb09b5b57875f334f61aebed695e2e4193db5e",
"number": 1347,
// "state": "open",
"title": "new-feature",
"body": "Please pull these awesome changes",
"created_at": "2011-04-14T16:00:49Z",
"updated_at": "2011-04-14T16:00:49Z",
// "closed_at": "2011-04-14T16:00:49Z",
// "merged_at": "2011-04-14T16:00:49Z",
"head": {
"label": "new-topic",
"ref": "new-topic",
"sha": "6dcb09b5b57875f334f61aebed695e2e4193db5e",
"user": $apiUserJson,
"repo": $repositoryJson
},
"base": {
"label": "master",
"ref": "master",
"sha": "6dcb09b5b57875f334f61aebed695e2e4193db5e",
"user": $apiUserJson,
"repo": $repositoryJson
},
"user": $apiUserJson
// "merge_commit_sha": "e5bd3914e2e596debea16f433f57875b5b90bcd6",
// "merged": false,
// "mergeable": true,
// "merged_by": $$apiUserJson,
// "comments": 10,
// "commits": 3,
// "additions": 100,
// "deletions": 3,
// "changed_files": 5
}"""
def beFormatted(json2Arg:String) = new Matcher[String] {
def apply[S <: String](e: Expectable[S]) = {
import java.util.regex.Pattern
val json2 = Pattern.compile("""^\s*//.*$""", Pattern.MULTILINE).matcher(json2Arg).replaceAll("")
val js2 = try{
parse(json2)
}catch{
case e:com.fasterxml.jackson.core.JsonParseException => {
val p = java.lang.Math.max(e.getLocation.getCharOffset()-10,0).toInt
val message = json2.substring(p,java.lang.Math.min(p+100,json2.length))
throw new com.fasterxml.jackson.core.JsonParseException(message + e.getMessage , e.getLocation)
}
}
val js1 = parse(e.value)
result(js1 == js2,
"expected",
{
val diff = js2 diff js1
s"${pretty(js1)} is not ${pretty(js2)} \n\n ${pretty(Extraction.decompose(diff)(org.json4s.DefaultFormats))}"
},
e)
}
}
"JsonFormat" should {
"apiUser" in {
JsonFormat(apiUser) must beFormatted(apiUserJson)
}
"repository" in {
JsonFormat(repository) must beFormatted(repositoryJson)
}
"apiComment" in {
JsonFormat(apiComment) must beFormatted(apiCommentJson)
}
"apiCommitListItem" in {
JsonFormat(apiCommitListItem) must beFormatted(apiCommitListItemJson)
}
"apiCommitStatus" in {
JsonFormat(apiCommitStatus) must beFormatted(apiCommitStatusJson)
}
"apiCombinedCommitStatus" in {
JsonFormat(apiCombinedCommitStatus) must beFormatted(apiCombinedCommitStatusJson)
}
"apiIssue" in {
JsonFormat(apiIssue) must beFormatted(apiIssueJson)
}
"apiPullRequest" in {
JsonFormat(apiPullRequest) must beFormatted(apiPullRequestJson)
}
}
}