Compare commits

...

33 Commits
4.3 ... 4.4

Author SHA1 Message Date
Naoki Takezoe
48b6a590bf 4.4.0 release 2016-08-28 11:51:59 +09:00
Naoki Takezoe
285ef02a17 Merge pull request #1270 from S-YOU/patch-1
add copyright holder name in license
2016-08-28 11:10:42 +09:00
YOU
18375c741e Update LICENSE 2016-08-26 08:05:40 +00:00
Naoki Takezoe
21030344cc Merge pull request #1273 from kw-udon/fix-contents-api-default-ref-param
Set default value of parameter in Get-Contents API
2016-08-22 23:55:18 +09:00
Keiichi Watanabe
a494027217 Set default value to ref param in contents-API 2016-08-22 18:58:59 +09:00
Naoki Takezoe
7bca01af59 (refs #1230) Apply table-hover class for the commit history 2016-08-18 11:48:47 +09:00
YOU
acf3fa9980 add copyright holder name in license 2016-08-15 23:32:31 +09:00
Naoki Takezoe
c0ce0f8d19 (refs #1259) Add SQL import capability and remove XML export / import 2016-08-14 01:55:19 +09:00
Naoki Takezoe
56e7168461 Merge pull request #1268 from haru/FixgetGroupNames
Fix AccountService#getGroupNames returns duplicated group name .
2016-08-12 00:08:48 +09:00
Haruyuki Iida
c2d0d94f05 Fix AccountService#getGroupNames returns duplicated group name . 2016-08-11 15:28:29 +09:00
Naoki Takezoe
fc22cfbbdd Merge branch 'master' of https://github.com/gitbucket/gitbucket 2016-08-11 14:40:14 +09:00
Naoki Takezoe
d62adbf649 (refs #769) Output go-import meta tag in all repositories for go get 2016-08-11 14:40:06 +09:00
Naoki Takezoe
dba5539e3e (refs #1267) Graceful shutdown for the embedded jetty 2016-08-10 20:57:44 +09:00
Naoki Takezoe
f0a8b3bb17 (refs #1264) BugFix: File attachment does not work on the issue comment 2016-08-08 21:57:26 +09:00
Naoki Takezoe
f52e7e1bdd (refs #1255) Display the newest version as plugin version because if migration was failed, plugin is not registered. 2016-08-07 14:10:57 +09:00
Naoki Takezoe
58ba26f21e (refs #1255) Also check plugin version 2016-08-07 13:58:51 +09:00
Naoki Takezoe
bf7b30630c (refs #1255) Check whether database version is same as GitBucket version in startup 2016-08-07 13:42:42 +09:00
Naoki Takezoe
b5cac0308e Merge branch 'mcveat-217-sort-milestones' 2016-08-06 10:04:18 +09:00
Naoki Takezoe
373ea39048 (refs #219) Add milestoneId as a lowest priority sort column 2016-08-06 10:03:59 +09:00
Naoki Takezoe
427f5eec5f Merge branch '217-sort-milestones' of https://github.com/mcveat/gitbucket into mcveat-217-sort-milestones
# Conflicts:
#	src/main/scala/service/MilestonesService.scala
2016-08-06 09:56:56 +09:00
Naoki Takezoe
a4e9903e00 Merge pull request #1261 from UprootStaging/sshdUpdate
Sshd update
2016-08-04 15:51:03 +09:00
Naoki Takezoe
0d900a892c Merge pull request #1260 from team-lab/fix-blame-admin-lte
(fix #1246) cannot see the blame
2016-08-04 15:28:23 +09:00
hrj
dc6fdaf482 Fix for test compilation 2016-08-04 10:03:35 +05:30
hrj
b79498ed9f Update apache-sshd to latest version 2016-08-04 09:54:07 +05:30
nazoking
69e8f628df (fix #1246) cannot see the blame 2016-08-04 12:46:02 +09:00
Naoki Takezoe
d3d8e3ce5f Merge pull request #1256 from team-lab/git-is-reserved-user-name
(refs #1251) git is reserved user name. add validation.
2016-08-03 15:42:13 +09:00
nazoking
0499c47f4b (refs #1251, #1256) add admin, upload and api to reserved. 2016-08-03 12:14:32 +09:00
nazoking
7fd0cdd7d8 (refs #1251) git is reserved user name 2016-08-02 18:00:40 +09:00
Naoki Takezoe
49eaf79e01 Merge pull request #1253 from gitbucket/publish-maven-central
(refs #935) Update project configuration for deploying artifacts to Maven central
2016-07-31 21:45:04 +09:00
Naoki Takezoe
3a96c30aa8 (refs #935) Reoveride artifact to remove war from published artifacts 2016-07-31 21:21:27 +09:00
Naoki Takezoe
6d550fa485 (refs #935) Revert version to 4.3.0 2016-07-31 20:49:16 +09:00
Naoki Takezoe
7f9d69bb51 (refs #935) Update project configuration for deploying artifacts to Maven central 2016-07-31 18:08:47 +09:00
Piotr Adamski
3cc7bd3cdb #217 open milestones sorted by due date ascending, closed milestones sorted by close date descending 2013-12-01 14:09:25 +01:00
27 changed files with 164 additions and 187 deletions

View File

@@ -187,7 +187,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Copyright 2013-2016 GitBucket Team
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@@ -65,6 +65,12 @@ Support
Release Notes
-------------
### 4.4 - 28 Aug 2016
- Import a SQL dump file to the database
- `go get` support in private repositories
- Sort milestones by due date
- apache-sshd has been updated to 1.2.0
### 4.3 - 30 Jul 2016
- Emoji support by [gitbucket-emoji-plugin](https://github.com/gitbucket/gitbucket-emoji-plugin)
- User name suggestion

View File

@@ -1,6 +1,6 @@
val Organization = "gitbucket"
val Organization = "io.github.gitbucket"
val Name = "gitbucket"
val GitBucketVersion = "4.3.0"
val GitBucketVersion = "4.4.0"
val ScalatraVersion = "2.4.1"
val JettyVersion = "9.3.9.v20160517"
@@ -33,7 +33,7 @@ libraryDependencies ++= Seq(
"org.apache.commons" % "commons-compress" % "1.11",
"org.apache.commons" % "commons-email" % "1.4",
"org.apache.httpcomponents" % "httpclient" % "4.5.1",
"org.apache.sshd" % "apache-sshd" % "1.0.0",
"org.apache.sshd" % "apache-sshd" % "1.2.0",
"org.apache.tika" % "tika-core" % "1.13",
"com.typesafe.slick" %% "slick" % "2.1.0",
"com.novell.ldap" % "jldap" % "2009-10-07",
@@ -170,3 +170,56 @@ Keys.artifact in (Compile, executableKey) ~= {
}
addArtifact(Keys.artifact in (Compile, executableKey), executableKey)
*/
publishTo <<= version { (v: String) =>
val nexus = "https://oss.sonatype.org/"
if (v.trim.endsWith("SNAPSHOT")) Some("snapshots" at nexus + "content/repositories/snapshots")
else Some("releases" at nexus + "service/local/staging/deploy/maven2")
}
publishMavenStyle := true
pomIncludeRepository := { _ => false }
artifact in Keys.`package` := Artifact(moduleName.value)
pomExtra := (
<url>https://github.com/gitbucket/gitbucket</url>
<licenses>
<license>
<name>The Apache Software License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
</license>
</licenses>
<scm>
<url>https://github.com/gitbucket/gitbucket</url>
<connection>scm:git:https://github.com/gitbucket/gitbucket.git</connection>
</scm>
<developers>
<developer>
<id>takezoe</id>
<name>Naoki Takezoe</name>
<url>https://github.com/takezoe</url>
</developer>
<developer>
<id>shimamoto</id>
<name>Takako Shimamoto</name>
<url>https://github.com/shimamoto</url>
</developer>
<developer>
<id>tanacasino</id>
<name>Tomofumi Tanaka</name>
<url>https://github.com/tanacasino</url>
</developer>
<developer>
<id>mrkm4ntr</id>
<name>Shintaro Murakami</name>
<url>https://github.com/mrkm4ntr</url>
</developer>
<developer>
<id>nazoking</id>
<name>nazoking</name>
<url>https://github.com/nazoking</url>
</developer>
<developer>
<id>McFoggy</id>
<name>Matthieu Brouillard</name>
<url>https://github.com/McFoggy</url>
</developer>
</developers>
)

View File

@@ -4,3 +4,4 @@ addSbtPlugin("com.typesafe.sbt" % "sbt-twirl" % "1.0.4")
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.12.0")
addSbtPlugin("com.earldouglas" % "xsbt-web-plugin" % "2.1.0")
addSbtPlugin("fi.gekkio.sbtplugins" % "sbt-jrebel-plugin" % "0.10.0")
addSbtPlugin("com.typesafe.sbt" % "sbt-pgp" % "0.8.3")

View File

@@ -60,6 +60,8 @@ public class JettyLauncher {
}
server.setHandler(context);
server.setStopAtShutdown(true);
server.setStopTimeout(7_000);
server.start();
server.join();
}

View File

@@ -13,5 +13,6 @@ object GitBucketCoreModule extends Module("gitbucket-core",
new LiquibaseMigration("update/gitbucket-core_4.2.xml")
),
new Version("4.2.1"),
new Version("4.3.0")
new Version("4.3.0"),
new Version("4.4.0")
)

View File

@@ -38,7 +38,7 @@ trait AccountControllerBase extends AccountManagementControllerBase {
case class PersonalTokenForm(note: String)
val newForm = mapping(
"userName" -> trim(label("User name" , text(required, maxlength(100), identifier, uniqueUserName))),
"userName" -> trim(label("User name" , text(required, maxlength(100), identifier, uniqueUserName, reservedNames))),
"password" -> trim(label("Password" , text(required, maxlength(20)))),
"fullName" -> trim(label("Full Name" , text(required, maxlength(100)))),
"mailAddress" -> trim(label("Mail Address" , text(required, maxlength(100), uniqueMailAddress()))),
@@ -68,7 +68,7 @@ trait AccountControllerBase extends AccountManagementControllerBase {
case class EditGroupForm(groupName: String, url: Option[String], fileId: Option[String], members: String, clearImage: Boolean)
val newGroupForm = mapping(
"groupName" -> trim(label("Group name" ,text(required, maxlength(100), identifier, uniqueUserName))),
"groupName" -> trim(label("Group name" ,text(required, maxlength(100), identifier, uniqueUserName, reservedNames))),
"url" -> trim(label("URL" ,optional(text(maxlength(200))))),
"fileId" -> trim(label("File ID" ,optional(text()))),
"members" -> trim(label("Members" ,text(required, members)))

View File

@@ -110,7 +110,7 @@ trait ApiControllerBase extends ControllerBase {
*/
get("/api/v3/repos/:owner/:repo/contents/*")(referrersOnly { repository =>
val (id, path) = repository.splitPath(multiParams("splat").head)
val refStr = params("ref")
val refStr = params.getOrElse("ref", repository.repository.defaultBranch)
using(Git.open(getRepositoryDir(params("owner"), params("repo")))){ git =>
if (path.isEmpty) {
JsonFormat(getFileList(git, refStr, ".").map{f => ApiContents(f)})

View File

@@ -244,4 +244,13 @@ trait AccountManagementControllerBase extends ControllerBase {
.map { _ => "Mail address is already registered." }
}
val allReservedNames = Set("git", "admin", "upload", "api")
protected def reservedNames(): Constraint = new Constraint(){
override def validate(name: String, value: String, messages: Messages): Option[String] = if(allReservedNames.contains(value)){
Some(s"${value} is reserved")
}else{
None
}
}
}

View File

@@ -79,15 +79,10 @@ class FileUploadController extends ScalatraServlet with FileUploadSupport with R
}
post("/import") {
import JDBCUtil._
session.get(Keys.Session.LoginAccount).collect { case loginAccount: Account if loginAccount.isAdmin =>
execute({ (file, fileId) =>
if(file.getName.endsWith(".xml")){
import JDBCUtil._
val conn = request2Session(request).conn
conn.importAsXML(file.getInputStream)
} else {
throw new RuntimeException("Import is available for only the XML file.")
}
request2Session(request).conn.importAsSQL(file.getInputStream)
}, _ => true)
}
redirect("/admin/data")

View File

@@ -117,9 +117,14 @@ trait RepositoryViewerControllerBase extends ControllerBase {
/**
* Displays the file list of the repository root and the default branch.
*/
get("/:owner/:repository")(referrersOnly {
fileList(_)
})
get("/:owner/:repository") {
params.get("go-get") match {
case Some("1") => defining(request.paths){ paths =>
getRepository(paths(0), paths(1)).map(gitbucket.core.html.goget(_))getOrElse NotFound()
}
case _ => referrersOnly(fileList(_))
}
}
/**
* Displays the file list of the specified path and branch.

View File

@@ -13,9 +13,7 @@ import gitbucket.core.util.ControlUtil._
import gitbucket.core.util.Directory._
import gitbucket.core.util.StringUtil._
import io.github.gitbucket.scalatra.forms._
import io.github.gitbucket.solidbase.manager.JDBCVersionManager
import org.apache.commons.io.{FileUtils, IOUtils}
import org.apache.commons.mail.{DefaultAuthenticator, HtmlEmail}
import org.scalatra.i18n.Messages
class SystemSettingsController extends SystemSettingsControllerBase
@@ -105,7 +103,7 @@ trait SystemSettingsControllerBase extends AccountManagementControllerBase {
val newUserForm = mapping(
"userName" -> trim(label("Username" ,text(required, maxlength(100), identifier, uniqueUserName))),
"userName" -> trim(label("Username" ,text(required, maxlength(100), identifier, uniqueUserName, reservedNames))),
"password" -> trim(label("Password" ,text(required, maxlength(20)))),
"fullName" -> trim(label("Full Name" ,text(required, maxlength(100)))),
"mailAddress" -> trim(label("Mail Address" ,text(required, maxlength(100), uniqueMailAddress()))),
@@ -127,7 +125,7 @@ trait SystemSettingsControllerBase extends AccountManagementControllerBase {
)(EditUserForm.apply)
val newGroupForm = mapping(
"groupName" -> trim(label("Group name" ,text(required, maxlength(100), identifier, uniqueUserName))),
"groupName" -> trim(label("Group name" ,text(required, maxlength(100), identifier, uniqueUserName, reservedNames))),
"url" -> trim(label("URL" ,optional(text(maxlength(200))))),
"fileId" -> trim(label("File ID" ,optional(text()))),
"members" -> trim(label("Members" ,text(required, members)))
@@ -176,11 +174,7 @@ trait SystemSettingsControllerBase extends AccountManagementControllerBase {
})
get("/admin/plugins")(adminOnly {
val manager = new JDBCVersionManager(request2Session(request).conn)
val plugins = PluginRegistry().getPlugins().map { plugin =>
(plugin, manager.getCurrentVersion(plugin.pluginId))
}
html.plugins(plugins)
html.plugins(PluginRegistry().getPlugins())
})
@@ -309,12 +303,7 @@ trait SystemSettingsControllerBase extends AccountManagementControllerBase {
post("/admin/export")(adminOnly {
import gitbucket.core.util.JDBCUtil._
val session = request2Session(request)
val file = if(params("type") == "sql"){
session.conn.exportAsSQL(request.getParameterValues("tableNames").toSeq)
} else {
session.conn.exportAsXML(request.getParameterValues("tableNames").toSeq)
}
val file = request2Session(request).conn.exportAsSQL(request.getParameterValues("tableNames").toSeq)
contentType = "application/octet-stream"
response.setHeader("Content-Disposition", "attachment; filename=" + file.getName)

View File

@@ -13,6 +13,7 @@ import gitbucket.core.util.ControlUtil._
import gitbucket.core.util.DatabaseConfig
import gitbucket.core.util.Directory._
import io.github.gitbucket.solidbase.Solidbase
import io.github.gitbucket.solidbase.manager.JDBCVersionManager
import io.github.gitbucket.solidbase.model.Module
import org.apache.commons.codec.binary.{Base64, StringUtils}
import org.slf4j.LoggerFactory
@@ -161,6 +162,8 @@ object PluginRegistry {
*/
def initialize(context: ServletContext, settings: SystemSettings, conn: java.sql.Connection): Unit = {
val pluginDir = new File(PluginHome)
val manager = new JDBCVersionManager(conn)
if(pluginDir.exists && pluginDir.isDirectory){
pluginDir.listFiles(new FilenameFilter {
override def accept(dir: File, name: String): Boolean = name.endsWith(".jar")
@@ -173,6 +176,13 @@ object PluginRegistry {
val solidbase = new Solidbase()
solidbase.migrate(conn, classLoader, DatabaseConfig.liquiDriver, new Module(plugin.pluginId, plugin.versions: _*))
// Check version
val databaseVersion = manager.getCurrentVersion(plugin.pluginId)
val pluginVersion = plugin.versions.last.getVersion
if(databaseVersion != pluginVersion){
throw new IllegalStateException(s"Plugin version is ${pluginVersion}, but database version is ${databaseVersion}")
}
// Initialize
plugin.initialize(instance, context, settings)
instance.addPlugin(PluginInfo(
@@ -185,7 +195,7 @@ object PluginRegistry {
} catch {
case e: Throwable => {
logger.error(s"Error during plugin initialization", e)
logger.error(s"Error during plugin initialization: ${pluginJar.getAbsolutePath}", e)
}
}
}

View File

@@ -186,7 +186,7 @@ trait AccountService {
def getGroupNames(userName: String)(implicit s: Session): List[String] = {
List(userName) ++
Collaborators.filter(_.collaboratorName === userName.bind).sortBy(_.userName).map(_.userName).list
Collaborators.filter(_.collaboratorName === userName.bind).sortBy(_.userName).map(_.userName).list.distinct
}
}

View File

@@ -41,7 +41,7 @@ trait MilestonesService {
def getMilestonesWithIssueCount(owner: String, repository: String)(implicit s: Session): List[(Milestone, Int, Int)] = {
val counts = Issues
.filter { t => (t.byRepository(owner, repository)) && (t.milestoneId.? isDefined) }
.filter { t => t.byRepository(owner, repository) && (t.milestoneId.? isDefined) }
.groupBy { t => t.milestoneId -> t.closed }
.map { case (t1, t2) => t1._1 -> t1._2 -> t2.length }
.toMap
@@ -52,6 +52,6 @@ trait MilestonesService {
}
def getMilestones(owner: String, repository: String)(implicit s: Session): List[Milestone] =
Milestones.filter(_.byRepository(owner, repository)).sortBy(_.milestoneId asc).list
Milestones.filter(_.byRepository(owner, repository)).sortBy(t => (t.dueDate.asc, t.closedDate.desc, t.milestoneId.desc)).list
}

View File

@@ -17,6 +17,7 @@ import org.apache.commons.io.FileUtils
import org.slf4j.LoggerFactory
import akka.actor.{Actor, Props, ActorSystem}
import com.typesafe.akka.extension.quartz.QuartzSchedulerExtension
import scala.collection.JavaConverters._
/**
* Initialize GitBucket system.
@@ -80,8 +81,14 @@ class InitializeListener extends ServletContextListener with SystemSettingsServi
// Rescue code for users who updated from 3.14 to 4.0.0
// https://github.com/gitbucket/gitbucket/issues/1227
val currentVersion = manager.getCurrentVersion(GitBucketCoreModule.getModuleId)
if(currentVersion == "4.0"){
val databaseVersion = if(currentVersion == "4.0"){
manager.updateVersion(GitBucketCoreModule.getModuleId, "4.0.0")
"4.0.0"
} else currentVersion
val gitbucketVersion = GitBucketCoreModule.getVersions.asScala.last.getVersion
if(databaseVersion != gitbucketVersion){
throw new IllegalStateException(s"Initialization failed. GitBucket version is ${gitbucketVersion}, but database version is ${databaseVersion}.")
}
// Load plugins

View File

@@ -13,7 +13,7 @@ import ControlUtil._
import org.eclipse.jgit.api.Git
import Directory._
import org.eclipse.jgit.transport.{ReceivePack, UploadPack}
import org.apache.sshd.server.command.UnknownCommand
import org.apache.sshd.server.scp.UnknownCommand
import org.eclipse.jgit.errors.RepositoryNotFoundException
object GitCommand {

View File

@@ -7,12 +7,12 @@ import gitbucket.core.service.SshKeyService
import gitbucket.core.servlet.Database
import org.apache.sshd.server.auth.pubkey.PublickeyAuthenticator
import org.apache.sshd.server.session.ServerSession
import org.apache.sshd.common.session.Session
import org.apache.sshd.common.AttributeStore
import org.slf4j.LoggerFactory
object PublicKeyAuthenticator {
// put in the ServerSession here to be read by GitCommand later
private val userNameSessionKey = new Session.AttributeKey[String]
private val userNameSessionKey = new AttributeStore.AttributeKey[String]
def putUserName(serverSession:ServerSession, userName:String):Unit =
serverSession.setAttribute(userNameSessionKey, userName)

View File

@@ -3,11 +3,8 @@ package gitbucket.core.util
import java.io._
import java.sql._
import java.text.SimpleDateFormat
import javax.xml.stream.{XMLStreamConstants, XMLInputFactory, XMLOutputFactory}
import ControlUtil._
import scala.StringBuilder
import scala.annotation.tailrec
import scala.collection.mutable
import scala.collection.mutable.ListBuffer
/**
@@ -64,65 +61,34 @@ object JDBCUtil {
}
}
def importAsXML(in: InputStream): Unit = {
def importAsSQL(in: InputStream): Unit = {
conn.setAutoCommit(false)
try {
val factory = XMLInputFactory.newInstance()
using(factory.createXMLStreamReader(in, "UTF-8")){ reader =>
// stateful objects
var elementName = ""
var insertTable = ""
var insertColumns = Map.empty[String, (String, String)]
using(in){ in =>
var out = new ByteArrayOutputStream()
while(reader.hasNext){
reader.next()
var length = 0
val bytes = new scala.Array[Byte](1024 * 8)
var stringLiteral = false
reader.getEventType match {
case XMLStreamConstants.START_ELEMENT =>
elementName = reader.getName.getLocalPart
if(elementName == "insert"){
insertTable = reader.getAttributeValue(null, "table")
} else if(elementName == "delete"){
val tableName = reader.getAttributeValue(null, "table")
conn.update(s"DELETE FROM ${tableName}")
} else if(elementName == "column"){
val columnName = reader.getAttributeValue(null, "name")
val columnType = reader.getAttributeValue(null, "type")
val columnValue = reader.getElementText
insertColumns = insertColumns + (columnName -> (columnType, columnValue))
var count = 0
while({ length = in.read(bytes); length != -1 }){
for(i <- 0 to length - 1){
val c = bytes(i)
if(c == '\''){
stringLiteral = !stringLiteral
}
case XMLStreamConstants.END_ELEMENT =>
// Execute insert statement
reader.getName.getLocalPart match {
case "insert" => {
val sb = new StringBuilder()
sb.append(s"INSERT INTO ${insertTable} (")
sb.append(insertColumns.map { case (columnName, _) => columnName }.mkString(", "))
sb.append(") VALUES (")
sb.append(insertColumns.map { case (_, (columnType, columnValue)) =>
if(columnType == null || columnValue == null){
"NULL"
} else if(columnType == "string"){
"'" + columnValue.replace("'", "''") + "'"
} else if(columnType == "timestamp"){
"'" + columnValue + "'"
if(c == ';' && !stringLiteral){
val sql = new String(out.toByteArray, "UTF-8")
conn.update(sql)
out = new ByteArrayOutputStream()
} else {
columnValue.toString
}
}.mkString(", "))
sb.append(")")
conn.update(sb.toString)
insertColumns = Map.empty[String, (String, String)] // Clear column information
}
case _ => // Nothing to do
}
case _ => // Nothing to do
out.write(c)
}
}
}
}
conn.commit()
} catch {
@@ -133,68 +99,6 @@ object JDBCUtil {
}
}
def exportAsXML(targetTables: Seq[String]): File = {
val dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss")
val file = File.createTempFile("gitbucket-export-", ".xml")
val factory = XMLOutputFactory.newInstance()
using(factory.createXMLStreamWriter(new FileOutputStream(file), "UTF-8")){ writer =>
val dbMeta = conn.getMetaData
val allTablesInDatabase = allTablesOrderByDependencies(dbMeta)
writer.writeStartDocument("UTF-8", "1.0")
writer.writeStartElement("tables")
println(allTablesInDatabase.mkString(", "))
allTablesInDatabase.reverse.foreach { tableName =>
if (targetTables.contains(tableName)) {
writer.writeStartElement("delete")
writer.writeAttribute("table", tableName)
writer.writeEndElement()
}
}
allTablesInDatabase.foreach { tableName =>
if (targetTables.contains(tableName)) {
select(s"SELECT * FROM ${tableName}") { rs =>
writer.writeStartElement("insert")
writer.writeAttribute("table", tableName)
val rsMeta = rs.getMetaData
(1 to rsMeta.getColumnCount).foreach { i =>
val columnName = rsMeta.getColumnName(i)
val (columnType, columnValue) = if(rs.getObject(columnName) == null){
(null, null)
} else {
rsMeta.getColumnType(i) match {
case Types.BOOLEAN | Types.BIT => ("boolean", rs.getBoolean(columnName))
case Types.VARCHAR | Types.CLOB | Types.CHAR | Types.LONGVARCHAR => ("string", rs.getString(columnName))
case Types.INTEGER => ("int", rs.getInt(columnName))
case Types.TIMESTAMP => ("timestamp", dateFormat.format(rs.getTimestamp(columnName)))
}
}
writer.writeStartElement("column")
writer.writeAttribute("name", columnName)
if(columnType != null){
writer.writeAttribute("type", columnType)
}
if(columnValue != null){
writer.writeCharacters(columnValue.toString)
}
writer.writeEndElement()
}
writer.writeEndElement()
}
}
}
writer.writeEndElement()
writer.writeEndDocument()
}
file
}
def exportAsSQL(targetTables: Seq[String]): File = {
val dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss")
val file = File.createTempFile("gitbucket-export-", ".sql")

View File

@@ -13,22 +13,12 @@
</div>
}
<input type="submit" class="btn btn-success pull-right" value="Export">
<div class="radio pull-right" style="margin-right: 10px;">
<label>
<input type="radio" name="type" value="sql">SQL
</label>
</div>
<div class="radio pull-right" style="margin-right: 10px;">
<label>
<input type="radio" name="type" value="xml" checked>XML
</label>
</div>
</form>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading strong">Import (only XML)</div>
<div class="panel-heading strong">Import</div>
<div class="panel-body">
<form class="form form-horizontal" action="@context.path/upload/import" method="POST" enctype="multipart/form-data" id="import-form">
<input type="file" name="file" id="file">
@@ -42,10 +32,10 @@
$(function(){
$('#import-form').submit(function(){
if($('#file').val() == ''){
alert('Choose an import XML file.');
alert('Choose an import SQL file.');
return false;
} else if(!$('#file').val().endsWith(".xml")){
alert('Import is available for only the XML file.');
} else if(!$('#file').val().endsWith(".sql")){
alert('Import is available for only the SQL file.');
return false;
}
return confirm('All existing data is deleted before importing.\nAre you sure?');

View File

@@ -1,16 +1,16 @@
@(plugins: List[(gitbucket.core.plugin.PluginInfo, String)])(implicit context: gitbucket.core.controller.Context)
@(plugins: List[gitbucket.core.plugin.PluginInfo])(implicit context: gitbucket.core.controller.Context)
@gitbucket.core.html.main("Plugins"){
@gitbucket.core.admin.html.menu("plugins") {
<h1>Installed plugins</h1>
@if(plugins.size > 0) {
<ul>
@plugins.map { case (plugin, migrationVersion) =>
<li><a href="#@plugin.pluginId">@plugin.pluginId:@migrationVersion</a></li>
@plugins.map { plugin =>
<li><a href="#@plugin.pluginId">@plugin.pluginId:@plugin.pluginVersion</a></li>
}
</ul>
@plugins.map { case (plugin, migrationVersion) =>
@plugins.map { plugin =>
<div class="panel panel-default">
<div class="panel-heading strong">@plugin.pluginName</div>
<div class="panel-body">
@@ -20,7 +20,7 @@
</div>
<div class="row">
<label class="col-md-2">Version</label>
<span class="col-md-10">@migrationVersion @if(plugin.pluginVersion != migrationVersion){ <span class="error">(Migration is failed, installed version is @plugin.pluginVersion)</span> }</span>
<span class="col-md-10">@plugin.pluginVersion</span>
</div>
<div class="row">
<label class="col-md-2">Name</label>

View File

@@ -0,0 +1,7 @@
@(repository: gitbucket.core.service.RepositoryService.RepositoryInfo)(implicit context: gitbucket.core.controller.Context)
<!DOCTYPE html>
<html>
<head>
<meta name="go-import" content="@context.baseUrl.replaceFirst("^https?://", "")/@repository.owner/@repository.name git @repository.httpUrl" />
</head>
</html>

View File

@@ -30,7 +30,7 @@
@gitbucket.core.helper.html.attached(
repository = repository,
completionContext = completionContext,
generateScript = enableWikiLink
generateScript = !enableWikiLink
)(textarea)
</div>
<div class="tab-pane" id="tab@(uid+1)">

View File

@@ -34,10 +34,8 @@
<script src="@helpers.assets/vendors/jquery-hotkeys/jquery.hotkeys.js"></script>
<script src="@helpers.assets/vendors/jquery-textcomplete-1.6.2/jquery.textcomplete.js"></script>
@repository.map { repository =>
@if(!repository.repository.isPrivate){
<meta name="go-import" content="@context.baseUrl.replaceFirst("^https?://", "")/@repository.owner/@repository.name git @repository.httpUrl" />
}
}
<script src="@helpers.assets/vendors/AdminLTE-2.2.3/js/app.js" type="text/javascript"></script>
</head>
<body class="skin-blue">

View File

@@ -150,7 +150,7 @@ $(window).load(function(){
var mode = m[1];
$('.blame-action').toggleClass("active", mode=='blame').attr('href', repository + (m[1] == 'blame' ? '/blob' : '/blame') + m[2]);
if(pre.parents("div.box-content-bottom").find(".blame").length){
pre.parents("div.container").toggleClass("blame-container", mode == 'blame');
pre.parent().toggleClass("blame-container", mode == 'blame');
updateSourceLineNum();
return;
}
@@ -161,7 +161,7 @@ $(window).load(function(){
$(document.body).toggleClass('no-box-shadow', document.body.style.boxShadow===undefined);
$('.blame-action').addClass("active");
var base = $('<div class="blame">').css({height: pre.height()}).prependTo(pre.parents("div.box-content-bottom"));
base.parents("div.container").addClass("blame-container");
base.parent().addClass("blame-container");
updateSourceLineNum();
$.get($('.blame-action').data('url')).done(function(data){
var blame = data.blame;

View File

@@ -33,7 +33,7 @@
}
</div>
<table class="table table-bordered">
<table class="table table-bordered table-hover">
@commits.map { day =>
<tr>
<th rowspan="@day.size" width="100">@helpers.date(day.head.commitTime)</th>

View File

@@ -1,6 +1,6 @@
package gitbucket.core.ssh
import org.apache.sshd.server.command.UnknownCommand
import org.apache.sshd.server.scp.UnknownCommand
import org.scalatest.FunSpec
class GitCommandFactorySpec extends FunSpec {