mirror of
https://github.com/gitbucket/gitbucket.git
synced 2026-05-07 21:06:36 +02:00
Compare commits
86 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
977f856854 | ||
|
|
da2a7bf77d | ||
|
|
3da3a048f0 | ||
|
|
7b5b453e56 | ||
|
|
c18f95edf8 | ||
|
|
71cf043f56 | ||
|
|
a31e4b5897 | ||
|
|
1679da4abe | ||
|
|
505bc71f9a | ||
|
|
4bc057c653 | ||
|
|
8eee13d7aa | ||
|
|
8981e339b4 | ||
|
|
e1dd5dd057 | ||
|
|
cb64f8eab8 | ||
|
|
c47d50d0df | ||
|
|
1f46da2273 | ||
|
|
06fc26cd06 | ||
|
|
3a4f9b9027 | ||
|
|
f98c849c7c | ||
|
|
aa0bd5b34a | ||
|
|
b52e904ed1 | ||
|
|
70e0dcf99d | ||
|
|
56bb20dfd2 | ||
|
|
7d7d2f488d | ||
|
|
72affd67b9 | ||
|
|
0cf1f43deb | ||
|
|
8494c682a7 | ||
|
|
1af5611159 | ||
|
|
4d39f63ef7 | ||
|
|
120d1c2fff | ||
|
|
62e9c0358a | ||
|
|
5a90848c75 | ||
|
|
760d443f74 | ||
|
|
5ee0e75dfe | ||
|
|
3b4d2d6f91 | ||
|
|
dfaabeb41d | ||
|
|
0fae2dac35 | ||
|
|
4db4fe28b4 | ||
|
|
5b87efa032 | ||
|
|
3ad609bad7 | ||
|
|
8145cba111 | ||
|
|
24b9a9a12c | ||
|
|
ee7220ebd2 | ||
|
|
8fb72fd55e | ||
|
|
a1eded2d9a | ||
|
|
7f184e1126 | ||
|
|
09aafbcce1 | ||
|
|
7f5024a746 | ||
|
|
8fec0870a8 | ||
|
|
a8d2afaff7 | ||
|
|
8fd92f1c2f | ||
|
|
419ea16ead | ||
|
|
e72d808a3c | ||
|
|
44e8c0a9be | ||
|
|
e2c39d7815 | ||
|
|
687cd54f9a | ||
|
|
911754e1dc | ||
|
|
0067cbce6f | ||
|
|
f40f8427aa | ||
|
|
98ceff2391 | ||
|
|
642a51a208 | ||
|
|
9ec7c321d8 | ||
|
|
a3c419b6f5 | ||
|
|
15c28cffa4 | ||
|
|
f4d0f16481 | ||
|
|
45535e4fdf | ||
|
|
64635c5dc6 | ||
|
|
2fd95c7f1a | ||
|
|
eb6da85183 | ||
|
|
bcc05f021c | ||
|
|
d58ed55c3a | ||
|
|
057f029c80 | ||
|
|
c9a12ff913 | ||
|
|
66bf00b5d3 | ||
|
|
7ba3ca6f15 | ||
|
|
a1bacccc09 | ||
|
|
333eeb4bad | ||
|
|
3f2935612d | ||
|
|
4c87bdd959 | ||
|
|
3543073150 | ||
|
|
e50fe604c2 | ||
|
|
63369258bd | ||
|
|
e7c3376303 | ||
|
|
86163f66ce | ||
|
|
518f0bfc28 | ||
|
|
0a759f6127 |
7
.github/CONTRIBUTING.md
vendored
Normal file
7
.github/CONTRIBUTING.md
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
# Guideline for Issues
|
||||
|
||||
- At first, See [FAQ](https://github.com/gitbucket/gitbucket/wiki/FAQ) and check issues whether there is a same question or request in the past.
|
||||
- If you can't find same question and report, send it to [gitter room](https://gitter.im/gitbucket/gitbucket) before raising an issue.
|
||||
- We can also support in Japaneses other than English at [gitter room for Japanese](https://gitter.im/gitbucket/gitbucket_ja).
|
||||
- Write an issue in English. At least, write subject in English.
|
||||
- First priority of GitBucket is easy installation and reproduce GitHub behavior, so we might reject if your request is against it.
|
||||
19
.github/ISSUE_TEMPLATE.md
vendored
Normal file
19
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
### Before submitting an issue to Gitbucket I have first:
|
||||
|
||||
- [] read the [contribution guidelines](https://github.com/gitbucket/gitbucket/blob/master/CONTRIBUTING.md)
|
||||
- [] searched for similar already existing issue
|
||||
- [] read the documentation and [wiki](https://github.com/gitbucket/gitbucket/wiki)
|
||||
|
||||
*(if you have performed all the above, remove the paragraph and continue describing the issue with template below)*
|
||||
|
||||
## Issue
|
||||
**Impacted version**: xxxx
|
||||
|
||||
**Deployment mode**: *explain here how you use gitbucket : standalone app, under webcontainer (which one), with an http frontend (nginx, httpd, ...)*
|
||||
|
||||
**Problem description**:
|
||||
- *be as explicit has you can*
|
||||
- *describe the problem and its symptoms*
|
||||
- *explain how to reproduce*
|
||||
- *attach whatever information that can help understanding the context (screen capture, log files)*
|
||||
- *do your best to use a correct english (re-read yourself)*
|
||||
8
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
8
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
### Before submitting a pull-request to Gitbucket I have first:
|
||||
|
||||
- [] read the [contribution guidelines](https://github.com/gitbucket/gitbucket/blob/master/CONTRIBUTING.md)
|
||||
- [] rebased my branch over master
|
||||
- [] verified that project is compiling
|
||||
- [] verified that tests are passing
|
||||
- [] squashed my commits as appropriate *(keep several commits if it is relevant to understand the PR)*
|
||||
- [] [marked as closed](https://help.github.com/articles/closing-issues-via-commit-messages/) all issue ID that this PR should correct
|
||||
@@ -1,7 +0,0 @@
|
||||
# Guideline for Issues
|
||||
|
||||
- If you have any question about GitBucket, send it to [gitter room](https://gitter.im/gitbucket/gitbucket) before raise an issue.
|
||||
- Make sure check whether there is a same question or request in the past.
|
||||
- When raise a new issue, write subject in **English** at least.
|
||||
- We can also support in Japaneses other than English at [gitter room for Japanese](https://gitter.im/gitbucket/gitbucket_ja).
|
||||
- First priority of GitBucket is easy installation and reproduce GitHub behavior, so we might reject if your request is against it.
|
||||
@@ -60,6 +60,13 @@ Support
|
||||
|
||||
Release Notes
|
||||
--------
|
||||
### 3.12 - 27 Feb 2016
|
||||
- New GitHub UI
|
||||
- Improve mobile view
|
||||
- Improve printing style
|
||||
- Individual URL for pull request tabs
|
||||
- SSH host configuration is separated from HTTP base URL
|
||||
|
||||
### 3.11 - 30 Jan 2016
|
||||
- Upgrade Scalatra to 2.4
|
||||
- Sidebar and Footer for Wiki
|
||||
@@ -67,6 +74,7 @@ Release Notes
|
||||
- Limit recent updated repositories list
|
||||
- Issue actions look-alike GitHub
|
||||
- Web API for labels
|
||||
- Requires Java 8
|
||||
|
||||
### 3.10 - 30 Dec 2015
|
||||
- Move to Bootstrap3
|
||||
|
||||
10
build.sbt
10
build.sbt
@@ -1,6 +1,6 @@
|
||||
val Organization = "gitbucket"
|
||||
val Name = "gitbucket"
|
||||
val GitBucketVersion = "3.11.0"
|
||||
val GitBucketVersion = "3.12.0"
|
||||
val ScalatraVersion = "2.4.0"
|
||||
val JettyVersion = "9.3.6.v20151106"
|
||||
|
||||
@@ -10,7 +10,7 @@ sourcesInBase := false
|
||||
organization := Organization
|
||||
name := Name
|
||||
version := GitBucketVersion
|
||||
scalaVersion := "2.11.6"
|
||||
scalaVersion := "2.11.7"
|
||||
|
||||
// dependency settings
|
||||
resolvers ++= Seq(
|
||||
@@ -43,8 +43,8 @@ libraryDependencies ++= Seq(
|
||||
"org.eclipse.jetty" % "jetty-webapp" % JettyVersion % "provided",
|
||||
"javax.servlet" % "javax.servlet-api" % "3.1.0" % "provided",
|
||||
"junit" % "junit" % "4.12" % "test",
|
||||
"org.scalatra" %% "scalatra-specs2" % ScalatraVersion % "test",
|
||||
"org.specs2" %% "specs2-junit" % "3.6.6" % "test"
|
||||
"org.scalatra" %% "scalatra-scalatest" % ScalatraVersion % "test",
|
||||
"org.scalaz" %% "scalaz-core" % "7.2.0" % "test"
|
||||
)
|
||||
|
||||
// Twirl settings
|
||||
@@ -52,7 +52,7 @@ play.twirl.sbt.Import.TwirlKeys.templateImports += "gitbucket.core._"
|
||||
|
||||
// Compiler settings
|
||||
scalacOptions := Seq("-deprecation", "-language:postfixOps")
|
||||
javacOptions in compile ++= Seq("-target", "7", "-source", "7")
|
||||
javacOptions in compile ++= Seq("-target", "8", "-source", "8")
|
||||
javaOptions in Jetty += "-Dlogback.configurationFile=/logback-dev.xml"
|
||||
testOptions in Test += Tests.Argument(TestFrameworks.Specs2, "junitxml", "console")
|
||||
javaOptions in Test += "-Dgitbucket.home=target/gitbucket_home_for_test"
|
||||
|
||||
@@ -1 +1 @@
|
||||
sbt.version=0.13.8
|
||||
sbt.version=0.13.9
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/bin/sh
|
||||
export GITBUCKET_VERSION=`cat ../project/build.scala | grep 'val Version' | cut -d \" -f 2`
|
||||
export GITBUCKET_VERSION=`cat ../build.sbt | grep 'val GitBucketVersion' | cut -d \" -f 2`
|
||||
echo "GITBUCKET_VERSION: $GITBUCKET_VERSION"
|
||||
|
||||
Binary file not shown.
2
sbt.bat
2
sbt.bat
@@ -1,2 +1,2 @@
|
||||
set SCRIPT_DIR=%~dp0
|
||||
java %JAVA_OPTS% -Dsbt.log.noformat=true -XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=256m -Xmx512M -Xss2M -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005 -jar "%SCRIPT_DIR%\sbt-launch-0.13.8.jar" %*
|
||||
java %JAVA_OPTS% -Dsbt.log.noformat=true -XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=256m -Xmx512M -Xss2M -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005 -jar "%SCRIPT_DIR%\sbt-launch-0.13.9.jar" %*
|
||||
|
||||
2
sbt.sh
2
sbt.sh
@@ -1,2 +1,2 @@
|
||||
#!/bin/sh
|
||||
java $JAVA_OPTS -Dsbt.log.noformat=true -XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=256m -Xmx512M -Xss2M -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005 -jar `dirname $0`/sbt-launch-0.13.8.jar "$@"
|
||||
java $JAVA_OPTS -Dsbt.log.noformat=true -XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=256m -Xmx512M -Xss2M -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005 -jar `dirname $0`/sbt-launch-0.13.9.jar "$@"
|
||||
|
||||
@@ -27,12 +27,10 @@ class ScalatraBootstrap extends LifeCycle {
|
||||
}
|
||||
|
||||
context.mount(new IndexController, "/")
|
||||
context.mount(new SearchController, "/")
|
||||
context.mount(new FileUploadController, "/upload")
|
||||
context.mount(new DashboardController, "/*")
|
||||
context.mount(new UserManagementController, "/*")
|
||||
context.mount(new SystemSettingsController, "/*")
|
||||
context.mount(new PluginsController, "/*")
|
||||
context.mount(new AccountController, "/*")
|
||||
context.mount(new RepositoryViewerController, "/*")
|
||||
context.mount(new WikiController, "/*")
|
||||
|
||||
@@ -133,7 +133,7 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
val members = getGroupMembers(account.userName)
|
||||
gitbucket.core.account.html.repositories(account,
|
||||
if(account.isGroupAccount) Nil else getGroupsByUserName(userName),
|
||||
getVisibleRepositories(context.loginAccount, context.baseUrl, Some(userName)),
|
||||
getVisibleRepositories(context.loginAccount, Some(userName)),
|
||||
context.loginAccount.exists(x => members.exists { member => member.userName == x.userName && member.isManager }))
|
||||
}
|
||||
}
|
||||
@@ -366,7 +366,7 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
*/
|
||||
post("/new", newRepositoryForm)(usersOnly { form =>
|
||||
LockUtil.lock(s"${form.owner}/${form.name}"){
|
||||
if(getRepository(form.owner, form.name, context.baseUrl).isEmpty){
|
||||
if(getRepository(form.owner, form.name).isEmpty){
|
||||
createRepository(form.owner, form.name, form.description, form.isPrivate, form.createReadme)
|
||||
}
|
||||
|
||||
@@ -385,9 +385,9 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
data <- extractFromJsonBody[CreateARepository] if data.isValid
|
||||
} yield {
|
||||
LockUtil.lock(s"${owner}/${data.name}") {
|
||||
if(getRepository(owner, data.name, context.baseUrl).isEmpty){
|
||||
if(getRepository(owner, data.name).isEmpty){
|
||||
createRepository(owner, data.name, data.description, data.`private`, data.auto_init)
|
||||
val repository = getRepository(owner, data.name, context.baseUrl).get
|
||||
val repository = getRepository(owner, data.name).get
|
||||
JsonFormat(ApiRepository(repository, ApiUser(getAccountByUserName(owner).get)))
|
||||
} else {
|
||||
ApiError(
|
||||
@@ -409,9 +409,9 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
data <- extractFromJsonBody[CreateARepository] if data.isValid
|
||||
} yield {
|
||||
LockUtil.lock(s"${groupName}/${data.name}") {
|
||||
if(getRepository(groupName, data.name, context.baseUrl).isEmpty){
|
||||
if(getRepository(groupName, data.name).isEmpty){
|
||||
createRepository(groupName, data.name, data.description, data.`private`, data.auto_init)
|
||||
val repository = getRepository(groupName, data.name, context.baseUrl).get
|
||||
val repository = getRepository(groupName, data.name).get
|
||||
JsonFormat(ApiRepository(repository, ApiUser(getAccountByUserName(groupName).get)))
|
||||
} else {
|
||||
ApiError(
|
||||
@@ -447,7 +447,7 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
val accountName = form.accountName
|
||||
|
||||
LockUtil.lock(s"${accountName}/${repository.name}"){
|
||||
if(getRepository(accountName, repository.name, baseUrl).isDefined ||
|
||||
if(getRepository(accountName, repository.name).isDefined ||
|
||||
(accountName != loginUserName && !getGroupsByUserName(loginUserName).contains(accountName))){
|
||||
// redirect to the repository if repository already exists
|
||||
redirect(s"/${accountName}/${repository.name}")
|
||||
|
||||
@@ -180,7 +180,6 @@ abstract class ControllerBase extends ScalatraFilter
|
||||
* Context object for the current request.
|
||||
*/
|
||||
case class Context(settings: SystemSettingsService.SystemSettings, loginAccount: Option[Account], request: HttpServletRequest){
|
||||
|
||||
val path = settings.baseUrl.getOrElse(request.getContextPath)
|
||||
val currentPath = request.getRequestURI.substring(request.getContextPath.length)
|
||||
val baseUrl = settings.baseUrl(request)
|
||||
|
||||
@@ -94,7 +94,7 @@ trait DashboardControllerBase extends ControllerBase {
|
||||
|
||||
val userName = context.loginAccount.get.userName
|
||||
val condition = getOrCreateCondition(Keys.Session.DashboardIssues, filter, userName)
|
||||
val userRepos = getUserRepositories(userName, context.baseUrl, true).map(repo => repo.owner -> repo.name)
|
||||
val userRepos = getUserRepositories(userName, true).map(repo => repo.owner -> repo.name)
|
||||
val page = IssueSearchCondition.page(request)
|
||||
|
||||
html.issues(
|
||||
|
||||
@@ -2,35 +2,46 @@ package gitbucket.core.controller
|
||||
|
||||
import gitbucket.core.api._
|
||||
import gitbucket.core.helper.xml
|
||||
import gitbucket.core.html
|
||||
import gitbucket.core.model.Account
|
||||
import gitbucket.core.service.{RepositoryService, ActivityService, AccountService}
|
||||
import gitbucket.core.service.{RepositoryService, ActivityService, AccountService, RepositorySearchService, IssuesService}
|
||||
import gitbucket.core.util.Implicits._
|
||||
import gitbucket.core.util.{LDAPUtil, Keys, UsersAuthenticator}
|
||||
import gitbucket.core.util.ControlUtil._
|
||||
import gitbucket.core.util.{LDAPUtil, Keys, UsersAuthenticator, ReferrerAuthenticator, StringUtil}
|
||||
|
||||
import io.github.gitbucket.scalatra.forms._
|
||||
|
||||
|
||||
class IndexController extends IndexControllerBase
|
||||
with RepositoryService with ActivityService with AccountService with UsersAuthenticator
|
||||
with RepositoryService with ActivityService with AccountService with RepositorySearchService with IssuesService
|
||||
with UsersAuthenticator with ReferrerAuthenticator
|
||||
|
||||
|
||||
trait IndexControllerBase extends ControllerBase {
|
||||
self: RepositoryService with ActivityService with AccountService with UsersAuthenticator =>
|
||||
self: RepositoryService with ActivityService with AccountService with RepositorySearchService
|
||||
with UsersAuthenticator with ReferrerAuthenticator =>
|
||||
|
||||
case class SignInForm(userName: String, password: String)
|
||||
|
||||
val form = mapping(
|
||||
val signinForm = mapping(
|
||||
"userName" -> trim(label("Username", text(required))),
|
||||
"password" -> trim(label("Password", text(required)))
|
||||
)(SignInForm.apply)
|
||||
|
||||
val searchForm = mapping(
|
||||
"query" -> trim(text(required)),
|
||||
"owner" -> trim(text(required)),
|
||||
"repository" -> trim(text(required))
|
||||
)(SearchForm.apply)
|
||||
|
||||
case class SearchForm(query: String, owner: String, repository: String)
|
||||
|
||||
|
||||
get("/"){
|
||||
val loginAccount = context.loginAccount
|
||||
if(loginAccount.isEmpty) {
|
||||
html.index(getRecentActivities(),
|
||||
getVisibleRepositories(loginAccount, context.baseUrl, withoutPhysicalInfo = true),
|
||||
loginAccount.map{ account => getUserRepositories(account.userName, context.baseUrl, withoutPhysicalInfo = true) }.getOrElse(Nil)
|
||||
gitbucket.core.html.index(getRecentActivities(),
|
||||
getVisibleRepositories(loginAccount, withoutPhysicalInfo = true),
|
||||
loginAccount.map{ account => getUserRepositories(account.userName, withoutPhysicalInfo = true) }.getOrElse(Nil)
|
||||
)
|
||||
} else {
|
||||
val loginUserName = loginAccount.get.userName
|
||||
@@ -39,9 +50,9 @@ trait IndexControllerBase extends ControllerBase {
|
||||
|
||||
visibleOwnerSet ++= loginUserGroups
|
||||
|
||||
html.index(getRecentActivitiesByOwners(visibleOwnerSet),
|
||||
getVisibleRepositories(loginAccount, context.baseUrl, withoutPhysicalInfo = true),
|
||||
loginAccount.map{ account => getUserRepositories(account.userName, context.baseUrl, withoutPhysicalInfo = true) }.getOrElse(Nil)
|
||||
gitbucket.core.html.index(getRecentActivitiesByOwners(visibleOwnerSet),
|
||||
getVisibleRepositories(loginAccount, withoutPhysicalInfo = true),
|
||||
loginAccount.map{ account => getUserRepositories(account.userName, withoutPhysicalInfo = true) }.getOrElse(Nil)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -51,10 +62,10 @@ trait IndexControllerBase extends ControllerBase {
|
||||
if(redirect.isDefined && redirect.get.startsWith("/")){
|
||||
flash += Keys.Flash.Redirect -> redirect.get
|
||||
}
|
||||
html.signin()
|
||||
gitbucket.core.html.signin()
|
||||
}
|
||||
|
||||
post("/signin", form){ form =>
|
||||
post("/signin", signinForm){ form =>
|
||||
authenticate(context.settings, form.userName, form.password) match {
|
||||
case Some(account) => signin(account)
|
||||
case None => redirect("/signin")
|
||||
@@ -119,4 +130,33 @@ trait IndexControllerBase extends ControllerBase {
|
||||
// this message is same as github enterprise...
|
||||
org.scalatra.NotFound(ApiError("Rate limiting is not enabled."))
|
||||
}
|
||||
|
||||
// TODO Move to RepositoryViwerController?
|
||||
post("/search", searchForm){ form =>
|
||||
redirect(s"/${form.owner}/${form.repository}/search?q=${StringUtil.urlEncode(form.query)}")
|
||||
}
|
||||
|
||||
// TODO Move to RepositoryViwerController?
|
||||
get("/:owner/:repository/search")(referrersOnly { repository =>
|
||||
defining(params("q").trim, params.getOrElse("type", "code")){ case (query, target) =>
|
||||
val page = try {
|
||||
val i = params.getOrElse("page", "1").toInt
|
||||
if(i <= 0) 1 else i
|
||||
} catch {
|
||||
case e: NumberFormatException => 1
|
||||
}
|
||||
|
||||
target.toLowerCase match {
|
||||
case "issue" => gitbucket.core.search.html.issues(
|
||||
searchIssues(repository.owner, repository.name, query),
|
||||
countFiles(repository.owner, repository.name, query),
|
||||
query, page, repository)
|
||||
|
||||
case _ => gitbucket.core.search.html.code(
|
||||
searchFiles(repository.owner, repository.name, query),
|
||||
countIssues(repository.owner, repository.name, query),
|
||||
query, page, repository)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
package gitbucket.core.controller
|
||||
|
||||
import gitbucket.core.admin.plugins.html
|
||||
import gitbucket.core.plugin.PluginRegistry
|
||||
import gitbucket.core.util.AdminAuthenticator
|
||||
|
||||
class PluginsController extends ControllerBase with AdminAuthenticator {
|
||||
get("/admin/plugins")(adminOnly {
|
||||
html.plugins(PluginRegistry().getPlugins())
|
||||
})
|
||||
}
|
||||
@@ -137,7 +137,7 @@ trait PullRequestsControllerBase extends ControllerBase {
|
||||
baseOwner <- users.get(repository.owner)
|
||||
headOwner <- users.get(pullRequest.requestUserName)
|
||||
issueUser <- users.get(issue.openedUserName)
|
||||
headRepo <- getRepository(pullRequest.requestUserName, pullRequest.requestRepositoryName, baseUrl)
|
||||
headRepo <- getRepository(pullRequest.requestUserName, pullRequest.requestRepositoryName)
|
||||
} yield {
|
||||
JsonFormat(ApiPullRequest(
|
||||
issue,
|
||||
@@ -196,7 +196,7 @@ trait PullRequestsControllerBase extends ControllerBase {
|
||||
issue,
|
||||
pullreq,
|
||||
repository,
|
||||
getRepository(pullreq.requestUserName, pullreq.requestRepositoryName, context.baseUrl).get)
|
||||
getRepository(pullreq.requestUserName, pullreq.requestRepositoryName).get)
|
||||
}
|
||||
} getOrElse NotFound
|
||||
})
|
||||
@@ -229,7 +229,7 @@ trait PullRequestsControllerBase extends ControllerBase {
|
||||
if(branchProtection.needStatusCheck(loginAccount.userName)){
|
||||
flash += "error" -> s"branch ${pullreq.requestBranch} is protected need status check."
|
||||
} else {
|
||||
val repository = getRepository(owner, name, context.baseUrl).get
|
||||
val repository = getRepository(owner, name).get
|
||||
LockUtil.lock(s"${owner}/${name}"){
|
||||
val alias = if(pullreq.repositoryName == pullreq.requestRepositoryName && pullreq.userName == pullreq.requestUserName){
|
||||
pullreq.branch
|
||||
@@ -310,7 +310,7 @@ trait PullRequestsControllerBase extends ControllerBase {
|
||||
pullreq.requestUserName, pullreq.requestRepositoryName, pullreq.commitIdTo)
|
||||
|
||||
// close issue by content of pull request
|
||||
val defaultBranch = getRepository(owner, name, context.baseUrl).get.repository.defaultBranch
|
||||
val defaultBranch = getRepository(owner, name).get.repository.defaultBranch
|
||||
if(pullreq.branch == defaultBranch){
|
||||
commits.flatten.foreach { commit =>
|
||||
closeIssuesFromMessage(commit.fullMessage, loginAccount.userName, owner, name)
|
||||
@@ -343,7 +343,7 @@ trait PullRequestsControllerBase extends ControllerBase {
|
||||
val headBranch:Option[String] = params.get("head")
|
||||
(forkedRepository.repository.originUserName, forkedRepository.repository.originRepositoryName) match {
|
||||
case (Some(originUserName), Some(originRepositoryName)) => {
|
||||
getRepository(originUserName, originRepositoryName, context.baseUrl).map { originRepository =>
|
||||
getRepository(originUserName, originRepositoryName).map { originRepository =>
|
||||
using(
|
||||
Git.open(getRepositoryDir(originUserName, originRepositoryName)),
|
||||
Git.open(getRepositoryDir(forkedRepository.owner, forkedRepository.name))
|
||||
@@ -384,12 +384,12 @@ trait PullRequestsControllerBase extends ControllerBase {
|
||||
forkedRepository.repository.originRepositoryName
|
||||
} else {
|
||||
// Sibling repository
|
||||
getUserRepositories(originOwner, context.baseUrl).find { x =>
|
||||
getUserRepositories(originOwner).find { x =>
|
||||
x.repository.originUserName == forkedRepository.repository.originUserName &&
|
||||
x.repository.originRepositoryName == forkedRepository.repository.originRepositoryName
|
||||
}.map(_.repository.repositoryName)
|
||||
};
|
||||
originRepository <- getRepository(originOwner, originRepositoryName, context.baseUrl)
|
||||
originRepository <- getRepository(originOwner, originRepositoryName)
|
||||
) yield {
|
||||
using(
|
||||
Git.open(getRepositoryDir(originRepository.owner, originRepository.name)),
|
||||
@@ -457,7 +457,7 @@ trait PullRequestsControllerBase extends ControllerBase {
|
||||
getForkedRepositories(forkedRepository.owner, forkedRepository.name).find(_._1 == originOwner).map(_._2)
|
||||
}
|
||||
};
|
||||
originRepository <- getRepository(originOwner, originRepositoryName, context.baseUrl)
|
||||
originRepository <- getRepository(originOwner, originRepositoryName)
|
||||
) yield {
|
||||
using(
|
||||
Git.open(getRepositoryDir(originRepository.owner, originRepository.name)),
|
||||
|
||||
@@ -560,8 +560,7 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
html.forked(
|
||||
getRepository(
|
||||
repository.repository.originUserName.getOrElse(repository.owner),
|
||||
repository.repository.originRepositoryName.getOrElse(repository.name),
|
||||
context.baseUrl),
|
||||
repository.repository.originRepositoryName.getOrElse(repository.name)),
|
||||
getForkedRepositories(
|
||||
repository.repository.originUserName.getOrElse(repository.owner),
|
||||
repository.repository.originRepositoryName.getOrElse(repository.name)),
|
||||
@@ -759,8 +758,6 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
.setTree(revCommit.getTree)
|
||||
.setOutputStream(response.getOutputStream)
|
||||
.call()
|
||||
|
||||
Unit
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
package gitbucket.core.controller
|
||||
|
||||
import gitbucket.core.search.html
|
||||
import gitbucket.core.service._
|
||||
import gitbucket.core.util.{StringUtil, ControlUtil, ReferrerAuthenticator, Implicits}
|
||||
import ControlUtil._
|
||||
import Implicits._
|
||||
import io.github.gitbucket.scalatra.forms._
|
||||
|
||||
class SearchController extends SearchControllerBase
|
||||
with RepositoryService with AccountService with ActivityService with RepositorySearchService with IssuesService with ReferrerAuthenticator
|
||||
|
||||
trait SearchControllerBase extends ControllerBase { self: RepositoryService
|
||||
with ActivityService with RepositorySearchService with ReferrerAuthenticator =>
|
||||
|
||||
val searchForm = mapping(
|
||||
"query" -> trim(text(required)),
|
||||
"owner" -> trim(text(required)),
|
||||
"repository" -> trim(text(required))
|
||||
)(SearchForm.apply)
|
||||
|
||||
case class SearchForm(query: String, owner: String, repository: String)
|
||||
|
||||
post("/search", searchForm){ form =>
|
||||
redirect(s"/${form.owner}/${form.repository}/search?q=${StringUtil.urlEncode(form.query)}")
|
||||
}
|
||||
|
||||
get("/:owner/:repository/search")(referrersOnly { repository =>
|
||||
defining(params("q").trim, params.getOrElse("type", "code")){ case (query, target) =>
|
||||
val page = try {
|
||||
val i = params.getOrElse("page", "1").toInt
|
||||
if(i <= 0) 1 else i
|
||||
} catch {
|
||||
case e: NumberFormatException => 1
|
||||
}
|
||||
|
||||
target.toLowerCase match {
|
||||
case "issue" => html.issues(
|
||||
searchIssues(repository.owner, repository.name, query),
|
||||
countFiles(repository.owner, repository.name, query),
|
||||
query, page, repository)
|
||||
|
||||
case _ => html.code(
|
||||
searchFiles(repository.owner, repository.name, query),
|
||||
countIssues(repository.owner, repository.name, query),
|
||||
query, page, repository)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import gitbucket.core.admin.html
|
||||
import gitbucket.core.service.{AccountService, SystemSettingsService}
|
||||
import gitbucket.core.util.AdminAuthenticator
|
||||
import gitbucket.core.ssh.SshServer
|
||||
import gitbucket.core.plugin.PluginRegistry
|
||||
import SystemSettingsService._
|
||||
import io.github.gitbucket.scalatra.forms._
|
||||
|
||||
@@ -23,6 +24,7 @@ trait SystemSettingsControllerBase extends ControllerBase {
|
||||
"notification" -> trim(label("Notification", boolean())),
|
||||
"activityLogLimit" -> trim(label("Limit of activity logs", optional(number()))),
|
||||
"ssh" -> trim(label("SSH access", boolean())),
|
||||
"sshHost" -> trim(label("SSH host", optional(text()))),
|
||||
"sshPort" -> trim(label("SSH port", optional(number()))),
|
||||
"useSMTP" -> trim(label("SMTP", boolean())),
|
||||
"smtp" -> optionalIfNotChecked("useSMTP", mapping(
|
||||
@@ -50,9 +52,14 @@ trait SystemSettingsControllerBase extends ControllerBase {
|
||||
"keystore" -> trim(label("Keystore", optional(text())))
|
||||
)(Ldap.apply))
|
||||
)(SystemSettings.apply).verifying { settings =>
|
||||
if(settings.ssh && settings.baseUrl.isEmpty){
|
||||
Seq("baseUrl" -> "Base URL is required if SSH access is enabled.")
|
||||
} else Nil
|
||||
Vector(
|
||||
if(settings.ssh && settings.baseUrl.isEmpty){
|
||||
Some("baseUrl" -> "Base URL is required if SSH access is enabled.")
|
||||
} else None,
|
||||
if(settings.ssh && settings.sshHost.isEmpty){
|
||||
Some("sshHost" -> "SSH host is required if SSH access is enabled.")
|
||||
} else None
|
||||
).flatten
|
||||
}
|
||||
|
||||
private val pluginForm = mapping(
|
||||
@@ -68,20 +75,21 @@ trait SystemSettingsControllerBase extends ControllerBase {
|
||||
post("/admin/system", form)(adminOnly { form =>
|
||||
saveSystemSettings(form)
|
||||
|
||||
if(form.ssh && SshServer.isActive && context.settings.sshPort != form.sshPort){
|
||||
SshServer.stop()
|
||||
}
|
||||
|
||||
if(form.ssh && !SshServer.isActive && form.baseUrl.isDefined){
|
||||
SshServer.start(
|
||||
form.sshPort.getOrElse(SystemSettingsService.DefaultSshPort),
|
||||
form.baseUrl.get)
|
||||
} else if(!form.ssh && SshServer.isActive){
|
||||
if (form.sshAddress != context.settings.sshAddress) {
|
||||
SshServer.stop()
|
||||
for {
|
||||
sshAddress <- form.sshAddress
|
||||
baseUrl <- form.baseUrl
|
||||
}
|
||||
SshServer.start(sshAddress, baseUrl)
|
||||
}
|
||||
|
||||
flash += "info" -> "System settings has been updated."
|
||||
redirect("/admin/system")
|
||||
})
|
||||
|
||||
get("/admin/plugins")(adminOnly {
|
||||
html.plugins(PluginRegistry().getPlugins())
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ protected[model] trait TemplateComponent { self: Profile =>
|
||||
byRepository(userName, repositoryName) && (this.labelId === labelId)
|
||||
|
||||
def byLabel(owner: String, repository: String, labelName: String) =
|
||||
byRepository(userName, repositoryName) && (this.labelName === labelName.bind)
|
||||
byRepository(owner, repository) && (this.labelName === labelName.bind)
|
||||
}
|
||||
|
||||
trait MilestoneTemplate extends BasicTemplate { self: Table[_] =>
|
||||
|
||||
@@ -399,7 +399,7 @@ trait IssuesService {
|
||||
object IssuesService {
|
||||
import javax.servlet.http.HttpServletRequest
|
||||
|
||||
val IssueLimit = 30
|
||||
val IssueLimit = 25
|
||||
|
||||
case class IssueSearchCondition(
|
||||
labels: Set[String] = Set.empty,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package gitbucket.core.service
|
||||
|
||||
import gitbucket.core.controller.Context
|
||||
import gitbucket.core.model.{Collaborator, Repository, Account}
|
||||
import gitbucket.core.model.Profile._
|
||||
import gitbucket.core.util.JGitUtil
|
||||
@@ -194,10 +195,9 @@ trait RepositoryService { self: AccountService =>
|
||||
*
|
||||
* @param userName the user name of the repository owner
|
||||
* @param repositoryName the repository name
|
||||
* @param baseUrl the base url of this application
|
||||
* @return the repository information
|
||||
*/
|
||||
def getRepository(userName: String, repositoryName: String, baseUrl: String)(implicit s: Session): Option[RepositoryInfo] = {
|
||||
def getRepository(userName: String, repositoryName: String)(implicit s: Session): Option[RepositoryInfo] = {
|
||||
(Repositories filter { t => t.byRepository(userName, repositoryName) } firstOption) map { repository =>
|
||||
// for getting issue count and pull request count
|
||||
val issues = Issues.filter { t =>
|
||||
@@ -205,7 +205,7 @@ trait RepositoryService { self: AccountService =>
|
||||
}.map(_.pullRequest).list
|
||||
|
||||
new RepositoryInfo(
|
||||
JGitUtil.getRepositoryInfo(repository.userName, repository.repositoryName, baseUrl),
|
||||
JGitUtil.getRepositoryInfo(repository.userName, repository.repositoryName),
|
||||
repository,
|
||||
issues.count(_ == false),
|
||||
issues.count(_ == true),
|
||||
@@ -234,7 +234,7 @@ trait RepositoryService { self: AccountService =>
|
||||
}.list
|
||||
}
|
||||
|
||||
def getUserRepositories(userName: String, baseUrl: String, withoutPhysicalInfo: Boolean = false)
|
||||
def getUserRepositories(userName: String, withoutPhysicalInfo: Boolean = false)
|
||||
(implicit s: Session): List[RepositoryInfo] = {
|
||||
Repositories.filter { t1 =>
|
||||
(t1.userName === userName.bind) ||
|
||||
@@ -242,9 +242,9 @@ trait RepositoryService { self: AccountService =>
|
||||
}.sortBy(_.lastActivityDate desc).list.map{ repository =>
|
||||
new RepositoryInfo(
|
||||
if(withoutPhysicalInfo){
|
||||
new JGitUtil.RepositoryInfo(repository.userName, repository.repositoryName, baseUrl)
|
||||
new JGitUtil.RepositoryInfo(repository.userName, repository.repositoryName)
|
||||
} else {
|
||||
JGitUtil.getRepositoryInfo(repository.userName, repository.repositoryName, baseUrl)
|
||||
JGitUtil.getRepositoryInfo(repository.userName, repository.repositoryName)
|
||||
},
|
||||
repository,
|
||||
getForkedCount(
|
||||
@@ -260,13 +260,12 @@ trait RepositoryService { self: AccountService =>
|
||||
* If repositoryUserName is given then filters results by repository owner.
|
||||
*
|
||||
* @param loginAccount the logged in account
|
||||
* @param baseUrl the base url of this application
|
||||
* @param repositoryUserName the repository owner (if None then returns all repositories which are visible for logged in user)
|
||||
* @param withoutPhysicalInfo if true then the result does not include physical repository information such as commit count,
|
||||
* branches and tags
|
||||
* @return the repository information which is sorted in descending order of lastActivityDate.
|
||||
*/
|
||||
def getVisibleRepositories(loginAccount: Option[Account], baseUrl: String, repositoryUserName: Option[String] = None,
|
||||
def getVisibleRepositories(loginAccount: Option[Account], repositoryUserName: Option[String] = None,
|
||||
withoutPhysicalInfo: Boolean = false)
|
||||
(implicit s: Session): List[RepositoryInfo] = {
|
||||
(loginAccount match {
|
||||
@@ -284,9 +283,9 @@ trait RepositoryService { self: AccountService =>
|
||||
}.sortBy(_.lastActivityDate desc).list.map{ repository =>
|
||||
new RepositoryInfo(
|
||||
if(withoutPhysicalInfo){
|
||||
new JGitUtil.RepositoryInfo(repository.userName, repository.repositoryName, baseUrl)
|
||||
new JGitUtil.RepositoryInfo(repository.userName, repository.repositoryName)
|
||||
} else {
|
||||
JGitUtil.getRepositoryInfo(repository.userName, repository.repositoryName, baseUrl)
|
||||
JGitUtil.getRepositoryInfo(repository.userName, repository.repositoryName)
|
||||
},
|
||||
repository,
|
||||
getForkedCount(
|
||||
@@ -389,32 +388,39 @@ trait RepositoryService { self: AccountService =>
|
||||
|
||||
object RepositoryService {
|
||||
|
||||
case class RepositoryInfo(owner: String, name: String, httpUrl: String, repository: Repository,
|
||||
case class RepositoryInfo(owner: String, name: String, repository: Repository,
|
||||
issueCount: Int, pullCount: Int, commitCount: Int, forkedCount: Int,
|
||||
branchList: Seq[String], tags: Seq[JGitUtil.TagInfo], managers: Seq[String]){
|
||||
|
||||
lazy val host = """^https?://(.+?)(:\d+)?/""".r.findFirstMatchIn(httpUrl).get.group(1)
|
||||
|
||||
def sshUrl(port: Int, userName: String) = s"ssh://${userName}@${host}:${port}/${owner}/${name}.git"
|
||||
|
||||
def sshOpenRepoUrl(platform: String, port: Int, userName: String) = openRepoUrl(platform, sshUrl(port, userName))
|
||||
|
||||
def httpOpenRepoUrl(platform: String) = openRepoUrl(platform, httpUrl)
|
||||
|
||||
def openRepoUrl(platform: String, openUrl: String) = s"github-${platform}://openRepo/${openUrl}"
|
||||
branchList: Seq[String], tags: Seq[JGitUtil.TagInfo], managers: Seq[String]) {
|
||||
|
||||
/**
|
||||
* Creates instance with issue count and pull request count.
|
||||
*/
|
||||
def this(repo: JGitUtil.RepositoryInfo, model: Repository, issueCount: Int, pullCount: Int, forkedCount: Int, managers: Seq[String]) =
|
||||
this(repo.owner, repo.name, repo.url, model, issueCount, pullCount, repo.commitCount, forkedCount, repo.branchList, repo.tags, managers)
|
||||
this(
|
||||
repo.owner, repo.name, model,
|
||||
issueCount, pullCount, repo.commitCount, forkedCount,
|
||||
repo.branchList, repo.tags, managers)
|
||||
|
||||
/**
|
||||
* Creates instance without issue count and pull request count.
|
||||
*/
|
||||
def this(repo: JGitUtil.RepositoryInfo, model: Repository, forkedCount: Int, managers: Seq[String]) =
|
||||
this(repo.owner, repo.name, repo.url, model, 0, 0, repo.commitCount, forkedCount, repo.branchList, repo.tags, managers)
|
||||
def this(repo: JGitUtil.RepositoryInfo, model: Repository, forkedCount: Int, managers: Seq[String]) =
|
||||
this(
|
||||
repo.owner, repo.name, model,
|
||||
0, 0, repo.commitCount, forkedCount,
|
||||
repo.branchList, repo.tags, managers)
|
||||
|
||||
def httpUrl(implicit context: Context): String = RepositoryService.httpUrl(owner, name)
|
||||
def sshUrl(implicit context: Context): Option[String] = RepositoryService.sshUrl(owner, name)
|
||||
}
|
||||
|
||||
case class RepositoryTreeNode(owner: String, name: String, children: List[RepositoryTreeNode])
|
||||
def httpUrl(owner: String, name: String)(implicit context: Context): String = s"${context.baseUrl}/git/${owner}/${name}.git"
|
||||
def sshUrl(owner: String, name: String)(implicit context: Context): Option[String] =
|
||||
if(context.settings.ssh){
|
||||
context.loginAccount.flatMap { loginAccount =>
|
||||
context.settings.sshAddress.map { x => s"ssh://${loginAccount.userName}@${x.host}:${x.port}/${owner}/${name}.git" }
|
||||
}
|
||||
} else None
|
||||
def openRepoUrl(openUrl: String)(implicit context: Context): String = s"github-${context.platform}://openRepo/${openUrl}"
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package gitbucket.core.service
|
||||
|
||||
import gitbucket.core.util.{Directory, ControlUtil}
|
||||
import gitbucket.core.util.Implicits._
|
||||
import Directory._
|
||||
import ControlUtil._
|
||||
import SystemSettingsService._
|
||||
@@ -21,6 +22,7 @@ trait SystemSettingsService {
|
||||
props.setProperty(Notification, settings.notification.toString)
|
||||
settings.activityLogLimit.foreach(x => props.setProperty(ActivityLogLimit, x.toString))
|
||||
props.setProperty(Ssh, settings.ssh.toString)
|
||||
settings.sshHost.foreach(x => props.setProperty(SshHost, x.trim))
|
||||
settings.sshPort.foreach(x => props.setProperty(SshPort, x.toString))
|
||||
props.setProperty(UseSMTP, settings.useSMTP.toString)
|
||||
if(settings.useSMTP) {
|
||||
@@ -75,6 +77,7 @@ trait SystemSettingsService {
|
||||
getValue(props, Notification, false),
|
||||
getOptionValue[Int](props, ActivityLogLimit, None),
|
||||
getValue(props, Ssh, false),
|
||||
getOptionValue[String](props, SshHost, None).map(_.trim),
|
||||
getOptionValue(props, SshPort, Some(DefaultSshPort)),
|
||||
getValue(props, UseSMTP, getValue(props, Notification, false)), // handle migration scenario from only notification to useSMTP
|
||||
if(getValue(props, UseSMTP, getValue(props, Notification, false))){
|
||||
@@ -126,16 +129,19 @@ object SystemSettingsService {
|
||||
notification: Boolean,
|
||||
activityLogLimit: Option[Int],
|
||||
ssh: Boolean,
|
||||
sshHost: Option[String],
|
||||
sshPort: Option[Int],
|
||||
useSMTP: Boolean,
|
||||
smtp: Option[Smtp],
|
||||
ldapAuthentication: Boolean,
|
||||
ldap: Option[Ldap]){
|
||||
def baseUrl(request: HttpServletRequest): String = baseUrl.getOrElse {
|
||||
defining(request.getRequestURL.toString){ url =>
|
||||
url.substring(0, url.length - (request.getRequestURI.length - request.getContextPath.length))
|
||||
def baseUrl(request: HttpServletRequest): String = baseUrl.fold(request.baseUrl)(_.stripSuffix("/"))
|
||||
|
||||
def sshAddress:Option[SshAddress] =
|
||||
for {
|
||||
host <- sshHost if ssh
|
||||
}
|
||||
}.stripSuffix("/")
|
||||
yield SshAddress(host, sshPort.getOrElse(DefaultSshPort))
|
||||
}
|
||||
|
||||
case class Ldap(
|
||||
@@ -161,6 +167,10 @@ object SystemSettingsService {
|
||||
fromAddress: Option[String],
|
||||
fromName: Option[String])
|
||||
|
||||
case class SshAddress(
|
||||
host:String,
|
||||
port:Int)
|
||||
|
||||
val DefaultSshPort = 29418
|
||||
val DefaultSmtpPort = 25
|
||||
val DefaultLdapPort = 389
|
||||
@@ -174,6 +184,7 @@ object SystemSettingsService {
|
||||
private val Notification = "notification"
|
||||
private val ActivityLogLimit = "activity_log_limit"
|
||||
private val Ssh = "ssh"
|
||||
private val SshHost = "ssh.host"
|
||||
private val SshPort = "ssh.port"
|
||||
private val UseSMTP = "useSMTP"
|
||||
private val SmtpHost = "smtp.host"
|
||||
@@ -216,7 +227,4 @@ object SystemSettingsService {
|
||||
else value
|
||||
}
|
||||
|
||||
// // TODO temporary flag
|
||||
// val enablePluginSystem = Option(System.getProperty("enable.plugin")).getOrElse("false").toBoolean
|
||||
|
||||
}
|
||||
|
||||
@@ -161,7 +161,7 @@ trait WebHookPullRequestService extends WebHookService {
|
||||
baseOwner <- users.get(repository.owner)
|
||||
headOwner <- users.get(pullRequest.requestUserName)
|
||||
issueUser <- users.get(issue.openedUserName)
|
||||
headRepo <- getRepository(pullRequest.requestUserName, pullRequest.requestRepositoryName, baseUrl)
|
||||
headRepo <- getRepository(pullRequest.requestUserName, pullRequest.requestRepositoryName)
|
||||
} yield {
|
||||
WebHookPullRequestPayload(
|
||||
action = action,
|
||||
@@ -200,7 +200,7 @@ trait WebHookPullRequestService extends WebHookService {
|
||||
import WebHookService._
|
||||
for{
|
||||
((issue, issueUser, pullRequest, baseOwner, headOwner), webHooks) <- getPullRequestsByRequestForWebhook(requestRepository.owner, requestRepository.name, requestBranch)
|
||||
baseRepo <- getRepository(pullRequest.userName, pullRequest.repositoryName, baseUrl)
|
||||
baseRepo <- getRepository(pullRequest.userName, pullRequest.repositoryName)
|
||||
} yield {
|
||||
val payload = WebHookPullRequestPayload(
|
||||
action = action,
|
||||
@@ -229,7 +229,7 @@ trait WebHookPullRequestReviewCommentService extends WebHookService {
|
||||
baseOwner <- users.get(repository.owner)
|
||||
headOwner <- users.get(pullRequest.requestUserName)
|
||||
issueUser <- users.get(issue.openedUserName)
|
||||
headRepo <- getRepository(pullRequest.requestUserName, pullRequest.requestRepositoryName, baseUrl)
|
||||
headRepo <- getRepository(pullRequest.requestUserName, pullRequest.requestRepositoryName)
|
||||
} yield {
|
||||
WebHookPullRequestReviewCommentPayload(
|
||||
action = action,
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package gitbucket.core.service
|
||||
|
||||
import java.util.Date
|
||||
import gitbucket.core.controller.Context
|
||||
import gitbucket.core.model.Account
|
||||
import gitbucket.core.service.RepositoryService.RepositoryInfo
|
||||
import gitbucket.core.util._
|
||||
import gitbucket.core.util.ControlUtil._
|
||||
import org.eclipse.jgit.api.Git
|
||||
@@ -13,7 +15,6 @@ import java.io.ByteArrayInputStream
|
||||
import org.eclipse.jgit.patch._
|
||||
import org.eclipse.jgit.api.errors.PatchFormatException
|
||||
import scala.collection.JavaConverters._
|
||||
import RepositoryService.RepositoryInfo
|
||||
|
||||
object WikiService {
|
||||
|
||||
@@ -38,10 +39,13 @@ object WikiService {
|
||||
*/
|
||||
case class WikiPageHistoryInfo(name: String, committer: String, message: String, date: Date)
|
||||
|
||||
def httpUrl(repository: RepositoryInfo) = repository.httpUrl.replaceFirst("\\.git\\Z", ".wiki.git")
|
||||
|
||||
def sshUrl(repository: RepositoryInfo, settings: SystemSettingsService.SystemSettings, userName: String) =
|
||||
repository.sshUrl(settings.sshPort.getOrElse(SystemSettingsService.DefaultSshPort), userName).replaceFirst("\\.git\\Z", ".wiki.git")
|
||||
def wikiHttpUrl(repositoryInfo: RepositoryInfo)(implicit context: Context): String
|
||||
= RepositoryService.httpUrl(repositoryInfo.owner, repositoryInfo.name + ".wiki")
|
||||
|
||||
def wikiSshUrl(repositoryInfo: RepositoryInfo)(implicit context: Context): Option[String]
|
||||
= RepositoryService.sshUrl(repositoryInfo.owner, repositoryInfo.name + ".wiki")
|
||||
|
||||
}
|
||||
|
||||
trait WikiService {
|
||||
|
||||
@@ -21,6 +21,7 @@ object AutoUpdate {
|
||||
* The history of versions. A head of this sequence is the current GitBucket version.
|
||||
*/
|
||||
val versions = Seq(
|
||||
new Version(3, 12),
|
||||
new Version(3, 11),
|
||||
new Version(3, 10),
|
||||
new Version(3, 9),
|
||||
|
||||
@@ -74,7 +74,7 @@ class BasicAuthenticationFilter extends Filter with RepositoryService with Accou
|
||||
|
||||
request.paths match {
|
||||
case Array(_, repositoryOwner, repositoryName, _*) =>
|
||||
getRepository(repositoryOwner, repositoryName.replaceFirst("\\.wiki\\.git$|\\.git$", ""), "") match {
|
||||
getRepository(repositoryOwner, repositoryName.replaceFirst("\\.wiki\\.git$|\\.git$", "")) match {
|
||||
case Some(repository) => {
|
||||
if(!isUpdating && !repository.repository.isPrivate && settings.allowAnonymousAccess){
|
||||
chain.doFilter(request, response)
|
||||
|
||||
@@ -160,7 +160,7 @@ class CommitLogHook(owner: String, repository: String, pusher: String, baseUrl:
|
||||
countIssue(IssueSearchCondition(state = "open"), false, owner -> repository) +
|
||||
countIssue(IssueSearchCondition(state = "closed"), false, owner -> repository)
|
||||
|
||||
val repositoryInfo = getRepository(owner, repository, baseUrl).get
|
||||
val repositoryInfo = getRepository(owner, repository).get
|
||||
|
||||
// Extract new commit and apply issue comment
|
||||
val defaultBranch = repositoryInfo.repository.defaultBranch
|
||||
|
||||
@@ -87,11 +87,11 @@ abstract class DefaultGitCommand(val owner: String, val repoName: String) extend
|
||||
}
|
||||
|
||||
|
||||
class DefaultGitUploadPack(owner: String, repoName: String, baseUrl: String) extends DefaultGitCommand(owner, repoName)
|
||||
class DefaultGitUploadPack(owner: String, repoName: String) extends DefaultGitCommand(owner, repoName)
|
||||
with RepositoryService with AccountService {
|
||||
|
||||
override protected def runTask(user: String)(implicit session: Session): Unit = {
|
||||
getRepository(owner, repoName.replaceFirst("\\.wiki\\Z", ""), baseUrl).foreach { repositoryInfo =>
|
||||
getRepository(owner, repoName.replaceFirst("\\.wiki\\Z", "")).foreach { repositoryInfo =>
|
||||
if(!repositoryInfo.repository.isPrivate || isWritableUser(user, repositoryInfo)){
|
||||
using(Git.open(getRepositoryDir(owner, repoName))) { git =>
|
||||
val repository = git.getRepository
|
||||
@@ -107,7 +107,7 @@ class DefaultGitReceivePack(owner: String, repoName: String, baseUrl: String) ex
|
||||
with RepositoryService with AccountService {
|
||||
|
||||
override protected def runTask(user: String)(implicit session: Session): Unit = {
|
||||
getRepository(owner, repoName.replaceFirst("\\.wiki\\Z", ""), baseUrl).foreach { repositoryInfo =>
|
||||
getRepository(owner, repoName.replaceFirst("\\.wiki\\Z", "")).foreach { repositoryInfo =>
|
||||
if(isWritableUser(user, repositoryInfo)){
|
||||
using(Git.open(getRepositoryDir(owner, repoName))) { git =>
|
||||
val repository = git.getRepository
|
||||
@@ -124,7 +124,7 @@ class DefaultGitReceivePack(owner: String, repoName: String, baseUrl: String) ex
|
||||
}
|
||||
}
|
||||
|
||||
class PluginGitUploadPack(repoName: String, baseUrl: String, routing: GitRepositoryRouting) extends GitCommand
|
||||
class PluginGitUploadPack(repoName: String, routing: GitRepositoryRouting) extends GitCommand
|
||||
with SystemSettingsService {
|
||||
|
||||
override protected def runTask(user: String)(implicit session: Session): Unit = {
|
||||
@@ -139,7 +139,7 @@ class PluginGitUploadPack(repoName: String, baseUrl: String, routing: GitReposit
|
||||
}
|
||||
}
|
||||
|
||||
class PluginGitReceivePack(repoName: String, baseUrl: String, routing: GitRepositoryRouting) extends GitCommand
|
||||
class PluginGitReceivePack(repoName: String, routing: GitRepositoryRouting) extends GitCommand
|
||||
with SystemSettingsService {
|
||||
|
||||
override protected def runTask(user: String)(implicit session: Session): Unit = {
|
||||
@@ -163,9 +163,9 @@ class GitCommandFactory(baseUrl: String) extends CommandFactory {
|
||||
logger.debug(s"command: $command")
|
||||
|
||||
command match {
|
||||
case SimpleCommandRegex ("upload" , repoName) if(pluginRepository(repoName)) => new PluginGitUploadPack (repoName, baseUrl, routing(repoName))
|
||||
case SimpleCommandRegex ("receive", repoName) if(pluginRepository(repoName)) => new PluginGitReceivePack(repoName, baseUrl, routing(repoName))
|
||||
case DefaultCommandRegex("upload" , owner, repoName) => new DefaultGitUploadPack (owner, repoName, baseUrl)
|
||||
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 DefaultCommandRegex("upload" , owner, repoName) => new DefaultGitUploadPack (owner, repoName)
|
||||
case DefaultCommandRegex("receive", owner, repoName) => new DefaultGitReceivePack(owner, repoName, baseUrl)
|
||||
case _ => new UnknownCommand(command)
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package gitbucket.core.ssh
|
||||
|
||||
import gitbucket.core.service.SystemSettingsService
|
||||
import gitbucket.core.service.SystemSettingsService.SshAddress
|
||||
import org.apache.sshd.common.Factory
|
||||
import org.apache.sshd.server.{Environment, ExitCallback, Command}
|
||||
import java.io.{OutputStream, InputStream}
|
||||
import org.eclipse.jgit.lib.Constants
|
||||
|
||||
class NoShell extends Factory[Command] with SystemSettingsService {
|
||||
class NoShell(sshAddress:SshAddress) extends Factory[Command] {
|
||||
override def create(): Command = new Command() {
|
||||
private var in: InputStream = null
|
||||
private var out: OutputStream = null
|
||||
@@ -15,7 +16,6 @@ class NoShell extends Factory[Command] with SystemSettingsService {
|
||||
|
||||
override def start(env: Environment): Unit = {
|
||||
val user = env.getEnv.get("USER")
|
||||
val port = loadSystemSettings().sshPort.getOrElse(SystemSettingsService.DefaultSshPort)
|
||||
val message =
|
||||
"""
|
||||
| Welcome to
|
||||
@@ -31,8 +31,8 @@ class NoShell extends Factory[Command] with SystemSettingsService {
|
||||
|
|
||||
| Please use:
|
||||
|
|
||||
| git clone ssh://%s@GITBUCKET_HOST:%d/OWNER/REPOSITORY_NAME.git
|
||||
""".stripMargin.format(user, port).replace("\n", "\r\n") + "\r\n"
|
||||
| git clone ssh://%s@%s:%d/OWNER/REPOSITORY_NAME.git
|
||||
""".stripMargin.format(user, sshAddress.host, sshAddress.port).replace("\n", "\r\n") + "\r\n"
|
||||
err.write(Constants.encode(message))
|
||||
err.flush()
|
||||
in.close()
|
||||
|
||||
@@ -5,7 +5,8 @@ import java.util.concurrent.atomic.AtomicBoolean
|
||||
import javax.servlet.{ServletContextEvent, ServletContextListener}
|
||||
|
||||
import gitbucket.core.service.SystemSettingsService
|
||||
import gitbucket.core.util.Directory
|
||||
import gitbucket.core.service.SystemSettingsService.SshAddress
|
||||
import gitbucket.core.util.{Directory}
|
||||
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
@@ -14,20 +15,20 @@ object SshServer {
|
||||
private val server = org.apache.sshd.server.SshServer.setUpDefaultServer()
|
||||
private val active = new AtomicBoolean(false)
|
||||
|
||||
private def configure(port: Int, baseUrl: String) = {
|
||||
server.setPort(port)
|
||||
private def configure(sshAddress: SshAddress, baseUrl: String) = {
|
||||
server.setPort(sshAddress.port)
|
||||
val provider = new SimpleGeneratorHostKeyProvider(new File(s"${Directory.GitBucketHome}/gitbucket.ser"))
|
||||
provider.setAlgorithm("RSA")
|
||||
provider.setOverwriteAllowed(false)
|
||||
server.setKeyPairProvider(provider)
|
||||
server.setPublickeyAuthenticator(new PublicKeyAuthenticator)
|
||||
server.setCommandFactory(new GitCommandFactory(baseUrl))
|
||||
server.setShellFactory(new NoShell)
|
||||
server.setShellFactory(new NoShell(sshAddress))
|
||||
}
|
||||
|
||||
def start(port: Int, baseUrl: String) = {
|
||||
def start(sshAddress: SshAddress, baseUrl: String) = {
|
||||
if(active.compareAndSet(false, true)){
|
||||
configure(port, baseUrl)
|
||||
configure(sshAddress, baseUrl)
|
||||
server.start()
|
||||
logger.info(s"Start SSH Server Listen on ${server.getPort}")
|
||||
}
|
||||
@@ -55,20 +56,18 @@ class SshServerListener extends ServletContextListener with SystemSettingsServic
|
||||
|
||||
override def contextInitialized(sce: ServletContextEvent): Unit = {
|
||||
val settings = loadSystemSettings()
|
||||
if(settings.ssh){
|
||||
settings.baseUrl match {
|
||||
case None =>
|
||||
logger.error("Could not start SshServer because the baseUrl is not configured.")
|
||||
case Some(baseUrl) =>
|
||||
SshServer.start(settings.sshPort.getOrElse(SystemSettingsService.DefaultSshPort), baseUrl)
|
||||
}
|
||||
if (settings.sshAddress.isDefined && settings.baseUrl.isEmpty) {
|
||||
logger.error("Could not start SshServer because the baseUrl is not configured.")
|
||||
}
|
||||
for {
|
||||
sshAddress <- settings.sshAddress
|
||||
baseUrl <- settings.baseUrl
|
||||
}
|
||||
SshServer.start(sshAddress, baseUrl)
|
||||
}
|
||||
|
||||
override def contextDestroyed(sce: ServletContextEvent): Unit = {
|
||||
if(loadSystemSettings().ssh){
|
||||
SshServer.stop()
|
||||
}
|
||||
SshServer.stop()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ trait OwnerAuthenticator { self: ControllerBase with RepositoryService with Acco
|
||||
private def authenticate(action: (RepositoryInfo) => Any) = {
|
||||
{
|
||||
defining(request.paths){ paths =>
|
||||
getRepository(paths(0), paths(1), baseUrl).map { repository =>
|
||||
getRepository(paths(0), paths(1)).map { repository =>
|
||||
context.loginAccount match {
|
||||
case Some(x) if(x.isAdmin) => action(repository)
|
||||
case Some(x) if(repository.owner == x.userName) => action(repository)
|
||||
@@ -95,7 +95,7 @@ trait CollaboratorsAuthenticator { self: ControllerBase with RepositoryService =
|
||||
private def authenticate(action: (RepositoryInfo) => Any) = {
|
||||
{
|
||||
defining(request.paths){ paths =>
|
||||
getRepository(paths(0), paths(1), baseUrl).map { repository =>
|
||||
getRepository(paths(0), paths(1)).map { repository =>
|
||||
context.loginAccount match {
|
||||
case Some(x) if(x.isAdmin) => action(repository)
|
||||
case Some(x) if(paths(0) == x.userName) => action(repository)
|
||||
@@ -118,7 +118,7 @@ trait ReferrerAuthenticator { self: ControllerBase with RepositoryService =>
|
||||
private def authenticate(action: (RepositoryInfo) => Any) = {
|
||||
{
|
||||
defining(request.paths){ paths =>
|
||||
getRepository(paths(0), paths(1), baseUrl).map { repository =>
|
||||
getRepository(paths(0), paths(1)).map { repository =>
|
||||
if(!repository.repository.isPrivate){
|
||||
action(repository)
|
||||
} else {
|
||||
@@ -145,7 +145,7 @@ trait ReadableUsersAuthenticator { self: ControllerBase with RepositoryService =
|
||||
private def authenticate(action: (RepositoryInfo) => Any) = {
|
||||
{
|
||||
defining(request.paths){ paths =>
|
||||
getRepository(paths(0), paths(1), baseUrl).map { repository =>
|
||||
getRepository(paths(0), paths(1)).map { repository =>
|
||||
context.loginAccount match {
|
||||
case Some(x) if(x.isAdmin) => action(repository)
|
||||
case Some(x) if(!repository.repository.isPrivate) => action(repository)
|
||||
|
||||
@@ -75,6 +75,11 @@ object Implicits {
|
||||
|
||||
def gitRepositoryPath: String = request.getRequestURI.replaceFirst("^/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(session: HttpSession){
|
||||
|
||||
@@ -32,14 +32,13 @@ object JGitUtil {
|
||||
*
|
||||
* @param owner the user name of the repository owner
|
||||
* @param name the repository name
|
||||
* @param url the repository URL
|
||||
* @param commitCount the commit count. If the repository has over 1000 commits then this property is 1001.
|
||||
* @param branchList the list of branch names
|
||||
* @param tags the list of tags
|
||||
*/
|
||||
case class RepositoryInfo(owner: String, name: String, url: String, commitCount: Int, branchList: List[String], tags: List[TagInfo]){
|
||||
def this(owner: String, name: String, baseUrl: String) = {
|
||||
this(owner, name, s"${baseUrl}/git/${owner}/${name}.git", 0, Nil, Nil)
|
||||
case class RepositoryInfo(owner: String, name: String, commitCount: Int, branchList: List[String], tags: List[TagInfo]){
|
||||
def this(owner: String, name: String) = {
|
||||
this(owner, name, 0, Nil, Nil)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,14 +173,14 @@ object JGitUtil {
|
||||
/**
|
||||
* Returns the repository information. It contains branch names and tag names.
|
||||
*/
|
||||
def getRepositoryInfo(owner: String, repository: String, baseUrl: String): RepositoryInfo = {
|
||||
def getRepositoryInfo(owner: String, repository: String): RepositoryInfo = {
|
||||
using(Git.open(getRepositoryDir(owner, repository))){ git =>
|
||||
try {
|
||||
// get commit count
|
||||
val commitCount = git.log.all.call.iterator.asScala.map(_ => 1).take(10001).sum
|
||||
|
||||
RepositoryInfo(
|
||||
owner, repository, s"${baseUrl}/git/${owner}/${repository}.git",
|
||||
owner, repository,
|
||||
// commit count
|
||||
commitCount,
|
||||
// branches
|
||||
@@ -197,7 +196,7 @@ object JGitUtil {
|
||||
} catch {
|
||||
// not initialized
|
||||
case e: NoHeadException => RepositoryInfo(
|
||||
owner, repository, s"${baseUrl}/git/${owner}/${repository}.git", 0, Nil, Nil)
|
||||
owner, repository, 0, Nil, Nil)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import gitbucket.core.plugin.{RenderRequest, PluginRegistry}
|
||||
import gitbucket.core.service.{RepositoryService, RequestCache}
|
||||
import gitbucket.core.util.{FileUtil, JGitUtil, StringUtil}
|
||||
|
||||
import play.twirl.api.Html
|
||||
import play.twirl.api.{Html, HtmlFormat}
|
||||
|
||||
/**
|
||||
* Provides helper methods for Twirl templates.
|
||||
@@ -225,6 +225,13 @@ object helpers extends AvatarImageProvider with LinkConverter with RequestCache
|
||||
def avatarLink(userName: String, size: Int, mailAddress: String = "", tooltip: Boolean = false)(implicit context: Context): Html =
|
||||
userWithContent(userName, mailAddress)(avatar(userName, size, tooltip, mailAddress))
|
||||
|
||||
/**
|
||||
* Generates the avatar link to the account page.
|
||||
* If user does not exist or disabled, this method returns avatar image without link.
|
||||
*/
|
||||
def avatarLink(commit: JGitUtil.CommitInfo, size: Int)(implicit context: Context): Html =
|
||||
userWithContent(commit.authorName, commit.authorEmailAddress)(avatar(commit, size))
|
||||
|
||||
private def userWithContent(userName: String, mailAddress: String = "", styleClass: String = "")(content: Html)(implicit context: Context): Html =
|
||||
(if(mailAddress.isEmpty){
|
||||
getAccountByUserName(userName)
|
||||
@@ -306,6 +313,19 @@ object helpers extends AvatarImageProvider with LinkConverter with RequestCache
|
||||
private[this] val detectAndRenderLinksRegex = """(?i)\b((?:https?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,13}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))""".r
|
||||
|
||||
def detectAndRenderLinks(text: String): Html = {
|
||||
Html(detectAndRenderLinksRegex.replaceAllIn(text, m => s"""<a href="${m.group(0)}">${m.group(0)}</a>"""))
|
||||
val matches = detectAndRenderLinksRegex.findAllMatchIn(text).toSeq
|
||||
|
||||
val (x, pos) = matches.foldLeft((collection.immutable.Seq.empty[Html], 0)){ case ((x, pos), m) =>
|
||||
val url = m.group(0)
|
||||
val href = url.replace("\"", """)
|
||||
(x ++ (Seq(
|
||||
if(pos < m.start) Some(HtmlFormat.escape(text.substring(pos, m.start))) else None,
|
||||
Some(Html(s"""<a href="${href}">${url}</a>"""))
|
||||
).flatten), m.end)
|
||||
}
|
||||
// append rest fragment
|
||||
val out = if (pos < text.length) x :+ HtmlFormat.escape(text.substring(pos)) else x
|
||||
|
||||
HtmlFormat.fill(out)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
@import context._
|
||||
@import gitbucket.core.view.helpers._
|
||||
@html.main("Applications"){
|
||||
<div class="container">
|
||||
<div class="container body">
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
@menu("application", settings.ssh)
|
||||
@@ -16,24 +16,27 @@
|
||||
@if(personalTokens.isEmpty && gneratedToken.isEmpty){
|
||||
No tokens.
|
||||
} else {
|
||||
Tokens you have generated that can be used to access the GitBucket API.<hr>
|
||||
Tokens you have generated that can be used to access the GitBucket API.
|
||||
<hr style="margin-top: 10px;">
|
||||
}
|
||||
@gneratedToken.map{ case (token, tokenString) =>
|
||||
<div class="alert alert-info">
|
||||
Make sure to copy your new personal access token now. You won't be able to see it again!
|
||||
</div>
|
||||
@helper.html.copy("generated-token-copy", tokenString){
|
||||
<input type="text" value="@tokenString" style="width:21em" readonly>
|
||||
}
|
||||
<a href="@path/@account.userName/_personalToken/delete/@token.accessTokenId" class="btn btn-mini btn-danger pull-right">Delete</a>
|
||||
<hr>
|
||||
<a href="@path/@account.userName/_personalToken/delete/@token.accessTokenId" class="btn btn-sm btn-danger pull-right">Delete</a>
|
||||
<div style="width: 50%;">
|
||||
@helper.html.copy("generated-token-copy", tokenString){
|
||||
<input type="text" value="@tokenString" class="form-control input-sm" readonly>
|
||||
}
|
||||
</div>
|
||||
<hr style="margin-top: 10px;">
|
||||
}
|
||||
@personalTokens.zipWithIndex.map { case (token, i) =>
|
||||
@if(i != 0){
|
||||
<hr>
|
||||
<hr style="margin-top: 10px;">
|
||||
}
|
||||
<strong>@token.note</strong>
|
||||
<a href="@path/@account.userName/_personalToken/delete/@token.accessTokenId" class="btn btn-mini btn-danger pull-right">Delete</a>
|
||||
<a href="@path/@account.userName/_personalToken/delete/@token.accessTokenId" class="btn btn-sm btn-danger pull-right">Delete</a>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
@@ -44,7 +47,7 @@
|
||||
<fieldset>
|
||||
<label for="note" class="strong">Token description</label>
|
||||
<div><span id="error-note" class="error"></span></div>
|
||||
<input type="text" name="note" id="note" class="form-control" style="width: 400px;"/>
|
||||
<input type="text" name="note" id="note" class="form-control"/>
|
||||
<p class="muted">What's this token for?</p>
|
||||
</fieldset>
|
||||
<input type="submit" class="btn btn-success" value="Generate token"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
@import context._
|
||||
@import gitbucket.core.view.helpers._
|
||||
@html.main("Edit your profile"){
|
||||
<div class="container">
|
||||
<div class="container body">
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
@menu("profile", settings.ssh)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
@import context._
|
||||
@import gitbucket.core.view.helpers._
|
||||
@html.main(if(account.isEmpty) "Create group" else "Edit group"){
|
||||
<div class="container">
|
||||
<div class="container body">
|
||||
<form id="form" method="post" action="@if(account.isEmpty){@path/groups/new} else {@path/@account.get.userName/_editgroup}" validate="true">
|
||||
<div class="row">
|
||||
<div class="col-md-5">
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
@import context._
|
||||
@import gitbucket.core.view.helpers._
|
||||
@html.main(account.userName){
|
||||
<div class="container">
|
||||
<div class="container body">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
@@ -22,7 +22,7 @@
|
||||
<div>
|
||||
<div>Groups</div>
|
||||
@groupNames.map { groupName =>
|
||||
<a href="@url(groupName)">@avatar(groupName, 36, tooltip = true)</a>
|
||||
@avatarLink(groupName, 36, tooltip = true)
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ isCreateRepoOptionPublic: Boolean)(implicit context: gitbucket.core.controller.C
|
||||
@import context._
|
||||
@import gitbucket.core.view.helpers._
|
||||
@html.main("Create a New Repository"){
|
||||
<div style="width: 600px; margin: 10px auto;">
|
||||
<div class="body" style="width: 600px; margin: 10px auto;">
|
||||
<h2>Create a new repository</h2>
|
||||
<p class="muted">
|
||||
A repository contains all the files for your project, including the revision history.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
@import context._
|
||||
@import gitbucket.core.view.helpers._
|
||||
@html.main("Create your account"){
|
||||
<div class="container">
|
||||
<div class="container body">
|
||||
<h3>Create your account</h3>
|
||||
<form action="@path/register" method="POST" validate="true">
|
||||
<div class="row">
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
@import context._
|
||||
@import gitbucket.core.view.helpers._
|
||||
@html.main("SSH Keys"){
|
||||
<div class="container">
|
||||
<div class="container body">
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
@menu("ssh", settings.ssh)
|
||||
@@ -17,10 +17,10 @@
|
||||
}
|
||||
@sshKeys.zipWithIndex.map { case (key, i) =>
|
||||
@if(i != 0){
|
||||
<hr>
|
||||
<hr style="margin-top: 10px;">
|
||||
}
|
||||
<strong>@key.title</strong> (@SshUtil.fingerPrint(key.publicKey).getOrElse("Key is invalid."))
|
||||
<a href="@path/@account.userName/_ssh/delete/@key.sshKeyId" class="btn btn-mini btn-danger pull-right">Delete</a>
|
||||
<a href="@path/@account.userName/_ssh/delete/@key.sshKeyId" class="btn btn-sm btn-danger pull-right">Delete</a>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
@@ -31,12 +31,12 @@
|
||||
<fieldset class="form-group">
|
||||
<label for="title" class="strong">Title</label>
|
||||
<div><span id="error-title" class="error"></span></div>
|
||||
<input type="text" name="title" id="title" class="form-control" style="width: 400px;"/>
|
||||
<input type="text" name="title" id="title" class="form-control"/>
|
||||
</fieldset>
|
||||
<fieldset class="form-group">
|
||||
<label for="publicKey" class="strong">Key</label>
|
||||
<div><span id="error-publicKey" class="error"></span></div>
|
||||
<textarea name="publicKey" id="publicKey" class="form-control" style="width: 600px; height: 250px;"></textarea>
|
||||
<textarea name="publicKey" id="publicKey" class="form-control" style="height: 250px;"></textarea>
|
||||
</fieldset>
|
||||
<input type="submit" class="btn btn-success" value="Add"/>
|
||||
</div>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<a href="@path/admin/system">System Settings</a>
|
||||
</li>
|
||||
<li@if(active=="plugins"){ class="active"}>
|
||||
<a href="@path/admin/plugins">Plugins</a>
|
||||
<a href="@path/admin/plugins">Plugins</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="@path/console/login.jsp">H2 Console</a>
|
||||
|
||||
@@ -111,15 +111,24 @@
|
||||
Enable SSH access to git repository
|
||||
</label>
|
||||
</fieldset>
|
||||
<div class="form-group ssh">
|
||||
<label class="control-label col-md-3" for="sshPort">SSH Port</label>
|
||||
<div class="col-md-9">
|
||||
<input type="text" id="sshPort" name="sshPort" class="form-control" value="@settings.sshPort"/>
|
||||
<span id="error-sshPort" class="error"></span>
|
||||
<div class="ssh">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-md-3" for="sshHost">SSH Host</label>
|
||||
<div class="col-md-9">
|
||||
<input type="text" id="sshHost" name="sshHost" class="form-control" value="@settings.sshHost"/>
|
||||
<span id="error-sshHost" class="error"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-md-3" for="sshPort">SSH Port</label>
|
||||
<div class="col-md-9">
|
||||
<input type="text" id="sshPort" name="sshPort" class="form-control" value="@settings.sshPort"/>
|
||||
<span id="error-sshPort" class="error"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="muted">
|
||||
Base URL is required if SSH access is enabled.
|
||||
Both of SSH host and Base URL are required if SSH access is enabled.
|
||||
</p>
|
||||
<!--====================================================================-->
|
||||
<!-- Authentication -->
|
||||
|
||||
@@ -8,9 +8,11 @@
|
||||
@import context._
|
||||
@import gitbucket.core.view.helpers._
|
||||
@html.main("Issues"){
|
||||
@dashboard.html.tab("issues")
|
||||
<div class="container">
|
||||
@issuesnavi(filter, "issues", condition)
|
||||
@issueslist(issues, page, openCount, closedCount, condition, filter, groups)
|
||||
<div class="body">
|
||||
@dashboard.html.tab("issues")
|
||||
<div class="container">
|
||||
@issuesnavi(filter, "issues", condition)
|
||||
@issueslist(issues, page, openCount, closedCount, condition, filter, groups)
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -8,9 +8,11 @@
|
||||
@import context._
|
||||
@import gitbucket.core.view.helpers._
|
||||
@html.main("Pull Requests"){
|
||||
@dashboard.html.tab("pulls")
|
||||
<div class="container">
|
||||
@issuesnavi(filter, "pulls", condition)
|
||||
@issueslist(issues, page, openCount, closedCount, condition, filter, groups)
|
||||
<div class="body">
|
||||
@dashboard.html.tab("pulls")
|
||||
<div class="container">
|
||||
@issuesnavi(filter, "pulls", condition)
|
||||
@issueslist(issues, page, openCount, closedCount, condition, filter, groups)
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -27,12 +27,6 @@ $(function(){
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
// Adjust clickable area width
|
||||
$('#@textareaId').next('div.clickable').css({
|
||||
'width': ($('#@textareaId').width() + 18) + 'px',
|
||||
'font-size': '13px'
|
||||
});
|
||||
});
|
||||
</script>
|
||||
}
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
@if(comment.fileName.isDefined){filename="@comment.fileName.get"}
|
||||
@if(comment.newLine.isDefined){newline="@comment.newLine.get"}
|
||||
@if(comment.oldLine.isDefined){oldline="@comment.oldLine.get"}>
|
||||
<div class="issue-avatar-image">@avatar(comment.commentedUserName, 48)</div>
|
||||
<div class="panel- panel-default commit-comment-box commit-comment-@comment.commentId">
|
||||
<div class="issue-avatar-image">@avatarLink(comment.commentedUserName, 48)</div>
|
||||
<div class="panel panel-default commit-comment-box commit-comment-@comment.commentId">
|
||||
<div class="panel-heading">
|
||||
@user(comment.commentedUserName, styleClass="username strong")
|
||||
<span class="muted">
|
||||
|
||||
@@ -1,8 +1,16 @@
|
||||
@(id: String, value: String, prepend: Boolean = false)(html: Html)
|
||||
<div class="input-group @if(prepend){input-prepend}" style="margin-bottom: 0px;">
|
||||
@html
|
||||
<span class="input-group-btn"><span id="@id" class="btn btn-sm btn-default" data-clipboard-text="@value" data-placement="bottom" title="copy to clipboard"><i class="octicon octicon-clippy"></i></span></span>
|
||||
</div>
|
||||
@(id: String, value: String, style: String = "")(html: Html = Html(""))
|
||||
@if(html.body.nonEmpty){
|
||||
<div class="input-group" style="margin-bottom: 0px;">
|
||||
@html
|
||||
<span class="input-group-btn">
|
||||
<span id="@id" class="btn btn-sm btn-default" @if(style.nonEmpty){style="@style"}
|
||||
data-clipboard-text="@value" data-placement="bottom" title="copy to clipboard"><i class="octicon octicon-clippy"></i></span>
|
||||
</span>
|
||||
</div>
|
||||
} else {
|
||||
<span id="@id" class="btn btn-sm btn-default" @if(style.nonEmpty){style="@style"}
|
||||
data-clipboard-text="@value" data-placement="bottom" title="copy to clipboard"><i class="octicon octicon-clippy"></i></span>
|
||||
}
|
||||
<script>
|
||||
// copy to clipboard
|
||||
(function() {
|
||||
|
||||
@@ -4,79 +4,81 @@
|
||||
@import context._
|
||||
@import gitbucket.core.view.helpers._
|
||||
@main("GitBucket"){
|
||||
@dashboard.html.tab()
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<div class="pull-right">
|
||||
<a href="@path/activities.atom"><img src="@assets/common/images/feed.png" alt="activities"></a>
|
||||
</div>
|
||||
@helper.html.activities(activities)
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
@settings.information.map { information =>
|
||||
<div class="alert alert-info" style="background-color: white; color: #555; border-color: #4183c4; font-size: small; line-height: 120%;">
|
||||
<button type="button" class="close" data-dismiss="alert">×</button>
|
||||
@Html(information)
|
||||
<div class="body">
|
||||
@dashboard.html.tab()
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<div class="pull-right">
|
||||
<a href="@path/activities.atom"><img src="@assets/common/images/feed.png" alt="activities"></a>
|
||||
</div>
|
||||
}
|
||||
@if(loginAccount.isEmpty){
|
||||
@signinform(settings)
|
||||
} else {
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading strong">
|
||||
<div class="pull-right">
|
||||
<a href="@path/new" class="btn btn-success btn-sm">New repository</a>
|
||||
</div>
|
||||
Your repositories <span class="badge">@userRepositories.size</span>
|
||||
@helper.html.activities(activities)
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
@settings.information.map { information =>
|
||||
<div class="alert alert-info" style="background-color: white; color: #555; border-color: #4183c4; font-size: small; line-height: 120%;">
|
||||
<button type="button" class="close" data-dismiss="alert">×</button>
|
||||
@Html(information)
|
||||
</div>
|
||||
<ul class="list-group list-group-flush">
|
||||
@if(userRepositories.isEmpty){
|
||||
<li class="list-group-item">No repositories</li>
|
||||
} else {
|
||||
@defining(20){ max =>
|
||||
@userRepositories.zipWithIndex.map { case (repository, i) =>
|
||||
<li class="list-group-item repo-link" style="@if(i > max - 1){display:none;}">
|
||||
@helper.html.repositoryicon(repository, false)
|
||||
@if(repository.owner == loginAccount.get.userName){
|
||||
<a href="@url(repository)"><span class="strong">@repository.name</span></a>
|
||||
} else {
|
||||
<a href="@url(repository)">@repository.owner/<span class="strong">@repository.name</span></a>
|
||||
}
|
||||
</li>
|
||||
}
|
||||
@if(userRepositories.size > max){
|
||||
<li class="list-group-item show-more">
|
||||
<a href="javascript:void(0);" id="show-more-repos">Show @{userRepositories.size - max} more repositories...</a>
|
||||
</li>
|
||||
}
|
||||
@if(loginAccount.isEmpty){
|
||||
<div id="dashboard-signin-form">@signinform(settings)</div>
|
||||
} else {
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading strong">
|
||||
<div class="pull-right">
|
||||
<a href="@path/new" class="btn btn-success btn-sm">New repository</a>
|
||||
</div>
|
||||
Your repositories <span class="badge">@userRepositories.size</span>
|
||||
</div>
|
||||
<ul class="list-group list-group-flush">
|
||||
@if(userRepositories.isEmpty){
|
||||
<li class="list-group-item">No repositories</li>
|
||||
} else {
|
||||
@defining(20){ max =>
|
||||
@userRepositories.zipWithIndex.map { case (repository, i) =>
|
||||
<li class="list-group-item repo-link" style="@if(i > max - 1){display:none;}">
|
||||
@helper.html.repositoryicon(repository, false)
|
||||
@if(repository.owner == loginAccount.get.userName){
|
||||
<a href="@url(repository)"><span class="strong">@repository.name</span></a>
|
||||
} else {
|
||||
<a href="@url(repository)">@repository.owner/<span class="strong">@repository.name</span></a>
|
||||
}
|
||||
</li>
|
||||
}
|
||||
@if(userRepositories.size > max){
|
||||
<li class="list-group-item show-more">
|
||||
<a href="javascript:void(0);" id="show-more-repos">Show @{userRepositories.size - max} more repositories...</a>
|
||||
</li>
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading strong">Recent updated repositories</div>
|
||||
<ul class="list-group list-group-flush">
|
||||
@if(recentRepositories.isEmpty){
|
||||
<li class="list-group-item">No repositories</li>
|
||||
} else {
|
||||
@defining(20){ max =>
|
||||
@recentRepositories.zipWithIndex.map { case (repository, i) =>
|
||||
<li class="list-group-item repo-link" style="@if(i > max - 1){display:none;}">
|
||||
@helper.html.repositoryicon(repository, false)
|
||||
<a href="@url(repository)">@repository.owner/<span class="strong">@repository.name</span></a>
|
||||
</li>
|
||||
}
|
||||
@if(recentRepositories.size > max){
|
||||
<li class="list-group-item show-more">
|
||||
<a href="javascript:void(0);" id="show-more-recent-repos">Show @{recentRepositories.size - max} more repositories...</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading strong">Recent updated repositories</div>
|
||||
<ul class="list-group list-group-flush">
|
||||
@if(recentRepositories.isEmpty){
|
||||
<li class="list-group-item">No repositories</li>
|
||||
} else {
|
||||
@defining(20){ max =>
|
||||
@recentRepositories.zipWithIndex.map { case (repository, i) =>
|
||||
<li class="list-group-item repo-link" style="@if(i > max - 1){display:none;}">
|
||||
@helper.html.repositoryicon(repository, false)
|
||||
<a href="@url(repository)">@repository.owner/<span class="strong">@repository.name</span></a>
|
||||
</li>
|
||||
}
|
||||
@if(recentRepositories.size > max){
|
||||
<li class="list-group-item show-more">
|
||||
<a href="javascript:void(0);" id="show-more-recent-repos">Show @{recentRepositories.size - max} more repositories...</a>
|
||||
</li>
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</ul>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
@if(loginAccount.isDefined){
|
||||
<hr/><br/>
|
||||
<form method="POST" validate="true">
|
||||
<div class="issue-avatar-image">@avatar(loginAccount.get.userName, 48)</div>
|
||||
<div class="issue-avatar-image">@avatarLink(loginAccount.get.userName, 48)</div>
|
||||
<div class="panel panel-default issue-comment-box">
|
||||
<div class="panel-body">
|
||||
@helper.html.preview(
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
@import gitbucket.core.view.helpers._
|
||||
@import gitbucket.core.model.CommitComment
|
||||
@if(issue.isDefined){
|
||||
<div class="issue-avatar-image">@avatar(issue.get.openedUserName, 48)</div>
|
||||
<div class="issue-avatar-image">@avatarLink(issue.get.openedUserName, 48)</div>
|
||||
<div class="panel panel-default issue-comment-box">
|
||||
<div class="panel-heading">
|
||||
@user(issue.get.openedUserName, styleClass="username strong") <span class="muted">commented @helper.html.datetimeago(issue.get.registeredDate)</span>
|
||||
@@ -36,7 +36,7 @@
|
||||
case comment: gitbucket.core.model.IssueComment => {
|
||||
@if(comment.action != "close" && comment.action != "reopen" && comment.action != "delete_branch"
|
||||
&& comment.action != "commit" && comment.action != "refer"){
|
||||
<div class="issue-avatar-image">@avatar(comment.commentedUserName, 48)</div>
|
||||
<div class="issue-avatar-image">@avatarLink(comment.commentedUserName, 48)</div>
|
||||
<div class="panel panel-default issue-comment-box" id="comment-@comment.commentId">
|
||||
<div class="panel-heading">
|
||||
@user(comment.commentedUserName, styleClass="username strong")
|
||||
@@ -210,7 +210,7 @@ $(function(){
|
||||
$(document).on('click', '.commit-comment-box i.octicon-pencil', function(){
|
||||
var id = $(this).closest('a').data('comment-id');
|
||||
var url = '@url(repository)/commit_comments/_data/' + id;
|
||||
var $content = $('.commit-commentContent-' + id, $(this).closest('.box'));
|
||||
var $content = $('.commit-commentContent-' + id, $(this).closest('.commit-comment-box'));
|
||||
|
||||
$.get(url,
|
||||
{
|
||||
|
||||
@@ -10,11 +10,11 @@
|
||||
<form action="@url(repository)/issues/new" method="POST" validate="true" class="form-group">
|
||||
<div class="row">
|
||||
<div class="col-md-10">
|
||||
<div class="issue-avatar-image">@avatar(loginAccount.get.userName, 48)</div>
|
||||
<div class="issue-avatar-image">@avatarLink(loginAccount.get.userName, 48)</div>
|
||||
<div class="panel panel-default issue-box">
|
||||
<div class="panel-body">
|
||||
<span id="error-title" class="error"></span>
|
||||
<input type="text" name="title" class="form-control input-lg" value="" placeholder="Title" style="width: 680px;" autofocus/>
|
||||
<input type="text" id="issue-title" name="title" class="form-control input-lg" value="" placeholder="Title" autofocus/>
|
||||
@helper.html.preview(
|
||||
repository = repository,
|
||||
content = "",
|
||||
@@ -23,7 +23,7 @@
|
||||
enableLineBreaks = true,
|
||||
enableTaskList = true,
|
||||
hasWritePermission = hasWritePermission,
|
||||
style = "width: 680px; height: 200px; max-height: 250px;",
|
||||
style = "height: 200px; max-height: 250px;",
|
||||
elastic = true
|
||||
)
|
||||
<div class="align-right">
|
||||
|
||||
@@ -49,7 +49,8 @@
|
||||
<div class="small" style="padding-left: 20px;">
|
||||
@milestone.dueDate.map { dueDate =>
|
||||
@if(isPast(dueDate)){
|
||||
<i class="octicon octicon-alert" style="color:#BD2C00;"></i><span class="milestone-alert">Due by @date(dueDate)</span>
|
||||
<i class="octicon octicon-alert" style="color:#BD2C00;"></i>
|
||||
<span class="milestone-alert">Due by @date(dueDate)</span>
|
||||
} else {
|
||||
<span class="muted">Due by @date(dueDate)</span>
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<span class="input-group-addon"><i style="background-color: #@label.map(_.color).getOrElse("888888");"></i></span>
|
||||
</div>
|
||||
<script>
|
||||
$('div#label-color-@labelId').colorpicker();
|
||||
$('div#label-color-@labelId').colorpicker({format: "hex"});
|
||||
</script>
|
||||
<span class="pull-right">
|
||||
<span id="label-error-@labelId" class="error"></span>
|
||||
|
||||
@@ -41,7 +41,8 @@
|
||||
} else {
|
||||
@milestone.dueDate.map { dueDate =>
|
||||
@if(isPast(dueDate)){
|
||||
<i class="octicon octicon-alert" style="color:#BD2C00;"></i><span class="muted milestone-alert">Due by @date(dueDate)</span>
|
||||
<i class="octicon octicon-alert" style="color:#BD2C00;"></i>
|
||||
<span class="muted milestone-alert">Due by @date(dueDate)</span>
|
||||
} else {
|
||||
<span class="muted">Due by @date(dueDate)</span>
|
||||
}
|
||||
|
||||
@@ -1,30 +1,28 @@
|
||||
@(active: String,
|
||||
repository: gitbucket.core.service.RepositoryService.RepositoryInfo,
|
||||
id: Option[String] = None,
|
||||
expand: Boolean = false,
|
||||
isRepoTop: Boolean = false,
|
||||
isNoGroup: Boolean = true,
|
||||
info: Option[Any] = None,
|
||||
error: Option[Any] = None)(body: Html)(implicit context: gitbucket.core.controller.Context)
|
||||
@import gitbucket.core.service.SystemSettingsService
|
||||
@import context._
|
||||
@import gitbucket.core.view.helpers._
|
||||
|
||||
@sidemenu(path: String, name: String, icon: String, label: String, count: Int = 0) = {
|
||||
<li @if(active == name){class="active"} @if(!expand){data-toggle="tooltip" data-placement="left" data-original-title="@label"}>
|
||||
@menuitem(path: String, name: String, icon: String, label: String, count: Int = 0) = {
|
||||
<li @if(active == name){class="active"}>
|
||||
<a href="@url(repository)@path">
|
||||
<i class="menu-icon @if(active == name){menu-icon-active} octicon octicon-@{icon} "></i>
|
||||
@if(expand){ @label}
|
||||
@if(expand && count > 0){
|
||||
<div class="pull-right"><span class="badge">@count</span></div>
|
||||
<i class="menu-icon @if(active == name){menu-icon-active} octicon octicon-@{icon} "></i> <span class="pc">@label</span>
|
||||
@if(count > 0){
|
||||
<span class="badge">@count</span>
|
||||
}
|
||||
</a>
|
||||
</li>
|
||||
}
|
||||
|
||||
<div class="container">
|
||||
@helper.html.information(info)
|
||||
@helper.html.error(error)
|
||||
<div class="row">
|
||||
<div class="headbar">
|
||||
<div class="container">
|
||||
@helper.html.information(info)
|
||||
@helper.html.error(error)
|
||||
<div class="head">
|
||||
@if(repository.commitCount > 0){
|
||||
<div class="input-group pull-right">
|
||||
@@ -60,87 +58,52 @@
|
||||
}
|
||||
}
|
||||
</div>
|
||||
<ul class="headmenu">
|
||||
@menuitem("" , "code" , "code" , "Code")
|
||||
@menuitem("/issues", "issues" , "issue-opened" , "Issues", repository.issueCount)
|
||||
@menuitem("/pulls" , "pulls" , "git-pull-request" , "Pull Requests", repository.pullCount)
|
||||
@menuitem("/wiki" , "wiki" , "book" , "Wiki")
|
||||
@if(loginAccount.isDefined && (loginAccount.get.isAdmin || repository.managers.contains(loginAccount.get.userName))){
|
||||
@menuitem("/settings" , "settings" , "tools", "Settings")
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<hr style="margin-bottom: 20px;"/>
|
||||
<div class="container body">
|
||||
<div style="width: @if(expand){170px} else {40px};" class="pull-right">
|
||||
<ul class="sidemenu">
|
||||
<li style="height: 12px"><div class="gradient pull-left" style="height: 12px"></div></li>
|
||||
@sidemenu("" , "code" , "code" , "Code")
|
||||
@sidemenu("/issues", "issues" , "issue-opened" , "Issues", repository.issueCount)
|
||||
@sidemenu("/pulls" , "pulls" , "git-pull-request" , "Pull Requests", repository.pullCount)
|
||||
@sidemenu("/wiki" , "wiki" , "book" , "Wiki")
|
||||
@if(loginAccount.isDefined && (loginAccount.get.isAdmin || repository.managers.contains(loginAccount.get.userName))){
|
||||
@sidemenu("/settings" , "settings" , "tools", "Settings")
|
||||
}
|
||||
<li style="height: 12px"><div class="gradient pull-left" style="height: 12px"></div></li>
|
||||
</ul>
|
||||
@if(expand){
|
||||
<div class="small">
|
||||
<strong id="repository-url-proto">HTTP</strong> <span class="mute">clone URL</span>
|
||||
</div>
|
||||
@helper.html.copy("repository-url-copy", repository.httpUrl){
|
||||
<input type="text" value="@repository.httpUrl" id="repository-url" class="form-control input-sm" readonly>
|
||||
}
|
||||
@if(settings.ssh && loginAccount.isDefined){
|
||||
<div class="small">
|
||||
<span class="mute">You can clone <a href="javascript:void(0);" id="repository-url-http">HTTP</a> or <a href="javascript:void(0);" id="repository-url-ssh">SSH</a>.</span>
|
||||
</div>
|
||||
}
|
||||
@id.map { id =>
|
||||
@if(context.platform != "linux" && context.platform != null){
|
||||
<div style="margin-top: 10px;">
|
||||
<a href="@repository.httpOpenRepoUrl(context.platform)" id="repository-clone-url" class="btn btn-sm btn-default btn-block"><i class="octicon octicon-desktop-download"></i> Clone in Desktop</a>
|
||||
</div>
|
||||
}
|
||||
<div style="margin-top: 10px;">
|
||||
<a href="@{url(repository)}/archive/@{encodeRefName(id)}.zip" class="btn btn-sm btn-default btn-block"><i class="octicon octicon-cloud-download"></i>Download ZIP</a>
|
||||
</div>
|
||||
@*
|
||||
<div style="margin-top: 10px;">
|
||||
<a href="@{url(repository)}/archive/@{encodeRefName(id)}.tar.gz" class="btn btn-sm btn-default btn-block "><i class="octicon octicon-cloud-download"></i>Download TAR.GZ</a>
|
||||
</div>
|
||||
*@
|
||||
}
|
||||
@if(isRepoTop){
|
||||
@repository.repository.description.map { description =>
|
||||
<p class="description">@detectAndRenderLinks(description)</p>
|
||||
}
|
||||
</div>
|
||||
<div class="pull-left" style="width: @if(expand){770px} else {895px};">
|
||||
@if(expand){
|
||||
@repository.repository.description.map { description =>
|
||||
<p class="description">@detectAndRenderLinks(description)</p>
|
||||
}
|
||||
<div style="margin-bottom: 10px; padding: 4px;" class="panel panel-default">
|
||||
<table class="fill-width">
|
||||
<tr>
|
||||
<td style="width: 33%; text-align: center;">
|
||||
<a href="@url(repository)/commits/@encodeRefName(id.getOrElse(""))" class="header-link">
|
||||
<i class="octicon octicon-history"></i>
|
||||
@if(repository.commitCount > 10000){
|
||||
<strong>10000+</strong> commits
|
||||
} else {
|
||||
<strong>@repository.commitCount</strong> commits
|
||||
}
|
||||
</a>
|
||||
</td>
|
||||
<td style="width: 33%; text-align: center;">
|
||||
<a href="@url(repository)/branches" class="header-link" class="header-link">
|
||||
<i class="octicon octicon-git-branch"></i>
|
||||
<strong>@repository.branchList.length</strong> branches
|
||||
</a>
|
||||
</td>
|
||||
<td style="width: 33%; text-align: center;">
|
||||
<a href="@url(repository)/tags" class="header-link" class="header-link">
|
||||
<i class="octicon octicon-tag"></i>
|
||||
<strong>@repository.tags.length</strong> releases
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
}
|
||||
@body
|
||||
</div>
|
||||
<div style="margin-bottom: 10px; padding: 4px;" class="panel panel-default">
|
||||
<table class="fill-width">
|
||||
<tr>
|
||||
<td style="width: 33%; text-align: center;">
|
||||
<a href="@url(repository)/commits/@encodeRefName(id.getOrElse(""))" class="header-link">
|
||||
<i class="octicon octicon-history"></i>
|
||||
@if(repository.commitCount > 10000){
|
||||
<strong>10000+</strong> commits
|
||||
} else {
|
||||
<strong>@repository.commitCount</strong> commits
|
||||
}
|
||||
</a>
|
||||
</td>
|
||||
<td style="width: 33%; text-align: center;">
|
||||
<a href="@url(repository)/branches" class="header-link" class="header-link">
|
||||
<i class="octicon octicon-git-branch"></i>
|
||||
<strong>@repository.branchList.length</strong> branches
|
||||
</a>
|
||||
</td>
|
||||
<td style="width: 33%; text-align: center;">
|
||||
<a href="@url(repository)/tags" class="header-link" class="header-link">
|
||||
<i class="octicon octicon-tag"></i>
|
||||
<strong>@repository.tags.length</strong> releases
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
}
|
||||
@body
|
||||
</div>
|
||||
<script>
|
||||
$(function(){
|
||||
@@ -150,7 +113,7 @@ $(function(){
|
||||
if(e.target.tagName == "I"){
|
||||
target = e.target.parentElement;
|
||||
}
|
||||
$(target).prev ('div.gradient' ).css('border-left', '1px solid silver');
|
||||
$(target).prev('div.gradient').css('border-left', '1px solid silver');
|
||||
});
|
||||
|
||||
$('ul.sidemenu a').mouseout(function(e){
|
||||
@@ -158,7 +121,7 @@ $(function(){
|
||||
if(e.target.tagName == "I"){
|
||||
target = e.target.parentElement;
|
||||
}
|
||||
$(target).prev ('div.gradient' ).css('border-left', '1px solid #eee');
|
||||
$(target).prev('div.gradient').css('border-left', '1px solid #eee');
|
||||
});
|
||||
|
||||
$('a[rel*=facebox]').facebox({
|
||||
@@ -180,21 +143,5 @@ $(function(){
|
||||
$('#fork-form').submit();
|
||||
});
|
||||
}
|
||||
|
||||
@if(settings.ssh && loginAccount.isDefined){
|
||||
$('#repository-url-http').click(function(){
|
||||
$('#repository-url-proto').text('HTTP');
|
||||
$('#repository-url').val('@repository.httpUrl');
|
||||
$('#repository-clone-url').attr('href', '@repository.httpOpenRepoUrl(context.platform)')
|
||||
$('#repository-url-copy').attr('data-clipboard-text', $('#repository-url').val());
|
||||
});
|
||||
|
||||
$('#repository-url-ssh').click(function(){
|
||||
$('#repository-url-proto').text('SSH');
|
||||
$('#repository-url').val('@repository.sshUrl(settings.sshPort.getOrElse(SystemSettingsService.DefaultSshPort), loginAccount.get.userName)');
|
||||
$('#repository-clone-url').attr('href', '@repository.sshOpenRepoUrl(context.platform, settings.sshPort.getOrElse(SystemSettingsService.DefaultSshPort), loginAccount.get.userName)');
|
||||
$('#repository-url-copy').attr('data-clipboard-text', $('#repository-url').val());
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<li><a href="@url(repository)/tree/@commit.id" style="line-height: 16px;"><i class="octicon octicon-code link"></i></a></li>
|
||||
</ul>
|
||||
<div>
|
||||
<div class="commit-avatar-image">@avatar(commit, 40)</div>
|
||||
<div class="commit-avatar-image">@avatarLink(commit, 40)</div>
|
||||
<div>
|
||||
<a href="@url(repository)/commit/@commit.id" class="commit-message" style="font-weight: bold;">@link(commit.summary, repository)</a>
|
||||
@if(commit.description.isDefined){
|
||||
|
||||
@@ -55,11 +55,11 @@
|
||||
<form method="POST" action="@path/@originRepository.owner/@originRepository.name/pulls/new" validate="true">
|
||||
<div class="row">
|
||||
<div class="col-md-10">
|
||||
<div class="issue-avatar-image">@avatar(loginAccount.get.userName, 48)</div>
|
||||
<div class="issue-avatar-image">@avatarLink(loginAccount.get.userName, 48)</div>
|
||||
<div class="panel panel-default issue-box">
|
||||
<div class="panel-body">
|
||||
<span class="error" id="error-title"></span>
|
||||
<input type="text" name="title" class="form-control input-lg" style="width: 680px" placeholder="Title"/>
|
||||
<input type="text" name="title" class="form-control input-lg" placeholder="Title"/>
|
||||
@helper.html.preview(
|
||||
repository = repository,
|
||||
content = "",
|
||||
@@ -68,7 +68,7 @@
|
||||
enableLineBreaks = true,
|
||||
enableTaskList = true,
|
||||
hasWritePermission = true,
|
||||
style = "width: 680px; height: 200px;"
|
||||
style = "height: 200px;"
|
||||
)
|
||||
<input type="hidden" name="targetUserName" value="@originRepository.owner"/>
|
||||
<input type="hidden" name="targetBranch" value="@originId"/>
|
||||
|
||||
@@ -83,8 +83,8 @@
|
||||
</div>
|
||||
@if(status.hasMergePermission){
|
||||
<div style="padding:15px;border-top:solid 1px #e5e5e5;background:#fafafa">
|
||||
<input type="button" class="btn @if(!status.hasProblem){ btn-success }" id="merge-pull-request-button" value="Merge pull request"@if(!status.canMerge){ disabled="true"}/>
|
||||
You can also merge branches on the <a href="#" class="show-command-line">command line</a>.
|
||||
<input type="button" class="btn btn-lg @if(!status.hasProblem){btn-success} else {btn-default}" id="merge-pull-request-button" value="Merge pull request"@if(!status.canMerge){ disabled="true"}/>
|
||||
You can also merge branches on the <a href="#" class="show-command-line">command line</a>.
|
||||
<div id="command-line" style="display: none;margin-top: 15px;">
|
||||
<hr />
|
||||
@if(status.hasConflict){
|
||||
@@ -100,24 +100,23 @@
|
||||
you can perform a manual merge on the command line.
|
||||
</p>
|
||||
}
|
||||
@helper.html.copy("repository-url-copy", forkedRepository.httpUrl, true){
|
||||
<div class="btn-group" data-toggle="buttons-radio">
|
||||
<button class="btn btn-small active" type="button" id="repository-url-http">HTTP</button>
|
||||
@helper.html.copy("repository-url-copy", forkedRepository.httpUrl){
|
||||
<div class="input-group-btn" data-toggle="buttons">
|
||||
<label class="btn btn-sm btn-default active" id="repository-url-http"><input type="radio" checked>HTTP</label>
|
||||
@if(settings.ssh && loginAccount.isDefined){
|
||||
<button class="btn btn-small" type="button" id="repository-url-ssh" style="border-radius: 0px;">SSH</button>
|
||||
<label class="btn btn-sm btn-default" id="repository-url-ssh"><input type="radio">SSH</label>
|
||||
}
|
||||
</div>
|
||||
<input type="text" style="width: 500px;" value="@forkedRepository.httpUrl" id="repository-url" readonly />
|
||||
<input type="text" class="form-control input-sm" value="@forkedRepository.httpUrl" id="repository-url" readonly />
|
||||
}
|
||||
<div>
|
||||
<div style="margin-top: 10px;">
|
||||
<p>
|
||||
<span class="strong">Step 1:</span> From your project repository, check out a new branch and test the changes.
|
||||
</p>
|
||||
@defining(s"git checkout -b ${pullreq.requestUserName}-${pullreq.requestBranch} ${pullreq.branch}\n" +
|
||||
s"git pull ${forkedRepository.httpUrl} ${pullreq.requestBranch}"){ command =>
|
||||
@helper.html.copy("merge-command-copy-1", command){
|
||||
<pre style="width: 600px; float: left; font-size: 12px; border-radius: 3px 0px 3px 3px;" id="merge-command">@Html(command)</pre>
|
||||
}
|
||||
@helper.html.copy("merge-command-copy-1", command, "position: absolute; right: 31px;")()
|
||||
<pre style="font-size: 12px; border-radius: 3px;" id="merge-command">@Html(command)</pre>
|
||||
}
|
||||
</div>
|
||||
<div>
|
||||
@@ -126,9 +125,8 @@
|
||||
</p>
|
||||
@defining(s"git checkout ${pullreq.branch}\ngit merge --no-ff ${pullreq.requestUserName}-${pullreq.requestBranch}\n" +
|
||||
s"git push origin ${pullreq.branch}"){ command =>
|
||||
@helper.html.copy("merge-command-copy-2", command){
|
||||
<pre style="width: 600px; float: left; font-size: 12px; border-radius: 3px 0px 3px 3px;">@command</pre>
|
||||
}
|
||||
@helper.html.copy("merge-command-copy-2", command, "position: absolute; right: 31px;")()
|
||||
<pre style="font-size: 12px; border-radius: 3px;">@command</pre>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
@@ -141,7 +139,7 @@
|
||||
Merge pull request #@issue.issueId from @{pullreq.requestUserName}/@{pullreq.requestBranch}
|
||||
</div>
|
||||
<span id="error-message" class="error"></span>
|
||||
<textarea name="message" style="width: 635px; height: 80px;">@issue.title</textarea>
|
||||
<textarea name="message" style="height: 80px;" class="form-control">@issue.title</textarea>
|
||||
<div>
|
||||
<input type="button" class="btn" value="Cancel" id="cancel-merge-pull-request"/>
|
||||
<input type="submit" class="btn btn-success" value="Confirm merge"/>
|
||||
@@ -171,27 +169,25 @@ $(function(){
|
||||
$('#confirm-merge-form').show();
|
||||
});
|
||||
|
||||
@if(settings.ssh && loginAccount.isDefined){
|
||||
$('#repository-url-http').click(function(){
|
||||
@forkedRepository.sshUrl.map { sshUrl =>
|
||||
$('#repository-url-http').click(function(e){
|
||||
// Update URL box
|
||||
$('#repository-url').val('@forkedRepository.httpUrl');
|
||||
$('#repository-url-copy').attr('data-clipboard-text', $('#repository-url').val());
|
||||
// Update command guidance
|
||||
$('#merge-command').text($('#merge-command').text().replace(
|
||||
'@forkedRepository.sshUrl(settings.sshPort.getOrElse(SystemSettingsService.DefaultSshPort), loginAccount.get.userName)',
|
||||
'@forkedRepository.httpUrl'
|
||||
'@sshUrl', '@forkedRepository.httpUrl'
|
||||
));
|
||||
$('#merge-command-copy-1').attr('data-clipboard-text', $('#merge-command').text());
|
||||
});
|
||||
|
||||
$('#repository-url-ssh').click(function(){
|
||||
$('#repository-url-ssh').click(function(e){
|
||||
// Update URL box
|
||||
$('#repository-url').val('@forkedRepository.sshUrl(settings.sshPort.getOrElse(SystemSettingsService.DefaultSshPort), loginAccount.get.userName)');
|
||||
$('#repository-url').val('@sshUrl');
|
||||
$('#repository-url-copy').attr('data-clipboard-text', $('#repository-url').val());
|
||||
// Update command guidance
|
||||
$('#merge-command').text($('#merge-command').text().replace(
|
||||
'@forkedRepository.httpUrl',
|
||||
'@forkedRepository.sshUrl(settings.sshPort.getOrElse(SystemSettingsService.DefaultSshPort), loginAccount.get.userName)'
|
||||
'@forkedRepository.httpUrl', '@sshUrl'
|
||||
));
|
||||
$('#merge-command-copy-1').attr('data-clipboard-text', $('#merge-command').text());
|
||||
});
|
||||
|
||||
@@ -21,7 +21,9 @@
|
||||
@if(hasWritePermission || loginAccount.map(_.userName == issue.openedUserName).getOrElse(false)){
|
||||
<a class="btn" href="#" id="edit">Edit</a>
|
||||
}
|
||||
<a class="btn btn-success" href="@url(repository)/issues/new">New issue</a>
|
||||
@if(loginAccount.isDefined){
|
||||
<a class="btn btn-success" href="@url(repository)/compare">New pull request</a>
|
||||
}
|
||||
</div>
|
||||
<div class="edit-title pull-right" style="display: none;">
|
||||
<a class="btn" href="#" id="update">Save</a> <a href="#" id="cancel">Cancel</a>
|
||||
@@ -65,7 +67,7 @@
|
||||
}
|
||||
</div>
|
||||
<ul class="nav nav-tabs fill-width pull-left" id="pullreq-tab">
|
||||
<li class="active"><a href="#conversation">Conversation <span class="badge">@comments.flatMap @{
|
||||
<li><a href="#conversation">Conversation <span class="badge">@comments.flatMap @{
|
||||
case comment: IssueComment => Some(comment)
|
||||
case _: CommitComment => None
|
||||
}.size</span></a></li>
|
||||
@@ -73,7 +75,7 @@
|
||||
<li><a href="#files">Files Changed <span class="badge">@diffs.size</span></a></li>
|
||||
</ul>
|
||||
<div class="tab-content fill-width pull-left">
|
||||
<div class="tab-pane active" id="conversation">
|
||||
<div class="tab-pane" id="conversation">
|
||||
@flash.get("error").map{ error =>
|
||||
<div class="alert alert-error">@error</div>
|
||||
}
|
||||
@@ -94,6 +96,22 @@
|
||||
}
|
||||
<script>
|
||||
$(function(){
|
||||
// Determine active tab from hash
|
||||
if(location.hash == '#commits'){
|
||||
$('li:has(a[href=#commits])').addClass('active');
|
||||
$('div#commits').addClass('active');
|
||||
} else if(location.hash == '#files'){
|
||||
$('li:has(a[href=#files])').addClass('active');
|
||||
$('div#files').addClass('active');
|
||||
} else {
|
||||
$('li:has(a[href=#conversation])').addClass('active');
|
||||
$('div#conversation').addClass('active');
|
||||
}
|
||||
// Set hash when tab is clicked
|
||||
$('ul.nav-tabs li a').click(function(e){
|
||||
location.href = $(e.delegateTarget).attr("href");
|
||||
});
|
||||
|
||||
$('#pullreq-tab a').click(function (e) {
|
||||
e.preventDefault();
|
||||
$(this).tab('show');
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
@html.menu("code", repository){
|
||||
<div class="head">
|
||||
<div class="pull-right hide-if-blame"><div class="btn-group">
|
||||
<a href="@url(repository)/find/@encodeRefName(branch)" class="btn btn-sm btn-default" data-toggle="tooltip" data-placement="bottom" data-hotkey="t" title="Quickly jump between files"><i class="octicon octicon-list-unordered"></i></a>
|
||||
<a href="@url(repository)/find/@encodeRefName(branch)" class="btn btn-sm btn-default" data-hotkey="t">Find file</a>
|
||||
</div></div>
|
||||
<div class="line-age-legend">
|
||||
<span>Newer</span>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
@if(!fileName.isDefined){<hr/><br/>}
|
||||
<form method="POST" validate="true" style="max-width: 874px;">
|
||||
@if(!fileName.isDefined){
|
||||
<div class="issue-avatar-image">@avatar(loginAccount.get.userName, 48)</div>
|
||||
<div class="issue-avatar-image">@avatarLink(loginAccount.get.userName, 48)</div>
|
||||
}
|
||||
<div class="panel panel-default issue-comment-box">
|
||||
<div class="panel-body">
|
||||
@@ -23,7 +23,7 @@
|
||||
enableLineBreaks = true,
|
||||
enableTaskList = true,
|
||||
hasWritePermission = hasWritePermission,
|
||||
style = "width: 635px; height: 100px; max-height: 150px;",
|
||||
style = "height: 100px; max-height: 150px;",
|
||||
elastic = true
|
||||
)
|
||||
</div>
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
<li><a href="@url(repository)/tree/@commit.id" style="line-height: 16px;"><i class="octicon octicon-code link"></i></a></li>
|
||||
</ul>
|
||||
<div>
|
||||
<div class="commit-avatar-image">@avatar(commit, 40)</div>
|
||||
<div class="commit-avatar-image">@avatarLink(commit, 40)</div>
|
||||
<div>
|
||||
<a href="@url(repository)/commit/@commit.id" class="commit-message" style="font-weight: bold;">@link(commit.summary, repository)</a>
|
||||
@if(commit.description.isDefined){
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="issue-avatar-image">@avatar(loginAccount.get.userName, 48)</div>
|
||||
<div class="issue-avatar-image">@avatarLink(loginAccount.get.userName, 48)</div>
|
||||
<div class="box issue-comment-box">
|
||||
<div class="box-content">
|
||||
<div>
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
@import context._
|
||||
<span class="error-edit-content-@commentId error"></span>
|
||||
@helper.html.attached(owner, repository){
|
||||
<textarea style="width: 635px; height: 100px;" id="edit-content-@commentId">@content</textarea>
|
||||
<textarea style="height: 100px;" id="edit-content-@commentId" class="form-control">@content</textarea>
|
||||
}
|
||||
<div>
|
||||
<input type="button" class="cancel-comment-@commentId btn btn-small btn-danger" value="Cancel"/>
|
||||
<input type="button" class="update-comment-@commentId btn btn-small pull-right" value="Update comment"/>
|
||||
<input type="button" class="update-comment-@commentId btn btn-small btn-default pull-right" value="Update comment"/>
|
||||
</div>
|
||||
<script>
|
||||
$(function(){
|
||||
@@ -19,7 +19,7 @@ $(function(){
|
||||
}
|
||||
|
||||
$(document).on('click', '.update-comment-@commentId', function(){
|
||||
$box = $(this).closest('.box');
|
||||
$box = $(this).closest('.commit-comment-box');
|
||||
$('.update-comment-@commentId, .cancel-comment-@commentId', $box).attr('disabled', 'disabled');
|
||||
$.ajax({
|
||||
url: '@path/@owner/@repository/commit_comments/edit/@commentId',
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="issue-avatar-image">@avatar(loginAccount.get.userName, 48)</div>
|
||||
<div class="issue-avatar-image">@avatarLink(loginAccount.get.userName, 48)</div>
|
||||
<div class="panel panel-default issue-comment-box">
|
||||
<div class="panel-body">
|
||||
<div>
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
error: Option[Any] = None)(implicit context: gitbucket.core.controller.Context)
|
||||
@import context._
|
||||
@import gitbucket.core.view.helpers._
|
||||
@import gitbucket.core.service.RepositoryService._
|
||||
@html.main(
|
||||
if(pathList.isEmpty){
|
||||
if(branch == repository.repository.defaultBranch){
|
||||
@@ -23,32 +24,68 @@
|
||||
}, Some(repository)) {
|
||||
@html.menu("code", repository, Some(branch), pathList.isEmpty, groupNames.isEmpty, info, error){
|
||||
<div class="head">
|
||||
<div class="pull-right"><div class="btn-group">
|
||||
<a href="@url(repository)/find/@encodeRefName(branch)" class="btn btn-sm btn-default" data-toggle="tooltip" data-placement="bottom" data-hotkey="t" title="Quickly jump between files"><i class="octicon octicon-list-unordered"></i></a>
|
||||
@if(pathList.nonEmpty){
|
||||
<a href="@url(repository)/commits/@encodeRefName(branch)/@pathList.mkString("/")" class="btn btn-sm btn-default" data-toggle="tooltip" data-placement="bottom" title="Browse commits for this branch"><i class="octicon octicon-clock"></i></a>
|
||||
}
|
||||
</div></div>
|
||||
@branchPullRequest.map{ case (pullRequest, issue) =>
|
||||
<a href="@url(repository)/pull/@pullRequest.issueId" class="btn btn-sm btn-pullrequest-branch" title="@issue.title" data-toggle="tooltip">#@pullRequest.issueId</a>
|
||||
}.getOrElse{
|
||||
<a href="@url(repository)/compare?head=@urlEncode(encodeRefName(branch))" class="btn btn-sm btn-success"><i class="octicon octicon-git-compare" data-toggle="tooltip" title="Compare, review, create a pull request"></i></a>
|
||||
@if(pathList.isEmpty){
|
||||
<div class="pull-right pc">
|
||||
@if(platform != "linux" && platform != null){
|
||||
<a href="@openRepoUrl(repository.httpUrl)" id="repository-clone-url" class="btn btn-sm btn-default"><i class="octicon octicon-desktop-download"></i></a>
|
||||
}
|
||||
<a href="@{url(repository)}/archive/@{encodeRefName(branch)}.zip" class="btn btn-sm btn-default">Download ZIP</a>
|
||||
</div>
|
||||
<div class="pull-right pc">
|
||||
<div style="width: 240px; margin-top: 2px; margin-right: 5px; margin-left: 5px;">
|
||||
@helper.html.copy("repository-url-copy", repository.httpUrl){
|
||||
@if(repository.sshUrl.isDefined){
|
||||
<div class="btn-group input-group-btn">
|
||||
<button type="button" class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<span id="repository-url-proto">HTTP</span> <span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li>
|
||||
<a href="javascript:void(0);" id="repository-url-http">
|
||||
<strong>HTTP (recommended)</strong><br>
|
||||
Clone with Git using the repository's web address.
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="javascript:void(0);" id="repository-url-ssh">
|
||||
<strong>SSH</strong><br>
|
||||
Clone with an SSH key and passphrase from your GitBucket settings.
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
}
|
||||
<input type="text" value="@repository.httpUrl" id="repository-url" class="form-control input-sm" readonly>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@helper.html.branchcontrol(
|
||||
branch,
|
||||
repository,
|
||||
hasWritePermission
|
||||
){
|
||||
<div class="pull-right">
|
||||
<div class="btn-group">
|
||||
<a href="@url(repository)/new/@encodeRefName(branch)/@pathList.mkString("/")" class="btn btn-sm btn-default pc" title="Create a new file here" @if(!hasWritePermission){disabled}>New file</i></a>
|
||||
<a href="@url(repository)/find/@encodeRefName(branch)" class="btn btn-sm btn-default pc" data-hotkey="t">Find file</a>
|
||||
@if(pathList.nonEmpty){
|
||||
<a href="@url(repository)/commits/@encodeRefName(branch)/@pathList.mkString("/")" class="btn btn-sm btn-default" data-toggle="tooltip" data-placement="bottom" title="Browse commits for this branch">History</a>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@helper.html.branchcontrol(branch, repository, hasWritePermission){
|
||||
@repository.branchList.map { x =>
|
||||
<li><a href="@url(repository)/tree/@encodeRefName(x)">@helper.html.checkicon(x == branch) @x</a></li>
|
||||
}
|
||||
}
|
||||
<a href="@url(repository)/tree/@encodeRefName(branch)">@repository.name</a> /
|
||||
@pathList.zipWithIndex.map { case (section, i) =>
|
||||
<a href="@url(repository)/tree/@encodeRefName(branch)/@pathList.take(i + 1).mkString("/")">@section</a> /
|
||||
}
|
||||
@if(hasWritePermission){
|
||||
<a href="@url(repository)/new/@encodeRefName(branch)/@pathList.mkString("/")" title="Create a new file here" style="text-decoration: none;">+</i></a>
|
||||
@if(pathList.isEmpty){
|
||||
@branchPullRequest.map{ case (pullRequest, issue) =>
|
||||
<a href="@url(repository)/pull/@pullRequest.issueId" class="btn btn-sm btn-pullrequest-branch" title="@issue.title" data-toggle="tooltip">View #@pullRequest.issueId</a>
|
||||
}.getOrElse {
|
||||
<a href="@url(repository)/compare?head=@urlEncode(encodeRefName(branch))" class="btn btn-sm btn-success" @if(loginAccount.isEmpty){disabled}>New pull request</a>
|
||||
}
|
||||
} else {
|
||||
<a href="@url(repository)/tree/@encodeRefName(branch)">@repository.name</a> /
|
||||
@pathList.zipWithIndex.map { case (section, i) =>
|
||||
<a href="@url(repository)/tree/@encodeRefName(branch)/@pathList.take(i + 1).mkString("/")">@section</a> /
|
||||
}
|
||||
}
|
||||
</div>
|
||||
<table class="table table-file-list">
|
||||
@@ -141,3 +178,20 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
<script>
|
||||
@repository.sshUrl.map { sshUrl =>
|
||||
$('#repository-url-http').click(function(){
|
||||
$('#repository-url-proto').text('HTTP');
|
||||
$('#repository-url').val('@repository.httpUrl');
|
||||
$('#repository-clone-url').attr('href', '@openRepoUrl(repository.httpUrl)')
|
||||
$('#repository-url-copy').attr('data-clipboard-text', $('#repository-url').val());
|
||||
});
|
||||
|
||||
$('#repository-url-ssh').click(function(){
|
||||
$('#repository-url-proto').text('SSH');
|
||||
$('#repository-url').val('@sshUrl');
|
||||
$('#repository-clone-url').attr('href', '@openRepoUrl(sshUrl)');
|
||||
$('#repository-url-copy').attr('data-clipboard-text', $('#repository-url').val());
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
@if(originRepository.isDefined){
|
||||
@avatar(originRepository.get.owner, 20)
|
||||
<span@if(repository.owner == originRepository.get.owner){ class="highlight"}>
|
||||
<a href="@url(originRepository.get)">@originRepository.get.owner</a> / <a href="@path/@originRepository.get.owner/@originRepository.get.name">@originRepository.get.name</a>
|
||||
<a href="@url(originRepository.get.owner)">@originRepository.get.owner</a> / <a href="@path/@originRepository.get.owner/@originRepository.get.name">@originRepository.get.name</a>
|
||||
</span>
|
||||
} else {
|
||||
@avatar(repository.repository.originUserName.get, 20)
|
||||
|
||||
@@ -11,9 +11,9 @@
|
||||
<h3><strong>Quick setup</strong> — if you've done this kind of thing before</h3>
|
||||
<div class="empty-repo-options">
|
||||
via <a href="@repository.httpUrl" class="git-protocol-selector">HTTP</a>
|
||||
@if(settings.ssh && loginAccount.isDefined){
|
||||
@repository.sshUrl.map { sshUrl =>
|
||||
or
|
||||
<a href="@repository.sshUrl(settings.sshPort.getOrElse(SystemSettingsService.DefaultSshPort), loginAccount.get.userName)" class="git-protocol-selector">SSH</a>
|
||||
<a href="@sshUrl" class="git-protocol-selector">SSH</a>
|
||||
}
|
||||
</div>
|
||||
<h3 style="margin-top: 30px;">Create a new repository on the command line</h3>
|
||||
|
||||
@@ -24,7 +24,8 @@
|
||||
Opened by <a href="@url(issue.openedUserName)" class="username">@issue.openedUserName</a>
|
||||
@helper.html.datetimeago(issue.registeredDate)
|
||||
@if(issue.commentCount > 0){
|
||||
<i class="octicon octicon-comment"></i><span class="strong">@issue.commentCount</span> @plural(issue.commentCount, "comment")
|
||||
<i class="octicon octicon-comment"></i>
|
||||
<span class="strong">@issue.commentCount</span> @plural(issue.commentCount, "comment")
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
</ul>
|
||||
<form action="@url(repository)/wiki/@if(page.isEmpty){_new} else {_edit}" method="POST" validate="true">
|
||||
<span id="error-pageName" class="error"></span>
|
||||
<input type="text" name="pageName" value="@pageName" class="form-control input-lg" style="width: 900px; font-weight: bold;" placeholder="Input a page name."/>
|
||||
<input type="text" name="pageName" value="@pageName" class="form-control input-lg" style="font-weight: bold;" placeholder="Input a page name."/>
|
||||
@helper.html.preview(
|
||||
repository = repository,
|
||||
content = page.map(_.content).getOrElse(""),
|
||||
@@ -30,13 +30,13 @@
|
||||
enableLineBreaks = false,
|
||||
enableTaskList = false,
|
||||
hasWritePermission = false,
|
||||
style = "width: 900px; height: 400px;",
|
||||
style = "height: 400px;",
|
||||
styleClass = "monospace",
|
||||
placeholder = ""
|
||||
)
|
||||
<div class="form-group">
|
||||
<label for="message">Edit Message</label>
|
||||
<input type="text" id="message" name="message" value="" class="form-control" style="width: 900px;" placeholder="Write a small message here explaining this change. (Optional)"/>
|
||||
<input type="text" id="message" name="message" value="" class="form-control" placeholder="Write a small message here explaining this change. (Optional)"/>
|
||||
</div>
|
||||
<div class="form-group pull-right">
|
||||
<input type="hidden" name="currentPageName" value="@pageName"/>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
footer: Option[gitbucket.core.service.WikiService.WikiPageInfo])(implicit context: gitbucket.core.controller.Context)
|
||||
@import context._
|
||||
@import gitbucket.core.view.helpers._
|
||||
@import gitbucket.core.service.WikiService._
|
||||
@import gitbucket.core.service.WikiService.{wikiHttpUrl, wikiSshUrl}
|
||||
@html.main(s"${pageName} - ${repository.owner}/${repository.name}", Some(repository)){
|
||||
@html.menu("wiki", repository){
|
||||
<ul class="nav nav-tabs fill-width">
|
||||
@@ -26,7 +26,7 @@
|
||||
}
|
||||
</li>
|
||||
</ul>
|
||||
<div style="width: 200px; margin-top: 20px;" class="pull-right">
|
||||
<div style="width: 200px; margin-top: 20px;" class="pull-right pc">
|
||||
@defining(15){ max =>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading strong">
|
||||
@@ -67,10 +67,10 @@
|
||||
<div class="small">
|
||||
<strong>Clone this wiki locally</strong>
|
||||
</div>
|
||||
@helper.html.copy("repository-url-copy", httpUrl(repository)){
|
||||
<input type="text" value="@httpUrl(repository)" id="repository-url" class="form-control input-sm" readonly>
|
||||
@helper.html.copy("repository-url-copy", wikiHttpUrl(repository)){
|
||||
<input type="text" value="@wikiHttpUrl(repository)" id="repository-url" class="form-control input-sm" readonly>
|
||||
}
|
||||
@if(settings.ssh && loginAccount.isDefined){
|
||||
@if(wikiSshUrl(repository).isDefined) {
|
||||
<div class="small">
|
||||
<span class="mute">You can clone <a href="javascript:void(0);" id="repository-url-http">HTTP</a> or <a href="javascript:void(0);" id="repository-url-ssh">SSH</a>.</span>
|
||||
</div>
|
||||
@@ -131,13 +131,13 @@ $(function(){
|
||||
$('#triangle-right').show();
|
||||
}
|
||||
|
||||
@if(settings.ssh && loginAccount.isDefined){
|
||||
@wikiSshUrl(repository).map { sshUrl =>
|
||||
$('#repository-url-http').click(function(){
|
||||
$('#repository-url').val('@httpUrl(repository)');
|
||||
$('#repository-url').val('@wikiHttpUrl(repository)');
|
||||
$('#repository-url-copy').attr('data-clipboard-text', $('#repository-url').val());
|
||||
});
|
||||
$('#repository-url-ssh').click(function(){
|
||||
$('#repository-url').val('@sshUrl(repository, settings, loginAccount.get.userName)');
|
||||
$('#repository-url').val('@sshUrl');
|
||||
$('#repository-url-copy').attr('data-clipboard-text', $('#repository-url').val());
|
||||
});
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ h6 {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.head .octicon,.head .mega-octicon{
|
||||
.head .octicon, .head .mega-octicon{
|
||||
color : #BBB;
|
||||
}
|
||||
|
||||
@@ -70,57 +70,6 @@ blockquote p {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
/*
|
||||
.nav {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.table-bordered {
|
||||
border-collapse: inherit;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.table-bordered > thead > tr > th,
|
||||
.table-bordered > tbody > tr > th,
|
||||
.table-bordered > tbody > tr > td {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.table-bordered > thead > tr:first-child > th:nth-of-type(1),
|
||||
.table-bordered > tbody > tr:first-child > th:nth-of-type(1),
|
||||
.table-bordered > tbody > tr:first-child > td:nth-of-type(1) {
|
||||
border-top-left-radius: 4px;
|
||||
}
|
||||
|
||||
.table-bordered > thead > tr:first-child > th:nth-last-of-type(1),
|
||||
.table-bordered > tbody > tr:first-child > th:nth-last-of-type(1),
|
||||
.table-bordered > tbody > tr:first-child > td:nth-last-of-type(1) {
|
||||
border-top-right-radius: 4px;
|
||||
}
|
||||
|
||||
.table-bordered > tbody > tr:last-child > td:nth-of-type(1) {
|
||||
border-bottom-left-radius: 4px;
|
||||
}
|
||||
|
||||
.table-bordered > tbody > tr:last-child > td:nth-last-of-type(1) {
|
||||
border-bottom-right-radius: 4px;
|
||||
}
|
||||
|
||||
.table-bordered > tbody > tr:last-child > td {
|
||||
border-bottom: 1px solid #dddddd;
|
||||
}
|
||||
*/
|
||||
/*
|
||||
.table-bordered > thead > tr > th,
|
||||
.table-bordered > thead > tr > td {
|
||||
border-bottom-width: 1px;
|
||||
}
|
||||
*/
|
||||
/*
|
||||
.tab-content {
|
||||
margin-top: 20px;
|
||||
}
|
||||
*/
|
||||
.danger {
|
||||
color: #900;
|
||||
}
|
||||
@@ -167,43 +116,6 @@ pre.reset {
|
||||
/* ======================================================================== */
|
||||
/* Global Header */
|
||||
/* ======================================================================== */
|
||||
/*
|
||||
div.navbar-inner {
|
||||
border-radius: 0px;
|
||||
-webkit-border-radius: 0px;
|
||||
-moz-border-radius: 0px;
|
||||
border-top: none;
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
border-bottom: 1px solid #d4d4d4;
|
||||
padding-right: 0px;
|
||||
}
|
||||
|
||||
div.header-menu {
|
||||
line-height: 40px;
|
||||
}
|
||||
|
||||
div.header-menu .octicon{
|
||||
color: #333;
|
||||
}
|
||||
|
||||
div.header-menu input,
|
||||
div.header-menu a.btn {
|
||||
margin-top: 0px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
/*
|
||||
div.nav-collapse a.menu {
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
div.nav-collapse a.btn-last,
|
||||
div.nav-collapse a.menu-last {
|
||||
margin-right: 30px;
|
||||
}
|
||||
*/
|
||||
|
||||
.navbar-brand {
|
||||
height: unset;
|
||||
padding: 8px;
|
||||
@@ -211,6 +123,7 @@ div.nav-collapse a.menu-last {
|
||||
|
||||
.navbar {
|
||||
min-height: unset;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
span.header-version {
|
||||
@@ -277,6 +190,7 @@ div.pagination {
|
||||
*/
|
||||
|
||||
div.body {
|
||||
margin-top: 20px;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
@@ -412,27 +326,13 @@ div.box-content {
|
||||
padding: 4px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
/*
|
||||
div > div.box-content-row:nth-of-type(1) {
|
||||
border: none;
|
||||
}
|
||||
|
||||
div.box-content-row {
|
||||
border-top: 1px solid #d8d8d8;
|
||||
padding: 4px;
|
||||
}
|
||||
*/
|
||||
/*
|
||||
div.repo-link {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
*/
|
||||
|
||||
li.repo-link, li.page-link {
|
||||
padding-top: 4px;
|
||||
padding-bottom: 4px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
div.box-content-bottom {
|
||||
@@ -444,6 +344,10 @@ div.box-content-bottom {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
div.box-content-bottom img {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
table.table th.box-header {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
@@ -533,61 +437,56 @@ a.btn-danger:hover .octicon {
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
/* Side Menu */
|
||||
/* Head Menu */
|
||||
/****************************************************************************/
|
||||
ul.sidemenu {
|
||||
div.headbar {
|
||||
background-color: #fafafa;
|
||||
padding-top: 19px;
|
||||
border-bottom: 1px solid #eee;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
|
||||
ul.headmenu {
|
||||
margin-top: 20px;
|
||||
margin-left: 0px;
|
||||
padding-left: 0px;
|
||||
margin-bottom: -1px;
|
||||
}
|
||||
|
||||
ul.sidemenu a {
|
||||
display: block;
|
||||
padding: 8px 10px;
|
||||
}
|
||||
|
||||
ul.sidemenu a:hover {
|
||||
ul.headmenu a:hover {
|
||||
text-decoration: none;
|
||||
color: black;
|
||||
}
|
||||
|
||||
ul.sidemenu li.active {
|
||||
border-top: 1px solid #eee;
|
||||
border-bottom: 1px solid #eee;
|
||||
border-right: 3px solid #bb4444;
|
||||
border-left: 1px solid white;
|
||||
ul.headmenu li {
|
||||
display: inline-block;
|
||||
list-style-type: none;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
ul.sidemenu li.active a {
|
||||
ul.headmenu li a {
|
||||
color: #666;
|
||||
padding: 8px 10px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
ul.headmenu li.active a {
|
||||
color: black;
|
||||
}
|
||||
|
||||
ul.headmenu li.active {
|
||||
border-top: 3px solid #bb4444;
|
||||
border-left: 1px solid #eee;
|
||||
border-right: 1px solid #eee;
|
||||
border-bottom: none;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
ul.headmenu li.active a {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
ul.sidemenu {
|
||||
background-image: -webkit-linear-gradient(left, #f6f6f6 0%, #fff 8px);
|
||||
background-image: linear-gradient(to right, #f6f6f6 0%, #fff 8px);
|
||||
box-shadow: inset 1px 0 0 #eee;
|
||||
}
|
||||
|
||||
ul.sidemenu div.margin {
|
||||
width: 5px;
|
||||
height: 30px;
|
||||
margin-right: 4px;
|
||||
border-left: 1px solid white;
|
||||
}
|
||||
|
||||
ul.sidemenu li {
|
||||
border-left: 1px solid #eee;
|
||||
margin-left:0px;
|
||||
border-right: 2px solid white;
|
||||
list-style-type: none;
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
ul.sidemenu span.badge {
|
||||
|
||||
}
|
||||
|
||||
ul.sidemenu a:hover i.menu-icon, ul.sidemenu i.menu-icon-active {
|
||||
color: #333;
|
||||
}
|
||||
/****************************************************************************/
|
||||
/* Create Repository */
|
||||
/****************************************************************************/
|
||||
@@ -636,18 +535,6 @@ a#show-pages-index {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/*
|
||||
ul.nav-stacked.side-menu li span.header {
|
||||
border-top-right-radius: 3px;
|
||||
border-top-left-radius: 3px;
|
||||
border: 1px solid #d8d8d8;
|
||||
display: block;
|
||||
padding: 8px 15px 9px;
|
||||
margin-right: 2px;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
*/
|
||||
|
||||
ul.nav-stacked.side-menu li a:hover {
|
||||
background-color: transparent;
|
||||
}
|
||||
@@ -750,7 +637,6 @@ div.repository-content {
|
||||
padding: 0 3px;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************/
|
||||
/* Activity */
|
||||
/****************************************************************************/
|
||||
@@ -978,73 +864,6 @@ span.simplified-path {
|
||||
color: #0088cc;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
/* nav pulls group */
|
||||
/****************************************************************************/
|
||||
|
||||
|
||||
/*
|
||||
.nav-pills-group:after {
|
||||
display: table;
|
||||
line-height: 0;
|
||||
content: "";
|
||||
}
|
||||
|
||||
.nav-pills-group:after {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.nav-pills-group > li {
|
||||
float: left;
|
||||
}
|
||||
*/
|
||||
/*
|
||||
.nav-pills > li + li {
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
.nav-pills > li > a {
|
||||
padding-right: 12px;
|
||||
padding-left: 12px;
|
||||
line-height: 14px;
|
||||
color: #666;
|
||||
font-weight: bold;
|
||||
-webkit-border-radius: 0;
|
||||
-moz-border-radius: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.nav-pills > li > a {
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
border-left : 1px solid #e5e5e5;
|
||||
border-top : 1px solid #e5e5e5;
|
||||
border-bottom : 1px solid #e5e5e5;
|
||||
}
|
||||
|
||||
.nav-pills > li:nth-of-type(1) > a {
|
||||
-webkit-border-radius: 4px 0 0 4px;
|
||||
-moz-border-radius: 4px 0 0 4px;
|
||||
border-radius: 4px 0 0 4px;
|
||||
}
|
||||
|
||||
.nav-pills > li:nth-last-of-type(1) > a {
|
||||
-webkit-border-radius: 0 4px 4px 0;
|
||||
-moz-border-radius: 0 4px 4px 0;
|
||||
border-radius: 0 4px 4px 0;
|
||||
border-right : 1px solid #e5e5e5;
|
||||
}
|
||||
*/
|
||||
/*
|
||||
.nav-pills-group > .active > a,
|
||||
.nav-pills-group > .active > a:hover,
|
||||
.nav-pills-group > .active > a:focus {
|
||||
color: #ffffff;
|
||||
background-color: #0088cc;
|
||||
border-color: #0088cc;
|
||||
}
|
||||
*/
|
||||
|
||||
/****************************************************************************/
|
||||
/* Issues */
|
||||
/****************************************************************************/
|
||||
@@ -1081,11 +900,11 @@ table.table-issues {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
table.table-issues td .octicon-issue-opened,table.table-issues td .octicon-git-pull-request .open {
|
||||
table.table-issues td .octicon-issue-opened, table.table-issues td .octicon-git-pull-request .open {
|
||||
color: #6CC644;
|
||||
}
|
||||
|
||||
table.table-issues td .octicon-issue-closed,table.table-issues td .octicon-git-pull-request .closed{
|
||||
table.table-issues td .octicon-issue-closed, table.table-issues td .octicon-git-pull-request .closed{
|
||||
color : #BD2C00;;
|
||||
}
|
||||
|
||||
@@ -1099,6 +918,10 @@ a.issue-title {
|
||||
background-color: #6cc644;
|
||||
}
|
||||
|
||||
.label-important {
|
||||
background-color: #bd2c00;
|
||||
}
|
||||
|
||||
ul.label-list {
|
||||
list-style-type: none;
|
||||
padding-left: 0px;
|
||||
@@ -1153,47 +976,6 @@ div.milestone-menu a.delete {
|
||||
color: #b00;
|
||||
}
|
||||
|
||||
/*
|
||||
div#milestone-progress-area {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
div#milestone-progress-area div.milestone-progress {
|
||||
width: 130px;
|
||||
margin-bottom: -6px;
|
||||
}
|
||||
|
||||
div.milestone-progress {
|
||||
position: relative;
|
||||
height: 10px;
|
||||
color: white;
|
||||
margin-bottom: 4px;
|
||||
font-weight: bold;
|
||||
font-size: 12px;
|
||||
text-shadow: 0px 0px 5px #444;
|
||||
background-color: silver;
|
||||
border-radius: 4px;
|
||||
-webkit-border-radius: 4px;
|
||||
-moz-border-radius: 4px;
|
||||
}
|
||||
|
||||
span.milestone-progress {
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
background-color: green;
|
||||
border-radius: 4px;
|
||||
-webkit-border-radius: 4px;
|
||||
-moz-border-radius: 4px;
|
||||
}
|
||||
|
||||
div.issue-header {
|
||||
padding-left: 8px;
|
||||
padding-right: 8px;
|
||||
padding-top: 12px;
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
*/
|
||||
|
||||
div.issue-info {
|
||||
border-top: 1px solid #e5e5e5;
|
||||
border-bottom: 1px solid #e5e5e5;
|
||||
@@ -1203,21 +985,6 @@ div.issue-info {
|
||||
margin-right: 0px;
|
||||
}
|
||||
|
||||
/*
|
||||
div.issue-content {
|
||||
padding: 13px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
div.issue-content p:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
div.issue-content p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
*/
|
||||
|
||||
h4#issueTitle {
|
||||
font-size: large;
|
||||
font-weight: bold;
|
||||
@@ -1258,7 +1025,6 @@ div.commit-comment-box > div.panel-body {
|
||||
|
||||
|
||||
div.issue-comment-box textarea {
|
||||
width: 650px;
|
||||
height: 100px;
|
||||
max-height: 300px;
|
||||
}
|
||||
@@ -1425,18 +1191,6 @@ a.absent {
|
||||
color: #c00;
|
||||
}
|
||||
|
||||
/*
|
||||
div.wiki-index-header {
|
||||
background-color: #f5f5f5;
|
||||
color: #333333;
|
||||
margin: 0;
|
||||
border-top-left-radius: 3px;
|
||||
border-top-right-radius: 3px;
|
||||
border: 1px solid #d8d8d8;
|
||||
padding: 8px 8px 8px 8px;
|
||||
}
|
||||
*/
|
||||
|
||||
div.wiki-sidebar {
|
||||
background-color: white;
|
||||
border: 1px solid #d8d8d8;
|
||||
@@ -1466,18 +1220,6 @@ div.wiki-footer {
|
||||
color: gray;
|
||||
}
|
||||
|
||||
/*
|
||||
div.wiki-index-content {
|
||||
background-color: white;
|
||||
border: 1px solid #d8d8d8;
|
||||
padding: 0px;
|
||||
border-bottom-left-radius: 3px;
|
||||
border-bottom-right-radius: 3px;
|
||||
margin-bottom: 20px;
|
||||
border-top: none;
|
||||
}
|
||||
*/
|
||||
|
||||
/****************************************************************************/
|
||||
/* Commit */
|
||||
/****************************************************************************/
|
||||
@@ -2216,94 +1958,96 @@ div.container.blame-container{
|
||||
/* Mobile */
|
||||
/****************************************************************************/
|
||||
@media (max-width: 767px) {
|
||||
body>form#search {
|
||||
margin: 0 -20px 20px -20px;
|
||||
}
|
||||
/* Hide header search box */
|
||||
input[name=query] {
|
||||
display: none;
|
||||
}
|
||||
#dashboard-signin-form {
|
||||
display: none;
|
||||
}
|
||||
.container {
|
||||
width: auto !important;
|
||||
}
|
||||
.body>div.pull-left {
|
||||
width: auto !important;
|
||||
}
|
||||
.pc {
|
||||
display: none;
|
||||
}
|
||||
|
||||
body>div.dashboard-nav {
|
||||
margin: 0 -20px 20px -20px;
|
||||
padding: 0 10px;
|
||||
}
|
||||
/* Adjust issue / comment form */
|
||||
#issue-title {
|
||||
width: 100% !important;
|
||||
}
|
||||
div.attachable>textarea,
|
||||
div.attachable>div.clickable {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.container {
|
||||
width: auto !important;
|
||||
}
|
||||
|
||||
/* Adjust issue search box size and position */
|
||||
#search-filter-box {
|
||||
width: 90% !important;
|
||||
position: absolute;
|
||||
left: 14px;
|
||||
right: 20px;
|
||||
margin-top: 42px;
|
||||
}
|
||||
|
||||
form#search-filter-form {
|
||||
float: none !important;
|
||||
margin-bottom: 80px !important;
|
||||
}
|
||||
|
||||
.table-issues a.button-link {
|
||||
width: 42px;
|
||||
height: 16px;
|
||||
overflow: hidden;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.nav-tabs a.btn[href$="/_edit"] {
|
||||
width: 24px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
padding: 4px 6px;
|
||||
margin: 3px 4px 0 0;
|
||||
}
|
||||
|
||||
body>div.container.body {
|
||||
margin: 0 -12px 40px -12px;
|
||||
}
|
||||
|
||||
.container.body>div[style="width: 170px;"]{
|
||||
width: 32px !important;
|
||||
margin-right: -5px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.container.body>div[style="margin-right: 180px;"]{
|
||||
margin-right: 32px !important;
|
||||
}
|
||||
|
||||
.container.body>div[style="width: 170px;"] .sidemenu i, .container.body>div[style="width: 170px;"] .sidemenu img {
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
/* Hide repository url box */
|
||||
.container.body>div[style="width: 170px;"] .small,.container.body>div[style="width: 170px;"] .input-group {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.container.body>div[style="width: 170px;"] div[style="margin-top: 10px;"] a.btn{
|
||||
width: 26px !important;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.container.body>div[style="width: 170px;"] div[style="margin-top: 10px;"] a.btn i {
|
||||
margin: 5px 10px 5px 6px;
|
||||
}
|
||||
|
||||
/* Hide fork button */
|
||||
div.col-md-1>div.input-group.pull-right {
|
||||
display: none;
|
||||
}
|
||||
|
||||
body>.container>#fork-form{
|
||||
display: inline;
|
||||
}
|
||||
/* Adjust issue search box size and position */
|
||||
#search-filter-box {
|
||||
width: 100% !important;
|
||||
}
|
||||
form#search-filter-form {
|
||||
float: none !important;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
form#search-filter-form>div.form-group {
|
||||
width: 100% !important;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.table-issues a.button-link {
|
||||
width: 42px;
|
||||
height: 16px;
|
||||
overflow: hidden;
|
||||
display: inline-block;
|
||||
}
|
||||
/*
|
||||
.nav-tabs a.btn[href$="/_edit"] {
|
||||
width: 24px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
padding: 4px 6px;
|
||||
margin: 3px 4px 0 0;
|
||||
}
|
||||
*/
|
||||
body>div.container.body {
|
||||
margin: 0 -12px 40px -12px;
|
||||
}
|
||||
/* Adjust sidemenu */
|
||||
.container.body>div[style="width: 170px;"]{
|
||||
width: 32px !important;
|
||||
margin-right: -5px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
/* Hide badge of sidemenu */
|
||||
.container.body>div[style="width: 170px;"] span.badge {
|
||||
display: none;
|
||||
}
|
||||
/* Hide download button */
|
||||
.container.body>div[style="width: 170px;"] a.btn-sm {
|
||||
display: none;
|
||||
}
|
||||
/* Hide repository url box */
|
||||
.container.body>div[style="width: 170px;"] .small,
|
||||
.container.body>div[style="width: 170px;"] .input-group {
|
||||
display: none;
|
||||
}
|
||||
/* Hide fork button */
|
||||
div.input-group>span.fork {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
/* Print */
|
||||
/****************************************************************************/
|
||||
a[href]:after {
|
||||
display: none;
|
||||
@media print {
|
||||
div.headbar {
|
||||
display: none;
|
||||
}
|
||||
a[href]:after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,16 +2,14 @@ package gitbucket.core.api
|
||||
|
||||
import gitbucket.core.util.RepositoryName
|
||||
|
||||
import org.specs2.mutable.Specification
|
||||
import org.json4s.jackson.JsonMethods.{pretty, parse}
|
||||
import org.json4s.jackson.JsonMethods.parse
|
||||
import org.json4s._
|
||||
import org.specs2.matcher._
|
||||
import org.scalatest.FunSuite
|
||||
|
||||
import java.util.{Calendar, TimeZone, Date}
|
||||
|
||||
|
||||
|
||||
class JsonFormatSpec extends Specification {
|
||||
class JsonFormatSpec extends FunSuite {
|
||||
val date1 = {
|
||||
val d = Calendar.getInstance(TimeZone.getTimeZone("UTC"))
|
||||
d.set(2011,3,14,16,0,49)
|
||||
@@ -374,67 +372,58 @@ class JsonFormatSpec extends Specification {
|
||||
}
|
||||
}"""
|
||||
|
||||
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)
|
||||
}
|
||||
def assertJson(resultJson: String, expectJson: String) = {
|
||||
import java.util.regex.Pattern
|
||||
val json2 = Pattern.compile("""^\s*//.*$""", Pattern.MULTILINE).matcher(expectJson).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)
|
||||
}
|
||||
val js1 = parse(resultJson)
|
||||
assert(js1 === js2)
|
||||
}
|
||||
"JsonFormat" should {
|
||||
"apiUser" in {
|
||||
JsonFormat(apiUser) must beFormatted(apiUserJson)
|
||||
}
|
||||
"repository" in {
|
||||
JsonFormat(repository) must beFormatted(repositoryJson)
|
||||
}
|
||||
"apiPushCommit" in {
|
||||
JsonFormat(apiPushCommit) must beFormatted(apiPushCommitJson)
|
||||
}
|
||||
"apiComment" in {
|
||||
JsonFormat(apiComment) must beFormatted(apiCommentJson)
|
||||
JsonFormat(apiCommentPR) must beFormatted(apiCommentPRJson)
|
||||
}
|
||||
"apiCommitListItem" in {
|
||||
JsonFormat(apiCommitListItem) must beFormatted(apiCommitListItemJson)
|
||||
}
|
||||
"apiCommitStatus" in {
|
||||
JsonFormat(apiCommitStatus) must beFormatted(apiCommitStatusJson)
|
||||
}
|
||||
"apiCombinedCommitStatus" in {
|
||||
JsonFormat(apiCombinedCommitStatus) must beFormatted(apiCombinedCommitStatusJson)
|
||||
}
|
||||
"apiLabel" in {
|
||||
JsonFormat(apiLabel) must beFormatted(apiLabelJson)
|
||||
}
|
||||
"apiIssue" in {
|
||||
JsonFormat(apiIssue) must beFormatted(apiIssueJson)
|
||||
JsonFormat(apiIssuePR) must beFormatted(apiIssuePRJson)
|
||||
}
|
||||
"apiPullRequest" in {
|
||||
JsonFormat(apiPullRequest) must beFormatted(apiPullRequestJson)
|
||||
}
|
||||
"apiPullRequestReviewComment" in {
|
||||
JsonFormat(apiPullRequestReviewComment) must beFormatted(apiPullRequestReviewCommentJson)
|
||||
}
|
||||
"apiBranchProtection" in {
|
||||
JsonFormat(apiBranchProtection) must beFormatted(apiBranchProtectionJson)
|
||||
}
|
||||
|
||||
test("apiUser") {
|
||||
assertJson(JsonFormat(apiUser), apiUserJson)
|
||||
}
|
||||
test("repository") {
|
||||
assertJson(JsonFormat(repository), repositoryJson)
|
||||
}
|
||||
test("apiPushCommit") {
|
||||
assertJson(JsonFormat(apiPushCommit), apiPushCommitJson)
|
||||
}
|
||||
test("apiComment") {
|
||||
assertJson(JsonFormat(apiComment), apiCommentJson)
|
||||
assertJson(JsonFormat(apiCommentPR), apiCommentPRJson)
|
||||
}
|
||||
test("apiCommitListItem") {
|
||||
assertJson(JsonFormat(apiCommitListItem), apiCommitListItemJson)
|
||||
}
|
||||
test("apiCommitStatus") {
|
||||
assertJson(JsonFormat(apiCommitStatus), apiCommitStatusJson)
|
||||
}
|
||||
test("apiCombinedCommitStatus") {
|
||||
assertJson(JsonFormat(apiCombinedCommitStatus), apiCombinedCommitStatusJson)
|
||||
}
|
||||
test("apiLabel") {
|
||||
assertJson(JsonFormat(apiLabel), apiLabelJson)
|
||||
}
|
||||
test("apiIssue") {
|
||||
assertJson(JsonFormat(apiIssue), apiIssueJson)
|
||||
assertJson(JsonFormat(apiIssuePR), apiIssuePRJson)
|
||||
}
|
||||
test("apiPullRequest") {
|
||||
assertJson(JsonFormat(apiPullRequest), apiPullRequestJson)
|
||||
}
|
||||
test("apiPullRequestReviewComment") {
|
||||
assertJson(JsonFormat(apiPullRequestReviewComment), apiPullRequestReviewCommentJson)
|
||||
}
|
||||
test("apiBranchProtection") {
|
||||
assertJson(JsonFormat(apiBranchProtection), apiBranchProtectionJson)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +1,25 @@
|
||||
package gitbucket.core.model
|
||||
|
||||
import gitbucket.core.model.CommitState._
|
||||
|
||||
import org.specs2.mutable.Specification
|
||||
import org.scalatest.FunSpec
|
||||
|
||||
|
||||
class CommitStateSpec extends Specification {
|
||||
"CommitState" should {
|
||||
"combine empty must eq PENDING" in {
|
||||
combine(Set()) must_== PENDING
|
||||
class CommitStateSpec extends FunSpec {
|
||||
describe("CommitState") {
|
||||
it("should combine empty must eq PENDING") {
|
||||
assert(combine(Set()) == PENDING)
|
||||
}
|
||||
"combine includes ERROR must eq FAILURE" in {
|
||||
combine(Set(ERROR, SUCCESS, PENDING)) must_== FAILURE
|
||||
it("should combine includes ERROR must eq FAILURE") {
|
||||
assert(combine(Set(ERROR, SUCCESS, PENDING)) == FAILURE)
|
||||
}
|
||||
"combine includes FAILURE must eq peinding" in {
|
||||
combine(Set(FAILURE, SUCCESS, PENDING)) must_== FAILURE
|
||||
it("should combine includes FAILURE must eq peinding") {
|
||||
assert(combine(Set(FAILURE, SUCCESS, PENDING)) == FAILURE)
|
||||
}
|
||||
"combine includes PENDING must eq peinding" in {
|
||||
combine(Set(PENDING, SUCCESS)) must_== PENDING
|
||||
it("should combine includes PENDING must eq peinding") {
|
||||
assert(combine(Set(PENDING, SUCCESS)) == PENDING)
|
||||
}
|
||||
"combine only SUCCESS must eq SUCCESS" in {
|
||||
combine(Set(SUCCESS)) must_== SUCCESS
|
||||
it("should combine only SUCCESS must eq SUCCESS") {
|
||||
assert(combine(Set(SUCCESS)) == SUCCESS)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,91 +1,78 @@
|
||||
package gitbucket.core.service
|
||||
|
||||
import gitbucket.core.model._
|
||||
|
||||
import org.specs2.mutable.Specification
|
||||
|
||||
import java.util.Date
|
||||
import org.scalatest.FunSuite
|
||||
|
||||
|
||||
class AccessTokenServiceSpec extends Specification with ServiceSpecBase {
|
||||
class AccessTokenServiceSpec extends FunSuite with ServiceSpecBase {
|
||||
|
||||
"AccessTokenService" should {
|
||||
"generateAccessToken" in { withTestDB { implicit session =>
|
||||
AccessTokenService.generateAccessToken("root", "note") must be like{
|
||||
case (id, token) if id != 0 => ok
|
||||
}
|
||||
}}
|
||||
test("generateAccessToken") { withTestDB { implicit session =>
|
||||
assert(AccessTokenService.generateAccessToken("root", "note") match {
|
||||
case (id, token) => id != 0
|
||||
})
|
||||
}}
|
||||
|
||||
"getAccessTokens" in { withTestDB { implicit session =>
|
||||
val (id, token) = AccessTokenService.generateAccessToken("root", "note")
|
||||
val tokenHash = AccessTokenService.tokenToHash(token)
|
||||
test("getAccessTokens") { withTestDB { implicit session =>
|
||||
val (id, token) = AccessTokenService.generateAccessToken("root", "note")
|
||||
val tokenHash = AccessTokenService.tokenToHash(token)
|
||||
|
||||
AccessTokenService.getAccessTokens("root") must be like{
|
||||
case List(AccessToken(`id`, "root", `tokenHash`, "note")) => ok
|
||||
}
|
||||
}}
|
||||
assert(AccessTokenService.getAccessTokens("root") == List(AccessToken(`id`, "root", `tokenHash`, "note")))
|
||||
}}
|
||||
|
||||
"getAccessTokens(root) get root's tokens" in { withTestDB { implicit session =>
|
||||
val (id, token) = AccessTokenService.generateAccessToken("root", "note")
|
||||
val tokenHash = AccessTokenService.tokenToHash(token)
|
||||
val user2 = generateNewAccount("user2")
|
||||
AccessTokenService.generateAccessToken("user2", "note2")
|
||||
test("getAccessTokens(root) get root's tokens") { withTestDB { implicit session =>
|
||||
val (id, token) = AccessTokenService.generateAccessToken("root", "note")
|
||||
val tokenHash = AccessTokenService.tokenToHash(token)
|
||||
val user2 = generateNewAccount("user2")
|
||||
AccessTokenService.generateAccessToken("user2", "note2")
|
||||
|
||||
AccessTokenService.getAccessTokens("root") must be like{
|
||||
case List(AccessToken(`id`, "root", `tokenHash`, "note")) => ok
|
||||
}
|
||||
}}
|
||||
assert(AccessTokenService.getAccessTokens("root") == List(AccessToken(`id`, "root", `tokenHash`, "note")))
|
||||
}}
|
||||
|
||||
"deleteAccessToken" in { withTestDB { implicit session =>
|
||||
val (id, token) = AccessTokenService.generateAccessToken("root", "note")
|
||||
val user2 = generateNewAccount("user2")
|
||||
AccessTokenService.generateAccessToken("user2", "note2")
|
||||
test("deleteAccessToken") { withTestDB { implicit session =>
|
||||
val (id, token) = AccessTokenService.generateAccessToken("root", "note")
|
||||
val user2 = generateNewAccount("user2")
|
||||
AccessTokenService.generateAccessToken("user2", "note2")
|
||||
|
||||
AccessTokenService.deleteAccessToken("root", id)
|
||||
AccessTokenService.deleteAccessToken("root", id)
|
||||
|
||||
AccessTokenService.getAccessTokens("root") must beEmpty
|
||||
}}
|
||||
assert(AccessTokenService.getAccessTokens("root").isEmpty)
|
||||
}}
|
||||
|
||||
"getAccountByAccessToken" in { withTestDB { implicit session =>
|
||||
val (id, token) = AccessTokenService.generateAccessToken("root", "note")
|
||||
AccessTokenService.getAccountByAccessToken(token) must beSome.like {
|
||||
case user => user.userName must_== "root"
|
||||
}
|
||||
}}
|
||||
test("getAccountByAccessToken") { withTestDB { implicit session =>
|
||||
val (id, token) = AccessTokenService.generateAccessToken("root", "note")
|
||||
assert(AccessTokenService.getAccountByAccessToken(token) match {
|
||||
case Some(user) => user.userName == "root"
|
||||
})
|
||||
}}
|
||||
|
||||
"getAccountByAccessToken don't get removed account" in { withTestDB { implicit session =>
|
||||
val user2 = generateNewAccount("user2")
|
||||
val (id, token) = AccessTokenService.generateAccessToken("user2", "note")
|
||||
AccountService.updateAccount(user2.copy(isRemoved=true))
|
||||
test("getAccountByAccessToken don't get removed account") { withTestDB { implicit session =>
|
||||
val user2 = generateNewAccount("user2")
|
||||
val (id, token) = AccessTokenService.generateAccessToken("user2", "note")
|
||||
AccountService.updateAccount(user2.copy(isRemoved=true))
|
||||
|
||||
AccessTokenService.getAccountByAccessToken(token) must beEmpty
|
||||
}}
|
||||
assert(AccessTokenService.getAccountByAccessToken(token).isEmpty)
|
||||
}}
|
||||
|
||||
"generateAccessToken create uniq token" in { withTestDB { implicit session =>
|
||||
val tokenIt = List("token1","token1","token1","token2").iterator
|
||||
val service = new AccessTokenService{
|
||||
override def makeAccessTokenString:String = tokenIt.next
|
||||
}
|
||||
test("generateAccessToken create uniq token") { withTestDB { implicit session =>
|
||||
val tokenIt = List("token1","token1","token1","token2").iterator
|
||||
val service = new AccessTokenService{
|
||||
override def makeAccessTokenString:String = tokenIt.next
|
||||
}
|
||||
|
||||
service.generateAccessToken("root", "note1") must like{
|
||||
case (_, "token1") => ok
|
||||
}
|
||||
service.generateAccessToken("root", "note2") must like{
|
||||
case (_, "token2") => ok
|
||||
}
|
||||
}}
|
||||
assert(service.generateAccessToken("root", "note1")._2 == "token1")
|
||||
assert(service.generateAccessToken("root", "note2")._2 == "token2")
|
||||
}}
|
||||
|
||||
"when update Account.userName then AccessToken.userName changed" in { withTestDB { implicit session =>
|
||||
val user2 = generateNewAccount("user2")
|
||||
val (id, token) = AccessTokenService.generateAccessToken("user2", "note")
|
||||
import gitbucket.core.model.Profile._
|
||||
import profile.simple._
|
||||
Accounts.filter(_.userName === "user2".bind).map(_.userName).update("user3")
|
||||
test("when update Account.userName then AccessToken.userName changed") { withTestDB { implicit session =>
|
||||
val user2 = generateNewAccount("user2")
|
||||
val (id, token) = AccessTokenService.generateAccessToken("user2", "note")
|
||||
import gitbucket.core.model.Profile._
|
||||
import profile.simple._
|
||||
Accounts.filter(_.userName === "user2".bind).map(_.userName).update("user3")
|
||||
|
||||
AccessTokenService.getAccountByAccessToken(token) must beSome.like {
|
||||
case user => user.userName must_== "user3"
|
||||
}
|
||||
}}
|
||||
}
|
||||
assert(AccessTokenService.getAccountByAccessToken(token) match {
|
||||
case Some(user) => user.userName == "user3"
|
||||
})
|
||||
}}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,79 +1,71 @@
|
||||
package gitbucket.core.service
|
||||
|
||||
import gitbucket.core.model.{Account, GroupMember}
|
||||
import org.specs2.mutable.Specification
|
||||
import java.util.Date
|
||||
import org.scalatest.FunSuite
|
||||
|
||||
class AccountServiceSpec extends Specification with ServiceSpecBase {
|
||||
class AccountServiceSpec extends FunSuite with ServiceSpecBase {
|
||||
|
||||
"AccountService" should {
|
||||
val RootMailAddress = "root@localhost"
|
||||
val RootMailAddress = "root@localhost"
|
||||
|
||||
"getAllUsers" in { withTestDB { implicit session =>
|
||||
AccountService.getAllUsers() must be like{
|
||||
case List(Account("root", "root", RootMailAddress, _, true, _, _, _, None, None, false, false)) => ok
|
||||
}
|
||||
}}
|
||||
test("getAllUsers") { withTestDB { implicit session =>
|
||||
assert(AccountService.getAllUsers() match {
|
||||
case List(Account("root", "root", RootMailAddress, _, true, _, _, _, None, None, false, false)) => true
|
||||
case _ => false
|
||||
})
|
||||
}}
|
||||
|
||||
"getAccountByUserName" in { withTestDB { implicit session =>
|
||||
AccountService.getAccountByUserName("root") must beSome.like {
|
||||
case user => user.userName must_== "root"
|
||||
}
|
||||
test("getAccountByUserName") { withTestDB { implicit session =>
|
||||
assert(AccountService.getAccountByUserName("root").get.userName == "root")
|
||||
assert(AccountService.getAccountByUserName("invalid user name").isEmpty)
|
||||
}}
|
||||
|
||||
AccountService.getAccountByUserName("invalid user name") must beNone
|
||||
}}
|
||||
test("getAccountByMailAddress") { withTestDB { implicit session =>
|
||||
assert(AccountService.getAccountByMailAddress(RootMailAddress).isDefined)
|
||||
}}
|
||||
|
||||
"getAccountByMailAddress" in { withTestDB { implicit session =>
|
||||
AccountService.getAccountByMailAddress(RootMailAddress) must beSome
|
||||
}}
|
||||
test("updateLastLoginDate") { withTestDB { implicit session =>
|
||||
val root = "root"
|
||||
def user() = AccountService.getAccountByUserName(root).getOrElse(sys.error(s"user $root does not exists"))
|
||||
|
||||
"updateLastLoginDate" in { withTestDB { implicit session =>
|
||||
val root = "root"
|
||||
def user() =
|
||||
AccountService.getAccountByUserName(root).getOrElse(sys.error(s"user $root does not exists"))
|
||||
assert(user().lastLoginDate.isEmpty)
|
||||
|
||||
user().lastLoginDate must beNone
|
||||
val date1 = new Date
|
||||
AccountService.updateLastLoginDate(root)
|
||||
user().lastLoginDate must beSome.like{ case date =>
|
||||
date must be_>(date1)
|
||||
}
|
||||
val date2 = new Date
|
||||
Thread.sleep(1000)
|
||||
AccountService.updateLastLoginDate(root)
|
||||
user().lastLoginDate must beSome.like{ case date =>
|
||||
date must be_>(date2)
|
||||
}
|
||||
}}
|
||||
val date1 = new Date
|
||||
AccountService.updateLastLoginDate(root)
|
||||
assert(user().lastLoginDate.get.compareTo(date1) > 0)
|
||||
|
||||
"updateAccount" in { withTestDB { implicit session =>
|
||||
val root = "root"
|
||||
def user() =
|
||||
AccountService.getAccountByUserName(root).getOrElse(sys.error(s"user $root does not exists"))
|
||||
val date2 = new Date
|
||||
Thread.sleep(1000)
|
||||
AccountService.updateLastLoginDate(root)
|
||||
assert(user().lastLoginDate.get.compareTo(date2) > 0)
|
||||
}}
|
||||
|
||||
val newAddress = "new mail address"
|
||||
AccountService.updateAccount(user().copy(mailAddress = newAddress))
|
||||
user().mailAddress must_== newAddress
|
||||
}}
|
||||
test("updateAccount") { withTestDB { implicit session =>
|
||||
val root = "root"
|
||||
def user() = AccountService.getAccountByUserName(root).getOrElse(sys.error(s"user $root does not exists"))
|
||||
|
||||
"group" in { withTestDB { implicit session =>
|
||||
val group1 = "group1"
|
||||
val user1 = "root"
|
||||
AccountService.createGroup(group1, None)
|
||||
val newAddress = "new mail address"
|
||||
AccountService.updateAccount(user().copy(mailAddress = newAddress))
|
||||
assert(user().mailAddress == newAddress)
|
||||
}}
|
||||
|
||||
AccountService.getGroupMembers(group1) must_== Nil
|
||||
AccountService.getGroupsByUserName(user1) must_== Nil
|
||||
test("group") { withTestDB { implicit session =>
|
||||
val group1 = "group1"
|
||||
val user1 = "root"
|
||||
AccountService.createGroup(group1, None)
|
||||
|
||||
AccountService.updateGroupMembers(group1, List((user1, true)))
|
||||
assert(AccountService.getGroupMembers(group1) == Nil)
|
||||
assert(AccountService.getGroupsByUserName(user1) == Nil)
|
||||
|
||||
AccountService.getGroupMembers(group1) must_== List(GroupMember(group1, user1, true))
|
||||
AccountService.getGroupsByUserName(user1) must_== List(group1)
|
||||
AccountService.updateGroupMembers(group1, List((user1, true)))
|
||||
|
||||
AccountService.updateGroupMembers(group1, Nil)
|
||||
assert(AccountService.getGroupMembers(group1) == List(GroupMember(group1, user1, true)))
|
||||
assert(AccountService.getGroupsByUserName(user1) == List(group1))
|
||||
|
||||
AccountService.getGroupMembers(group1) must_== Nil
|
||||
AccountService.getGroupsByUserName(user1) must_== Nil
|
||||
}}
|
||||
}
|
||||
AccountService.updateGroupMembers(group1, Nil)
|
||||
|
||||
assert(AccountService.getGroupMembers(group1) == Nil)
|
||||
assert(AccountService.getGroupsByUserName(user1) == Nil)
|
||||
}}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
package gitbucket.core.service
|
||||
|
||||
import gitbucket.core.model._
|
||||
import gitbucket.core.model.Profile._
|
||||
import profile.simple._
|
||||
|
||||
import org.specs2.mutable.Specification
|
||||
|
||||
import java.util.Date
|
||||
|
||||
|
||||
class CommitStatusServiceSpec extends Specification with ServiceSpecBase with CommitStatusService
|
||||
with RepositoryService with AccountService{
|
||||
val now = new java.util.Date()
|
||||
val fixture1 = CommitStatus(
|
||||
userName = "root",
|
||||
repositoryName = "repo",
|
||||
commitId = "0e97b8f59f7cdd709418bb59de53f741fd1c1bd7",
|
||||
context = "jenkins/test",
|
||||
creator = "tester",
|
||||
state = CommitState.PENDING,
|
||||
targetUrl = Some("http://example.com/target"),
|
||||
description = Some("description"),
|
||||
updatedDate = now,
|
||||
registeredDate = now)
|
||||
def findById(id: Int)(implicit s:Session) = CommitStatuses.filter(_.byPrimaryKey(id)).firstOption
|
||||
def generateFixture1(tester:Account)(implicit s:Session) = createCommitStatus(
|
||||
userName = fixture1.userName,
|
||||
repositoryName = fixture1.repositoryName,
|
||||
sha = fixture1.commitId,
|
||||
context = fixture1.context,
|
||||
state = fixture1.state,
|
||||
targetUrl = fixture1.targetUrl,
|
||||
description = fixture1.description,
|
||||
creator = tester,
|
||||
now = fixture1.registeredDate)
|
||||
"CommitStatusService" should {
|
||||
"createCommitState can insert and update" in { withTestDB { implicit session =>
|
||||
val tester = generateNewAccount(fixture1.creator)
|
||||
createRepository(fixture1.repositoryName,fixture1.userName,None,false)
|
||||
val id = generateFixture1(tester:Account)
|
||||
getCommitStatus(fixture1.userName, fixture1.repositoryName, id) must_==
|
||||
Some(fixture1.copy(commitStatusId=id))
|
||||
// other one can update
|
||||
val tester2 = generateNewAccount("tester2")
|
||||
val time2 = new java.util.Date();
|
||||
val id2 = createCommitStatus(
|
||||
userName = fixture1.userName,
|
||||
repositoryName = fixture1.repositoryName,
|
||||
sha = fixture1.commitId,
|
||||
context = fixture1.context,
|
||||
state = CommitState.SUCCESS,
|
||||
targetUrl = Some("http://example.com/target2"),
|
||||
description = Some("description2"),
|
||||
creator = tester2,
|
||||
now = time2)
|
||||
getCommitStatus(fixture1.userName, fixture1.repositoryName, id2) must_== Some(fixture1.copy(
|
||||
commitStatusId = id,
|
||||
creator = "tester2",
|
||||
state = CommitState.SUCCESS,
|
||||
targetUrl = Some("http://example.com/target2"),
|
||||
description = Some("description2"),
|
||||
updatedDate = time2))
|
||||
}}
|
||||
"getCommitStatus can find by commitId and context" in { withTestDB { implicit session =>
|
||||
val tester = generateNewAccount(fixture1.creator)
|
||||
createRepository(fixture1.repositoryName,fixture1.userName,None,false)
|
||||
val id = generateFixture1(tester:Account)
|
||||
getCommitStatus(fixture1.userName, fixture1.repositoryName, fixture1.commitId, fixture1.context) must_== Some(fixture1.copy(commitStatusId=id))
|
||||
}}
|
||||
"getCommitStatus can find by commitStatusId" in { withTestDB { implicit session =>
|
||||
val tester = generateNewAccount(fixture1.creator)
|
||||
createRepository(fixture1.repositoryName,fixture1.userName,None,false)
|
||||
val id = generateFixture1(tester:Account)
|
||||
getCommitStatus(fixture1.userName, fixture1.repositoryName, id) must_== Some(fixture1.copy(commitStatusId=id))
|
||||
}}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package gitbucket.core.service
|
||||
|
||||
import gitbucket.core.model._
|
||||
import gitbucket.core.model.Profile._
|
||||
import profile.simple._
|
||||
import org.scalatest.FunSuite
|
||||
|
||||
|
||||
class CommitStatusServiceSpec extends FunSuite with ServiceSpecBase with CommitStatusService
|
||||
with RepositoryService with AccountService{
|
||||
val now = new java.util.Date()
|
||||
val fixture1 = CommitStatus(
|
||||
userName = "root",
|
||||
repositoryName = "repo",
|
||||
commitId = "0e97b8f59f7cdd709418bb59de53f741fd1c1bd7",
|
||||
context = "jenkins/test",
|
||||
creator = "tester",
|
||||
state = CommitState.PENDING,
|
||||
targetUrl = Some("http://example.com/target"),
|
||||
description = Some("description"),
|
||||
updatedDate = now,
|
||||
registeredDate = now)
|
||||
def findById(id: Int)(implicit s:Session) = CommitStatuses.filter(_.byPrimaryKey(id)).firstOption
|
||||
def generateFixture1(tester:Account)(implicit s:Session) = createCommitStatus(
|
||||
userName = fixture1.userName,
|
||||
repositoryName = fixture1.repositoryName,
|
||||
sha = fixture1.commitId,
|
||||
context = fixture1.context,
|
||||
state = fixture1.state,
|
||||
targetUrl = fixture1.targetUrl,
|
||||
description = fixture1.description,
|
||||
creator = tester,
|
||||
now = fixture1.registeredDate)
|
||||
test("createCommitState can insert and update") { withTestDB { implicit session =>
|
||||
val tester = generateNewAccount(fixture1.creator)
|
||||
createRepository(fixture1.repositoryName,fixture1.userName,None,false)
|
||||
val id = generateFixture1(tester:Account)
|
||||
assert(getCommitStatus(fixture1.userName, fixture1.repositoryName, id) == Some(fixture1.copy(commitStatusId=id)))
|
||||
// other one can update
|
||||
val tester2 = generateNewAccount("tester2")
|
||||
val time2 = new java.util.Date();
|
||||
val id2 = createCommitStatus(
|
||||
userName = fixture1.userName,
|
||||
repositoryName = fixture1.repositoryName,
|
||||
sha = fixture1.commitId,
|
||||
context = fixture1.context,
|
||||
state = CommitState.SUCCESS,
|
||||
targetUrl = Some("http://example.com/target2"),
|
||||
description = Some("description2"),
|
||||
creator = tester2,
|
||||
now = time2)
|
||||
assert(getCommitStatus(fixture1.userName, fixture1.repositoryName, id2) == Some(fixture1.copy(
|
||||
commitStatusId = id,
|
||||
creator = "tester2",
|
||||
state = CommitState.SUCCESS,
|
||||
targetUrl = Some("http://example.com/target2"),
|
||||
description = Some("description2"),
|
||||
updatedDate = time2)))
|
||||
}}
|
||||
|
||||
test("getCommitStatus can find by commitId and context") { withTestDB { implicit session =>
|
||||
val tester = generateNewAccount(fixture1.creator)
|
||||
createRepository(fixture1.repositoryName,fixture1.userName,None,false)
|
||||
val id = generateFixture1(tester:Account)
|
||||
assert(getCommitStatus(fixture1.userName, fixture1.repositoryName, fixture1.commitId, fixture1.context) == Some(fixture1.copy(commitStatusId=id)))
|
||||
}}
|
||||
|
||||
test("getCommitStatus can find by commitStatusId") { withTestDB { implicit session =>
|
||||
val tester = generateNewAccount(fixture1.creator)
|
||||
createRepository(fixture1.repositoryName,fixture1.userName,None,false)
|
||||
val id = generateFixture1(tester:Account)
|
||||
assert(getCommitStatus(fixture1.userName, fixture1.repositoryName, id) == Some(fixture1.copy(commitStatusId=id)))
|
||||
}}
|
||||
}
|
||||
@@ -2,49 +2,44 @@ package gitbucket.core.service
|
||||
|
||||
import gitbucket.core.model._
|
||||
import gitbucket.core.service.IssuesService._
|
||||
|
||||
import org.specs2.mutable.Specification
|
||||
|
||||
import java.util.Date
|
||||
import org.scalatest.FunSuite
|
||||
|
||||
|
||||
class IssuesServiceSpec extends Specification with ServiceSpecBase {
|
||||
"IssuesService" should {
|
||||
"getCommitStatues" in { withTestDB { implicit session =>
|
||||
val user1 = generateNewUserWithDBRepository("user1","repo1")
|
||||
class IssuesServiceSpec extends FunSuite with ServiceSpecBase {
|
||||
test("getCommitStatues") { withTestDB { implicit session =>
|
||||
val user1 = generateNewUserWithDBRepository("user1","repo1")
|
||||
|
||||
def getCommitStatues = dummyService.getCommitStatues(List(("user1","repo1",1),("user1","repo1",2)))
|
||||
def getCommitStatues = dummyService.getCommitStatues(List(("user1","repo1",1),("user1","repo1",2)))
|
||||
|
||||
getCommitStatues must_== Map.empty
|
||||
assert(getCommitStatues == Map.empty)
|
||||
|
||||
val now = new java.util.Date()
|
||||
val issueId = generateNewIssue("user1","repo1")
|
||||
issueId must_== 1
|
||||
val now = new java.util.Date()
|
||||
val issueId = generateNewIssue("user1","repo1")
|
||||
assert(issueId == 1)
|
||||
|
||||
getCommitStatues must_== Map.empty
|
||||
assert(getCommitStatues == Map.empty)
|
||||
|
||||
val cs = dummyService.createCommitStatus("user1","repo1","shasha", "default", CommitState.SUCCESS, Some("http://exmple.com/ci"), Some("exampleService"), now, user1)
|
||||
val cs = dummyService.createCommitStatus("user1","repo1","shasha", "default", CommitState.SUCCESS, Some("http://exmple.com/ci"), Some("exampleService"), now, user1)
|
||||
|
||||
getCommitStatues must_== Map.empty
|
||||
assert(getCommitStatues == Map.empty)
|
||||
|
||||
val (is2, pr2) = generateNewPullRequest("user1/repo1/master","user1/repo1/feature1")
|
||||
pr2.issueId must_== 2
|
||||
val (is2, pr2) = generateNewPullRequest("user1/repo1/master","user1/repo1/feature1")
|
||||
assert(pr2.issueId == 2)
|
||||
|
||||
// if there are no statuses, state is none
|
||||
getCommitStatues must_== Map.empty
|
||||
// if there are no statuses, state is none
|
||||
assert(getCommitStatues == Map.empty)
|
||||
|
||||
// if there is a status, state is that
|
||||
val cs2 = dummyService.createCommitStatus("user1","repo1","feature1", "default", CommitState.SUCCESS, Some("http://exmple.com/ci"), Some("exampleService"), now, user1)
|
||||
getCommitStatues must_== Map(("user1","repo1",2) -> CommitStatusInfo(1,1,Some("default"),Some(CommitState.SUCCESS),Some("http://exmple.com/ci"),Some("exampleService")))
|
||||
// if there is a status, state is that
|
||||
val cs2 = dummyService.createCommitStatus("user1","repo1","feature1", "default", CommitState.SUCCESS, Some("http://exmple.com/ci"), Some("exampleService"), now, user1)
|
||||
assert(getCommitStatues == Map(("user1","repo1",2) -> CommitStatusInfo(1,1,Some("default"),Some(CommitState.SUCCESS),Some("http://exmple.com/ci"),Some("exampleService"))))
|
||||
|
||||
// if there are two statuses, state is none
|
||||
val cs3 = dummyService.createCommitStatus("user1","repo1","feature1", "pend", CommitState.PENDING, Some("http://exmple.com/ci"), Some("exampleService"), now, user1)
|
||||
getCommitStatues must_== Map(("user1","repo1",2) -> CommitStatusInfo(2,1,None,None,None,None))
|
||||
// if there are two statuses, state is none
|
||||
val cs3 = dummyService.createCommitStatus("user1","repo1","feature1", "pend", CommitState.PENDING, Some("http://exmple.com/ci"), Some("exampleService"), now, user1)
|
||||
assert(getCommitStatues == Map(("user1","repo1",2) -> CommitStatusInfo(2,1,None,None,None,None)))
|
||||
|
||||
// get only statuses in query issues
|
||||
val (is3, pr3) = generateNewPullRequest("user1/repo1/master","user1/repo1/feature3")
|
||||
val cs4 = dummyService.createCommitStatus("user1","repo1","feature3", "none", CommitState.PENDING, None, None, now, user1)
|
||||
getCommitStatues must_== Map(("user1","repo1",2) -> CommitStatusInfo(2,1,None,None,None,None))
|
||||
} }
|
||||
}
|
||||
// get only statuses in query issues
|
||||
val (is3, pr3) = generateNewPullRequest("user1/repo1/master","user1/repo1/feature3")
|
||||
val cs4 = dummyService.createCommitStatus("user1","repo1","feature3", "none", CommitState.PENDING, None, None, now, user1)
|
||||
assert(getCommitStatues == Map(("user1","repo1",2) -> CommitStatusInfo(2,1,None,None,None,None)))
|
||||
} }
|
||||
}
|
||||
@@ -1,12 +1,11 @@
|
||||
package gitbucket.core.service
|
||||
|
||||
import gitbucket.core.model._
|
||||
import org.scalatest.FunSpec
|
||||
|
||||
import org.specs2.mutable.Specification
|
||||
|
||||
class LabelsServiceSpec extends Specification with ServiceSpecBase {
|
||||
"getLabels" should {
|
||||
"be empty when not have any labels" in { withTestDB { implicit session =>
|
||||
class LabelsServiceSpec extends FunSpec with ServiceSpecBase {
|
||||
describe("getLabels") {
|
||||
it("should be empty when not have any labels") { withTestDB { implicit session =>
|
||||
generateNewUserWithDBRepository("user1", "repo1")
|
||||
|
||||
generateNewUserWithDBRepository("user1", "repo2")
|
||||
@@ -15,9 +14,9 @@ class LabelsServiceSpec extends Specification with ServiceSpecBase {
|
||||
generateNewUserWithDBRepository("user2", "repo1")
|
||||
dummyService.createLabel("user2", "repo1", "label1", "000000")
|
||||
|
||||
dummyService.getLabels("user1", "repo1") must haveSize(0)
|
||||
assert(dummyService.getLabels("user1", "repo1").isEmpty)
|
||||
}}
|
||||
"return contained labels" in { withTestDB { implicit session =>
|
||||
it("should return contained labels") { withTestDB { implicit session =>
|
||||
generateNewUserWithDBRepository("user1", "repo1")
|
||||
val labelId1 = dummyService.createLabel("user1", "repo1", "label1", "000000")
|
||||
val labelId2 = dummyService.createLabel("user1", "repo1", "label2", "ffffff")
|
||||
@@ -30,20 +29,22 @@ class LabelsServiceSpec extends Specification with ServiceSpecBase {
|
||||
|
||||
def getLabels = dummyService.getLabels("user1", "repo1")
|
||||
|
||||
getLabels must haveSize(2)
|
||||
getLabels must_== List(
|
||||
assert(getLabels.length == 2)
|
||||
assert(getLabels == List(
|
||||
Label("user1", "repo1", labelId1, "label1", "000000"),
|
||||
Label("user1", "repo1", labelId2, "label2", "ffffff"))
|
||||
)
|
||||
}}
|
||||
}
|
||||
"getLabel" should {
|
||||
"return None when the label not exist" in { withTestDB { implicit session =>
|
||||
|
||||
describe("getLabel") {
|
||||
it("should return None when the label not exist") { withTestDB { implicit session =>
|
||||
generateNewUserWithDBRepository("user1", "repo1")
|
||||
|
||||
dummyService.getLabel("user1", "repo1", 1) must beNone
|
||||
dummyService.getLabel("user1", "repo1", "label1") must beNone
|
||||
assert(dummyService.getLabel("user1", "repo1", 1) == None)
|
||||
assert(dummyService.getLabel("user1", "repo1", "label1") == None)
|
||||
}}
|
||||
"return a label fetched by label id" in { withTestDB { implicit session =>
|
||||
it("should return a label fetched by label id") { withTestDB { implicit session =>
|
||||
generateNewUserWithDBRepository("user1", "repo1")
|
||||
val labelId1 = dummyService.createLabel("user1", "repo1", "label1", "000000")
|
||||
dummyService.createLabel("user1", "repo1", "label2", "ffffff")
|
||||
@@ -55,9 +56,9 @@ class LabelsServiceSpec extends Specification with ServiceSpecBase {
|
||||
dummyService.createLabel("user2", "repo1", "label1", "000000")
|
||||
|
||||
def getLabel = dummyService.getLabel("user1", "repo1", labelId1)
|
||||
getLabel must_== Some(Label("user1", "repo1", labelId1, "label1", "000000"))
|
||||
assert(getLabel == Some(Label("user1", "repo1", labelId1, "label1", "000000")))
|
||||
}}
|
||||
"return a label fetched by label name" in { withTestDB { implicit session =>
|
||||
it("should return a label fetched by label name") { withTestDB { implicit session =>
|
||||
generateNewUserWithDBRepository("user1", "repo1")
|
||||
val labelId1 = dummyService.createLabel("user1", "repo1", "label1", "000000")
|
||||
dummyService.createLabel("user1", "repo1", "label2", "ffffff")
|
||||
@@ -69,11 +70,11 @@ class LabelsServiceSpec extends Specification with ServiceSpecBase {
|
||||
dummyService.createLabel("user2", "repo1", "label1", "000000")
|
||||
|
||||
def getLabel = dummyService.getLabel("user1", "repo1", "label1")
|
||||
getLabel must_== Some(Label("user1", "repo1", labelId1, "label1", "000000"))
|
||||
getLabel == Some(Label("user1", "repo1", labelId1, "label1", "000000"))
|
||||
}}
|
||||
}
|
||||
"createLabel" should {
|
||||
"return accurate label id" in { withTestDB { implicit session =>
|
||||
describe("createLabel") {
|
||||
it("should return accurate label id") { withTestDB { implicit session =>
|
||||
generateNewUserWithDBRepository("user1", "repo1")
|
||||
generateNewUserWithDBRepository("user1", "repo2")
|
||||
generateNewUserWithDBRepository("user2", "repo1")
|
||||
@@ -81,13 +82,13 @@ class LabelsServiceSpec extends Specification with ServiceSpecBase {
|
||||
dummyService.createLabel("user1", "repo2", "label1", "000000")
|
||||
dummyService.createLabel("user2", "repo1", "label1", "000000")
|
||||
val labelId = dummyService.createLabel("user1", "repo1", "label2", "000000")
|
||||
labelId must_== 4
|
||||
assert(labelId == 4)
|
||||
def getLabel = dummyService.getLabel("user1", "repo1", labelId)
|
||||
getLabel must_== Some(Label("user1", "repo1", labelId, "label2", "000000"))
|
||||
assert(getLabel == Some(Label("user1", "repo1", labelId, "label2", "000000")))
|
||||
}}
|
||||
}
|
||||
"updateLabel" should {
|
||||
"change target label" in { withTestDB { implicit session =>
|
||||
describe("updateLabel") {
|
||||
it("should change target label") { withTestDB { implicit session =>
|
||||
generateNewUserWithDBRepository("user1", "repo1")
|
||||
generateNewUserWithDBRepository("user1", "repo2")
|
||||
generateNewUserWithDBRepository("user2", "repo1")
|
||||
@@ -96,11 +97,11 @@ class LabelsServiceSpec extends Specification with ServiceSpecBase {
|
||||
dummyService.createLabel("user2", "repo1", "label1", "000000")
|
||||
dummyService.updateLabel("user1", "repo1", labelId, "updated-label", "ffffff")
|
||||
def getLabel = dummyService.getLabel("user1", "repo1", labelId)
|
||||
getLabel must_== Some(Label("user1", "repo1", labelId, "updated-label", "ffffff"))
|
||||
assert(getLabel == Some(Label("user1", "repo1", labelId, "updated-label", "ffffff")))
|
||||
}}
|
||||
}
|
||||
"deleteLabel" should {
|
||||
"remove target label" in { withTestDB { implicit session =>
|
||||
describe("deleteLabel") {
|
||||
it("should remove target label") { withTestDB { implicit session =>
|
||||
generateNewUserWithDBRepository("user1", "repo1")
|
||||
generateNewUserWithDBRepository("user1", "repo2")
|
||||
generateNewUserWithDBRepository("user2", "repo1")
|
||||
@@ -108,7 +109,7 @@ class LabelsServiceSpec extends Specification with ServiceSpecBase {
|
||||
dummyService.createLabel("user1", "repo2", "label1", "000000")
|
||||
dummyService.createLabel("user2", "repo1", "label1", "000000")
|
||||
dummyService.deleteLabel("user1", "repo1", labelId)
|
||||
dummyService.getLabel("user1", "repo1", labelId) must beNone
|
||||
assert(dummyService.getLabel("user1", "repo1", labelId) == None)
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +1,17 @@
|
||||
package gitbucket.core.service
|
||||
|
||||
import gitbucket.core.model._
|
||||
import gitbucket.core.util.JGitUtil
|
||||
import gitbucket.core.util.Directory._
|
||||
import gitbucket.core.util.Implicits._
|
||||
import gitbucket.core.util.ControlUtil._
|
||||
import gitbucket.core.util.GitSpecUtil._
|
||||
|
||||
import org.apache.commons.io.FileUtils
|
||||
import org.eclipse.jgit.api.Git
|
||||
import org.eclipse.jgit.dircache.DirCache
|
||||
import org.eclipse.jgit.lib._
|
||||
import org.eclipse.jgit.revwalk._
|
||||
import org.eclipse.jgit.treewalk._
|
||||
import org.specs2.mutable.Specification
|
||||
import org.scalatest.FunSpec
|
||||
|
||||
import java.io.File
|
||||
import java.nio.file._
|
||||
import java.util.Date
|
||||
|
||||
class MergeServiceSpec extends Specification {
|
||||
sequential
|
||||
class MergeServiceSpec extends FunSpec {
|
||||
val service = new MergeService{}
|
||||
val branch = "master"
|
||||
val issueId = 10
|
||||
@@ -36,95 +27,95 @@ class MergeServiceSpec extends Specification {
|
||||
createFile(git, s"refs/heads/${branch}", "test.txt", "hoge2" )
|
||||
createFile(git, s"refs/pull/${issueId}/head", "test.txt", "hoge4" )
|
||||
}
|
||||
"checkConflict, checkConflictCache" should {
|
||||
"checkConflict false if not conflicted, and create cache" in {
|
||||
describe("checkConflict, checkConflictCache") {
|
||||
it("checkConflict false if not conflicted, and create cache") {
|
||||
val repo1Dir = initRepository("user1","repo1")
|
||||
service.checkConflictCache("user1", "repo1", branch, issueId) mustEqual None
|
||||
assert(service.checkConflictCache("user1", "repo1", branch, issueId) == None)
|
||||
val conflicted = service.checkConflict("user1", "repo1", branch, issueId)
|
||||
service.checkConflictCache("user1", "repo1", branch, issueId) mustEqual Some(false)
|
||||
conflicted mustEqual false
|
||||
assert(service.checkConflictCache("user1", "repo1", branch, issueId) == Some(false))
|
||||
assert(conflicted == false)
|
||||
}
|
||||
"checkConflict true if not conflicted, and create cache" in {
|
||||
it("checkConflict true if not conflicted, and create cache") {
|
||||
val repo2Dir = initRepository("user1","repo2")
|
||||
using(Git.open(repo2Dir)){ git =>
|
||||
createConfrict(git)
|
||||
}
|
||||
service.checkConflictCache("user1", "repo2", branch, issueId) mustEqual None
|
||||
assert(service.checkConflictCache("user1", "repo2", branch, issueId) == None)
|
||||
val conflicted = service.checkConflict("user1", "repo2", branch, issueId)
|
||||
conflicted mustEqual true
|
||||
service.checkConflictCache("user1", "repo2", branch, issueId) mustEqual Some(true)
|
||||
assert(conflicted == true)
|
||||
assert(service.checkConflictCache("user1", "repo2", branch, issueId) == Some(true))
|
||||
}
|
||||
}
|
||||
"checkConflictCache" should {
|
||||
"merged cache invalid if origin branch moved" in {
|
||||
describe("checkConflictCache") {
|
||||
it("merged cache invalid if origin branch moved") {
|
||||
val repo3Dir = initRepository("user1","repo3")
|
||||
service.checkConflict("user1", "repo3", branch, issueId) mustEqual false
|
||||
service.checkConflictCache("user1", "repo3", branch, issueId) mustEqual Some(false)
|
||||
assert(service.checkConflict("user1", "repo3", branch, issueId) == false)
|
||||
assert(service.checkConflictCache("user1", "repo3", branch, issueId) == Some(false))
|
||||
using(Git.open(repo3Dir)){ git =>
|
||||
createFile(git, s"refs/heads/${branch}", "test.txt", "hoge2" )
|
||||
}
|
||||
service.checkConflictCache("user1", "repo3", branch, issueId) mustEqual None
|
||||
assert(service.checkConflictCache("user1", "repo3", branch, issueId) == None)
|
||||
}
|
||||
"merged cache invalid if request branch moved" in {
|
||||
it("merged cache invalid if request branch moved") {
|
||||
val repo4Dir = initRepository("user1","repo4")
|
||||
service.checkConflict("user1", "repo4", branch, issueId) mustEqual false
|
||||
service.checkConflictCache("user1", "repo4", branch, issueId) mustEqual Some(false)
|
||||
assert(service.checkConflict("user1", "repo4", branch, issueId) == false)
|
||||
assert(service.checkConflictCache("user1", "repo4", branch, issueId) == Some(false))
|
||||
using(Git.open(repo4Dir)){ git =>
|
||||
createFile(git, s"refs/pull/${issueId}/head", "test.txt", "hoge4" )
|
||||
}
|
||||
service.checkConflictCache("user1", "repo4", branch, issueId) mustEqual None
|
||||
assert(service.checkConflictCache("user1", "repo4", branch, issueId) == None)
|
||||
}
|
||||
"merged cache invalid if origin branch moved" in {
|
||||
it("should merged cache invalid if origin branch moved") {
|
||||
val repo5Dir = initRepository("user1","repo5")
|
||||
service.checkConflict("user1", "repo5", branch, issueId) mustEqual false
|
||||
service.checkConflictCache("user1", "repo5", branch, issueId) mustEqual Some(false)
|
||||
assert(service.checkConflict("user1", "repo5", branch, issueId) == false)
|
||||
assert(service.checkConflictCache("user1", "repo5", branch, issueId) == Some(false))
|
||||
using(Git.open(repo5Dir)){ git =>
|
||||
createFile(git, s"refs/heads/${branch}", "test.txt", "hoge2" )
|
||||
}
|
||||
service.checkConflictCache("user1", "repo5", branch, issueId) mustEqual None
|
||||
assert(service.checkConflictCache("user1", "repo5", branch, issueId) == None)
|
||||
}
|
||||
"conflicted cache invalid if request branch moved" in {
|
||||
it("conflicted cache invalid if request branch moved") {
|
||||
val repo6Dir = initRepository("user1","repo6")
|
||||
using(Git.open(repo6Dir)){ git =>
|
||||
createConfrict(git)
|
||||
}
|
||||
service.checkConflict("user1", "repo6", branch, issueId) mustEqual true
|
||||
service.checkConflictCache("user1", "repo6", branch, issueId) mustEqual Some(true)
|
||||
assert(service.checkConflict("user1", "repo6", branch, issueId) == true)
|
||||
assert(service.checkConflictCache("user1", "repo6", branch, issueId) == Some(true))
|
||||
using(Git.open(repo6Dir)){ git =>
|
||||
createFile(git, s"refs/pull/${issueId}/head", "test.txt", "hoge4" )
|
||||
}
|
||||
service.checkConflictCache("user1", "repo6", branch, issueId) mustEqual None
|
||||
assert(service.checkConflictCache("user1", "repo6", branch, issueId) == None)
|
||||
}
|
||||
"conflicted cache invalid if origin branch moved" in {
|
||||
it("conflicted cache invalid if origin branch moved") {
|
||||
val repo7Dir = initRepository("user1","repo7")
|
||||
using(Git.open(repo7Dir)){ git =>
|
||||
createConfrict(git)
|
||||
}
|
||||
service.checkConflict("user1", "repo7", branch, issueId) mustEqual true
|
||||
service.checkConflictCache("user1", "repo7", branch, issueId) mustEqual Some(true)
|
||||
assert(service.checkConflict("user1", "repo7", branch, issueId) == true)
|
||||
assert(service.checkConflictCache("user1", "repo7", branch, issueId) == Some(true))
|
||||
using(Git.open(repo7Dir)){ git =>
|
||||
createFile(git, s"refs/heads/${branch}", "test.txt", "hoge4" )
|
||||
}
|
||||
service.checkConflictCache("user1", "repo7", branch, issueId) mustEqual None
|
||||
assert(service.checkConflictCache("user1", "repo7", branch, issueId) == None)
|
||||
}
|
||||
}
|
||||
"mergePullRequest" should {
|
||||
"can merge" in {
|
||||
describe("mergePullRequest") {
|
||||
it("can merge") {
|
||||
val repo8Dir = initRepository("user1","repo8")
|
||||
using(Git.open(repo8Dir)){ git =>
|
||||
createFile(git, s"refs/pull/${issueId}/head", "test.txt", "hoge2" )
|
||||
val committer = new PersonIdent("dummy2", "dummy2@example.com")
|
||||
getFile(git, branch, "test.txt").content.get mustEqual "hoge"
|
||||
assert(getFile(git, branch, "test.txt").content.get == "hoge")
|
||||
val requestBranchId = git.getRepository.resolve(s"refs/pull/${issueId}/head")
|
||||
val masterId = git.getRepository.resolve(branch)
|
||||
service.mergePullRequest(git, branch, issueId, "merged", committer)
|
||||
val lastCommitId = git.getRepository.resolve(branch);
|
||||
val lastCommitId = git.getRepository.resolve(branch)
|
||||
val commit = using(new RevWalk(git.getRepository))(_.parseCommit(lastCommitId))
|
||||
commit.getCommitterIdent() mustEqual committer
|
||||
commit.getAuthorIdent() mustEqual committer
|
||||
commit.getFullMessage() mustEqual "merged"
|
||||
commit.getParents.toSet mustEqual Set( requestBranchId, masterId )
|
||||
getFile(git, branch, "test.txt").content.get mustEqual "hoge2"
|
||||
assert(commit.getCommitterIdent() == committer)
|
||||
assert(commit.getAuthorIdent() == committer)
|
||||
assert(commit.getFullMessage() == "merged")
|
||||
assert(commit.getParents.toSet == Set( requestBranchId, masterId ))
|
||||
assert(getFile(git, branch, "test.txt").content.get == "hoge2")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,134 +1,134 @@
|
||||
package gitbucket.core.service
|
||||
|
||||
import gitbucket.core.util.GitSpecUtil._
|
||||
import org.specs2.mutable.Specification
|
||||
import org.eclipse.jgit.transport.{ReceivePack, ReceiveCommand}
|
||||
import org.eclipse.jgit.lib.ObjectId
|
||||
import gitbucket.core.model.CommitState
|
||||
import gitbucket.core.service.ProtectedBranchService.{ProtectedBranchReceiveHook, ProtectedBranchInfo}
|
||||
import scalaz._, Scalaz._
|
||||
import org.scalatest.FunSpec
|
||||
|
||||
class ProtectedBranchServiceSpec extends Specification with ServiceSpecBase with ProtectedBranchService with CommitStatusService {
|
||||
class ProtectedBranchServiceSpec extends FunSpec with ServiceSpecBase with ProtectedBranchService with CommitStatusService {
|
||||
|
||||
val receiveHook = new ProtectedBranchReceiveHook()
|
||||
val now = new java.util.Date()
|
||||
val sha = "0c77148632618b59b6f70004e3084002be2b8804"
|
||||
val sha2 = "0c77148632618b59b6f70004e3084002be2b8805"
|
||||
|
||||
"getProtectedBranchInfo" should {
|
||||
"empty is disabled" in {
|
||||
describe("getProtectedBranchInfo") {
|
||||
it("should empty is disabled") {
|
||||
withTestDB { implicit session =>
|
||||
getProtectedBranchInfo("user1", "repo1", "branch") must_== ProtectedBranchInfo.disabled("user1", "repo1")
|
||||
assert(getProtectedBranchInfo("user1", "repo1", "branch") == ProtectedBranchInfo.disabled("user1", "repo1"))
|
||||
}
|
||||
}
|
||||
"enable and update and disable" in {
|
||||
it("should enable and update and disable") {
|
||||
withTestDB { implicit session =>
|
||||
generateNewUserWithDBRepository("user1", "repo1")
|
||||
enableBranchProtection("user1", "repo1", "branch", false, Nil)
|
||||
getProtectedBranchInfo("user1", "repo1", "branch") must_== ProtectedBranchInfo("user1", "repo1", true, Nil, false)
|
||||
assert(getProtectedBranchInfo("user1", "repo1", "branch") == ProtectedBranchInfo("user1", "repo1", true, Nil, false))
|
||||
enableBranchProtection("user1", "repo1", "branch", true, Seq("hoge","huge"))
|
||||
getProtectedBranchInfo("user1", "repo1", "branch") must_== ProtectedBranchInfo("user1", "repo1", true, Seq("hoge","huge"), true)
|
||||
assert(getProtectedBranchInfo("user1", "repo1", "branch") == ProtectedBranchInfo("user1", "repo1", true, Seq("hoge","huge"), true))
|
||||
disableBranchProtection("user1", "repo1", "branch")
|
||||
getProtectedBranchInfo("user1", "repo1", "branch") must_== ProtectedBranchInfo.disabled("user1", "repo1")
|
||||
assert(getProtectedBranchInfo("user1", "repo1", "branch") == ProtectedBranchInfo.disabled("user1", "repo1"))
|
||||
}
|
||||
}
|
||||
"empty contexts is no-include-administrators" in {
|
||||
it("should empty contexts is no-include-administrators") {
|
||||
withTestDB { implicit session =>
|
||||
generateNewUserWithDBRepository("user1", "repo1")
|
||||
enableBranchProtection("user1", "repo1", "branch", false, Nil)
|
||||
getProtectedBranchInfo("user1", "repo1", "branch").includeAdministrators must_== false
|
||||
assert(getProtectedBranchInfo("user1", "repo1", "branch").includeAdministrators == false)
|
||||
enableBranchProtection("user1", "repo1", "branch", true, Nil)
|
||||
getProtectedBranchInfo("user1", "repo1", "branch").includeAdministrators must_== false
|
||||
assert(getProtectedBranchInfo("user1", "repo1", "branch").includeAdministrators == false)
|
||||
}
|
||||
}
|
||||
"getProtectedBranchList" in {
|
||||
it("getProtectedBranchList") {
|
||||
withTestDB { implicit session =>
|
||||
generateNewUserWithDBRepository("user1", "repo1")
|
||||
enableBranchProtection("user1", "repo1", "branch", false, Nil)
|
||||
enableBranchProtection("user1", "repo1", "branch2", false, Seq("fuga"))
|
||||
enableBranchProtection("user1", "repo1", "branch3", true, Seq("hoge"))
|
||||
getProtectedBranchList("user1", "repo1").toSet must_== Set("branch", "branch2", "branch3")
|
||||
assert(getProtectedBranchList("user1", "repo1").toSet == Set("branch", "branch2", "branch3"))
|
||||
}
|
||||
}
|
||||
"getBranchProtectedReason on force push from admin" in {
|
||||
it("getBranchProtectedReason on force push from admin") {
|
||||
withTestDB { implicit session =>
|
||||
withTestRepository { git =>
|
||||
val rp = new ReceivePack(git.getRepository) <| { _.setAllowNonFastForwards(true) }
|
||||
val rc = new ReceiveCommand(ObjectId.fromString(sha), ObjectId.fromString(sha2), "refs/heads/branch", ReceiveCommand.Type.UPDATE_NONFASTFORWARD)
|
||||
generateNewUserWithDBRepository("user1", "repo1")
|
||||
receiveHook.preReceive("user1", "repo1", rp, rc, "user1") must_== None
|
||||
assert(receiveHook.preReceive("user1", "repo1", rp, rc, "user1") == None)
|
||||
enableBranchProtection("user1", "repo1", "branch", false, Nil)
|
||||
receiveHook.preReceive("user1", "repo1", rp, rc, "user1") must_== Some("Cannot force-push to a protected branch")
|
||||
assert(receiveHook.preReceive("user1", "repo1", rp, rc, "user1") == Some("Cannot force-push to a protected branch"))
|
||||
}
|
||||
}
|
||||
}
|
||||
"getBranchProtectedReason on force push from othre" in {
|
||||
it("getBranchProtectedReason on force push from other") {
|
||||
withTestDB { implicit session =>
|
||||
withTestRepository { git =>
|
||||
val rp = new ReceivePack(git.getRepository) <| { _.setAllowNonFastForwards(true) }
|
||||
val rc = new ReceiveCommand(ObjectId.fromString(sha), ObjectId.fromString(sha2), "refs/heads/branch", ReceiveCommand.Type.UPDATE_NONFASTFORWARD)
|
||||
generateNewUserWithDBRepository("user1", "repo1")
|
||||
receiveHook.preReceive("user1", "repo1", rp, rc, "user2") must_== None
|
||||
assert(receiveHook.preReceive("user1", "repo1", rp, rc, "user2") == None)
|
||||
enableBranchProtection("user1", "repo1", "branch", false, Nil)
|
||||
receiveHook.preReceive("user1", "repo1", rp, rc, "user2") must_== Some("Cannot force-push to a protected branch")
|
||||
assert(receiveHook.preReceive("user1", "repo1", rp, rc, "user2") == Some("Cannot force-push to a protected branch"))
|
||||
}
|
||||
}
|
||||
}
|
||||
"getBranchProtectedReason check status on push from othre" in {
|
||||
it("getBranchProtectedReason check status on push from other") {
|
||||
withTestDB { implicit session =>
|
||||
withTestRepository { git =>
|
||||
val rp = new ReceivePack(git.getRepository) <| { _.setAllowNonFastForwards(false) }
|
||||
val rc = new ReceiveCommand(ObjectId.fromString(sha), ObjectId.fromString(sha2), "refs/heads/branch", ReceiveCommand.Type.UPDATE)
|
||||
val user1 = generateNewUserWithDBRepository("user1", "repo1")
|
||||
receiveHook.preReceive("user1", "repo1", rp, rc, "user2") must_== None
|
||||
assert(receiveHook.preReceive("user1", "repo1", rp, rc, "user2") == None)
|
||||
enableBranchProtection("user1", "repo1", "branch", false, Seq("must"))
|
||||
receiveHook.preReceive("user1", "repo1", rp, rc, "user2") must_== Some("Required status check \"must\" is expected")
|
||||
assert(receiveHook.preReceive("user1", "repo1", rp, rc, "user2") == Some("Required status check \"must\" is expected"))
|
||||
enableBranchProtection("user1", "repo1", "branch", false, Seq("must", "must2"))
|
||||
receiveHook.preReceive("user1", "repo1", rp, rc, "user2") must_== Some("2 of 2 required status checks are expected")
|
||||
assert(receiveHook.preReceive("user1", "repo1", rp, rc, "user2") == Some("2 of 2 required status checks are expected"))
|
||||
createCommitStatus("user1", "repo1", sha2, "context", CommitState.SUCCESS, None, None, now, user1)
|
||||
receiveHook.preReceive("user1", "repo1", rp, rc, "user2") must_== Some("2 of 2 required status checks are expected")
|
||||
assert(receiveHook.preReceive("user1", "repo1", rp, rc, "user2") == Some("2 of 2 required status checks are expected"))
|
||||
createCommitStatus("user1", "repo1", sha2, "must", CommitState.SUCCESS, None, None, now, user1)
|
||||
receiveHook.preReceive("user1", "repo1", rp, rc, "user2") must_== Some("Required status check \"must2\" is expected")
|
||||
assert(receiveHook.preReceive("user1", "repo1", rp, rc, "user2") == Some("Required status check \"must2\" is expected"))
|
||||
createCommitStatus("user1", "repo1", sha2, "must2", CommitState.SUCCESS, None, None, now, user1)
|
||||
receiveHook.preReceive("user1", "repo1", rp, rc, "user2") must_== None
|
||||
assert(receiveHook.preReceive("user1", "repo1", rp, rc, "user2") == None)
|
||||
}
|
||||
}
|
||||
}
|
||||
"getBranchProtectedReason check status on push from admin" in {
|
||||
it("getBranchProtectedReason check status on push from admin") {
|
||||
withTestDB { implicit session =>
|
||||
withTestRepository { git =>
|
||||
val rp = new ReceivePack(git.getRepository) <| { _.setAllowNonFastForwards(false) }
|
||||
val rc = new ReceiveCommand(ObjectId.fromString(sha), ObjectId.fromString(sha2), "refs/heads/branch", ReceiveCommand.Type.UPDATE)
|
||||
val user1 = generateNewUserWithDBRepository("user1", "repo1")
|
||||
receiveHook.preReceive("user1", "repo1", rp, rc, "user1") must_== None
|
||||
assert(receiveHook.preReceive("user1", "repo1", rp, rc, "user1") == None)
|
||||
enableBranchProtection("user1", "repo1", "branch", false, Seq("must"))
|
||||
receiveHook.preReceive("user1", "repo1", rp, rc, "user1") must_== None
|
||||
assert(receiveHook.preReceive("user1", "repo1", rp, rc, "user1") == None)
|
||||
enableBranchProtection("user1", "repo1", "branch", true, Seq("must"))
|
||||
receiveHook.preReceive("user1", "repo1", rp, rc, "user1") must_== Some("Required status check \"must\" is expected")
|
||||
assert(receiveHook.preReceive("user1", "repo1", rp, rc, "user1") == Some("Required status check \"must\" is expected"))
|
||||
enableBranchProtection("user1", "repo1", "branch", false, Seq("must", "must2"))
|
||||
receiveHook.preReceive("user1", "repo1", rp, rc, "user1") must_== None
|
||||
assert(receiveHook.preReceive("user1", "repo1", rp, rc, "user1") == None)
|
||||
enableBranchProtection("user1", "repo1", "branch", true, Seq("must", "must2"))
|
||||
receiveHook.preReceive("user1", "repo1", rp, rc, "user1") must_== Some("2 of 2 required status checks are expected")
|
||||
assert(receiveHook.preReceive("user1", "repo1", rp, rc, "user1") == Some("2 of 2 required status checks are expected"))
|
||||
createCommitStatus("user1", "repo1", sha2, "context", CommitState.SUCCESS, None, None, now, user1)
|
||||
receiveHook.preReceive("user1", "repo1", rp, rc, "user1") must_== Some("2 of 2 required status checks are expected")
|
||||
assert(receiveHook.preReceive("user1", "repo1", rp, rc, "user1") == Some("2 of 2 required status checks are expected"))
|
||||
createCommitStatus("user1", "repo1", sha2, "must", CommitState.SUCCESS, None, None, now, user1)
|
||||
receiveHook.preReceive("user1", "repo1", rp, rc, "user1") must_== Some("Required status check \"must2\" is expected")
|
||||
assert(receiveHook.preReceive("user1", "repo1", rp, rc, "user1") == Some("Required status check \"must2\" is expected"))
|
||||
createCommitStatus("user1", "repo1", sha2, "must2", CommitState.SUCCESS, None, None, now, user1)
|
||||
receiveHook.preReceive("user1", "repo1", rp, rc, "user1") must_== None
|
||||
assert(receiveHook.preReceive("user1", "repo1", rp, rc, "user1") == None)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"ProtectedBranchInfo" should {
|
||||
"administrator is owner" in {
|
||||
describe("ProtectedBranchInfo") {
|
||||
it("administrator is owner") {
|
||||
withTestDB { implicit session =>
|
||||
generateNewUserWithDBRepository("user1", "repo1")
|
||||
val x = ProtectedBranchInfo("user1", "repo1", true, Nil, false)
|
||||
x.isAdministrator("user1") must_== true
|
||||
x.isAdministrator("user2") must_== false
|
||||
assert(x.isAdministrator("user1") == true)
|
||||
assert(x.isAdministrator("user2") == false)
|
||||
}
|
||||
}
|
||||
"administrator is manager" in {
|
||||
it("administrator is manager") {
|
||||
withTestDB { implicit session =>
|
||||
val x = ProtectedBranchInfo("grp1", "repo1", true, Nil, false)
|
||||
x.createGroup("grp1", None)
|
||||
@@ -137,49 +137,49 @@ class ProtectedBranchServiceSpec extends Specification with ServiceSpecBase with
|
||||
generateNewAccount("user3")
|
||||
|
||||
x.updateGroupMembers("grp1", List("user1"->true, "user2"->false))
|
||||
x.isAdministrator("user1") must_== true
|
||||
x.isAdministrator("user2") must_== false
|
||||
x.isAdministrator("user3") must_== false
|
||||
assert(x.isAdministrator("user1") == true)
|
||||
assert(x.isAdministrator("user2") == false)
|
||||
assert(x.isAdministrator("user3") == false)
|
||||
}
|
||||
}
|
||||
"unSuccessedContexts" in {
|
||||
it("unSuccessedContexts") {
|
||||
withTestDB { implicit session =>
|
||||
val user1 = generateNewUserWithDBRepository("user1", "repo1")
|
||||
val x = ProtectedBranchInfo("user1", "repo1", true, List("must"), false)
|
||||
x.unSuccessedContexts(sha) must_== Set("must")
|
||||
assert(x.unSuccessedContexts(sha) == Set("must"))
|
||||
createCommitStatus("user1", "repo1", sha, "context", CommitState.SUCCESS, None, None, now, user1)
|
||||
x.unSuccessedContexts(sha) must_== Set("must")
|
||||
assert(x.unSuccessedContexts(sha) == Set("must"))
|
||||
createCommitStatus("user1", "repo1", sha, "must", CommitState.ERROR, None, None, now, user1)
|
||||
x.unSuccessedContexts(sha) must_== Set("must")
|
||||
assert(x.unSuccessedContexts(sha) == Set("must"))
|
||||
createCommitStatus("user1", "repo1", sha, "must", CommitState.PENDING, None, None, now, user1)
|
||||
x.unSuccessedContexts(sha) must_== Set("must")
|
||||
assert(x.unSuccessedContexts(sha) == Set("must"))
|
||||
createCommitStatus("user1", "repo1", sha, "must", CommitState.FAILURE, None, None, now, user1)
|
||||
x.unSuccessedContexts(sha) must_== Set("must")
|
||||
assert(x.unSuccessedContexts(sha) == Set("must"))
|
||||
createCommitStatus("user1", "repo1", sha, "must", CommitState.SUCCESS, None, None, now, user1)
|
||||
x.unSuccessedContexts(sha) must_== Set()
|
||||
assert(x.unSuccessedContexts(sha) == Set())
|
||||
}
|
||||
}
|
||||
"unSuccessedContexts when empty" in {
|
||||
it("unSuccessedContexts when empty") {
|
||||
withTestDB { implicit session =>
|
||||
val user1 = generateNewUserWithDBRepository("user1", "repo1")
|
||||
val x = ProtectedBranchInfo("user1", "repo1", true, Nil, false)
|
||||
val sha = "0c77148632618b59b6f70004e3084002be2b8804"
|
||||
x.unSuccessedContexts(sha) must_== Nil
|
||||
assert(x.unSuccessedContexts(sha) == Set())
|
||||
createCommitStatus("user1", "repo1", sha, "context", CommitState.SUCCESS, None, None, now, user1)
|
||||
x.unSuccessedContexts(sha) must_== Nil
|
||||
assert(x.unSuccessedContexts(sha) == Set())
|
||||
}
|
||||
}
|
||||
"if disabled, needStatusCheck is false" in {
|
||||
it("if disabled, needStatusCheck is false") {
|
||||
withTestDB { implicit session =>
|
||||
ProtectedBranchInfo("user1", "repo1", false, Seq("must"), true).needStatusCheck("user1") must_== false
|
||||
assert(ProtectedBranchInfo("user1", "repo1", false, Seq("must"), true).needStatusCheck("user1") == false)
|
||||
}
|
||||
}
|
||||
"needStatusCheck includeAdministrators" in {
|
||||
it("needStatusCheck includeAdministrators") {
|
||||
withTestDB { implicit session =>
|
||||
ProtectedBranchInfo("user1", "repo1", true, Seq("must"), false).needStatusCheck("user2") must_== true
|
||||
ProtectedBranchInfo("user1", "repo1", true, Seq("must"), false).needStatusCheck("user1") must_== false
|
||||
ProtectedBranchInfo("user1", "repo1", true, Seq("must"), true ).needStatusCheck("user2") must_== true
|
||||
ProtectedBranchInfo("user1", "repo1", true, Seq("must"), true ).needStatusCheck("user1") must_== true
|
||||
assert(ProtectedBranchInfo("user1", "repo1", true, Seq("must"), false).needStatusCheck("user2") == true)
|
||||
assert(ProtectedBranchInfo("user1", "repo1", true, Seq("must"), false).needStatusCheck("user1") == false)
|
||||
assert(ProtectedBranchInfo("user1", "repo1", true, Seq("must"), true ).needStatusCheck("user2") == true)
|
||||
assert(ProtectedBranchInfo("user1", "repo1", true, Seq("must"), true ).needStatusCheck("user1") == true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
package gitbucket.core.service
|
||||
|
||||
import gitbucket.core.model._
|
||||
import gitbucket.core.model.Profile._
|
||||
import org.scalatest.FunSpec
|
||||
|
||||
import org.specs2.mutable.Specification
|
||||
class PullRequestServiceSpec extends FunSpec with ServiceSpecBase with PullRequestService with IssuesService {
|
||||
|
||||
class PullRequestServiceSpec extends Specification with ServiceSpecBase with PullRequestService with IssuesService {
|
||||
def swap(r: (Issue, PullRequest)) = (r._2 -> r._1)
|
||||
"PullRequestService.getPullRequestFromBranch" should {
|
||||
"""
|
||||
|
||||
describe("PullRequestService.getPullRequestFromBranch") {
|
||||
it("""should
|
||||
|return pull request if exists pull request from `branch` to `defaultBranch` and not closed.
|
||||
|return pull request if exists pull request from `branch` to othre branch and not closed.
|
||||
|return None if all pull request is closed""".stripMargin.trim in { withTestDB { implicit se =>
|
||||
|return None if all pull request is closed""".stripMargin.trim) { withTestDB { implicit se =>
|
||||
generateNewUserWithDBRepository("user1", "repo1")
|
||||
generateNewUserWithDBRepository("user1", "repo2")
|
||||
generateNewUserWithDBRepository("user2", "repo1")
|
||||
@@ -22,12 +22,12 @@ class PullRequestServiceSpec extends Specification with ServiceSpecBase with Pul
|
||||
val r1 = swap(generateNewPullRequest("user1/repo1/master2", "user1/repo1/head1"))
|
||||
val r2 = swap(generateNewPullRequest("user1/repo1/master", "user1/repo1/head1"))
|
||||
val r3 = swap(generateNewPullRequest("user1/repo1/master4", "user1/repo1/head1"))
|
||||
getPullRequestFromBranch("user1", "repo1", "head1", "master") must_== Some(r2)
|
||||
assert(getPullRequestFromBranch("user1", "repo1", "head1", "master") == Some(r2))
|
||||
updateClosed("user1", "repo1", r2._1.issueId, true)
|
||||
getPullRequestFromBranch("user1", "repo1", "head1", "master").get must beOneOf(r1, r2)
|
||||
assert(Seq(r1, r2).contains(getPullRequestFromBranch("user1", "repo1", "head1", "master").get))
|
||||
updateClosed("user1", "repo1", r1._1.issueId, true)
|
||||
updateClosed("user1", "repo1", r3._1.issueId, true)
|
||||
getPullRequestFromBranch("user1", "repo1", "head1", "master") must beNone
|
||||
assert(getPullRequestFromBranch("user1", "repo1", "head1", "master") == None)
|
||||
} }
|
||||
}
|
||||
}
|
||||
@@ -1,39 +1,33 @@
|
||||
package gitbucket.core.service
|
||||
|
||||
import gitbucket.core.model._
|
||||
import org.specs2.mutable.Specification
|
||||
import org.scalatest.FunSuite
|
||||
|
||||
class RepositoryServiceSpec extends FunSuite with ServiceSpecBase with RepositoryService with AccountService{
|
||||
test("renameRepository can rename CommitState, ProtectedBranches") { withTestDB { implicit session =>
|
||||
val tester = generateNewAccount("tester")
|
||||
createRepository("repo", "root", None, false)
|
||||
val service = new CommitStatusService with ProtectedBranchService {}
|
||||
val id = service.createCommitStatus(
|
||||
userName = "root",
|
||||
repositoryName = "repo",
|
||||
sha = "0e97b8f59f7cdd709418bb59de53f741fd1c1bd7",
|
||||
context = "jenkins/test",
|
||||
state = CommitState.PENDING,
|
||||
targetUrl = Some("http://example.com/target"),
|
||||
description = Some("description"),
|
||||
creator = tester,
|
||||
now = new java.util.Date)
|
||||
|
||||
class RepositoryServiceSpec extends Specification with ServiceSpecBase with RepositoryService with AccountService{
|
||||
"RepositoryService" should {
|
||||
"renameRepository can rename CommitState, ProtectedBranches" in { withTestDB { implicit session =>
|
||||
val tester = generateNewAccount("tester")
|
||||
createRepository("repo","root",None,false)
|
||||
val service = new CommitStatusService with ProtectedBranchService {}
|
||||
val id = service.createCommitStatus(
|
||||
userName = "root",
|
||||
repositoryName = "repo",
|
||||
sha = "0e97b8f59f7cdd709418bb59de53f741fd1c1bd7",
|
||||
context = "jenkins/test",
|
||||
state = CommitState.PENDING,
|
||||
targetUrl = Some("http://example.com/target"),
|
||||
description = Some("description"),
|
||||
creator = tester,
|
||||
now = new java.util.Date)
|
||||
service.enableBranchProtection("root", "repo", "branch", true, Seq("must1", "must2"))
|
||||
var orgPbi = service.getProtectedBranchInfo("root", "repo", "branch")
|
||||
val org = service.getCommitStatus("root","repo", id).get
|
||||
service.enableBranchProtection("root", "repo", "branch", true, Seq("must1", "must2"))
|
||||
|
||||
renameRepository("root","repo","tester","repo2")
|
||||
val orgPbi = service.getProtectedBranchInfo("root", "repo", "branch")
|
||||
val org = service.getCommitStatus("root","repo", id).get
|
||||
|
||||
val neo = service.getCommitStatus("tester","repo2", org.commitId, org.context).get
|
||||
neo must_==
|
||||
org.copy(
|
||||
commitStatusId=neo.commitStatusId,
|
||||
repositoryName="repo2",
|
||||
userName="tester")
|
||||
service.getProtectedBranchInfo("tester", "repo2", "branch") must_==
|
||||
orgPbi.copy(owner="tester", repository="repo2")
|
||||
}}
|
||||
}
|
||||
renameRepository("root","repo","tester","repo2")
|
||||
|
||||
val neo = service.getCommitStatus("tester","repo2", org.commitId, org.context).get
|
||||
assert(neo == org.copy(commitStatusId = neo.commitStatusId, repositoryName = "repo2", userName = "tester"))
|
||||
assert(service.getProtectedBranchInfo("tester", "repo2", "branch") == orgPbi.copy(owner = "tester", repository = "repo2"))
|
||||
}}
|
||||
}
|
||||
|
||||
@@ -1,76 +1,75 @@
|
||||
package gitbucket.core.service
|
||||
|
||||
import org.specs2.mutable.Specification
|
||||
import gitbucket.core.model.WebHook
|
||||
import org.scalatest.FunSuite
|
||||
|
||||
|
||||
class WebHookServiceSpec extends Specification with ServiceSpecBase {
|
||||
class WebHookServiceSpec extends FunSuite with ServiceSpecBase {
|
||||
lazy val service = new WebHookPullRequestService with AccountService with RepositoryService with PullRequestService with IssuesService
|
||||
|
||||
"WebHookPullRequestService.getPullRequestsByRequestForWebhook" should {
|
||||
"find from request branch" in { withTestDB { implicit session =>
|
||||
val user1 = generateNewUserWithDBRepository("user1","repo1")
|
||||
val user2 = generateNewUserWithDBRepository("user2","repo2")
|
||||
val user3 = generateNewUserWithDBRepository("user3","repo3")
|
||||
val issueUser = user("root")
|
||||
val (issue1, pullreq1) = generateNewPullRequest("user1/repo1/master1", "user2/repo2/master2", loginUser="root")
|
||||
val (issue3, pullreq3) = generateNewPullRequest("user3/repo3/master3", "user2/repo2/master2", loginUser="root")
|
||||
val (issue32, pullreq32) = generateNewPullRequest("user3/repo3/master32", "user2/repo2/master2", loginUser="root")
|
||||
generateNewPullRequest("user2/repo2/master2", "user1/repo1/master2")
|
||||
service.addWebHook("user1", "repo1", "webhook1-1", Set(WebHook.PullRequest))
|
||||
service.addWebHook("user1", "repo1", "webhook1-2", Set(WebHook.PullRequest))
|
||||
service.addWebHook("user2", "repo2", "webhook2-1", Set(WebHook.PullRequest))
|
||||
service.addWebHook("user2", "repo2", "webhook2-2", Set(WebHook.PullRequest))
|
||||
service.addWebHook("user3", "repo3", "webhook3-1", Set(WebHook.PullRequest))
|
||||
service.addWebHook("user3", "repo3", "webhook3-2", Set(WebHook.PullRequest))
|
||||
test("WebHookPullRequestService.getPullRequestsByRequestForWebhook") { withTestDB { implicit session =>
|
||||
val user1 = generateNewUserWithDBRepository("user1","repo1")
|
||||
val user2 = generateNewUserWithDBRepository("user2","repo2")
|
||||
val user3 = generateNewUserWithDBRepository("user3","repo3")
|
||||
val issueUser = user("root")
|
||||
val (issue1, pullreq1) = generateNewPullRequest("user1/repo1/master1", "user2/repo2/master2", loginUser="root")
|
||||
val (issue3, pullreq3) = generateNewPullRequest("user3/repo3/master3", "user2/repo2/master2", loginUser="root")
|
||||
val (issue32, pullreq32) = generateNewPullRequest("user3/repo3/master32", "user2/repo2/master2", loginUser="root")
|
||||
generateNewPullRequest("user2/repo2/master2", "user1/repo1/master2")
|
||||
service.addWebHook("user1", "repo1", "webhook1-1", Set(WebHook.PullRequest))
|
||||
service.addWebHook("user1", "repo1", "webhook1-2", Set(WebHook.PullRequest))
|
||||
service.addWebHook("user2", "repo2", "webhook2-1", Set(WebHook.PullRequest))
|
||||
service.addWebHook("user2", "repo2", "webhook2-2", Set(WebHook.PullRequest))
|
||||
service.addWebHook("user3", "repo3", "webhook3-1", Set(WebHook.PullRequest))
|
||||
service.addWebHook("user3", "repo3", "webhook3-2", Set(WebHook.PullRequest))
|
||||
|
||||
service.getPullRequestsByRequestForWebhook("user1","repo1","master1") must_== Map.empty
|
||||
assert(service.getPullRequestsByRequestForWebhook("user1","repo1","master1") == Map.empty)
|
||||
|
||||
var r = service.getPullRequestsByRequestForWebhook("user2","repo2","master2").mapValues(_.map(_.url).toSet)
|
||||
val r = service.getPullRequestsByRequestForWebhook("user2","repo2","master2").mapValues(_.map(_.url).toSet)
|
||||
|
||||
r.size must_== 3
|
||||
r((issue1, issueUser, pullreq1, user1, user2)) must_== Set("webhook1-1","webhook1-2")
|
||||
r((issue3, issueUser, pullreq3, user3, user2)) must_== Set("webhook3-1","webhook3-2")
|
||||
r((issue32, issueUser, pullreq32, user3, user2)) must_== Set("webhook3-1","webhook3-2")
|
||||
assert(r.size == 3)
|
||||
assert(r((issue1, issueUser, pullreq1, user1, user2)) == Set("webhook1-1","webhook1-2"))
|
||||
assert(r((issue3, issueUser, pullreq3, user3, user2)) == Set("webhook3-1","webhook3-2"))
|
||||
assert(r((issue32, issueUser, pullreq32, user3, user2)) == Set("webhook3-1","webhook3-2"))
|
||||
|
||||
// when closed, it not founds.
|
||||
service.updateClosed("user1","repo1",issue1.issueId, true)
|
||||
// when closed, it not founds.
|
||||
service.updateClosed("user1","repo1",issue1.issueId, true)
|
||||
|
||||
var r2 = service.getPullRequestsByRequestForWebhook("user2","repo2","master2").mapValues(_.map(_.url).toSet)
|
||||
r2.size must_== 2
|
||||
r2((issue3, issueUser, pullreq3, user3, user2)) must_== Set("webhook3-1","webhook3-2")
|
||||
r2((issue32, issueUser, pullreq32, user3, user2)) must_== Set("webhook3-1","webhook3-2")
|
||||
} }
|
||||
}
|
||||
val r2 = service.getPullRequestsByRequestForWebhook("user2","repo2","master2").mapValues(_.map(_.url).toSet)
|
||||
assert(r2.size == 2)
|
||||
assert(r2((issue3, issueUser, pullreq3, user3, user2)) == Set("webhook3-1","webhook3-2"))
|
||||
assert(r2((issue32, issueUser, pullreq32, user3, user2)) == Set("webhook3-1","webhook3-2"))
|
||||
} }
|
||||
|
||||
"add and get and update and delete" in { withTestDB { implicit session =>
|
||||
test("add and get and update and delete") { withTestDB { implicit session =>
|
||||
val user1 = generateNewUserWithDBRepository("user1","repo1")
|
||||
service.addWebHook("user1", "repo1", "http://example.com", Set(WebHook.PullRequest))
|
||||
service.getWebHooks("user1", "repo1") must_== List((WebHook("user1","repo1","http://example.com"),Set(WebHook.PullRequest)))
|
||||
service.getWebHook("user1", "repo1", "http://example.com") must_== Some((WebHook("user1","repo1","http://example.com"),Set(WebHook.PullRequest)))
|
||||
service.getWebHooksByEvent("user1", "repo1", WebHook.PullRequest) must_== List((WebHook("user1","repo1","http://example.com")))
|
||||
service.getWebHooksByEvent("user1", "repo1", WebHook.Push) must_== Nil
|
||||
service.getWebHook("user1", "repo1", "http://example.com2") must_== None
|
||||
service.getWebHook("user2", "repo1", "http://example.com") must_== None
|
||||
service.getWebHook("user1", "repo2", "http://example.com") must_== None
|
||||
assert(service.getWebHooks("user1", "repo1") == List((WebHook("user1","repo1","http://example.com"),Set(WebHook.PullRequest))))
|
||||
assert(service.getWebHook("user1", "repo1", "http://example.com") == Some((WebHook("user1","repo1","http://example.com"),Set(WebHook.PullRequest))))
|
||||
assert(service.getWebHooksByEvent("user1", "repo1", WebHook.PullRequest) == List((WebHook("user1","repo1","http://example.com"))))
|
||||
assert(service.getWebHooksByEvent("user1", "repo1", WebHook.Push) == Nil)
|
||||
assert(service.getWebHook("user1", "repo1", "http://example.com2") == None)
|
||||
assert(service.getWebHook("user2", "repo1", "http://example.com") == None)
|
||||
assert(service.getWebHook("user1", "repo2", "http://example.com") == None)
|
||||
service.updateWebHook("user1", "repo1", "http://example.com", Set(WebHook.Push, WebHook.Issues))
|
||||
service.getWebHook("user1", "repo1", "http://example.com") must_== Some((WebHook("user1","repo1","http://example.com"),Set(WebHook.Push, WebHook.Issues)))
|
||||
service.getWebHooksByEvent("user1", "repo1", WebHook.PullRequest) must_== Nil
|
||||
service.getWebHooksByEvent("user1", "repo1", WebHook.Push) must_== List((WebHook("user1","repo1","http://example.com")))
|
||||
assert(service.getWebHook("user1", "repo1", "http://example.com") == Some((WebHook("user1","repo1","http://example.com"),Set(WebHook.Push, WebHook.Issues))))
|
||||
assert(service.getWebHooksByEvent("user1", "repo1", WebHook.PullRequest) == Nil)
|
||||
assert(service.getWebHooksByEvent("user1", "repo1", WebHook.Push) == List((WebHook("user1","repo1","http://example.com"))))
|
||||
service.deleteWebHook("user1", "repo1", "http://example.com")
|
||||
service.getWebHook("user1", "repo1", "http://example.com") must_== None
|
||||
assert(service.getWebHook("user1", "repo1", "http://example.com") == None)
|
||||
} }
|
||||
"getWebHooks, getWebHooksByEvent" in { withTestDB { implicit session =>
|
||||
|
||||
test("getWebHooks, getWebHooksByEvent") { withTestDB { implicit session =>
|
||||
val user1 = generateNewUserWithDBRepository("user1","repo1")
|
||||
service.addWebHook("user1", "repo1", "http://example.com/1", Set(WebHook.PullRequest))
|
||||
service.addWebHook("user1", "repo1", "http://example.com/2", Set(WebHook.Push))
|
||||
service.addWebHook("user1", "repo1", "http://example.com/3", Set(WebHook.PullRequest,WebHook.Push))
|
||||
service.getWebHooks("user1", "repo1") must_== List(
|
||||
assert(service.getWebHooks("user1", "repo1") == List(
|
||||
WebHook("user1","repo1","http://example.com/1")->Set(WebHook.PullRequest),
|
||||
WebHook("user1","repo1","http://example.com/2")->Set(WebHook.Push),
|
||||
WebHook("user1","repo1","http://example.com/3")->Set(WebHook.PullRequest,WebHook.Push))
|
||||
service.getWebHooksByEvent("user1", "repo1", WebHook.PullRequest) must_== List(
|
||||
WebHook("user1","repo1","http://example.com/3")->Set(WebHook.PullRequest,WebHook.Push)))
|
||||
assert(service.getWebHooksByEvent("user1", "repo1", WebHook.PullRequest) == List(
|
||||
WebHook("user1","repo1","http://example.com/1"),
|
||||
WebHook("user1","repo1","http://example.com/3"))
|
||||
WebHook("user1","repo1","http://example.com/3")))
|
||||
} }
|
||||
}
|
||||
@@ -1,39 +1,35 @@
|
||||
package gitbucket.core.ssh
|
||||
|
||||
import org.specs2.mutable._
|
||||
import org.specs2.mock.Mockito
|
||||
import org.apache.sshd.server.command.UnknownCommand
|
||||
import javax.servlet.ServletContext
|
||||
import org.scalatest.FunSpec
|
||||
|
||||
class GitCommandFactorySpec extends Specification with Mockito {
|
||||
class GitCommandFactorySpec extends FunSpec {
|
||||
|
||||
val factory = new GitCommandFactory("http://localhost:8080")
|
||||
|
||||
"createCommand" should {
|
||||
"returns GitReceivePack when command is git-receive-pack" in {
|
||||
factory.createCommand("git-receive-pack '/owner/repo.git'").isInstanceOf[DefaultGitReceivePack] must beTrue
|
||||
factory.createCommand("git-receive-pack '/owner/repo.wiki.git'").isInstanceOf[DefaultGitReceivePack] must beTrue
|
||||
|
||||
describe("createCommand") {
|
||||
it("should return GitReceivePack when command is git-receive-pack"){
|
||||
assert(factory.createCommand("git-receive-pack '/owner/repo.git'").isInstanceOf[DefaultGitReceivePack] == true)
|
||||
assert(factory.createCommand("git-receive-pack '/owner/repo.wiki.git'").isInstanceOf[DefaultGitReceivePack] == true)
|
||||
}
|
||||
"returns GitUploadPack when command is git-upload-pack" in {
|
||||
factory.createCommand("git-upload-pack '/owner/repo.git'").isInstanceOf[DefaultGitUploadPack] must beTrue
|
||||
factory.createCommand("git-upload-pack '/owner/repo.wiki.git'").isInstanceOf[DefaultGitUploadPack] must beTrue
|
||||
|
||||
it("should return GitUploadPack when command is git-upload-pack"){
|
||||
assert(factory.createCommand("git-upload-pack '/owner/repo.git'").isInstanceOf[DefaultGitUploadPack] == true)
|
||||
assert(factory.createCommand("git-upload-pack '/owner/repo.wiki.git'").isInstanceOf[DefaultGitUploadPack] == true)
|
||||
}
|
||||
"returns UnknownCommand when command is not git-(upload|receive)-pack" in {
|
||||
factory.createCommand("git- '/owner/repo.git'").isInstanceOf[UnknownCommand] must beTrue
|
||||
factory.createCommand("git-pack '/owner/repo.git'").isInstanceOf[UnknownCommand] must beTrue
|
||||
factory.createCommand("git-a-pack '/owner/repo.git'").isInstanceOf[UnknownCommand] must beTrue
|
||||
factory.createCommand("git-up-pack '/owner/repo.git'").isInstanceOf[UnknownCommand] must beTrue
|
||||
factory.createCommand("\ngit-upload-pack '/owner/repo.git'").isInstanceOf[UnknownCommand] must beTrue
|
||||
it("should return UnknownCommand when command is not git-(upload|receive)-pack"){
|
||||
assert(factory.createCommand("git- '/owner/repo.git'").isInstanceOf[UnknownCommand] == true)
|
||||
assert(factory.createCommand("git-pack '/owner/repo.git'").isInstanceOf[UnknownCommand] == true)
|
||||
assert(factory.createCommand("git-a-pack '/owner/repo.git'").isInstanceOf[UnknownCommand] == true)
|
||||
assert(factory.createCommand("git-up-pack '/owner/repo.git'").isInstanceOf[UnknownCommand] == true)
|
||||
assert(factory.createCommand("\ngit-upload-pack '/owner/repo.git'").isInstanceOf[UnknownCommand] == true)
|
||||
}
|
||||
"returns UnknownCommand when git command has no valid arguments" in {
|
||||
it("should return UnknownCommand when git command has no valid arguments"){
|
||||
// must be: git-upload-pack '/owner/repository_name.git'
|
||||
factory.createCommand("git-upload-pack").isInstanceOf[UnknownCommand] must beTrue
|
||||
factory.createCommand("git-upload-pack /owner/repo.git").isInstanceOf[UnknownCommand] must beTrue
|
||||
factory.createCommand("git-upload-pack 'owner/repo.git'").isInstanceOf[UnknownCommand] must beTrue
|
||||
factory.createCommand("git-upload-pack '/ownerrepo.git'").isInstanceOf[UnknownCommand] must beTrue
|
||||
factory.createCommand("git-upload-pack '/owner/repo.wiki'").isInstanceOf[UnknownCommand] must beTrue
|
||||
assert(factory.createCommand("git-upload-pack").isInstanceOf[UnknownCommand] == true)
|
||||
assert(factory.createCommand("git-upload-pack /owner/repo.git").isInstanceOf[UnknownCommand] == true)
|
||||
assert(factory.createCommand("git-upload-pack 'owner/repo.git'").isInstanceOf[UnknownCommand] == true)
|
||||
assert(factory.createCommand("git-upload-pack '/ownerrepo.git'").isInstanceOf[UnknownCommand] == true)
|
||||
assert(factory.createCommand("git-upload-pack '/owner/repo.wiki'").isInstanceOf[UnknownCommand] == true)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
package gitbucket.core.util
|
||||
|
||||
import org.specs2.mutable._
|
||||
import org.scalatest.FunSpec
|
||||
|
||||
class DirectorySpec extends FunSpec {
|
||||
|
||||
class DirectorySpec extends Specification {
|
||||
"GitBucketHome" should {
|
||||
"set under target in test scope" in {
|
||||
Directory.GitBucketHome mustEqual new java.io.File("target/gitbucket_home_for_test").getAbsolutePath
|
||||
}
|
||||
"exists" in {
|
||||
new java.io.File(Directory.GitBucketHome).exists
|
||||
describe("GitBucketHome"){
|
||||
it("should set under target in test scope"){
|
||||
assert(Directory.GitBucketHome == new java.io.File("target/gitbucket_home_for_test").getAbsolutePath)
|
||||
}
|
||||
}
|
||||
// test("GitBucketHome should exists"){
|
||||
// new java.io.File(Directory.GitBucketHome).exists
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
@@ -1,103 +1,104 @@
|
||||
package gitbucket.core.util
|
||||
|
||||
import org.specs2.mutable._
|
||||
import GitSpecUtil._
|
||||
import org.scalatest.FunSuite
|
||||
|
||||
class JGitUtilSpec extends Specification {
|
||||
class JGitUtilSpec extends FunSuite {
|
||||
|
||||
"getFileList(git: Git, revision: String, path)" should {
|
||||
test("getFileList(git: Git, revision: String, path)"){
|
||||
withTestRepository { git =>
|
||||
def list(branch: String, path: String) =
|
||||
JGitUtil.getFileList(git, branch, path).map(finfo => (finfo.name, finfo.message, finfo.isDirectory))
|
||||
list("master", ".") mustEqual Nil
|
||||
list("master", "dir/subdir") mustEqual Nil
|
||||
list("branch", ".") mustEqual Nil
|
||||
list("branch", "dir/subdir") mustEqual Nil
|
||||
assert(list("master", ".") == Nil)
|
||||
assert(list("master", "dir/subdir") == Nil)
|
||||
assert(list("branch", ".") == Nil)
|
||||
assert(list("branch", "dir/subdir") == Nil)
|
||||
|
||||
createFile(git, "master", "README.md", "body1", message = "commit1")
|
||||
|
||||
list("master", ".") mustEqual List(("README.md", "commit1", false))
|
||||
list("master", "dir/subdir") mustEqual Nil
|
||||
list("branch", ".") mustEqual Nil
|
||||
list("branch", "dir/subdir") mustEqual Nil
|
||||
assert(list("master", ".") == List(("README.md", "commit1", false)))
|
||||
assert(list("master", "dir/subdir") == Nil)
|
||||
assert(list("branch", ".") == Nil)
|
||||
assert(list("branch", "dir/subdir") == Nil)
|
||||
|
||||
createFile(git, "master", "README.md", "body2", message = "commit2")
|
||||
|
||||
list("master", ".") mustEqual List(("README.md", "commit2", false))
|
||||
list("master", "dir/subdir") mustEqual Nil
|
||||
list("branch", ".") mustEqual Nil
|
||||
list("branch", "dir/subdir") mustEqual Nil
|
||||
assert(list("master", ".") == List(("README.md", "commit2", false)))
|
||||
assert(list("master", "dir/subdir") == Nil)
|
||||
assert(list("branch", ".") == Nil)
|
||||
assert(list("branch", "dir/subdir") == Nil)
|
||||
|
||||
createFile(git, "master", "dir/subdir/File3.md", "body3", message = "commit3")
|
||||
|
||||
list("master", ".") mustEqual List(("dir/subdir", "commit3", true), ("README.md", "commit2", false))
|
||||
list("master", "dir/subdir") mustEqual List(("File3.md", "commit3", false))
|
||||
list("branch", ".") mustEqual Nil
|
||||
list("branch", "dir/subdir") mustEqual Nil
|
||||
assert(list("master", ".") == List(("dir/subdir", "commit3", true), ("README.md", "commit2", false)))
|
||||
assert(list("master", "dir/subdir") == List(("File3.md", "commit3", false)))
|
||||
assert(list("branch", ".") == Nil)
|
||||
assert(list("branch", "dir/subdir") == Nil)
|
||||
|
||||
createFile(git, "master", "dir/subdir/File4.md", "body4", message = "commit4")
|
||||
|
||||
list("master", ".") mustEqual List(("dir/subdir", "commit4", true), ("README.md", "commit2", false))
|
||||
list("master", "dir/subdir") mustEqual List(("File3.md", "commit3", false), ("File4.md", "commit4", false))
|
||||
list("branch", ".") mustEqual Nil
|
||||
list("branch", "dir/subdir") mustEqual Nil
|
||||
assert(list("master", ".") == List(("dir/subdir", "commit4", true), ("README.md", "commit2", false)))
|
||||
assert(list("master", "dir/subdir") == List(("File3.md", "commit3", false), ("File4.md", "commit4", false)))
|
||||
assert(list("branch", ".") == Nil)
|
||||
assert(list("branch", "dir/subdir") == Nil)
|
||||
|
||||
createFile(git, "master", "README5.md", "body5", message = "commit5")
|
||||
|
||||
list("master", ".") mustEqual List(("dir/subdir", "commit4", true), ("README.md", "commit2", false), ("README5.md", "commit5", false))
|
||||
list("master", "dir/subdir") mustEqual List(("File3.md", "commit3", false), ("File4.md", "commit4", false))
|
||||
list("branch", ".") mustEqual Nil
|
||||
list("branch", "dir/subdir") mustEqual Nil
|
||||
assert(list("master", ".") == List(("dir/subdir", "commit4", true), ("README.md", "commit2", false), ("README5.md", "commit5", false)))
|
||||
assert(list("master", "dir/subdir") == List(("File3.md", "commit3", false), ("File4.md", "commit4", false)))
|
||||
assert(list("branch", ".") == Nil)
|
||||
assert(list("branch", "dir/subdir") == Nil)
|
||||
|
||||
createFile(git, "master", "README.md", "body6", message = "commit6")
|
||||
|
||||
list("master", ".") mustEqual List(("dir/subdir", "commit4", true), ("README.md", "commit6", false), ("README5.md", "commit5", false))
|
||||
list("master", "dir/subdir") mustEqual List(("File3.md", "commit3", false), ("File4.md", "commit4", false))
|
||||
list("branch", ".") mustEqual Nil
|
||||
list("branch", "dir/subdir") mustEqual Nil
|
||||
assert(list("master", ".") == List(("dir/subdir", "commit4", true), ("README.md", "commit6", false), ("README5.md", "commit5", false)))
|
||||
assert(list("master", "dir/subdir") == List(("File3.md", "commit3", false), ("File4.md", "commit4", false)))
|
||||
assert(list("branch", ".") == Nil)
|
||||
assert(list("branch", "dir/subdir") == Nil)
|
||||
|
||||
git.branchCreate().setName("branch").setStartPoint("master").call()
|
||||
|
||||
list("master", ".") mustEqual List(("dir/subdir", "commit4", true), ("README.md", "commit6", false), ("README5.md", "commit5", false))
|
||||
list("master", "dir/subdir") mustEqual List(("File3.md", "commit3", false), ("File4.md", "commit4", false))
|
||||
list("branch", ".") mustEqual List(("dir/subdir", "commit4", true), ("README.md", "commit6", false), ("README5.md", "commit5", false))
|
||||
list("branch", "dir/subdir") mustEqual List(("File3.md", "commit3", false), ("File4.md", "commit4", false))
|
||||
assert(list("master", ".") == List(("dir/subdir", "commit4", true), ("README.md", "commit6", false), ("README5.md", "commit5", false)))
|
||||
assert(list("master", "dir/subdir") == List(("File3.md", "commit3", false), ("File4.md", "commit4", false)))
|
||||
assert(list("branch", ".") == List(("dir/subdir", "commit4", true), ("README.md", "commit6", false), ("README5.md", "commit5", false)))
|
||||
assert(list("branch", "dir/subdir") == List(("File3.md", "commit3", false), ("File4.md", "commit4", false)))
|
||||
|
||||
createFile(git, "branch", "dir/subdir/File3.md", "body7", message = "commit7")
|
||||
|
||||
list("master", ".") mustEqual List(("dir/subdir", "commit4", true), ("README.md", "commit6", false), ("README5.md", "commit5", false))
|
||||
list("master", "dir/subdir") mustEqual List(("File3.md", "commit3", false), ("File4.md", "commit4", false))
|
||||
list("branch", ".") mustEqual List(("dir/subdir", "commit7", true), ("README.md", "commit6", false), ("README5.md", "commit5", false))
|
||||
list("branch", "dir/subdir") mustEqual List(("File3.md", "commit7", false), ("File4.md", "commit4", false))
|
||||
assert(list("master", ".") == List(("dir/subdir", "commit4", true), ("README.md", "commit6", false), ("README5.md", "commit5", false)))
|
||||
assert(list("master", "dir/subdir") == List(("File3.md", "commit3", false), ("File4.md", "commit4", false)))
|
||||
assert(list("branch", ".") == List(("dir/subdir", "commit7", true), ("README.md", "commit6", false), ("README5.md", "commit5", false)))
|
||||
assert(list("branch", "dir/subdir") == List(("File3.md", "commit7", false), ("File4.md", "commit4", false)))
|
||||
|
||||
createFile(git, "master", "dir8/File8.md", "body8", message = "commit8")
|
||||
|
||||
list("master", ".") mustEqual List(("dir/subdir", "commit4", true), ("dir8", "commit8", true), ("README.md", "commit6", false), ("README5.md", "commit5", false))
|
||||
list("master", "dir/subdir") mustEqual List(("File3.md", "commit3", false), ("File4.md", "commit4", false))
|
||||
list("branch", ".") mustEqual List(("dir/subdir", "commit7", true), ("README.md", "commit6", false), ("README5.md", "commit5", false))
|
||||
list("branch", "dir/subdir") mustEqual List(("File3.md", "commit7", false), ("File4.md", "commit4", false))
|
||||
assert(list("master", ".") == List(("dir/subdir", "commit4", true), ("dir8", "commit8", true), ("README.md", "commit6", false), ("README5.md", "commit5", false)))
|
||||
assert(list("master", "dir/subdir") == List(("File3.md", "commit3", false), ("File4.md", "commit4", false)))
|
||||
assert(list("branch", ".") == List(("dir/subdir", "commit7", true), ("README.md", "commit6", false), ("README5.md", "commit5", false)))
|
||||
assert(list("branch", "dir/subdir") == List(("File3.md", "commit7", false), ("File4.md", "commit4", false)))
|
||||
|
||||
createFile(git, "branch", "dir/subdir9/File9.md", "body9", message = "commit9")
|
||||
|
||||
list("master", ".") mustEqual List(("dir/subdir", "commit4", true), ("dir8", "commit8", true), ("README.md", "commit6", false), ("README5.md", "commit5", false))
|
||||
list("master", "dir/subdir") mustEqual List(("File3.md", "commit3", false), ("File4.md", "commit4", false))
|
||||
list("branch", ".") mustEqual List(("dir", "commit9", true), ("README.md", "commit6", false), ("README5.md", "commit5", false))
|
||||
list("branch", "dir/subdir") mustEqual List(("File3.md", "commit7", false), ("File4.md", "commit4", false))
|
||||
assert(list("master", ".") == List(("dir/subdir", "commit4", true), ("dir8", "commit8", true), ("README.md", "commit6", false), ("README5.md", "commit5", false)))
|
||||
assert(list("master", "dir/subdir") == List(("File3.md", "commit3", false), ("File4.md", "commit4", false)))
|
||||
assert(list("branch", ".") == List(("dir", "commit9", true), ("README.md", "commit6", false), ("README5.md", "commit5", false)))
|
||||
assert(list("branch", "dir/subdir") == List(("File3.md", "commit7", false), ("File4.md", "commit4", false)))
|
||||
|
||||
mergeAndCommit(git, "master", "branch", message = "merge10")
|
||||
|
||||
list("master", ".") mustEqual List(("dir", "commit9", true), ("dir8", "commit8", true), ("README.md", "commit6", false), ("README5.md", "commit5", false))
|
||||
list("master", "dir/subdir") mustEqual List(("File3.md", "commit7", false), ("File4.md", "commit4", false))
|
||||
assert(list("master", ".") == List(("dir", "commit9", true), ("dir8", "commit8", true), ("README.md", "commit6", false), ("README5.md", "commit5", false)))
|
||||
assert(list("master", "dir/subdir") == List(("File3.md", "commit7", false), ("File4.md", "commit4", false)))
|
||||
}
|
||||
}
|
||||
"getFileList subfolder multi-origin (issue #721)" should {
|
||||
|
||||
test("getFileList subfolder multi-origin (issue #721)") {
|
||||
withTestRepository { git =>
|
||||
def list(branch: String, path: String) =
|
||||
JGitUtil.getFileList(git, branch, path).map(finfo => (finfo.name, finfo.message, finfo.isDirectory))
|
||||
createFile(git, "master", "README.md", "body1", message = "commit1")
|
||||
createFile(git, "branch", "test/text2.txt", "body2", message = "commit2")
|
||||
mergeAndCommit(git, "master", "branch", message = "merge3")
|
||||
list("master", "test") mustEqual List(("text2.txt", "commit2", false))
|
||||
assert(list("master", "test") == List(("text2.txt", "commit2", false)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,66 +1,66 @@
|
||||
package gitbucket.core.util
|
||||
|
||||
import org.specs2.mutable._
|
||||
import org.scalatest.FunSpec
|
||||
|
||||
class StringUtilSpec extends Specification {
|
||||
class StringUtilSpec extends FunSpec {
|
||||
|
||||
"urlEncode" should {
|
||||
"encode whitespace to %20" in {
|
||||
describe("urlEncode") {
|
||||
it("should encode whitespace to %20") {
|
||||
val encoded = StringUtil.urlEncode("aa bb")
|
||||
encoded mustEqual "aa%20bb"
|
||||
assert(encoded == "aa%20bb")
|
||||
}
|
||||
}
|
||||
|
||||
"urlDecode" should {
|
||||
"decode encoded string to original string" in {
|
||||
describe("urlDecode") {
|
||||
it("should decode encoded string to original string") {
|
||||
val encoded = StringUtil.urlEncode("あいうえお")
|
||||
StringUtil.urlDecode(encoded) mustEqual "あいうえお"
|
||||
assert(StringUtil.urlDecode(encoded) == "あいうえお")
|
||||
}
|
||||
"decode en%20 to whitespace" in {
|
||||
StringUtil.urlDecode("aa%20bb") mustEqual "aa bb"
|
||||
it("should decode en%20 to whitespace") {
|
||||
assert(StringUtil.urlDecode("aa%20bb") == "aa bb")
|
||||
}
|
||||
}
|
||||
|
||||
"splitWords" should {
|
||||
"split string by whitespaces" in {
|
||||
describe("splitWords") {
|
||||
it("should split string by whitespaces") {
|
||||
val split = StringUtil.splitWords("aa bb\tcc dd \t ee")
|
||||
split mustEqual Array("aa", "bb", "cc", "dd", "ee")
|
||||
assert(split === Array("aa", "bb", "cc", "dd", "ee"))
|
||||
}
|
||||
}
|
||||
|
||||
"escapeHtml" should {
|
||||
"escape &, <, > and \"" in {
|
||||
StringUtil.escapeHtml("<a href=\"/test\">a & b</a>") mustEqual "<a href="/test">a & b</a>"
|
||||
describe("escapeHtml") {
|
||||
it("should escape &, <, > and \"") {
|
||||
assert(StringUtil.escapeHtml("<a href=\"/test\">a & b</a>") == "<a href="/test">a & b</a>")
|
||||
}
|
||||
}
|
||||
|
||||
"md5" should {
|
||||
"generate MD5 hash" in {
|
||||
StringUtil.md5("abc") mustEqual "900150983cd24fb0d6963f7d28e17f72"
|
||||
describe("md5") {
|
||||
it("should generate MD5 hash") {
|
||||
assert(StringUtil.md5("abc") == "900150983cd24fb0d6963f7d28e17f72")
|
||||
}
|
||||
}
|
||||
|
||||
"sha1" should {
|
||||
"generate SHA1 hash" in {
|
||||
StringUtil.sha1("abc") mustEqual "a9993e364706816aba3e25717850c26c9cd0d89d"
|
||||
describe("sha1") {
|
||||
it("should generate SHA1 hash") {
|
||||
assert(StringUtil.sha1("abc") == "a9993e364706816aba3e25717850c26c9cd0d89d")
|
||||
}
|
||||
}
|
||||
|
||||
"extractIssueId" should {
|
||||
"extract '#xxx' and return extracted id" in {
|
||||
StringUtil.extractIssueId("(refs #123)").toSeq mustEqual Seq("123")
|
||||
describe("extractIssueId") {
|
||||
it("should extract '#xxx' and return extracted id") {
|
||||
assert(StringUtil.extractIssueId("(refs #123)").toSeq == Seq("123"))
|
||||
}
|
||||
"returns Nil from message which does not contain #xxx" in {
|
||||
StringUtil.extractIssueId("this is test!").toSeq mustEqual Nil
|
||||
it("should return Nil from message which does not contain #xxx") {
|
||||
assert(StringUtil.extractIssueId("this is test!").toSeq == Nil)
|
||||
}
|
||||
}
|
||||
|
||||
"extractCloseId" should {
|
||||
"extract 'close #xxx' and return extracted id" in {
|
||||
StringUtil.extractCloseId("(close #123)").toSeq mustEqual Seq("123")
|
||||
describe("extractCloseId") {
|
||||
it("should extract 'close #xxx' and return extracted id") {
|
||||
assert(StringUtil.extractCloseId("(close #123)").toSeq == Seq("123"))
|
||||
}
|
||||
"returns Nil from message which does not contain close command" in {
|
||||
StringUtil.extractCloseId("(refs #123)").toSeq mustEqual Nil
|
||||
it("should returns Nil from message which does not contain close command") {
|
||||
assert(StringUtil.extractCloseId("(refs #123)").toSeq == Nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,35 +1,35 @@
|
||||
package gitbucket.core.util
|
||||
|
||||
import org.specs2.mutable._
|
||||
import org.scalatra.i18n.Messages
|
||||
import org.scalatest.FunSpec
|
||||
|
||||
class ValidationsSpec extends Specification with Validations {
|
||||
class ValidationsSpec extends FunSpec with Validations {
|
||||
|
||||
"identifier" should {
|
||||
"validate id string " in {
|
||||
identifier.validate("id", "aa_ZZ-00.01", null) mustEqual None
|
||||
identifier.validate("id", "_aaaa", null) mustEqual Some("id starts with invalid character.")
|
||||
identifier.validate("id", "-aaaa", null) mustEqual Some("id starts with invalid character.")
|
||||
identifier.validate("id", "aa_ZZ#01", null) mustEqual Some("id contains invalid character.")
|
||||
describe("identifier") {
|
||||
it("should validate id string ") {
|
||||
assert(identifier.validate("id", "aa_ZZ-00.01", null) == None)
|
||||
assert(identifier.validate("id", "_aaaa", null) == Some("id starts with invalid character."))
|
||||
assert(identifier.validate("id", "-aaaa", null) == Some("id starts with invalid character."))
|
||||
assert(identifier.validate("id", "aa_ZZ#01", null) == Some("id contains invalid character."))
|
||||
}
|
||||
}
|
||||
|
||||
"color" should {
|
||||
"validate color string " in {
|
||||
describe("color") {
|
||||
it("should validate color string ") {
|
||||
val messages = Messages()
|
||||
color.validate("color", "#88aaff", messages) mustEqual None
|
||||
color.validate("color", "#gghhii", messages) mustEqual Some("color must be '#[0-9a-fA-F]{6}'.")
|
||||
assert(color.validate("color", "#88aaff", messages) == None)
|
||||
assert(color.validate("color", "#gghhii", messages) == Some("color must be '#[0-9a-fA-F]{6}'."))
|
||||
}
|
||||
}
|
||||
|
||||
"date" should {
|
||||
describe("date") {
|
||||
// "validate date string " in {
|
||||
// date().validate("date", "2013-10-05", Map[String, String]()) mustEqual Nil
|
||||
// date().validate("date", "2013-10-5" , Map[String, String]()) mustEqual List(("date", "date must be '\\d{4}-\\d{2}-\\d{2}'."))
|
||||
// }
|
||||
"convert date string " in {
|
||||
it("should convert date string ") {
|
||||
val result = date().convert("2013-10-05", null)
|
||||
new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(result) mustEqual "2013-10-05 00:00:00"
|
||||
assert(new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(result) == "2013-10-05 00:00:00")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,74 +5,76 @@ import java.util.Date
|
||||
import gitbucket.core.model.Account
|
||||
import gitbucket.core.service.{SystemSettingsService, RequestCache}
|
||||
import gitbucket.core.controller.Context
|
||||
import org.specs2.mutable._
|
||||
import org.specs2.mock.Mockito
|
||||
import SystemSettingsService.SystemSettings
|
||||
import javax.servlet.http.HttpServletRequest
|
||||
import play.twirl.api.Html
|
||||
import org.scalatest.FunSpec
|
||||
import org.scalatest.mock.MockitoSugar
|
||||
import org.mockito.Mockito._
|
||||
|
||||
class AvatarImageProviderSpec extends Specification with Mockito {
|
||||
|
||||
class AvatarImageProviderSpec extends FunSpec with MockitoSugar {
|
||||
|
||||
val request = mock[HttpServletRequest]
|
||||
request.getRequestURL returns new StringBuffer("http://localhost:8080/path.html")
|
||||
request.getRequestURI returns "/path.html"
|
||||
request.getContextPath returns ""
|
||||
when(request.getRequestURL).thenReturn(new StringBuffer("http://localhost:8080/path.html"))
|
||||
when(request.getRequestURI).thenReturn("/path.html")
|
||||
when(request.getContextPath).thenReturn("")
|
||||
|
||||
"getAvatarImageHtml" should {
|
||||
"show Gravatar image for no image account if gravatar integration is enabled" in {
|
||||
describe("getAvatarImageHtml") {
|
||||
it("should show Gravatar image for no image account if gravatar integration is enabled") {
|
||||
implicit val context = Context(createSystemSettings(true), None, request)
|
||||
val provider = new AvatarImageProviderImpl(Some(createAccount(None)))
|
||||
|
||||
provider.toHtml("user", 32).toString mustEqual
|
||||
"<img src=\"https://www.gravatar.com/avatar/d41d8cd98f00b204e9800998ecf8427e?s=32&d=retro&r=g\" class=\"avatar\" style=\"width: 32px; height: 32px;\" />"
|
||||
assert(provider.toHtml("user", 32).toString ==
|
||||
"<img src=\"https://www.gravatar.com/avatar/d41d8cd98f00b204e9800998ecf8427e?s=32&d=retro&r=g\" class=\"avatar\" style=\"width: 32px; height: 32px;\" />")
|
||||
}
|
||||
|
||||
"show uploaded image even if gravatar integration is enabled" in {
|
||||
it("should show uploaded image even if gravatar integration is enabled") {
|
||||
implicit val context = Context(createSystemSettings(true), None, request)
|
||||
val provider = new AvatarImageProviderImpl(Some(createAccount(Some("icon.png"))))
|
||||
|
||||
provider.toHtml("user", 32).toString mustEqual
|
||||
"<img src=\"/user/_avatar\" class=\"avatar\" style=\"width: 32px; height: 32px;\" />"
|
||||
assert(provider.toHtml("user", 32).toString ==
|
||||
"<img src=\"/user/_avatar\" class=\"avatar\" style=\"width: 32px; height: 32px;\" />")
|
||||
}
|
||||
|
||||
"show local image for no image account if gravatar integration is disabled" in {
|
||||
it("should show local image for no image account if gravatar integration is disabled") {
|
||||
implicit val context = Context(createSystemSettings(false), None, request)
|
||||
val provider = new AvatarImageProviderImpl(Some(createAccount(None)))
|
||||
|
||||
provider.toHtml("user", 32).toString mustEqual
|
||||
"<img src=\"/user/_avatar\" class=\"avatar\" style=\"width: 32px; height: 32px;\" />"
|
||||
assert(provider.toHtml("user", 32).toString ==
|
||||
"<img src=\"/user/_avatar\" class=\"avatar\" style=\"width: 32px; height: 32px;\" />")
|
||||
}
|
||||
|
||||
"show Gravatar image for specified mail address if gravatar integration is enabled" in {
|
||||
it("should show Gravatar image for specified mail address if gravatar integration is enabled") {
|
||||
implicit val context = Context(createSystemSettings(true), None, request)
|
||||
val provider = new AvatarImageProviderImpl(None)
|
||||
|
||||
provider.toHtml("user", 20, "hoge@hoge.com").toString mustEqual
|
||||
"<img src=\"https://www.gravatar.com/avatar/4712f9b0e63f56ad952ad387eaa23b9c?s=20&d=retro&r=g\" class=\"avatar-mini\" style=\"width: 20px; height: 20px;\" />"
|
||||
assert(provider.toHtml("user", 20, "hoge@hoge.com").toString ==
|
||||
"<img src=\"https://www.gravatar.com/avatar/4712f9b0e63f56ad952ad387eaa23b9c?s=20&d=retro&r=g\" class=\"avatar-mini\" style=\"width: 20px; height: 20px;\" />")
|
||||
}
|
||||
|
||||
"show unknown image for unknown user if gravatar integration is enabled" in {
|
||||
it("should show unknown image for unknown user if gravatar integration is enabled") {
|
||||
implicit val context = Context(createSystemSettings(true), None, request)
|
||||
val provider = new AvatarImageProviderImpl(None)
|
||||
|
||||
provider.toHtml("user", 20).toString mustEqual
|
||||
"<img src=\"/_unknown/_avatar\" class=\"avatar-mini\" style=\"width: 20px; height: 20px;\" />"
|
||||
assert(provider.toHtml("user", 20).toString ==
|
||||
"<img src=\"/_unknown/_avatar\" class=\"avatar-mini\" style=\"width: 20px; height: 20px;\" />")
|
||||
}
|
||||
|
||||
"show unknown image for specified mail address if gravatar integration is disabled" in {
|
||||
it("should show unknown image for specified mail address if gravatar integration is disabled") {
|
||||
implicit val context = Context(createSystemSettings(false), None, request)
|
||||
val provider = new AvatarImageProviderImpl(None)
|
||||
|
||||
provider.toHtml("user", 20, "hoge@hoge.com").toString mustEqual
|
||||
"<img src=\"/_unknown/_avatar\" class=\"avatar-mini\" style=\"width: 20px; height: 20px;\" />"
|
||||
assert(provider.toHtml("user", 20, "hoge@hoge.com").toString ==
|
||||
"<img src=\"/_unknown/_avatar\" class=\"avatar-mini\" style=\"width: 20px; height: 20px;\" />")
|
||||
}
|
||||
|
||||
"add tooltip if it's enabled" in {
|
||||
it("should add tooltip if it's enabled") {
|
||||
implicit val context = Context(createSystemSettings(false), None, request)
|
||||
val provider = new AvatarImageProviderImpl(None)
|
||||
|
||||
provider.toHtml("user", 20, "hoge@hoge.com", true).toString mustEqual
|
||||
"<img src=\"/_unknown/_avatar\" class=\"avatar-mini\" style=\"width: 20px; height: 20px;\" data-toggle=\"tooltip\" title=\"user\"/>"
|
||||
assert(provider.toHtml("user", 20, "hoge@hoge.com", true).toString ==
|
||||
"<img src=\"/_unknown/_avatar\" class=\"avatar-mini\" style=\"width: 20px; height: 20px;\" data-toggle=\"tooltip\" title=\"user\"/>")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,6 +104,7 @@ class AvatarImageProviderSpec extends Specification with Mockito {
|
||||
notification = false,
|
||||
activityLogLimit = None,
|
||||
ssh = false,
|
||||
sshHost = None,
|
||||
sshPort = None,
|
||||
useSMTP = false,
|
||||
smtp = None,
|
||||
|
||||
@@ -1,38 +1,59 @@
|
||||
package gitbucket.core.view
|
||||
|
||||
import org.specs2.mutable._
|
||||
import org.scalatest.FunSpec
|
||||
|
||||
class HelpersSpec extends Specification {
|
||||
class HelpersSpec extends FunSpec {
|
||||
|
||||
import helpers._
|
||||
|
||||
"detect and render links" should {
|
||||
describe("detect and render links") {
|
||||
|
||||
"pass identical string when no link is present" in {
|
||||
it("should pass identical string when no link is present") {
|
||||
val before = "Description"
|
||||
val after = detectAndRenderLinks(before).toString()
|
||||
after mustEqual before
|
||||
assert(after == before)
|
||||
}
|
||||
|
||||
"convert a single link" in {
|
||||
it("should convert a single link") {
|
||||
val before = "http://example.com"
|
||||
val after = detectAndRenderLinks(before).toString()
|
||||
after mustEqual """<a href="http://example.com">http://example.com</a>"""
|
||||
assert(after == """<a href="http://example.com">http://example.com</a>""")
|
||||
}
|
||||
|
||||
"convert a single link within trailing text" in {
|
||||
it("should convert a single link within trailing text") {
|
||||
val before = "Example Project. http://example.com"
|
||||
val after = detectAndRenderLinks(before).toString()
|
||||
after mustEqual """Example Project. <a href="http://example.com">http://example.com</a>"""
|
||||
assert(after == """Example Project. <a href="http://example.com">http://example.com</a>""")
|
||||
}
|
||||
|
||||
"convert a mulitple links within text" in {
|
||||
it("should convert a mulitple links within text") {
|
||||
val before = "Example Project. http://example.com. (See also https://github.com/)"
|
||||
val after = detectAndRenderLinks(before).toString()
|
||||
after mustEqual """Example Project. <a href="http://example.com">http://example.com</a>. (See also <a href="https://github.com/">https://github.com/</a>)"""
|
||||
assert(after == """Example Project. <a href="http://example.com">http://example.com</a>. (See also <a href="https://github.com/">https://github.com/</a>)""")
|
||||
}
|
||||
|
||||
it("should properly escape html metacharacters") {
|
||||
val before = "<>&"
|
||||
val after = detectAndRenderLinks(before).toString()
|
||||
assert(after == """<>&""")
|
||||
}
|
||||
|
||||
it("should escape html metacharacters adjacent to a link") {
|
||||
val before = "<http://example.com>"
|
||||
val after = detectAndRenderLinks(before).toString()
|
||||
assert(after == """<<a href="http://example.com">http://example.com</a>>""")
|
||||
}
|
||||
|
||||
it("should stop link recognition at a metacharacter") {
|
||||
val before = "http://exa<mple.com"
|
||||
val after = detectAndRenderLinks(before).toString()
|
||||
assert(after == """<a href="http://exa">http://exa</a><mple.com""")
|
||||
}
|
||||
|
||||
it("should make sure there are no double quotes in the href attribute") {
|
||||
val before = "http://exa\"mple.com"
|
||||
val after = detectAndRenderLinks(before).toString()
|
||||
assert(after == """<a href="http://exa"mple.com">http://exa"mple.com</a>""")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,92 +1,92 @@
|
||||
package gitbucket.core.view
|
||||
|
||||
import org.specs2.mutable._
|
||||
import org.scalatest.FunSpec
|
||||
|
||||
class MarkdownSpec extends Specification {
|
||||
class MarkdownSpec extends FunSpec {
|
||||
|
||||
import Markdown._
|
||||
|
||||
"generateAnchorName" should {
|
||||
"convert whitespace characters to hyphens" in {
|
||||
describe("generateAnchorName") {
|
||||
it("should convert whitespace characters to hyphens") {
|
||||
val before = "foo bar baz"
|
||||
val after = generateAnchorName(before)
|
||||
after mustEqual "foo-bar-baz"
|
||||
assert(after == "foo-bar-baz")
|
||||
}
|
||||
|
||||
"normalize characters with diacritics" in {
|
||||
it("should normalize characters with diacritics") {
|
||||
val before = "Dónde estará mi vida"
|
||||
val after = generateAnchorName(before)
|
||||
after mustEqual "do%cc%81nde-estara%cc%81-mi-vida"
|
||||
assert(after == "do%cc%81nde-estara%cc%81-mi-vida")
|
||||
}
|
||||
|
||||
"omit special characters" in {
|
||||
it("should omit special characters") {
|
||||
val before = "foo!bar@baz>9000"
|
||||
val after = generateAnchorName(before)
|
||||
after mustEqual "foo%21bar%40baz%3e9000"
|
||||
assert(after == "foo%21bar%40baz%3e9000")
|
||||
}
|
||||
}
|
||||
|
||||
"escapeTaskList" should {
|
||||
"convert '- [ ] ' to '* task: :'" in {
|
||||
describe("escapeTaskList") {
|
||||
it("should convert '- [ ] ' to '* task: :'") {
|
||||
val before = "- [ ] aaaa"
|
||||
val after = escapeTaskList(before)
|
||||
after mustEqual "* task: : aaaa"
|
||||
assert(after == "* task: : aaaa")
|
||||
}
|
||||
|
||||
"convert ' - [ ] ' to ' * task: :'" in {
|
||||
it("should convert ' - [ ] ' to ' * task: :'") {
|
||||
val before = " - [ ] aaaa"
|
||||
val after = escapeTaskList(before)
|
||||
after mustEqual " * task: : aaaa"
|
||||
assert(after == " * task: : aaaa")
|
||||
}
|
||||
|
||||
"convert only first '- [ ] '" in {
|
||||
it("should convert only first '- [ ] '") {
|
||||
val before = " - [ ] aaaa - [ ] bbb"
|
||||
val after = escapeTaskList(before)
|
||||
after mustEqual " * task: : aaaa - [ ] bbb"
|
||||
assert(after == " * task: : aaaa - [ ] bbb")
|
||||
}
|
||||
|
||||
"convert '- [x] ' to '* task:x:'" in {
|
||||
it("should convert '- [x] ' to '* task:x:'") {
|
||||
val before = " - [x] aaaa"
|
||||
val after = escapeTaskList(before)
|
||||
after mustEqual " * task:x: aaaa"
|
||||
assert(after == " * task:x: aaaa")
|
||||
}
|
||||
|
||||
"convert multi lines" in {
|
||||
it("should convert multi lines") {
|
||||
val before = """
|
||||
tasks
|
||||
- [x] aaaa
|
||||
- [ ] bbb
|
||||
"""
|
||||
val after = escapeTaskList(before)
|
||||
after mustEqual """
|
||||
assert(after == """
|
||||
tasks
|
||||
* task:x: aaaa
|
||||
* task: : bbb
|
||||
"""
|
||||
""")
|
||||
}
|
||||
|
||||
"no convert if inserted before '- [ ] '" in {
|
||||
it("should not convert if inserted before '- [ ] '") {
|
||||
val before = " a - [ ] aaaa"
|
||||
val after = escapeTaskList(before)
|
||||
after mustEqual " a - [ ] aaaa"
|
||||
assert(after == " a - [ ] aaaa")
|
||||
}
|
||||
|
||||
"no convert '- [] '" in {
|
||||
it("should not convert '- [] '") {
|
||||
val before = " - [] aaaa"
|
||||
val after = escapeTaskList(before)
|
||||
after mustEqual " - [] aaaa"
|
||||
assert(after == " - [] aaaa")
|
||||
}
|
||||
|
||||
"no convert '- [ ]a'" in {
|
||||
it("should not convert '- [ ]a'") {
|
||||
val before = " - [ ]a aaaa"
|
||||
val after = escapeTaskList(before)
|
||||
after mustEqual " - [ ]a aaaa"
|
||||
assert(after == " - [ ]a aaaa")
|
||||
}
|
||||
|
||||
"no convert '-[ ] '" in {
|
||||
it("should not convert '-[ ] '") {
|
||||
val before = " -[ ] aaaa"
|
||||
val after = escapeTaskList(before)
|
||||
after mustEqual " -[ ] aaaa"
|
||||
assert(after == " -[ ] aaaa")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,68 +1,68 @@
|
||||
package gitbucket.core.view
|
||||
|
||||
import gitbucket.core.util.ControlUtil
|
||||
import org.specs2.mutable._
|
||||
import ControlUtil._
|
||||
import org.scalatest.FunSpec
|
||||
|
||||
class PaginationSpec extends Specification {
|
||||
class PaginationSpec extends FunSpec {
|
||||
|
||||
"max" should {
|
||||
"return max page number" in {
|
||||
describe("max") {
|
||||
it("should return max page number") {
|
||||
val pagination = Pagination(1, 100, 10, 6)
|
||||
pagination.max mustEqual 10
|
||||
assert(pagination.max == 10)
|
||||
}
|
||||
}
|
||||
|
||||
"omitLeft and omitRight" should {
|
||||
"return true if pagination links at their side will be omitted" in {
|
||||
describe("omitLeft and omitRight") {
|
||||
it("should return true if pagination links at their side will be omitted") {
|
||||
defining(Pagination(1, 100, 10, 6)){ pagination =>
|
||||
pagination.omitLeft mustEqual false
|
||||
pagination.omitRight mustEqual true
|
||||
assert(pagination.omitLeft == false)
|
||||
assert(pagination.omitRight == true)
|
||||
}
|
||||
defining(Pagination(9, 100, 10, 6)){ pagination =>
|
||||
pagination.omitLeft mustEqual true
|
||||
pagination.omitRight mustEqual false
|
||||
assert(pagination.omitLeft == true)
|
||||
assert(pagination.omitRight == false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"visibleFor" should {
|
||||
"return true for visible pagination links" in {
|
||||
describe("visibleFor") {
|
||||
it("should return true for visible pagination links") {
|
||||
defining(Pagination(1, 100, 10, 6)){ pagination =>
|
||||
pagination.visibleFor(1) mustEqual true
|
||||
pagination.visibleFor(2) mustEqual true
|
||||
pagination.visibleFor(3) mustEqual true
|
||||
pagination.visibleFor(4) mustEqual true
|
||||
pagination.visibleFor(5) mustEqual true
|
||||
pagination.visibleFor(6) mustEqual false
|
||||
pagination.visibleFor(7) mustEqual false
|
||||
pagination.visibleFor(8) mustEqual false
|
||||
pagination.visibleFor(9) mustEqual false
|
||||
pagination.visibleFor(10) mustEqual true
|
||||
assert(pagination.visibleFor(1) == true)
|
||||
assert(pagination.visibleFor(2) == true)
|
||||
assert(pagination.visibleFor(3) == true)
|
||||
assert(pagination.visibleFor(4) == true)
|
||||
assert(pagination.visibleFor(5) == true)
|
||||
assert(pagination.visibleFor(6) == false)
|
||||
assert(pagination.visibleFor(7) == false)
|
||||
assert(pagination.visibleFor(8) == false)
|
||||
assert(pagination.visibleFor(9) == false)
|
||||
assert(pagination.visibleFor(10) == true)
|
||||
}
|
||||
defining(Pagination(5, 100, 10, 6)){ pagination =>
|
||||
pagination.visibleFor(1) mustEqual true
|
||||
pagination.visibleFor(2) mustEqual false
|
||||
pagination.visibleFor(3) mustEqual false
|
||||
pagination.visibleFor(4) mustEqual true
|
||||
pagination.visibleFor(5) mustEqual true
|
||||
pagination.visibleFor(6) mustEqual true
|
||||
pagination.visibleFor(7) mustEqual false
|
||||
pagination.visibleFor(8) mustEqual false
|
||||
pagination.visibleFor(9) mustEqual false
|
||||
pagination.visibleFor(10) mustEqual true
|
||||
assert(pagination.visibleFor(1) == true)
|
||||
assert(pagination.visibleFor(2) == false)
|
||||
assert(pagination.visibleFor(3) == false)
|
||||
assert(pagination.visibleFor(4) == true)
|
||||
assert(pagination.visibleFor(5) == true)
|
||||
assert(pagination.visibleFor(6) == true)
|
||||
assert(pagination.visibleFor(7) == false)
|
||||
assert(pagination.visibleFor(8) == false)
|
||||
assert(pagination.visibleFor(9) == false)
|
||||
assert(pagination.visibleFor(10) == true)
|
||||
}
|
||||
defining(Pagination(8, 100, 10, 6)){ pagination =>
|
||||
pagination.visibleFor(1) mustEqual true
|
||||
pagination.visibleFor(2) mustEqual false
|
||||
pagination.visibleFor(3) mustEqual false
|
||||
pagination.visibleFor(4) mustEqual false
|
||||
pagination.visibleFor(5) mustEqual false
|
||||
pagination.visibleFor(6) mustEqual true
|
||||
pagination.visibleFor(7) mustEqual true
|
||||
pagination.visibleFor(8) mustEqual true
|
||||
pagination.visibleFor(9) mustEqual true
|
||||
pagination.visibleFor(10) mustEqual true
|
||||
assert(pagination.visibleFor(1) == true)
|
||||
assert(pagination.visibleFor(2) == false)
|
||||
assert(pagination.visibleFor(3) == false)
|
||||
assert(pagination.visibleFor(4) == false)
|
||||
assert(pagination.visibleFor(5) == false)
|
||||
assert(pagination.visibleFor(6) == true)
|
||||
assert(pagination.visibleFor(7) == true)
|
||||
assert(pagination.visibleFor(8) == true)
|
||||
assert(pagination.visibleFor(9) == true)
|
||||
assert(pagination.visibleFor(10) == true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user