浏览代码

Merge branch 'dev' of github.com:gogits/gogs into dev

Lunny Xiao 11 年之前
父节点
当前提交
a85f242030

+ 1 - 0
.gopmfile

@@ -19,6 +19,7 @@ github.com/lib/pq =
 github.com/nfnt/resize = 
 github.com/qiniu/log = 
 github.com/robfig/cron = 
+github.com/juju2013/goldap = 
 
 [res]
 include = templates|public|conf

+ 2 - 0
CONTRIBUTING.md

@@ -10,6 +10,8 @@ Want to hack on Gogs? Awesome! Here are instructions to get you started. They ar
 
 ### Pull requests are always welcome
 
+**ALL PULL REQUESTS MUST SEND TO `DEV` BRANCH**
+
 We are always thrilled to receive pull requests, and do our best to process them as fast as possible. Not sure if that typo is worth a pull request? Do it! We will appreciate it.
 
 If your pull request is not accepted on the first try, don't be discouraged! If there's a problem with the implementation, hopefully you received feedback on what to improve.

+ 6 - 1
README.md

@@ -5,7 +5,7 @@ Gogs(Go Git Service) is a Self Hosted Git Service in the Go Programming Language
 
 ![Demo](http://gowalker.org/public/gogs_demo.gif)
 
-##### Current version: 0.3.0 Alpha
+##### Current version: 0.3.1 Alpha
 
 ### NOTICES
 
@@ -42,6 +42,11 @@ More importantly, Gogs only needs one binary to setup your own project hosting o
 - Supports MySQL, PostgreSQL and SQLite3.
 - Social account login(GitHub, Google, QQ, Weibo)
 
+## System Requirements
+
+- A cheap Raspberry Pi is powerful enough to match the minimal requirement.
+- 4 CPU Cores and 1GB RAM would be the baseline for teamwork.
+
 ## Installation
 
 Make sure you install [Prerequirements](https://github.com/gogits/gogs/wiki/Prerequirements) first.

+ 7 - 1
README_ZH.md

@@ -5,7 +5,7 @@ Gogs(Go Git Service) 是一个由 Go 语言编写的自助 Git 托管服务。
 
 ![Demo](http://gowalker.org/public/gogs_demo.gif)
 
-##### 当前版本:0.3.0 Alpha
+##### 当前版本:0.3.1 Alpha
 
 ## 开发目的
 
@@ -33,6 +33,12 @@ Gogs 完全使用 Go 语言来实现对 Git 数据的操作,实现 **零** 依
 - 支持 MySQL、PostgreSQL 以及 SQLite3 数据库
 - 社交帐号登录(GitHub、Google、QQ、微博)
 
+## 系统要求
+
+- 最低的系统硬件要求为一个廉价的树莓派
+- 如果用于团队项目,建议使用 4 核 CPU 及 1GB 内存
+
+
 ## 安装部署
 
 在安装 Gogs 之前,您需要先安装 [基本环境](https://github.com/gogits/gogs/wiki/Prerequirements)。

+ 2 - 0
conf/app.ini

@@ -16,6 +16,8 @@ LICENSES = Apache v2 License|GPL v2|MIT License|Affero GPL|Artistic License 2.0|
 PROTOCOL = http
 DOMAIN = localhost
 ROOT_URL = %(PROTOCOL)s://%(DOMAIN)s:%(HTTP_PORT)s/
+; Disable CDN even in "prod" mode
+OFFLINE_MODE = false
 HTTP_ADDR = 
 HTTP_PORT = 3000
 ; Generate steps:

+ 2 - 2
doc/install_gogs_from_binary_on_ubuntu.md

@@ -18,8 +18,8 @@
 ### install the gogs
 - mkdir gogs
 - cd gogs
-- curl -L http://gobuild.io/github.com/gogits/gogs/v0.2.0/linux/amd64 -o v0.2.0.zip
-- unzip v0.2.0.zip
+- curl -L http://gobuild.io/github.com/gogits/gogs/v0.3.0/linux/amd64 -o v0.3.0.zip
+- unzip v0.3.0.zip
 - ./start.sh
 
 > The up-to-date binary could be found at

+ 1 - 1
dockerfiles/images/gogits/Dockerfile

@@ -13,7 +13,7 @@ ENV GOROOT /usr/local/go
 ENV GOPATH /go
 
 RUN apt-get update && apt-get install --yes --force-yes curl git mercurial zip wget ca-certificates build-essential
-RUN apt-get install -yq vim
+RUN apt-get install -yq vim sudo
 
 RUN curl -s http://docker.u.qiniudn.com/go1.2.1.src.tar.gz | tar -v -C /usr/local -xz
 RUN cd /usr/local/go/src && ./make.bash --no-clean 2>&1

+ 2 - 1
dockerfiles/images/postgres/Dockerfile

@@ -9,7 +9,8 @@ RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys B97B0AFCAA
 
 # Add PostgreSQL's repository. It contains the most recent stable release
 #     of PostgreSQL, ``9.3``.
-RUN echo "deb http://apt.postgresql.org/pub/repos/apt/ precise-pgdg main" > /etc/apt/sources.list.d/pgdg.list
+# See http://apt.postgresql.org/pub/repos/apt/README
+RUN echo "deb http://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list
 
 # Update the Ubuntu and PostgreSQL repository indexes
 RUN apt-get update

+ 1 - 1
gogs.go

@@ -19,7 +19,7 @@ import (
 // Test that go1.2 tag above is included in builds. main.go refers to this definition.
 const go12tag = true
 
-const APP_VER = "0.3.0.0422 Alpha"
+const APP_VER = "0.3.1.0427 Alpha"
 
 func init() {
 	base.AppVer = APP_VER

+ 7 - 7
models/publickey.go

@@ -77,12 +77,12 @@ func init() {
 // PublicKey represents a SSH key of user.
 type PublicKey struct {
 	Id          int64
-	OwnerId     int64  `xorm:"unique(s) index not null"`
-	Name        string `xorm:"unique(s) not null"`
+	OwnerId     int64  `xorm:"UNIQUE(s) INDEX NOT NULL"`
+	Name        string `xorm:"UNIQUE(s) NOT NULL"`
 	Fingerprint string
-	Content     string    `xorm:"TEXT not null"`
-	Created     time.Time `xorm:"created"`
-	Updated     time.Time `xorm:"updated"`
+	Content     string    `xorm:"TEXT NOT NULL"`
+	Created     time.Time `xorm:"CREATED"`
+	Updated     time.Time `xorm:"UPDATED"`
 }
 
 // GenAuthorizedKey returns formatted public key string.
@@ -107,9 +107,9 @@ func AddPublicKey(key *PublicKey) (err error) {
 	if err = ioutil.WriteFile(tmpPath, []byte(key.Content), os.ModePerm); err != nil {
 		return err
 	}
-	stdout, _, err := com.ExecCmd("ssh-keygen", "-l", "-f", tmpPath)
+	stdout, stderr, err := com.ExecCmd("ssh-keygen", "-l", "-f", tmpPath)
 	if err != nil {
-		return err
+		return errors.New("ssh-keygen -l -f: " + stderr)
 	} else if len(stdout) < 2 {
 		return errors.New("Not enough output for calculating fingerprint")
 	}

+ 4 - 15
models/repo.go

@@ -159,9 +159,7 @@ func MirrorUpdate() {
 		repoPath := filepath.Join(base.RepoRootPath, m.RepoName+".git")
 		_, stderr, err := com.ExecCmdDir(repoPath, "git", "remote", "update")
 		if err != nil {
-			return err
-		} else if strings.Contains(stderr, "fatal:") {
-			return errors.New(stderr)
+			return errors.New("git remote update: " + stderr)
 		} else if err = git.UnpackRefs(repoPath); err != nil {
 			return err
 		}
@@ -177,9 +175,7 @@ func MirrorUpdate() {
 func MirrorRepository(repoId int64, userName, repoName, repoPath, url string) error {
 	_, stderr, err := com.ExecCmd("git", "clone", "--mirror", url, repoPath)
 	if err != nil {
-		return err
-	} else if strings.Contains(stderr, "fatal:") {
-		return errors.New(stderr)
+		return errors.New("git clone --mirror: " + stderr)
 	}
 
 	if _, err = orm.InsertOne(&Mirror{
@@ -219,23 +215,17 @@ func MigrateRepository(user *User, name, desc string, private, mirror bool, url
 	// Clone from local repository.
 	_, stderr, err := com.ExecCmd("git", "clone", repoPath, tmpDir)
 	if err != nil {
-		return repo, err
-	} else if strings.Contains(stderr, "fatal:") {
 		return repo, errors.New("git clone: " + stderr)
 	}
 
 	// Pull data from source.
 	_, stderr, err = com.ExecCmdDir(tmpDir, "git", "pull", url)
 	if err != nil {
-		return repo, err
-	} else if strings.Contains(stderr, "fatal:") {
 		return repo, errors.New("git pull: " + stderr)
 	}
 
 	// Push data to local repository.
 	if _, stderr, err = com.ExecCmdDir(tmpDir, "git", "push", "origin", "master"); err != nil {
-		return repo, err
-	} else if strings.Contains(stderr, "fatal:") {
 		return repo, errors.New("git push: " + stderr)
 	}
 
@@ -403,10 +393,11 @@ func initRepository(f string, user *User, repo *Repository, initReadme bool, rep
 		return err
 	}
 
+	rp := strings.NewReplacer("\\", "/", " ", "\\ ")
 	// hook/post-update
 	if err := createHookUpdate(filepath.Join(repoPath, "hooks", "update"),
 		fmt.Sprintf("#!/usr/bin/env %s\n%s update $1 $2 $3\n", base.ScriptType,
-			strings.Replace(appPath, "\\", "/", -1))); err != nil {
+			rp.Replace(appPath))); err != nil {
 		return err
 	}
 
@@ -428,8 +419,6 @@ func initRepository(f string, user *User, repo *Repository, initReadme bool, rep
 
 	_, stderr, err := com.ExecCmd("git", "clone", repoPath, tmpDir)
 	if err != nil {
-		return err
-	} else if strings.Contains(stderr, "fatal:") {
 		return errors.New("git clone: " + stderr)
 	}
 

+ 7 - 1
models/update.go

@@ -1,3 +1,7 @@
+// Copyright 2014 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
 package models
 
 import (
@@ -5,9 +9,11 @@ import (
 	"os/exec"
 	"strings"
 
+	qlog "github.com/qiniu/log"
+
 	"github.com/gogits/git"
+
 	"github.com/gogits/gogs/modules/base"
-	qlog "github.com/qiniu/log"
 )
 
 func Update(refName, oldCommitId, newCommitId, userName, repoName string, userId int64) {

+ 12 - 6
models/user.go

@@ -410,21 +410,27 @@ func GetUserByEmail(email string) (*User, error) {
 }
 
 // LoginUserPlain validates user by raw user name and password.
-func LoginUserPlain(name, passwd string) (*User, error) {
-	user := User{LowerName: strings.ToLower(name)}
-	has, err := orm.Get(&user)
+func LoginUserPlain(uname, passwd string) (*User, error) {
+	var u *User
+	if strings.Contains(uname, "@") {
+		u = &User{Email: uname}
+	} else {
+		u = &User{LowerName: strings.ToLower(uname)}
+	}
+
+	has, err := orm.Get(u)
 	if err != nil {
 		return nil, err
 	} else if !has {
 		return nil, ErrUserNotExist
 	}
 
-	newUser := &User{Passwd: passwd, Salt: user.Salt}
+	newUser := &User{Passwd: passwd, Salt: u.Salt}
 	newUser.EncodePasswd()
-	if user.Passwd != newUser.Passwd {
+	if u.Passwd != newUser.Passwd {
 		return nil, ErrUserNotExist
 	}
-	return &user, nil
+	return u, nil
 }
 
 // Follow is connection request for receiving user notifycation.

+ 1 - 1
modules/auth/auth.go

@@ -57,7 +57,7 @@ func (f *RegisterForm) Validate(errors *base.BindingErrors, req *http.Request, c
 }
 
 type LogInForm struct {
-	UserName string `form:"username" binding:"Required;AlphaDash;MaxSize(30)"`
+	UserName string `form:"username" binding:"Required;MaxSize(35)"`
 	Password string `form:"passwd" binding:"Required;MinSize(6);MaxSize(30)"`
 	Remember string `form:"remember"`
 }

+ 42 - 37
modules/base/conf.go

@@ -45,15 +45,15 @@ type Oauther struct {
 }
 
 var (
-	AppVer     string
-	AppName    string
-	AppLogo    string
-	AppUrl     string
-	IsProdMode bool
-	Domain     string
-	SecretKey  string
-	RunUser    string
-	LdapAuth   bool
+	AppVer      string
+	AppName     string
+	AppLogo     string
+	AppUrl      string
+	OfflineMode bool
+	ProdMode    bool
+	Domain      string
+	SecretKey   string
+	RunUser     string
 
 	RepoRootPath string
 	ScriptType   string
@@ -93,6 +93,7 @@ var Service struct {
 	NotifyMail           bool
 	ActiveCodeLives      int
 	ResetPwdCodeLives    int
+	LdapAuth             bool
 }
 
 func ExecDir() (string, error) {
@@ -178,6 +179,36 @@ func newLogService() {
 	log.Info("Log Mode: %s(%s)", strings.Title(LogMode), levelName)
 }
 
+func newLdapService() {
+	Service.LdapAuth = Cfg.MustBool("security", "LDAP_AUTH", false)
+	if !Service.LdapAuth {
+		return
+	}
+
+	nbsrc := 0
+	for _, v := range Cfg.GetSectionList() {
+		if matched, _ := regexp.MatchString("(?i)^LDAPSOURCE.*", v); matched {
+			ldapname := Cfg.MustValue(v, "name", v)
+			ldaphost := Cfg.MustValue(v, "host")
+			ldapport := Cfg.MustInt(v, "port", 389)
+			ldapbasedn := Cfg.MustValue(v, "basedn", "dc=*,dc=*")
+			ldapattribute := Cfg.MustValue(v, "attribute", "mail")
+			ldapfilter := Cfg.MustValue(v, "filter", "(*)")
+			ldapmsadsaformat := Cfg.MustValue(v, "MSADSAFORMAT", "%s")
+			ldap.AddSource(ldapname, ldaphost, ldapport, ldapbasedn, ldapattribute, ldapfilter, ldapmsadsaformat)
+			nbsrc++
+			log.Debug("%s added as LDAP source", ldapname)
+		}
+	}
+	if nbsrc == 0 {
+		log.Warn("No valide LDAP found, LDAP Authentication NOT enabled")
+		Service.LdapAuth = false
+		return
+	}
+
+	log.Info("LDAP Authentication Enabled")
+}
+
 func newCacheService() {
 	CacheAdapter = Cfg.MustValue("cache", "ADAPTER", "memory")
 	if EnableRedis {
@@ -295,6 +326,7 @@ func NewConfigContext() {
 	AppLogo = Cfg.MustValue("", "APP_LOGO", "img/favicon.png")
 	AppUrl = Cfg.MustValue("server", "ROOT_URL")
 	Domain = Cfg.MustValue("server", "DOMAIN")
+	OfflineMode = Cfg.MustBool("server", "OFFLINE_MODE", false)
 	SecretKey = Cfg.MustValue("security", "SECRET_KEY")
 
 	InstallLock = Cfg.MustBool("security", "INSTALL_LOCK", false)
@@ -312,34 +344,6 @@ func NewConfigContext() {
 	LogInRememberDays = Cfg.MustInt("security", "LOGIN_REMEMBER_DAYS")
 	CookieUserName = Cfg.MustValue("security", "COOKIE_USERNAME")
 	CookieRememberName = Cfg.MustValue("security", "COOKIE_REMEMBER_NAME")
-
-	// load LDAP authentication configuration if present
-	LdapAuth = Cfg.MustBool("security", "LDAP_AUTH", false)
-	if LdapAuth {
-		qlog.Debug("LDAP AUTHENTICATION activated")
-		nbsrc := 0
-		for _, v := range Cfg.GetSectionList() {
-			if matched, _ := regexp.MatchString("(?i)^LDAPSOURCE.*", v); matched {
-				ldapname := Cfg.MustValue(v, "name", v)
-				ldaphost := Cfg.MustValue(v, "host")
-				ldapport := Cfg.MustInt(v, "port", 389)
-				ldapbasedn := Cfg.MustValue(v, "basedn", "dc=*,dc=*")
-				ldapattribute := Cfg.MustValue(v, "attribute", "mail")
-				ldapfilter := Cfg.MustValue(v, "filter", "(*)")
-				ldapmsadsaformat := Cfg.MustValue(v, "MSADSAFORMAT", "%s")
-				ldap.AddSource(ldapname, ldaphost, ldapport, ldapbasedn, ldapattribute, ldapfilter, ldapmsadsaformat)
-				nbsrc += 1
-				qlog.Debug("%s added as LDAP source", ldapname)
-			}
-		}
-		if nbsrc == 0 {
-			qlog.Debug("No valide LDAP found, LDAP AUTHENTICATION NOT activated")
-			LdapAuth = false
-		}
-	} else {
-		qlog.Debug("LDAP AUTHENTICATION NOT activated")
-	}
-
 	PictureService = Cfg.MustValue("picture", "SERVICE")
 
 	// Determine and create root git reposiroty path.
@@ -357,6 +361,7 @@ func NewConfigContext() {
 func NewBaseServices() {
 	newService()
 	newLogService()
+	newLdapService()
 	newCacheService()
 	newSessionService()
 	newMailService()

+ 5 - 5
modules/base/template.go

@@ -56,8 +56,8 @@ var TemplateFuncs template.FuncMap = map[string]interface{}{
 	"AppDomain": func() string {
 		return Domain
 	},
-	"IsProdMode": func() bool {
-		return IsProdMode
+	"CdnMode": func() bool {
+		return ProdMode && !OfflineMode
 	},
 	"LoadTimes": func(startTime time.Time) string {
 		return fmt.Sprint(time.Since(startTime).Nanoseconds()/1e6) + "ms"
@@ -124,11 +124,11 @@ func ActionIcon(opType int) string {
 const (
 	TPL_CREATE_REPO    = `<a href="/user/%s">%s</a> created repository <a href="/%s">%s</a>`
 	TPL_COMMIT_REPO    = `<a href="/user/%s">%s</a> pushed to <a href="/%s/src/%s">%s</a> at <a href="/%s">%s</a>%s`
-	TPL_COMMIT_REPO_LI = `<div><img src="%s?s=16" alt="user-avatar"/> <a href="/%s/commit/%s">%s</a> %s</div>`
+	TPL_COMMIT_REPO_LI = `<div><img src="%s?s=16" alt="user-avatar"/> <a href="/%s/commit/%s" rel="nofollow">%s</a> %s</div>`
 	TPL_CREATE_ISSUE   = `<a href="/user/%s">%s</a> opened issue <a href="/%s/issues/%s">%s#%s</a>
 <div><img src="%s?s=16" alt="user-avatar"/> %s</div>`
 	TPL_TRANSFER_REPO = `<a href="/user/%s">%s</a> transfered repository <code>%s</code> to <a href="/%s">%s</a>`
-	TPL_PUSH_TAG      = `<a href="/user/%s">%s</a> pushed tag <a href="/%s/src/%s">%s</a> at <a href="/%s">%s</a>`
+	TPL_PUSH_TAG      = `<a href="/user/%s">%s</a> pushed tag <a href="/%s/src/%s" rel="nofollow">%s</a> at <a href="/%s">%s</a>`
 )
 
 type PushCommit struct {
@@ -165,7 +165,7 @@ func ActionDesc(act Actioner) string {
 			buf.WriteString(fmt.Sprintf(TPL_COMMIT_REPO_LI, AvatarLink(commit.AuthorEmail), repoLink, commit.Sha1, commit.Sha1[:7], commit.Message) + "\n")
 		}
 		if push.Len > 3 {
-			buf.WriteString(fmt.Sprintf(`<div><a href="/%s/%s/commits/%s">%d other commits >></a></div>`, actUserName, repoName, branch, push.Len))
+			buf.WriteString(fmt.Sprintf(`<div><a href="/%s/%s/commits/%s" rel="nofollow">%d other commits >></a></div>`, actUserName, repoName, branch, push.Len))
 		}
 		return fmt.Sprintf(TPL_COMMIT_REPO, actUserName, actUserName, repoLink, branch, branch, repoLink, repoLink,
 			buf.String())

+ 5 - 2
modules/middleware/repo.go

@@ -26,11 +26,14 @@ func RepoAssignment(redirect bool, args ...bool) martini.Handler {
 		var displayBare bool
 
 		if len(args) >= 1 {
-			validBranch = args[0]
+			// Note: argument has wrong value in Go1.3 martini.
+			// validBranch = args[0]
+			validBranch = true
 		}
 
 		if len(args) >= 2 {
-			displayBare = args[1]
+			// displayBare = args[1]
+			displayBare = true
 		}
 
 		var (

二进制
public/img/favicon.bak.png


二进制
public/img/favicon.png


+ 17 - 2
public/js/app.js

@@ -468,13 +468,28 @@ function initRepository() {
 function initInstall() {
     // database type change
     (function () {
+        var mysql_default    = '127.0.0.1:3306'
+        var postgres_default = '127.0.0.1:5432'
+
         $('#install-database').on("change", function () {
             var val = $(this).val();
-            if (val != "sqlite") {
+            if (val != "SQLite3") {
                 $('.server-sql').show();
                 $('.sqlite-setting').addClass("hide");
-                if (val == "pgsql") {
+                if (val == "PostgreSQL") {
                     $('.pgsql-setting').removeClass("hide");
+
+                    // Change the host value to the Postgres default, but only
+                    // if the user hasn't already changed it from the MySQL
+                    // default.
+                    if ($('#database-host').val() == mysql_default) {
+                        $('#database-host').val(postgres_default);
+                    }
+                } else if (val == 'MySQL') {
+                    $('.pgsql-setting').addClass("hide");
+                    if ($('#database-host').val() == postgres_default) {
+                        $('#database-host').val(mysql_default);
+                    }
                 } else {
                     $('.pgsql-setting').addClass("hide");
                 }

+ 2 - 0
routers/admin/admin.go

@@ -139,9 +139,11 @@ func Config(ctx *middleware.Context) {
 
 	ctx.Data["AppUrl"] = base.AppUrl
 	ctx.Data["Domain"] = base.Domain
+	ctx.Data["OfflineMode"] = base.OfflineMode
 	ctx.Data["RunUser"] = base.RunUser
 	ctx.Data["RunMode"] = strings.Title(martini.Env)
 	ctx.Data["RepoRootPath"] = base.RepoRootPath
+	ctx.Data["ScriptType"] = base.ScriptType
 
 	ctx.Data["Service"] = base.Service
 

+ 16 - 2
routers/install.go

@@ -30,7 +30,7 @@ func checkRunMode() {
 	switch base.Cfg.MustValue("", "RUN_MODE") {
 	case "prod":
 		martini.Env = martini.Prod
-		base.IsProdMode = true
+		base.ProdMode = true
 	case "test":
 		martini.Env = martini.Test
 	}
@@ -65,6 +65,10 @@ func GlobalInit() {
 	checkRunMode()
 }
 
+func renderDbOption(ctx *middleware.Context) {
+	ctx.Data["DbOptions"] = []string{"MySQL", "PostgreSQL", "SQLite3"}
+}
+
 func Install(ctx *middleware.Context, form auth.InstallForm) {
 	if base.InstallLock {
 		ctx.Handle(404, "install.Install", errors.New("Installation is prohibited"))
@@ -104,6 +108,13 @@ func Install(ctx *middleware.Context, form auth.InstallForm) {
 		form.AppUrl = base.AppUrl
 	}
 
+	renderDbOption(ctx)
+	curDbValue := ""
+	if models.EnableSQLite3 {
+		curDbValue = "SQLite3" // Default when enabled.
+	}
+	ctx.Data["CurDbValue"] = curDbValue
+
 	auth.AssignForm(form, ctx.Data)
 	ctx.HTML(200, "install")
 }
@@ -117,6 +128,9 @@ func InstallPost(ctx *middleware.Context, form auth.InstallForm) {
 	ctx.Data["Title"] = "Install"
 	ctx.Data["PageIsInstall"] = true
 
+	renderDbOption(ctx)
+	ctx.Data["CurDbValue"] = form.Database
+
 	if ctx.HasError() {
 		ctx.HTML(200, "install")
 		return
@@ -129,7 +143,7 @@ func InstallPost(ctx *middleware.Context, form auth.InstallForm) {
 
 	// Pass basic check, now test configuration.
 	// Test database setting.
-	dbTypes := map[string]string{"mysql": "mysql", "pgsql": "postgres", "sqlite": "sqlite3"}
+	dbTypes := map[string]string{"MySQL": "mysql", "PostgreSQL": "postgres", "SQLite3": "sqlite3"}
 	models.DbCfg.Type = dbTypes[form.Database]
 	models.DbCfg.Host = form.Host
 	models.DbCfg.User = form.User

+ 14 - 1
routers/repo/commit.go

@@ -91,10 +91,23 @@ func Diff(ctx *middleware.Context, params martini.Params) {
 		return isImage
 	}
 
+	parents := make([]string, commit.ParentCount())
+	for i := 0; i < commit.ParentCount(); i++ {
+		sha, err := commit.ParentId(i)
+		parents[i] = sha.String()
+		if err != nil {
+			ctx.Handle(404, "repo.Diff", err)
+			return
+		}
+	}
+
+	ctx.Data["Username"] = userName
+	ctx.Data["Reponame"] = repoName
 	ctx.Data["IsImageFile"] = isImageFile
-	ctx.Data["Title"] = commit.Message() + " · " + base.ShortSha(commitId)
+	ctx.Data["Title"] = commit.Summary() + " · " + base.ShortSha(commitId)
 	ctx.Data["Commit"] = commit
 	ctx.Data["Diff"] = diff
+	ctx.Data["Parents"] = parents
 	ctx.Data["DiffNotAvailable"] = diff.NumFiles() == 0
 	ctx.Data["IsRepoToolbarCommits"] = true
 	ctx.Data["SourcePath"] = "/" + path.Join(userName, repoName, "src", commitId)

+ 2 - 1
routers/user/setting.go

@@ -166,7 +166,8 @@ func SettingSSHKeys(ctx *middleware.Context, form auth.AddSSHKeyForm) {
 			return
 		}
 
-		k := &models.PublicKey{OwnerId: ctx.User.Id,
+		k := &models.PublicKey{
+			OwnerId: ctx.User.Id,
 			Name:    form.KeyName,
 			Content: form.KeyContent,
 		}

+ 5 - 24
routers/user/user.go

@@ -91,12 +91,14 @@ func SignInPost(ctx *middleware.Context, form auth.LogInForm) {
 
 	var user *models.User
 	var err error
-	// try to login against LDAP if defined
-	if base.LdapAuth {
+	if base.Service.LdapAuth {
 		user, err = models.LoginUserLdap(form.UserName, form.Password)
+		if err != nil {
+			log.Error("Fail to login through LDAP: %v", err)
+		}
 	}
 	// try local if not LDAP or it's failed
-	if (!base.LdapAuth) || (err != nil) {
+	if !base.Service.LdapAuth || err != nil {
 		user, err = models.LoginUserPlain(form.UserName, form.Password)
 	}
 	if err != nil {
@@ -142,27 +144,6 @@ func SignInPost(ctx *middleware.Context, form auth.LogInForm) {
 	ctx.Redirect("/")
 }
 
-func oauthSignInPost(ctx *middleware.Context, sid int64) {
-	ctx.Data["Title"] = "OAuth Sign Up"
-	ctx.Data["PageIsSignUp"] = true
-
-	if _, err := models.GetOauth2ById(sid); err != nil {
-		if err == models.ErrOauth2RecordNotExist {
-			ctx.Handle(404, "user.oauthSignUp(GetOauth2ById)", err)
-		} else {
-			ctx.Handle(500, "user.oauthSignUp(GetOauth2ById)", err)
-		}
-		return
-	}
-
-	ctx.Data["IsSocialLogin"] = true
-	ctx.Data["username"] = ctx.Session.Get("socialName")
-	ctx.Data["email"] = ctx.Session.Get("socialEmail")
-	log.Trace("user.oauthSignUp(social ID): %v", ctx.Session.Get("socialId"))
-
-	ctx.HTML(200, "user/signup")
-}
-
 func SignOut(ctx *middleware.Context) {
 	ctx.Session.Delete("userId")
 	ctx.Session.Delete("userName")

+ 4 - 0
templates/admin/config.tmpl

@@ -18,6 +18,8 @@
                     <dd>{{.AppUrl}}</dd>
                     <dt>Domain</dt>
                     <dd>{{.Domain}}</dd>
+                    <dt>Offline Mode</dt>
+                    <dd><i class="fa fa{{if .OfflineMode}}-check{{end}}-square-o"></i></dd>
                     <hr/>
                     <dt>Run User</dt>
                     <dd>{{.RunUser}}</dd>
@@ -26,6 +28,8 @@
                     <hr/>
                     <dt>Repository Root Path</dt>
                     <dd>{{.RepoRootPath}}</dd>
+                    <dt>Script Type</dt>
+                    <dd>{{.ScriptType}}</dd>
                 </dl>
             </div>
         </div>

+ 4 - 1
templates/base/footer.tmpl

@@ -13,7 +13,10 @@
 	    	<div class="col-md-1" style="margin: -5px;">
 		        <a target="_blank" href="https://github.com/gogits/gogs"><i class="fa fa-github fa-2x"></i></a>
 	        </div>
-	        <p class="desc"></p>
+
+	    	<div class="col-md-5">
+	        	<p class="desc"></p>
+	        </div>
     	</div>
     </div>
 </footer>

+ 1 - 1
templates/base/head.tmpl

@@ -12,7 +12,7 @@
 		{{if .Repository.IsGoget}}<meta name="go-import" content="{{.GoGetImport}} git {{.CloneLink.HTTPS}}">{{end}}
 
 		 <!-- Stylesheets -->
-		{{if IsProdMode}}
+		{{if CdnMode}}
 		<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
 		<link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet">
 

+ 3 - 3
templates/base/navbar.tmpl

@@ -3,7 +3,7 @@
         <nav class="nav">
             <a id="nav-logo" class="nav-item pull-left{{if .PageIsHome}} active{{end}}" href="/"><img src="/img/favicon.png" alt="Gogs Logo" id="logo"></a>
             <a class="nav-item pull-left{{if .PageIsUserDashboard}} active{{end}}" href="/">Dashboard</a>
-            <a class="nav-item pull-left{{if .PageIsHelp}} active{{end}}" href="https://github.com/gogits/gogs/wiki">Help</a>{{if .IsSigned}}
+            <a class="nav-item pull-left{{if .PageIsHelp}} active{{end}}" target="_blank" href="https://github.com/gogits/gogs/wiki">Help</a>{{if .IsSigned}}
             {{if .HasAccess}}<!-- <form class="nav-item pull-left{{if .PageIsNewRepo}} active{{end}}" id="nav-search-form">
                 <div class="input-group">
                     <div class="input-group-btn">
@@ -33,8 +33,8 @@
                     </ul>
                 </div>
             </div>
-            {{else}}<a id="nav-signin" class="nav-item navbar-right navbar-btn btn btn-danger" href="/user/login/">Sign In</a>
-            <a id="nav-signup" class="nav-item navbar-right" href="/user/sign_up/">Sign Up</a>{{end}}
+            {{else}}<a id="nav-signin" class="nav-item navbar-right navbar-btn btn btn-danger" href="/user/login/" rel="nofollow">Sign In</a>
+            <a id="nav-signup" class="nav-item navbar-right" href="/user/sign_up/" rel="nofollow">Sign Up</a>{{end}}
         </nav>
     </div>
 </div>

+ 8 - 7
templates/install.tmpl

@@ -9,18 +9,19 @@
             <label class="col-md-3 control-label">Database Type: </label>
             <div class="col-md-8">
                 <select name="database" id="install-database" class="form-control">
-                    <option value="mysql">MySQL</option>
-                    <option value="pgsql">PostgreSQL</option>
-                    <option value="sqlite">SQLite3</option>
+                    {{if .CurDbValue}}<option value="{{.CurDbValue}}">{{.CurDbValue}}</option>{{end}}
+                    {{range .DbOptions}}
+                    {{if not (eq $.CurDbValue .)}}<option value="{{.}}">{{.}}</option>{{end}}
+                    {{end}}
                 </select>
             </div>
         </div>
 
-        <div class="server-sql">
+        <div class="server-sql {{if eq .CurDbValue "SQLite3"}}hide{{end}}">
             <div class="form-group">
                 <label class="col-md-3 control-label">Host: </label>
                 <div class="col-md-8">
-                    <input name="host" class="form-control" placeholder="Type database server host" value="{{.host}}">
+                    <input name="host" id="database-host" class="form-control" placeholder="Type database server host" value="{{.host}}">
                 </div>
             </div>
 
@@ -49,7 +50,7 @@
                 </div>
             </div>
 
-            <div class="form-group pgsql-setting hide">
+            <div class="form-group pgsql-setting {{if not (eq .CurDbValue "PostgreSQL")}}hide{{end}}">
                 <label class="col-md-3 control-label">SSL Mode: </label>
                 <div class="col-md-8">
                     <select name="ssl_mode" class="form-control">
@@ -61,7 +62,7 @@
             </div>
         </div>
 
-        <div class="sqlite-setting hide">
+        <div class="sqlite-setting {{if not (eq .CurDbValue "SQLite3")}}hide{{end}}">
             <div class="form-group">
                 <label class="col-md-3 control-label">Path: </label>
 

+ 6 - 30
templates/release/list.tmpl

@@ -15,8 +15,8 @@
                 {{if .PublisherId}}
                 <div class="col-md-2 text-right">
                     {{if .IsPrerelease}}<span class="btn btn-warning status pre-release">Pre-Release</span>{{else}}<span class="btn btn-success status stable">Stable</span>{{end}}
-                    <a class="tag" href="{{$.RepoLink}}/src/{{.TagName}}"><i class="fa fa-tag"></i>{{.TagName}}</a>
-                    <a class="commit" href="{{$.RepoLink}}/src/{{.SHA1}}"><i class="fa fa-code"></i>{{ShortSha .SHA1}}</a>
+                    <a class="tag" href="{{$.RepoLink}}/src/{{.TagName}}" rel="nofollow"><i class="fa fa-tag"></i>{{.TagName}}</a>
+                    <a class="commit" href="{{$.RepoLink}}/src/{{.SHA1}}" rel="nofollow"><i class="fa fa-code"></i>{{ShortSha .SHA1}}</a>
                 </div>
                 <div class="col-md-10">
                     <h4 class="title"><a href="{{$.RepoLink}}/src/{{.TagName}}">{{.Title}}</a></h4>
@@ -30,19 +30,19 @@
                         {{str2html .Note}}
                     </div>
                     <p class="download">
-                        <a class="btn btn-default" href="{{$.RepoLink}}/archive/{{.TagName}}/{{$.Repository.Name}}.zip"><i class="fa fa-download"></i>Source Code (ZIP)</a>
+                        <a class="btn btn-default" href="{{$.RepoLink}}/archive/{{.TagName}}/{{$.Repository.Name}}.zip" rel="nofollow"><i class="fa fa-download"></i>Source Code (ZIP)</a>
                         <!-- <a class="btn btn-default" href="{release_download_link}"><i class="fa fa-download"></i>Source Code (TAR.GZ)</a> -->
                     </p>
                     <span class="dot">&nbsp;</span>
                 </div>
                 {{else}}
                 <div class="col-md-2 text-right">
-                    <a class="commit" href="{{$.RepoLink}}/src/{{.SHA1}}"><i class="fa fa-code"></i>{{ShortSha .SHA1}}</a>
+                    <a class="commit" href="{{$.RepoLink}}/src/{{.SHA1}}" rel="nofollow"><i class="fa fa-code"></i>{{ShortSha .SHA1}}</a>
                 </div>
                 <div class="col-md-10">
-                    <h5 class="title"><a href="{{$.RepoLink}}/src/{{.TagName}}">{{.TagName}}</a><i class="fa fa-tag"></i></h5>
+                    <h5 class="title"><a href="{{$.RepoLink}}/src/{{.TagName}}" rel="nofollow">{{.TagName}}</a><i class="fa fa-tag"></i></h5>
                     <p class="download">
-                        <a class="download-link" href="{{$.RepoLink}}/archive/{{.TagName}}/{{$.Repository.Name}}.zip"><i class="fa fa-download"></i>zip</a>
+                        <a class="download-link" href="{{$.RepoLink}}/archive/{{.TagName}}/{{$.Repository.Name}}.zip" rel="nofollow"><i class="fa fa-download"></i>zip</a>
                         <!-- <a class="download-link" href="{release_download_link}"><i class="fa fa-download"></i>tar.gz</a> -->
                     </p>
                     <span class="dot">&nbsp;</span>
@@ -50,30 +50,6 @@
                 {{end}}
             </li>
             {{end}}
-            <!-- <li class="release-item clearfix" id="release-{release_id}">
-                <div class="col-md-2 text-right">
-                    <span class="btn btn-warning status pre-release">Pre-Release</span>
-                    <a class="tag" href="{commit_link}"><i class="fa fa-tag"></i>release tag</a>
-                    <a class="commit" href="{commit_link}"><i class="fa fa-code"></i>commit-sha</a>
-                </div>
-                <div class="col-md-10">
-                    <h4 class="title"><a href="{release_single_link}">Release Title</a></h4>
-                    <p class="info">
-                        <span class="author"><img class="avatar" src="http://1.gravatar.com/avatar/f72f7454ce9d710baa506394f68f4132" alt="" width="20">&nbsp;&nbsp;
-                        <a href="/user/fuxiaohei">fuxiaohei</a></span>
-                        <span class="time">1 week ago</span>
-                        <span class="ahead"><strong>0</strong> commits since this tag</span>
-                    </p>
-                    <div class="markdown desc">
-                        release descriptions, support markdown content
-                    </div>
-                    <p class="download">
-                        <a class="btn btn-default" href="{release_download_link}"><i class="fa fa-download"></i>Source Code (ZIP)</a>
-                        <a class="btn btn-default" href="{release_download_link}"><i class="fa fa-download"></i>Source Code (TAR.GZ)</a>
-                    </p>
-                    <span class="dot">&nbsp;</span>
-                </div>
-            </li> -->
         </ul>
     </div>
 </div>

+ 3 - 3
templates/repo/commits.tmpl

@@ -33,7 +33,7 @@
                 <tr>
                     <td class="author"><img class="avatar" src="{{AvatarLink .Author.Email}}" alt=""/><a href="/user/email2user?email={{.Author.Email}}">{{.Author.Name}}</a></td>
                     <td class="sha"><a rel="nofollow" class="label label-success" href="/{{$username}}/{{$reponame}}/commit/{{.Id}} ">{{SubStr .Id.String 0 10}} </a></td>
-                    <td class="message">{{.Message}} </td>
+                    <td class="message">{{.Summary}} </td>
                     <td class="date">{{TimeSince .Author.When}}</td>
                 </tr>
                 {{end}}
@@ -41,8 +41,8 @@
             </table>
         </div>
         {{if not .IsSearchPage}}<ul class="pagination" id="commits-pager">
-            {{if .LastPageNum}}<li><a href="{{.RepoLink}}/commits/{{.BranchName}}?p={{.LastPageNum}}">&laquo; Newer</a></li>{{end}}
-            {{if .NextPageNum}}<li><a href="{{.RepoLink}}/commits/{{.BranchName}}?p={{.NextPageNum}}">&raquo; Older</a></li>{{end}}
+            {{if .LastPageNum}}<li><a href="{{.RepoLink}}/commits/{{.BranchName}}?p={{.LastPageNum}}" rel="nofollow">&laquo; Newer</a></li>{{end}}
+            {{if .NextPageNum}}<li><a href="{{.RepoLink}}/commits/{{.BranchName}}?p={{.NextPageNum}}" rel="nofollow">&raquo; Older</a></li>{{end}}
         </ul>{{end}}
     </div>
 </div>

+ 6 - 1
templates/repo/diff.tmpl

@@ -10,7 +10,12 @@
             </div>
             <div class="panel-body">
                 <span class="pull-right">
-                    commit <span class="label label-default sha">{{ShortSha .CommitId}}</span>
+                <ul class="list-unstyled">
+                    {{range .Parents}}
+                    <li>parent <a href="{{$.RepoLink}}/commit/{{.}}"><span class="label label-default sha">{{ShortSha .}}</span></a></li>
+                    {{end}}
+                    <li>commit <span class="label label-default sha">{{ShortSha .CommitId}}</span></li>
+                </ul>
                 </span>
                 <p class="author">
                     <img class="avatar" src="{{AvatarLink .Commit.Author.Email}}" alt=""/>

+ 2 - 2
templates/repo/nav.tmpl

@@ -23,10 +23,10 @@
                                 <button class="btn btn-default" type="button" data-toggle="tooltip" title="copy to clipboard" data-placement="top" data-init="copy" data-copy-val="val" data-copy-from="#repo-clone-ipt"><i class="fa fa-copy"></i></button>
                             </span>
                         </div>
-                        <p class="help-block text-center">Need help cloning? Visit <a href="#">Help</a>!</p>
+                        <p class="help-block text-center">Need help cloning? Visit <a target="_blank" href="https://help.github.com/articles/fork-a-repo">Help</a>!</p>
                         <hr/>
                         <div class="clone-zip text-center">
-                            <a class="btn btn-success btn-lg" href="{{.RepoLink}}/archive/{{.BranchName}}/{{.Repository.Name}}.zip"><i class="fa fa-suitcase"></i>Download ZIP</a>
+                            <a class="btn btn-success btn-lg" href="{{.RepoLink}}/archive/{{.BranchName}}/{{.Repository.Name}}.zip" rel="nofollow"><i class="fa fa-suitcase"></i>Download ZIP</a>
                         </div>
                     </div>
                 </div>

+ 24 - 23
templates/repo/single_file.tmpl

@@ -14,37 +14,38 @@
         {{if not .ReadmeInSingle}}
         <div class="btn-group pull-right">
             <a class="btn btn-default hidden" href="#">Edit</a>
-            <a class="btn btn-default" href="{{.FileLink}}">Raw</a>
+            <a class="btn btn-default" href="{{.FileLink}}" rel="nofollow">Raw</a>
             <a class="btn btn-default hidden" href="#">Blame</a>
             <a class="btn btn-default hidden" href="#">History</a>
             <a class="btn btn-danger hidden" href="#">Delete</a>
         </div>
         {{end}}
     </div>
+    
     {{if not .FileIsText}}
-        <div class="panel-footer text-center">
-            {{if .IsImageFile}}
-                <img src="{{.FileLink}}">
-            {{else}}
-                <a href="{{.FileLink}}" class="btn btn-default">View Raw</a>
-            {{end}}
-        </div>
-    {{else}}
-        {{if .ReadmeExist}}
-            <div class="panel-body file-body markdown">
-                {{.FileContent|str2html}}
-            </div>
+    <div class="panel-body file-body file-code code-view">
+        {{if .IsImageFile}}
+            <img src="{{.FileLink}}">
         {{else}}
-            <div class="panel-body file-body file-code code-view">
-                <table>
-                    <tbody>
-                        <tr>
-                            <td class="lines-num"></td>
-                            <td class="lines-code markdown"><pre class="prettyprint linenums{{if .FileExt}} lang-{{.FileExt}}{{end}}">{{.FileContent}}</pre></td>
-                        </tr>
-                    </tbody>
-                </table>
-            </div>
+            <a href="{{.FileLink}}" rel="nofollow" class="btn btn-default">View Raw</a>
         {{end}}
+    </div>
+    {{else}}
+    {{if .ReadmeExist}}
+    <div class="panel-body file-body markdown">
+        {{.FileContent|str2html}}
+    </div>
+    {{else}}
+    <div class="panel-body file-body file-code code-view">
+        <table>
+            <tbody>
+                <tr>
+                    <td class="lines-num"></td>
+                    <td class="lines-code markdown"><pre class="prettyprint linenums{{if .FileExt}} lang-{{.FileExt}}{{end}}">{{.FileContent}}</pre></td>
+                </tr>
+            </tbody>
+        </table>
+    </div>
+    {{end}}
     {{end}}
 </div>

+ 2 - 2
templates/repo/single_list.tmpl

@@ -1,6 +1,6 @@
 <div class="panel panel-default info-box">
     <div class="panel-heading info-head">
-        <a href="/{{.Username}}/{{.Reponame}}/commit/{{.LastCommit.Id}}">{{.LastCommit.Message}}</a>
+        <a href="/{{.Username}}/{{.Reponame}}/commit/{{.LastCommit.Id}}" rel="nofollow">{{.LastCommit.Summary}}</a>
     </div>
     <div class="panel-body info-content">
         <a href="/user/{{.LastCommit.Author.Name}}">{{.LastCommit.Author.Name}}</a> <span class="text-muted">{{TimeSince .LastCommit.Author.When}}</span>
@@ -36,7 +36,7 @@
                         </span>
                     </td>
                     <td class="text">
-                        <span class="wrap"><a rel="nofollow" href="/{{$.Username}}/{{$.Reponame}}/commit/{{$commit.Id}}">{{$commit.Message}}</a></span>
+                        <span class="wrap"><a rel="nofollow" href="/{{$.Username}}/{{$.Reponame}}/commit/{{$commit.Id}}">{{$commit.Summary}}</a></span>
                     </td>
                     <td class="date">
                         <span class="wrap">{{TimeSince $commit.Committer.When}}</span>

+ 3 - 3
templates/user/profile.tmpl

@@ -11,13 +11,13 @@
         <div class="profile-info">
             <ul class="list-group">
                 {{if .Owner.Location}}
-                    <li class="list-group-item"><i class="fa fa-thumb-tack"></i>{{.Owner.Location}}</li>
+                <li class="list-group-item"><i class="fa fa-thumb-tack"></i>{{.Owner.Location}}</li>
                 {{end}}
                 {{if .Owner.Email}}
-                    <li class="list-group-item"><i class="fa fa-envelope"></i><a href="mailto:{{.Owner.Email}}">{{.Owner.Email}}</a></li>
+                <li class="list-group-item"><i class="fa fa-envelope"></i><a href="mailto:{{.Owner.Email}}" rel="nofollow">{{.Owner.Email}}</a></li>
                 {{end}}
                 {{if .Owner.Website}}
-                    <li class="list-group-item"><i class="fa fa-link"></i><a target="_blank" href="{{.Owner.Website}}">{{.Owner.Website}}</a></li>
+                <li class="list-group-item"><i class="fa fa-link"></i><a target="_blank" href="{{.Owner.Website}}">{{.Owner.Website}}</a></li>
                 {{end}}
                 <li class="list-group-item"><i class="fa fa-clock-o"></i>Joined on {{DateFormat .Owner.Created "M d, Y"}}</li>
                 <!-- <hr> -->

+ 1 - 1
templates/user/signin.tmpl

@@ -10,7 +10,7 @@
         {{end}}
         {{template "base/alert" .}}
         <div class="form-group {{if .Err_UserName}}has-error has-feedback{{end}}">
-            <label class="col-md-4 control-label">Username: </label>
+            <label class="col-md-4 control-label">Username or e-mail: </label>
             <div class="col-md-6">
                 <input name="username" class="form-control" placeholder="Type your username" value="{{.username}}" required="required">
             </div>

+ 0 - 9
tests/.travel.yml

@@ -1,9 +0,0 @@
-command: go test -v {}
-include: ^.+_test\.go$
-path: ./
-depth: 1
-verbose: true
-timeout: 1m
-reload: false
-html: test.html
-notify: []

+ 0 - 13
tests/README.md

@@ -1,13 +0,0 @@
-## Gogs Test
-
-This is for developers.
-
-## Prepare Environment
-
-	go get -u github.com/shxsun/travelexec
-	# start gogs server
-	gogs web
-
-## Start Testing
-
-	travelexec

+ 0 - 17
tests/default_test.go

@@ -1,17 +0,0 @@
-package test
-
-import (
-	"net/http"
-	"testing"
-)
-
-func TestMain(t *testing.T) {
-	r, err := http.Get("http://localhost:3000/")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer r.Body.Close()
-	if r.StatusCode != http.StatusOK {
-		t.Error(r.StatusCode)
-	}
-}